I'm trying to create a program that demonstrates how issues like heartbleed can occur. This is what I have so far:
#include <stdio.h>
#include <sys/socket.h>
#include <strings.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <stdlib.h>
#define LPORT 5555
#define ACCEPT_QUEUE_SIZE 10
typedef struct sockaddr_in sockaddr_in;
typedef struct sockaddr sockaddr;
const char *login_msg = "=== Welcome to super secure admin control panel! ===\nPlease enter the password:";
const char *login_len_msg = "\nPlease enter the length of the password you entered: ";
const char *incorrect_password_msg = "\nACCESS DENIED USING PASSWORD: ";
const char *correct_password_msg = "\nACCESS GRANTED.\n";
int sockfd = 0;
sockaddr_in serv_addr;
void connection_handler(int connfd, const char *secret_password, char *client_address) {
pid_t my_pid = fork();
if (my_pid < 0) {
fprintf(stderr, "[!] Failed to fork a new process for connection handler\n");
exit(EXIT_FAILURE);
}
if (my_pid == 0) {
if (1) {
send(connfd, login_msg, strlen(login_msg), 0);
char user_resp[51], secret_key[10];
char user_resp_len_msg[6];
int user_resp_len = 0;
bzero(&user_resp, sizeof(user_resp));
bzero(&user_resp_len_msg, sizeof(user_resp_len_msg));
recv(connfd, &user_resp, 50, 0);
fprintf(stderr, "[*] Client %s sent password %s\n", client_address, user_resp);
send(connfd, login_len_msg, strlen(login_len_msg), 0);
recv(connfd, &user_resp_len_msg, 5, 0);
fprintf(stderr, "[*] Client %s sent password length string %s\n", client_address, user_resp_len_msg);
sscanf(user_resp_len_msg, "%d\n", &user_resp_len);
if (strncmp(secret_password, user_resp, strlen(secret_password)) == 0) {
fprintf(stderr, "[+] %s successfully completed the challenge\n", client_address);
send(connfd, correct_password_msg, strlen(correct_password_msg), 0);
}
else {
send(connfd, incorrect_password_msg, strlen(incorrect_password_msg), 0);
send(connfd, user_resp, user_resp_len, 0);
}
close(connfd);
exit(EXIT_SUCCESS);
}
}
void interrupt_handler(int signum) {
fprintf(stderr, "[*] Caught interrupt signal, dying\n");
close(sockfd);
exit(EXIT_SUCCESS);
}
int main(int argc, const char * argv[]) {
if (argc != 2) {
fprintf(stderr, "[!] Usage: %s [server password]\n", argv[0]);
exit(EXIT_FAILURE);
}
setpgrp();
signal(SIGHUP, SIG_IGN);
signal(SIGINT, interrupt_handler);
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
fprintf(stderr, "[!] Failed fo create socket\n");
exit(EXIT_FAILURE);
}
int optval = 1;
if( setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) != 0) {
fprintf(stderr, "[!] Failed to set SO_REUSEADDR option on socket\n");
exit(EXIT_FAILURE);
}
bzero(&serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(LPORT);
if (bind(sockfd, (sockaddr*)&serv_addr, sizeof(serv_addr)) != 0) {
fprintf(stderr, "[!] Failed to bind to port %d\n", LPORT);
exit(EXIT_FAILURE);
}
if (listen(sockfd, ACCEPT_QUEUE_SIZE) != 0) {
fprintf(stderr, "[!] Failed to listen on port %d with queue size %d\n", LPORT, ACCEPT_QUEUE_SIZE);
exit(EXIT_FAILURE);
}
sockaddr_in client_addr;
socklen_t client_addr_len = sizeof(client_addr);
char client_addr_str[INET_ADDRSTRLEN];
while (1) {
bzero(&client_addr, sizeof(client_addr));
bzero(&client_addr_str, sizeof(client_addr_str));
int connfd = accept(sockfd, (sockaddr*)&client_addr, &client_addr_len);
inet_ntop(AF_INET, &client_addr.sin_addr.s_addr, client_addr_str, client_addr_len);
fprintf(stderr, "[*] Got new connection from %s\n", client_addr_str);
connection_handler(connfd, argv[1], client_addr_str);
}
return 0;
}
It's run as ./program [password]. On OSX I noticed that argv got leaked, so I decided that's where the password should go. However, when I tested it on ubuntu this wasn't the case. Is there an easy way to make sure two buffers exist in adjacent parts of memory?
I recognize that predicting undefined behavior is very difficult and there may be no simple answer to the question.
Related
I have a problem with my clients. I used threads to have multiple connections to my server.The clients should connect to the server and talk to each other. The problem is they can't connect to the server.
This is my code:
client.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include<pthread.h>
typedef struct{
int portno;
int sockfd;
const char *ip;
const char *username;
}clients;
clients client;
int server_connect()
{
int sock;
struct sockaddr_in server;
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == -1)
{
errx(1, "Could not create socket");
exit(EXIT_FAILURE);
}
memset(&server, 0, sizeof server);
server.sin_addr.s_addr = inet_addr(client.ip);
server.sin_family = AF_INET;
server.sin_port = htons(client.portno);
if (connect(sock, (struct sockaddr *) &server, sizeof(server)) < 0)
{
errx(1, "Connect failed. Error");
exit(EXIT_FAILURE);
}
fprintf(stdout, "Connected to server\n");
client.sockfd = sock;
pthread_t send_thread, receive_thread;
if (pthread_create(&send_thread, NULL, send_message, (void *) &client.sockfd) < 0)
errx (1, "can not create send thread");
if (pthread_create(&receive_thread, NULL, receive_message, (void *) &client.sockfd) < 0)
errx (1, "can not create receive thread");
pthread_join(send_thread, NULL);
pthread_join(receive_thread, NULL);
close(sock);
return 0;
}
send_message() & receive_message()
void *send_message()
{
char buffer[256], log[256];
snprintf(log, sizeof log, "user %s is joined.", client.username);
if (send(client.sockfd, log, sizeof log, 0) < 0)
errx(1, "Send failed");
while (1) {
fprintf(stdout, "%s","> ");
bzero(buffer,256);
fgets(buffer,255,stdin);
if (send(client.sockfd, buffer, sizeof buffer, 0) < 0) {
errx(1, "Send failed");
}
}
}
void *receive_message() {
while (1) {
char server_reply[2000];
if (recv(client.sockfd, server_reply, 2000, 0) < 0) {
errx(1,"recv failed");
}
//Receive a reply from the server
fprintf(stdout, "%s\n", server_reply);
}
}
Some section of the code is not mine and I found it with search. Would you please help me to find the mistake?
I am trying to do a command line, based on socket communication.My only problem is that after exexvp is executed (and the data are being printed on the client's side), the client close and i want to keep him alive.
This is my code:
client.c
#include <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <string.h>
#include <sys/types.h>
#include <netdb.h>
#define PORT_NUMBER 1754
#define HOST_NUMBER
void error(const char *msg)
{
perror(msg);
exit(0);
}
int main(int argc, char *argv[])
{
int sockfd, port_number, n;
struct sockaddr_in serv_addr;
struct hostent *server;
char buffer[256];
if (argc < 3) {
//fprintf(stderr, "usage %s hostname port\n", argv[0]);
//first parameter is ip address
printf("usage %s hostname port\n", argv[0]);
exit(0);
}
port_number = atoi(argv[2]);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0 )
error("ERROR opening socket!Socket failed!");
printf("Trying to connect...\n");
server = gethostbyname(argv[1]); //ip address
if (server == NULL) {
error( "ERROR, no such host");
//fprintf(stderr, "ERROR, no such host\n"); exit(0);
}
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET; //AF_UNIX
bcopy((char *)server->h_addr, (char *)&serv_addr.sin_addr.s_addr, server->h_length);
serv_addr.sin_port = htons(port_number);
if (connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
error("ERROR connecting");
printf("Connected!\n");
printf("%s_>\n",argv[1]);
while(1) {
printf("Please enter the message: "); //THE CLIENT MUST WRITE A COMMAND
fgets(buffer, 256, stdin); //apo stdin sto buffer
n = write(sockfd, buffer, strlen(buffer)); //apo buffer sto socket
if(n < 0 ) {
error("ERROR writing to socket");
}
bzero(buffer, 256);
if ( recv(sockfd, buffer, 256, 0) < 0) {
printf("Server closed connection\n");
}
printf("%s\n", buffer);
}
return 0;
}
sever.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <sys/wait.h>
#include <errno.h>
void parse(char *vector_args[20], char *buffer){
buffer[strcspn(buffer, "\n")] =0;
int i=0;
char * pch;
pch = strtok (buffer," ");
while (pch != NULL )
{
vector_args[i]=pch;
printf (" %s\n",pch);
pch = strtok (NULL, " ");
i++;
}
vector_args[i]=NULL;
int k=0;
for(k=0; k<=i; k++) {
printf("vector %d = %s \n",k,vector_args[k]);
}
}
int main(int argc, char *argv[])
{
int sockfd, newsockfd, portno;
socklen_t clilen;
char buffer[256];
struct sockaddr_in serv_addr, cli_addr;
int n;
char str[INET_ADDRSTRLEN];
char *vector_args[20];
int status;
char *fd[2];
if (argc < 2)
{
fprintf(stderr, "No port provided\n");
exit(1);
}
unlink("sockfd"); //remove any old socket
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
if (bind(sockfd,(struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
error("ERROR on binding");
int l = listen(sockfd, 5);
if (l < 0)
{
error("listen failed!");
}
clilen = sizeof(cli_addr);
printf( "Server waiting for a connection...\n " );
while(1) {
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
if (newsockfd < 0)
error("ERROR on accept");
if (inet_ntop(AF_INET, &cli_addr.sin_addr, str, INET_ADDRSTRLEN) == NULL) {
fprintf(stderr, "Could not convert byte to address\n");
exit(1);
}
fprintf(stdout, "Connected!\nThe client address is :%s\n", str);
//fork new process
int pid = fork();
if (pid == -1 ) {
error("ERROR in new process creation");
close(newsockfd);
continue;
}else if( pid != 0){
//parent process
close(newsockfd);//h edw h prin to continue
printf( " I am parent process %d\n " ,getpid()); //BGALE
if (wait(&status)== -1) /* Wait for child*/
{
perror( " wait " );
}
check_child_exit(status);
continue;
}else if (pid == 0) {
//child process
close(sockfd);
bzero(buffer, 256);
while(1) {
n = read(newsockfd, buffer, 255); //apo socket ston buffer
if (n < 0 )
error("ERROR reading from socket");
printf("Here is the message: %s\n", buffer);
n = write(newsockfd, "I got your message", 18);
bzero(buffer, 256);
close(1); //close stdin
dup2( newsockfd, 1);
close(0); //close stdout
dup2( newsockfd, 0);
parse(vector_args,buffer);
execvp(vector_args[0] , vector_args );
perror( " execvp " );
exit(EXIT_FAILURE);
bzero(buffer, 256);
}
close(newsockfd);
break;
}
}
}
Do you have any ideas how could I change my code in order to work properly?
The loop
while (1) {
....
execvp(....);
}
is effectively executed once. The reason is that the successful execvp replaces the code with whatever vector_args requests, and the executed process just exits when done.
If I understand your goals correctly (one process per connection, executing external commands in the loop), you need one more fork, along the lines of
while (1) {
....
if ((pid = fork()) == 0) {
execvp(....);
} else if (pid > 0) {
waitpid(....);
} else {
handle_error();
}
}
If client send pwd, server may recv p w d or pw d or pwd and so on.
In my opinion, if client want to send pwd, client should send pwd\n, server will read command until \n. If server want to send 123, server should send 123\0, client will read until \0. I write a tiny example, you could learn from it. The server code will continue until client quit.
server.c
#include <arpa/inet.h>
#include <errno.h>
#include <netinet/in.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
void parse(char** argv, char* buffer) {
int i = 0;
argv[i] = strtok(buffer, " ");
while (argv[i] != NULL) argv[++i] = strtok(NULL, " ");
}
void handle_client(int con_socket) {
for (;;) {
char buf[1024];
ssize_t i = 0;
for (;;) {
ssize_t ret = read(con_socket, buf + i, 1);
if (ret == 0) return;
if (buf[i] == '\n') {
buf[i] = '\0';
break;
}
++i;
}
int pipe_fd[2];
pipe(pipe_fd);
if (fork() == 0) {
close(con_socket);
dup2(pipe_fd[1], 1);
close(pipe_fd[0]);
close(pipe_fd[1]);
char* argv[25];
parse(argv, buf);
execvp(argv[0], argv);
exit(EXIT_FAILURE);
} else {
close(pipe_fd[1]);
for (;;) {
ssize_t ret = read(pipe_fd[0], buf, sizeof(buf));
if (ret == 0) {
write(con_socket, "", 1);
break;
}
write(con_socket, buf, ret);
}
wait(NULL);
}
}
}
int main() {
const char* server_ip = "127.0.0.1";
uint16_t server_port = 6666;
struct sockaddr_in server_addr;
bzero(&server_addr, sizeof server_addr);
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(server_port);
inet_pton(AF_INET, server_ip, &server_addr.sin_addr);
int listen_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
int opt = 1;
setsockopt(listen_socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
bind(listen_socket, (struct sockaddr*)(&server_addr),
(socklen_t)(sizeof server_addr));
listen(listen_socket, 5);
for (;;) {
int con_socket = accept(listen_socket, NULL, NULL);
if (fork() > 0) {
close(con_socket);
wait(NULL);
continue;
} else {
close(listen_socket);
handle_client(con_socket);
close(con_socket);
break;
}
}
return 0;
}
client.c
#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
int main() {
const char* server_ip = "127.0.0.1";
uint16_t server_port = 6666;
struct sockaddr_in server_addr;
bzero(&server_addr, sizeof server_addr);
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(server_port);
inet_pton(AF_INET, server_ip, &server_addr.sin_addr);
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr));
for (;;) {
printf(">> ");
char buffer[256];
fgets(buffer, 256, stdin);
if (strlen(buffer) == 0) continue;
write(sockfd, buffer, strlen(buffer));
for (;;) {
ssize_t ret = recv(sockfd, buffer, 256, 0);
buffer[ret] = '\0';
printf("%s", buffer);
if (buffer[ret - 1] == '\0') break;
}
}
return 0;
}
I have been looking everywhere for an answer. I am new to coding in C and would have loved it if my Professor would have allowed us to choose the language, but I digress. I am running Oracle V-Box locally running Ubuntu client and a Ubuntu server. I compile the code below on both the server and the client, with a few warnings. I run the code on the server (seems fine) and then on the client. The client is asking to send over a PDF file just like I did with the TCP socket transfer (which worked great). I also have Wireshark running on the client and server, and it looks like the request is sent out from the client but the server doesn't do anything and just sits on both ends without pulling the file over. Not sure if it is the code or something else.
/* Echo server using UDP */
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define SERVER_UDP_PORT 2466
#define MAXLEN 4096
int main(int argc, char **argv)
{
int sd, client_len, port, n;
char buf[MAXLEN];
struct sockaddr_in server, client;
switch(argc) {
case 1:
port = SERVER_UDP_PORT;
break;
case 2:
port = atoi(argv[1]);
break;
default:
fprintf(stderr, "Usage: %s [port]\n", argv[0]);
exit(1);
}
/* Create a datagram socket */
if ((sd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
fprintf(stderr, "Can't create a socket\n");
exit(1);
}
/* Bind an address to the socket */
bzero((char *)&server, sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(port);
server.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(sd, (struct sockaddr *)&server,
sizeof(server)) == -1) {
fprintf(stderr, "Can't bind name to socket\n");
exit(1);
}
while (1) {
client_len = sizeof(client);
if ((n = recvfrom(sd, buf, MAXLEN, 0,
(struct sockaddr *)&client, &client_len)) < 0) {
fprintf(stderr, "Can't receive datagram\n");
exit(1);
}
if (sendto(sd, buf, n, 0,
(struct sockaddr *)&client, client_len) != n) {
fprintf(stderr, "Can't send datagram\n");
exit(1);
}
}
close(sd);
return(0);
}
This is the client code
// UDP Echo Client
#include <stdio.h>
#include <string.h>
#include <sys/time.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define SERVER_UDP_PORT 2466
#define MAXLEN 4096
#define DEFLEN 64
long delay(struct timeval t1, struct timeval t2)
{
long d;
d = (t2.tv_sec - t1.tv_sec) * 1000;
d += ((t2.tv_usec - t1.tv_usec + 500) / 1000);
return(d);
}
int main(int argc, char **argv)
{
int data_size = DEFLEN, port = SERVER_UDP_PORT;
int i, j, sd, server_len;
char *pname, *host, rbuf[MAXLEN], sbuf[MAXLEN];
struct hostent *hp;
struct sockaddr_in server;
struct timeval start, end;
unsigned long address;
pname = argv[0];
argc--;
argv++;
if (argc > 0 && (strcmp(*argv, "-s") == 0)) {
if (--argc > 0 && (data_size = atoi(*++argv))) {
argc--;
argv++;
}
else {
fprintf(stderr,
"Usage: %s [-s data_size] host [port]\n", pname);
exit(1);
}
}
if (argc > 0) {
host = *argv;
if (--argc > 0)
port = atoi(*++argv);
}
else {
fprintf(stderr,
"Usage: %s [-s data_size] host [port]\n", pname);
exit(1);
}
if ((sd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
fprintf(stderr, "Can't create a socket\n");
exit(1);
}
bzero((char *)&server, sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(port);
if ((hp = gethostbyname(host)) == NULL) {
fprintf(stderr, "Can't get server's IP address\n");
exit(1);
}
bcopy(hp->h_addr, (char *) &server.sin_addr, hp->h_length);
if (data_size > MAXLEN) {
fprintf(stderr, "Data is too big\n");
exit(1);
}
for (i = 0; i < data_size; i++) {
j = (i < 26) ? i : i % 26;
sbuf[i] = 'a' + j;
} // construct data to send to the server
gettimeofday(&start, NULL); /* start delay measurement */
server_len = sizeof(server);
if (sendto(sd, sbuf, data_size, 0, (struct sockaddr *)
&server, server_len) == -1) {
fprintf(stderr, "sendto error\n");
exit(1);
}
if (recvfrom(sd, rbuf, MAXLEN, 0, (struct sockaddr *)
&server, &server_len) < 0) {
fprintf(stderr, "recvfrom error\n");
exit(1);
}
gettimeofday(&end, NULL); /* end delay measurement */
if (strncmp(sbuf, rbuf, data_size) != 0)
printf("Data is corrupted\n");
close(sd);
return(0);
}
Once I compile I run the code on Server normally:
./udp_server
and just sits waiting from the client.
Once I compile I run the code on Client:
./udp_client -s 1500 10.0.2.11 2466 > test.pdf
I run this which is (./udp_client -s data_rate server_IP Server_Port > (output to file on desktop of client))
This just produces a blank page. It should have a few pages of text and pics.
I also am getting the send out from client on Wireshark but no reply from server.
This is what i am getting when i run STRACE from terminal
strace ./udp_server
I think you just forgot to print out the received data in the client:
if (strncmp(sbuf, rbuf, data_size) != 0)
printf("Data is corrupted\n");
close(sd);
printf(rbuf); // <----
return(0);
Your client code currently only prints out error messages. If everything works, it won't produce any output.
So I am trying to work on this toy client file server problem.
The iterative version works fine, but when I attempt to fork each new connection in the server code, the client code hangs on the recv call.
I am fairly sure the issue is with the peer_socket, but I have been unable to find my mistake.
It completes just fine if I hit the server with a Ctrl-c though.
CLIENT CODE:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netinet/in.h>
#define PORT_NUMBER 5108
#define SERVER_ADDRESS "localhost"
//#define FILENAME "test.txt"
int main(int argc, char **argv)
{
int client_socket;
ssize_t len;
struct sockaddr_in remote_addr;
char buffer[BUFSIZ];
char filename[256];
char local_filename[256];
int file_size;
FILE *received_file;
int remain_data = 0;
/* Zeroing remote_addr struct */
memset(&remote_addr, 0, sizeof(remote_addr));
memset(local_filename, 0, sizeof(local_filename));
if(argc >1){
strncpy(local_filename, argv[1], 256);
}
/* Construct remote_addr struct */
remote_addr.sin_family = AF_INET;
inet_pton(AF_INET, SERVER_ADDRESS, &(remote_addr.sin_addr));
remote_addr.sin_port = htons(PORT_NUMBER);
/* Create client socket */
client_socket = socket(AF_INET, SOCK_STREAM, 0);
if (client_socket == -1)
{
fprintf(stderr, "Error creating socket --> %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
//Prompt for file to retrieve
printf("Enter file name: ");
fgets(filename,sizeof(filename),stdin);
printf("Getting file %s", filename);
/* Connect to the server */
if (connect(client_socket, (struct sockaddr *)&remote_addr, sizeof(struct sockaddr)) == -1)
{
fprintf(stderr, "Error on connect --> %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
//Send filename to server
/*if(!send(client_socket,filename, sizeof(filename))) {
printf("Error sending filename\n");
exit(EXIT_FAILURE);
}*/
send(client_socket,filename, sizeof(filename),0);
printf("success\n");
/* Receiving file size */
memset(&buffer, 0, sizeof(buffer));
recv(client_socket, buffer, sizeof(buffer), 0);
file_size = atoi(buffer);
fprintf(stdout, "\nFile size : %d\n", file_size);
if(!local_filename[0]) {
received_file = fopen("test2.txt", "w");
}else{
received_file = fopen(local_filename, "w");
}
if (received_file == NULL)
{
fprintf(stderr, "Failed to open file foo --> %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
remain_data = file_size;
//THIS IS THE LOOP THAT HANGS!
while (((len = recv(client_socket, buffer, BUFSIZ, 0)) > 0) && (remain_data > 0))
{
fwrite(buffer, sizeof(char), len, received_file);
remain_data -= len;
fprintf(stdout, "Receive %d bytes and we hope :- %d bytes\n", len, remain_data);
}
printf("did we reach here in the code?\n");
fclose(received_file);
printf("did we reach here in the code?\n");
close(client_socket);
return 0;
}
SERVER CODE:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netinet/in.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/sendfile.h>
#include <signal.h>
#define PORT_NUMBER 5108
#define SERVER_ADDRESS "localhost"
//#define FILE_TO_SEND "hello.c"
int main(int argc, char **argv)
{
int server_socket;
socklen_t global_sock_len;
struct sockaddr_in server_addr;
struct sockaddr_in peer_addr;
/* Create server socket */
server_socket = socket(AF_INET, SOCK_STREAM, 0);
if (server_socket == -1)
{
fprintf(stderr, "Error creating socket --> %s", strerror(errno));
exit(EXIT_FAILURE);
}
/* Zeroing server_addr struct */
memset(&server_addr, 0, sizeof(server_addr));
/* Construct server_addr struct */
server_addr.sin_family = AF_INET;
inet_pton(AF_INET, SERVER_ADDRESS, &(server_addr.sin_addr));
server_addr.sin_port = htons(PORT_NUMBER);
/* Bind */
if ((bind(server_socket, (struct sockaddr *)&server_addr, sizeof(struct sockaddr))) == -1)
{
fprintf(stderr, "Error on bind --> %s", strerror(errno));
exit(EXIT_FAILURE);
}
/* Listening to incoming connections */
if ((listen(server_socket, 5)) == -1)
{
fprintf(stderr, "Error on listen --> %s", strerror(errno));
exit(EXIT_FAILURE);
}
//attempt multiple connections via fork
int peer_socket;
int fid;
while(1) {
bool servexit = false;
printf("did we reach HERE in the code?%d\n",getpid());
peer_socket = accept(server_socket, (struct sockaddr *) &peer_addr, &global_sock_len);
//printf("did we reach HERE in the code?\n");
if (peer_socket == -1) {
fprintf(stderr, "Error on accept --> %s", strerror(errno));
exit(EXIT_FAILURE);
}
if((fid = fork()) == -1) {
printf("error\n");
close(peer_socket);
//continue;
}else if(fid > 0){
printf("parent\n");
close(peer_socket);
//continue;
}else if(fid == 0) {
printf("child\n");
socklen_t sock_len;
ssize_t len;
int fd;
int sent_bytes = 0;
char FILE_TO_SEND[256];
char file_size[256];
struct stat file_stat;
off_t offset;
int remain_data;
//int peer_socket = peer_socket;
recv(peer_socket, FILE_TO_SEND, sizeof(FILE_TO_SEND), 0);
printf("Client requested %s", FILE_TO_SEND);
if (strlen(FILE_TO_SEND) > 1) {
strtok(FILE_TO_SEND, "\n");
}
//check for server close command from client
if(strcmp(FILE_TO_SEND,"quit") == 0){
servexit = true;
printf("Quiting server\n");
close(server_socket);
close(peer_socket);
pid_t pid = getppid();
kill(pid, SIGKILL);
exit(0);
}else {
fd = open(FILE_TO_SEND, O_RDONLY);
if (fd == -1) {
fprintf(stderr, "Error opening file --> %s", strerror(errno));
exit(EXIT_FAILURE);
}
/* Get file stats */
if (fstat(fd, &file_stat) < 0) {
fprintf(stderr, "Error fstat --> %s", strerror(errno));
exit(EXIT_FAILURE);
}
fprintf(stdout, "File Size: \n%d bytes\n", file_stat.st_size);
sock_len = sizeof(struct sockaddr_in);
fprintf(stdout, "Accept peer --> %s\n", inet_ntoa(peer_addr.sin_addr));
sprintf(file_size, "%d", file_stat.st_size);
/* Sending file size */
len = send(peer_socket, file_size, sizeof(file_size), 0);
if (len < 0) {
fprintf(stderr, "Error on sending greetings --> %s", strerror(errno));
exit(EXIT_FAILURE);
}
fprintf(stdout, "Server sent %d bytes for the size\n", len);
//fflush((FILE*)peer_socket);
offset = 0;
remain_data = file_stat.st_size;
/* Sending file data */
while (((sent_bytes = sendfile(peer_socket, fd, &offset, BUFSIZ)) > 0) && (remain_data > 0)) {
fprintf(stdout,
"1. Server sent %d bytes from file's data, offset is now : %d and remaining data = %d\n",
sent_bytes, offset, remain_data);
remain_data -= sent_bytes;
fprintf(stdout,
"2. Server sent %d bytes from file's data, offset is now : %d and remaining data = %d\n",
sent_bytes, offset, remain_data);
}
}
break;
}
}
return 0;
}
Ok, so, it turns out that sendfile() doesn't play as nicely as send() in this situation. I found two fixes.
1.) Use send() instead of sendfile()
2.) Retry in both sendfile() (Server) and recv() (client) if either returns -1 (error)
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I'm trying to send data from a server to a client whenever the client executes a recv() command. As the code stands right now, I cannot get the client to print any data it receives. I cannot figure out whether something is wrong with my server or client, so any help would be appreciated. Thanks!
client.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#define ECHO_PORT 9999
#define BUF_SIZE 4096
int main(int argc, char* argv[])
{
if (argc != 3)
{
fprintf(stderr, "usage: %s <server-ip> <port>",argv[0]);
return EXIT_FAILURE;
}
char buf[BUF_SIZE];
int status, sock, sock2;
struct addrinfo hints;
memset(&hints, 0, sizeof(struct addrinfo));
struct addrinfo *servinfo; //will point to the results
hints.ai_family = AF_INET; //IPv4
hints.ai_socktype = SOCK_STREAM; //TCP stream sockets
hints.ai_flags = AI_PASSIVE; //fill in my IP for me
if ((status = getaddrinfo(argv[1], argv[2], &hints, &servinfo)) != 0)
{
fprintf(stderr, "getaddrinfo error: %s \n", gai_strerror(status));
return EXIT_FAILURE;
}
if ((sock = socket(servinfo->ai_family, servinfo->ai_socktype, servinfo->ai_protocol)) == -1)
{
fprintf(stderr, "Socket failed");
return EXIT_FAILURE;
}
if ((connect(sock, (struct sockaddr *) servinfo->ai_addr, servinfo->ai_addrlen)) != 0)
{
fprintf(stderr, "Connection failed");
return EXIT_FAILURE;
}
if ((sock2 = socket(servinfo->ai_family, servinfo->ai_socktype, servinfo->ai_protocol)) == -1)
{
fprintf(stderr, "Socket failed");
return EXIT_FAILURE;
}
if ((connect(sock2, (struct sockaddr *) servinfo->ai_addr, servinfo->ai_addrlen)) != 0)
{
fprintf(stderr, "Connection failed");
return EXIT_FAILURE;
}
while (1) {
//char msg[BUF_SIZE] = "ashudfshuhafhu";
//char msg[BUF_SIZE];
//fgets(msg, BUF_SIZE, stdin);
//int i = 2;
//if (strlen(msg) == i)
// break;
int bytes_received;
// fprintf(stdout, "Sending %s", msg);
//send(sock, msg , strlen(msg), 0);
if((bytes_received = recv(sock, buf, BUF_SIZE, 0)) > 1)
{
buf[bytes_received] = '\0';
fprintf(stdout, "Received %s", buf);
}
}
freeaddrinfo(servinfo);
close(sock);
return EXIT_SUCCESS;
}
Server.c
#include <netinet/in.h>
#include <netinet/ip.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#define ECHO_PORT 9999
#define BUF_SIZE 4096
int close_socket(int sock)
{
if (close(sock))
{
fprintf(stderr, "Failed closing socket.\n");
return 1;
}
return 0;
}
int main(int argc, char* argv[])
{
int sock, client_sock;
ssize_t readret;
socklen_t cli_size;
struct timeval tv;
struct sockaddr_in addr, cli_addr;
char buf[BUF_SIZE] = "wetwetwetwetwetwetwetwet";
fd_set readfds, writefds;
fd_set activereadfds, activewritefds;
cli_size = sizeof(&cli_addr);
tv.tv_sec = 5;
tv.tv_usec = 0;
fprintf(stdout, "----- Echo Server -----\n");
/* all networked programs must create a socket */
if ((sock = socket(PF_INET, SOCK_STREAM, 0)) == -1)
{
fprintf(stderr, "Failed creating socket.\n");
return EXIT_FAILURE;
}
addr.sin_family = AF_INET;
addr.sin_port = htons(ECHO_PORT);
addr.sin_addr.s_addr = INADDR_ANY;
/* servers bind sockets to ports---notify the OS they accept connections */
if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)))
{
close_socket(sock);
fprintf(stderr, "Failed binding socket.\n");
return EXIT_FAILURE;
}
if (listen(sock, 5))
{
close_socket(sock);
fprintf(stderr, "Error listening on socket.\n");
return EXIT_FAILURE;
}
FD_ZERO(&readfds);
FD_SET(sock, &activereadfds);
while (1)
{
fprintf(stdout,"in here.\n");
readfds = activereadfds;
writefds = activewritefds;
FD_ZERO(&activereadfds);
FD_ZERO(&activewritefds);
if (select(51, &readfds, &writefds, NULL, &tv) < 0)
{
perror("select");
return EXIT_FAILURE;
}
for (int i = 0; i < 10; ++i)
{
if (FD_ISSET (i, &readfds))
{
if (i == sock)
{
fprintf(stdout, "main loop. \n");
client_sock = accept(sock,
(struct sockaddr *) &cli_addr, &cli_size);
FD_SET(client_sock, &activereadfds);
FD_SET(client_sock, &activewritefds);
if (client_sock < 0)
{
perror("accept");
return EXIT_FAILURE;
}
} else {
fprintf(stdout, "second loop \n");
readret = send(i,buf, strlen(buf),0);
if (readret < 0)
fprintf(stdout, "yay");
}
}
if (FD_ISSET(i, &writefds))
{ fprintf(stdout, "ugh \n");
readret = send(i,buf,BUF_SIZE,0);
//if (readret > 0)
//while((readret = recv(i, buf, BUF_SIZE, 0)) >= 1)
// {
//if (send(i, buf, readret, 0) != readret)
//{
// close_socket(i);
// close_socket(sock);
// fprintf(stderr, "Error sending to client.\n");
// return EXIT_FAILURE;
//}
}
}
}
close_socket(sock);
return EXIT_SUCCESS;
}
Your server is sending only when the socket is ready for reading, and as the client is never sending, the server isn't either. The server send should happen when the client socket turns up in the writefds, although actually this isn't the correct way to use that feature. Really you should just send, and only add into and worry about writefds if send() caused EAGAIN/EWOULDBLOCK.
You could be getting an undetected error in the client:
if((bytes_received = recv(sock, buf, BUF_SIZE, 0)) > 1)
{
buf[bytes_received] = '\0';
fprintf(stdout, "Received %s", buf);
}
This should continue:
else if (bytes_received == 0)
{
fprintf(stdout, "peer disconnected\n");
break;
}
else // < 0: error
{
fprintf(stdout, "recv() error %s\n", strerror(errno));
break;
}
You need to print the actual error like this whenever you get an error from a system call.