C server socket's read function writing dirty buffer - c

I have the following C server and client:
SERVER
int main(int argc, char **argv) {
int listenfd, connfd, n;
struct sockaddr_in servaddr;
char recvline[1025];
if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("Socket Error");
exit(1);
}
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(1024);
if (bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0) {
perror("Bind Error");
exit(1);
}
if (listen(listenfd, 1024) < 0) {
perror("Listen Error");
exit(1);
}
while(1) {
printf("Waiting connection...\n");
if ((connfd = accept(listenfd, (struct sockaddr *) NULL, NULL)) < 0) {
perror("Accept Error");
exit(1);
}
printf("Waiting for input.\n");
while ((n = read(listenfd, recvline, sizeof(recvline))) > 0) {
recvline[n] = '\0';
if (fputs(recvline, stdout) == EOF) {
fprintf(stderr,"fputs Error\n");
exit(1);
}
}
printf("Read string: %s", recvline);
close(connfd);
}
}
CLIENT
int main(int argc, char **argv) {
int sockfd, connfd, n;
struct sockaddr_in servaddr;
char buff[1025], matricola[15];
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("Socket Error");
exit(1);
}
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(1024);
if (inet_pton(AF_INET, argv[1], &servaddr.sin_addr) < 0) {
fprintf(stderr,"inet_pton Error for %s\n", argv[1]);
exit (1);
}
if (connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0) {
fprintf(stderr,"Connect Error\n");
exit(1);
}
printf("Matricola: ");
fflush(stdin);
scanf("%s", matricola);
strcpy(buff, matricola);
if (write(sockfd, buff, strlen(buff)) != strlen(buff)) {
perror("Write Error");
exit(1);
}
close(connfd);
}
I'm under Linux, I can start the server correctly from terminal that starts listening, but when I open another terminal instance and start the client, the server automatically executes the rest of the code and prints Read string: ### (random characters like dirty buffer). Is this because the server is not waiting for the client to write? What am I doing wrong in this code?
What I tought was that the server didn't wait for the client to write something, so I tried to add a sleep(10) before the server's read command, but nothing changes.
EDIT: I edited the read function from
n = read(listenfd, recvline, strlen(recvline) + 1)) > 0
to
n = read(listenfd, recvline, sizeof(recvline))) > 0
But still it doesn't fix the issue.

Change your inner while cycle to read from the connected file descriptor, not the listening file descriptor, like this:
while ((n = read(connfd, recvline, strlen(recvline) + 1)) > 0) {
recvline[n] = '\0';
if (fputs(recvline, stdout) == EOF) {
fprintf(stderr,"fputs Error\n");
exit(1);
}
}

This line
while ((n = read(listenfd, recvline, sizeof(recvline))) > 0) {
tries to read from the listening socket. This does not make sense.
You need to read from the accepted socket. So it should be:
while ((n = read(connfd, recvline, sizeof(recvline))) > 0) {
Moreover it should be
while ((n = read(connfd, recvline, sizeof(recvline) - 1)) > 0) {
as after the read() you do
recvline[n] = '\0';
For the OP's source if you'd have read sizeof recvline bytes recvline[n] would address one behind the last element of recvline.

Related

file server in C doesn't continually return files when requested

I'm new to network programming and recently finished reading through Beej's guide. I have a client/server program that I'm trying to get to continuously have the server return the contents of a file when the client requests it.
It works by the client sending the server a file path and the server reading it (if it exists) into a buffer then sending the buffer to the client which just prints the buffer.
It works, but it will only return one file then ignores any following requests. I have to shut down the client and reconnect again for it to work again. I can't figure out why. I've tried implementing select() and used aio_read() over the standard read() and I also forking a process for the send() function. Each of those those experiments had it working exactly the same pretty much.
Anyone have any tips? I'm at a loss where the problem could be.
Client
#define MAXDATASIZE 100 // max number of bytes at once
#define MAXMSG 25
#define MAXDATA 4096
#define SA struct sockaddr
// clean_str: make sure the string doesn't have junk spaces around it
void clean_str(char *s)
{
size_t len = strlen(s);
char tmp[MAXMSG] = {0};
strncpy(tmp, s, len-1);
memset(s, 0, len);
strncpy(s, tmp, len-1);
}
int main(int argc, char **argv)
{
int sockfd, numbytes;
struct addrinfo hints, *servinfo, *p;
int rv;
char s[INET6_ADDRSTRLEN];
char file_request[MAXMSG] = {0};
char file_buf[MAXDATA];
if (argc != 3) {
fprintf(stderr, "usage: client <hostname> <port>\n");
exit(EXIT_FAILURE);
}
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
// load the struct
if ((rv = getaddrinfo(argv[1], argv[2], &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
exit(EXIT_FAILURE);
}
// loop trhough all results and connect to the first one we can
for (p = servinfo; p != NULL; p = p->ai_next) {
if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) < 0) {
perror("client: socket");
continue;
}
if (connect(sockfd, p->ai_addr, p->ai_addrlen) < 0) {
close(sockfd);
perror("client: connect");
continue;
}
// if we make it here, we've got a connection
break;
}
if (p == NULL) {
fprintf(stderr, "client: failed to connect\n");
exit(EXIT_FAILURE);
}
inet_ntop(p->ai_family, (SA*)&p->ai_addr, s, sizeof s);
printf("client: connecting to %s\n", s);
freeaddrinfo(servinfo);
// stay connect until client exits
int n;
while (1) {
// make sure everything is cleared to minimize issues
memset(file_buf, 0, MAXDATA);
memset(file_request, 0, sizeof MAXMSG);
numbytes = 0;
// get client request from stdin
int b = read(STDIN_FILENO, file_request, MAXMSG);
if (b < 0) {
perror("client: read");
}
clean_str(file_request);
// send the request to the server
if ((numbytes = send(sockfd, file_request, strlen(file_request), 0)) < 0) {
perror("send");
exit(EXIT_FAILURE);
}
// now we wait for a response
while ((n = read(sockfd, file_buf, MAXDATA-1)) > 0)
printf("%s\n", file_buf);
if (n < 0) {
perror("read");
}
}
return 0;
}
Server
#define PORT 3490
#define MAXDATA 4096
#define FILENAME 256
#define SA struct sockaddr // for less messy casting
// get_file: open file, read contents info a buffer, return buffer
char *get_file(const char *path) {
int n, bytes;
static char buf[MAXDATA];
// try to open file
n = open(path, O_RDONLY);
if (n < 0) {
strcpy(buf, "problem opening file");
printf("%s\n", buf);
return buf;
}
// if exists, read it into buffer on
bytes = read(n, buf, sizeof buf-1);
if (bytes < 0) {
strcpy(buf, "problem reading file");
printf("%s\n", buf);
return buf;
}
close(n);
return buf;
}
int main()
{
int sockfd, filefd;
struct sockaddr_in servaddr;
struct sockaddr_storage client_addr;
socklen_t len;
int nbytes;
char file_request[FILENAME]; // buf to hold client's request string
// clear servaddr struct
memset(&servaddr, 0, sizeof servaddr);
servaddr.sin_family = AF_INET; // IPv4 for simplicity
servaddr.sin_addr.s_addr = htonl(INADDR_ANY); // use my IP
servaddr.sin_port = htons(PORT); // short, network by order
// create socket file descriptor
// #param3 is the protocol. 0 means TCP
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
perror("socket");
exit(EXIT_FAILURE);
}
// bind the socket to the PORT
if (bind(sockfd, (SA*)&servaddr, sizeof servaddr) < 0) {
perror("bind");
exit(EXIT_FAILURE);
}
// this prevents the 'bind: address already in use' issue
int yes = 1;
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes) < 0) {
perror("setsocket");
exit(EXIT_FAILURE);
}
if (listen(sockfd, 10) < 0) {
perror("listen");
exit(EXIT_FAILURE);
}
printf("server running and waiting for connection...\n");
int open = 1; // keep track if there's an accepted() fd
char *open_file;
while (1) {
// clear the file_request buffer
memset(file_request, 0, FILENAME);
memset(&open_file, 0, sizeof open_file);
nbytes = 0;
if (open) {
// we're only going to connect to one client for now
len = sizeof client_addr;
filefd = accept(sockfd, (SA*)&client_addr, &len);
if (filefd < 0) {
perror("accept");
continue;
} else {
printf("connected to a client\n");
open = 0; // keep track that there's an open fd
}
}
// recieve data from a client
if ((nbytes = recv(filefd, file_request, sizeof file_request, 0)) <= 0) {
// got error or connection was closed by client
if (nbytes == 0) {
printf("file-server: client hung up\n");
close(filefd);
open = 1;
continue;
} else {
perror("recv");
close(filefd);
open = 1;
continue;
}
close(filefd);
} else {
// we got some data
// manage it and get file contents
open_file = get_file(file_request);
if (strcmp(open_file, "0") == 0) {
continue;
}
if (send(filefd, open_file, strlen(open_file), 0) < 0) {
perror("send");
continue;
}
}
}
close(sockfd);
return 0;
}

Socket programming, using ip addresses

I have a simple tcp client server program. Client sends text, server prints it ito terminal. I need to make it so client can connect to server by ip address, no just a port (i have it on localhost now). How can I do this? Tried many things, getting errors everytime.
Here's the client code:
int client(char * add) //add is an address passed, either hostname (for ex. google.com)
{ //or just a normal dotted ip (1.2.3.4)
int s, t, len;
struct sockaddr_un remote;
char str[100];
if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
perror("socket");
exit(1);
}
printf("Trying to connect...\n");
remote.sun_family = AF_UNIX;
strcpy(remote.sun_path, SOCK_PATH);
len = strlen(remote.sun_path) + sizeof(remote.sun_family);
if (connect(s, (struct sockaddr *)&remote, len) == -1) {
perror("connect");
exit(1);
}
printf("Connected.\n");
int i=0;
while(fgets(str, 100, stdin)) {
if (send(s, str, strlen(str), 0) == -1) {
perror("send");
exit(1);
}
}
close(s);
return 0;
}
And tere's a server:
int server(void)
{
int s, s2, t, len;
int z;
struct sockaddr_un local, remote;
char str[100];
if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
perror("socket");
exit(1);
}
local.sun_family = AF_UNIX;
strcpy(local.sun_path, SOCK_PATH);
unlink(local.sun_path);
len = strlen(local.sun_path) + sizeof(local.sun_family);
if (bind(s, (struct sockaddr *)&local, len) == -1) {
perror("bind");
exit(1);
}
if (listen(s, 5) == -1) {
perror("listen");
exit(1);
}
for(;;) {
int done, n;
t = sizeof(remote);
if ((s2 = accept(s, (struct sockaddr *) &remote, (socklen_t *) &t)) == -1) {
perror("accept");
exit(1);
}
done = 0;
do {
n = recv(s2, str, 100, 0);
if (n <= 0) {
if (n < 0) perror("recv");
done = 1;
}
if (!done)
printf("%s", str);
fflush(stdout);
sleep(1);
} while (!done);
close(s2);
}
return 0;
}
Can I connect my client with that server using ip address?
My driver funtion chooses if I want to start a server or a client, it's all in one file.
To start a server i use:
./main.o -l [port]
and to start a client I'd want to use:
./main.o [address] [port]
I don't realy know how to translate the address and then use it to connect. I mean, I've tried gethostbyname(), but then I didn't know where tu put this address because sockaddr_un has no address field to fill.

How do I make the program exit when server is disconnected instead of going into an infinte loop?

I have created a server and client communication system in C and when the server is shutdown or quit, the client goes into an infinite loop repeating the last received message instead of quitting. I think the problem lies in recieveMessage function declaration but can't seem to pinpoint it.
How do I resolve this and how can I avoid this in the future?
#include"stdio.h"
#include"stdlib.h"
#include"sys/types.h"
#include"sys/socket.h"
#include"string.h"
#include"netinet/in.h"
#include"netdb.h"
#include"pthread.h"
#define PORT 4444
#define BUF_SIZE 2000
void * receiveMessage(void * socket) {
int sockfd, ret;
char buffer[BUF_SIZE];
sockfd = (int) socket;
memset(buffer, 0, BUF_SIZE);
for (;;) {
ret = recvfrom(sockfd, buffer, BUF_SIZE, 0, NULL, NULL);
if (ret < 0) {
printf("Error receiving data!\n");
break;
} else {
printf("server: ");
fputs(buffer, stdout);
//printf("\n");
}
}
}
int main(int argc, char**argv) {
struct sockaddr_in addr, cl_addr;
int sockfd, ret;
char buffer[BUF_SIZE];
char * serverAddr;
pthread_t rThread;
if (argc > 2) {
printf("usage: client < ip address >\n");
exit(1);
}
serverAddr = argv[1];
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
printf("Error creating socket!\n");
exit(1);
}
printf("Socket created...\n");
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("192.168.31.90");
addr.sin_port = PORT;
ret = connect(sockfd, (struct sockaddr *) &addr, sizeof(addr));
if (ret < 0) {
printf("Error connecting to the server!\n");
exit(1);
}
printf("Connected to the server...\n");
memset(buffer, 0, BUF_SIZE);
printf("Enter your messages one by one and press return key!\n");
//creating a new thread for receiving messages from the server
ret = pthread_create(&rThread, NULL, receiveMessage, (void *) sockfd);
if (ret) {
printf("ERROR: Return Code from pthread_create() is %d\n", ret);
exit(1);
}
while (fgets(buffer, BUF_SIZE, stdin) != NULL) {
ret = sendto(sockfd, buffer, BUF_SIZE, 0, (struct sockaddr *) &addr, sizeof(addr));
if (ret < 0) {
printf("Error sending data!\n\t-%s", buffer);
break;
}
puts(buffer);
}
close(sockfd);
pthread_exit(NULL);
return 0;
}
recvfrom returns zero when the other end of the connection is closed, not < 0.
Change your test of the return result as follows:
if (ret == 0)
{
printf("Connection closed!\n");
exit(0);
}
else if (ret < 0) {
printf("Error connecting to the server!\n");
exit(1);
}

Accepting sequential user input with socket program

My question today is in regards to socket programming. I'm working on a program that creates a client and a server, where the client interacts with the records in the server database via given commands. I'm very new to socket programming, and i've been given some starter code to get the server and client connected and interacting. That being said, i'm very unfamiliar with which part of said code needs to be iterated in order to receive and send another message until the "stop" command is given. Until then, I want the user to continue to be able to send messages to the server.
(relevant) server code:
void error(char *msg)
{
perror(msg);
exit(1);
}
int main () {
int num = 1;
int del;
int sockfd, newsockfd, portno;
socklen_t clilen;
char buffer[256];
struct sockaddr_in serv_addr, cli_addr;
int n;
/*STEP 1*********************************************/
sockfd = socket(AF_INET, SOCK_STREAM, 0);
/*Make sure opening was successful*/
if (sockfd < 0)
error("ERROR opening socket");
/*STEP 2********************************************
0 out the server address*/
memset((char *) &serv_addr, 0, sizeof(serv_addr));
/*convert argument to int*/
portno = PORTNO;
/*this is always the same for this type of connection*/
serv_addr.sin_family = AF_INET;
/*INADDR_ANY is a macro that will find the current machine IP*/
serv_addr.sin_addr.s_addr = INADDR_ANY;
/*make sure byte order is correct
may be a no-op, but better safe than sorry*/
serv_addr.sin_port = htons(portno);
/*STEP 3********************************************/
if (bind(sockfd, (struct sockaddr *) &serv_addr,
sizeof(serv_addr)) < 0) {
error("ERROR on binding");
}
/*STEP 4********************************************
Open server up for listening, if you don't listen
you won't hear*/
listen(sockfd,5);
/*STEP 5******************************************/
clilen = sizeof(cli_addr);
/*Accept blocks until a connection with
a client is made. Returns a new socket
to communicate with the new connection.
Also receives address data about client*/
/*Communicate************************************/
char *array[20];
do {
newsockfd = accept(sockfd,
(struct sockaddr *) &cli_addr,
&clilen);
if (newsockfd < 0)
error("ERROR on accept");
memset(buffer, 0, 256);
printf("%s", "Enter Message:");
n = read(newsockfd,buffer,255);
printf("I read %d\n",n);
if (n < 0) error("ERROR reading from socket");
printf("Here is the message: %s",buffer);
n = write(newsockfd,"I got your message",18);
if (n < 0) error("ERROR writing to socket");
int i = 0;
char *p = strtok(buffer, " ");
while (p != NULL)
{
array[i++] = p;
p = strtok (NULL, " ");
}
if (strcmp(array[0], "put") == 0) {
insert(&front, array);
puts("PUT COMMAND");
} else if (strcmp(array[0], "get") == 0 && strcmp(array[1], "lname") == 0) {
puts("GET LNAME COMMAND");
} else if (strcmp(array[0], "get") == 0 && strcmp(array[1], "fname") == 0) {
puts("GET FNAME COMMAND");
} else if (strcmp(array[0], "get") == 0 && strcmp(array[1], "SID") == 0) {
puts("GET SID COMMAND");
} else if (strcmp(array[0], "get") == 0 && strcmp(array[1], "GPA") == 0) {
puts("GET GPA COMMAND");
} else if (strcmp(array[0], "delete") == 0 && strcmp(array[1], "SID") == 0) {
puts("DELETE COMMAND");
} else {
printf("%s\n", "Not a valid command.");
}
} while (strcmp(array[0], "stop") != 0);
return 0;
}
(relevant) client code:
#define PORTNO 20321
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <unistd.h>
void error(char *msg)
{
perror(msg);
exit(0);
}
int main(int argc, char *argv[])
{
/*set up ints for socket file descriptor
port number and return of read/write*/
int sockfd, portno, n;
int i;
/*structure for server info*/
struct sockaddr_in serv_addr;
/*used to hold the return of the function
that finds our server address, will
be copied into serv_addr*/
struct hostent *server;
/*for our message*/
char buffer[256];
/*make sure usage is correct*/
if (argc < 2) {
fprintf(stderr,"usage %s hostname\n", argv[0]);
exit(0);
}
/*convert our port number*/
portno = PORTNO;
/*create the socket*/
sockfd = socket(AF_INET, SOCK_STREAM, 0);
/*make sure it was made*/
if (sockfd < 0)
error("ERROR opening socket");
/*gethostbyname takes our host domain name and
resolves it to an address, there is a similar
function, gethostbyaddr that takes an address
and returns the same struct, struct hostent*/
server = gethostbyname(argv[1]);
/*make sure the host exists*/
if (server == NULL) {
fprintf(stderr,"ERROR, no such host\n");
exit(0);
}
/*0 out the server address stuct and set members*/
memset((char *) &serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
/*copy the data returned from gethostbyname
into the server address struct*/
memcpy((char *)server->h_addr_list,
(char *)&serv_addr.sin_addr.s_addr,
server->h_length);
serv_addr.sin_port = htons(portno);
/*Request a connection to the server through the socket we set up
make sure it connected, this function will also do the binding
of our socket and server info*/
if (connect(sockfd,(struct sockaddr*) &serv_addr,sizeof(serv_addr)) < 0) {
error("ERROR connecting");
}
for (i = 0; i < 3; i++) {
printf("Choose an operation: \n 1. put ln,fn,mi,SID,GPA\n 2. get lname\n 3. get fname\n 4. get SID\n 5. get GPA\n 6. delete (SID)\n 7. stop\nChoice: ");
/*Retrieve a message to send from the user*/
memset(buffer, 0, 256);
fgets(buffer,255,stdin);
/*send the message to the socket*/
printf("length is %d\n", (int)strlen(buffer));
n = write(sockfd,buffer,strlen(buffer));
if (n < 0)
error("ERROR writing to socket");
memset(buffer, 0, 256);
/*await an incoming message, read stops all process*/
n = read(sockfd,buffer,255);
if (n < 0)
error("ERROR reading from socket");
printf("%s\n",buffer);
return 0;
}
}
My server seems to be waiting for messages correctly, as I can restart my client program and send another message while the server is waiting and it is received as usual. But the way it stands, it will ask for another message, but it doesn't get properly sent/received like the first one did. For now, I have it set to loop 3 times just as a test. How do I properly create this read/write loop to the server?
Assuming you only want to have a single connection at a time then this, untested, version of you while loop should work.
while (true)
{
newsockfd = accept(sockfd,
(struct sockaddr *) &cli_addr,
&clilen);
if (newsockfd < 0)
error("ERROR on accept");
while (true)
{
memset(buffer, 0, 256);
printf("%s", "Enter Message:");
n = read(newsockfd,buffer,255);
printf("I read %d\n",n);
if (n < 0) error("ERROR reading from socket");
printf("Here is the message: %s",buffer);
n = write(newsockfd,"I got your message",18);
if (n < 0) error("ERROR writing to socket");
int i = 0;
char *p = strtok(buffer, " ");
while (p != NULL)
{
array[i++] = p;
p = strtok (NULL, " ");
}
if (strcmp(array[0], "put") == 0) {
insert(&front, array);
puts("PUT COMMAND");
} else if (strcmp(array[0], "get") == 0 && strcmp(array[1], "lname") == 0) {
puts("GET LNAME COMMAND");
} else if (strcmp(array[0], "get") == 0 && strcmp(array[1], "fname") == 0) {
puts("GET FNAME COMMAND");
} else if (strcmp(array[0], "get") == 0 && strcmp(array[1], "SID") == 0) {
puts("GET SID COMMAND");
} else if (strcmp(array[0], "get") == 0 && strcmp(array[1], "GPA") == 0) {
puts("GET GPA COMMAND");
} else if (strcmp(array[0], "delete") == 0 && strcmp(array[1], "SID") == 0) {
puts("DELETE COMMAND");
}
// Checking for stop command here
else if (strcmp(array[0], "stop") ==0)
{
close(newsockfd);
break;
}
else {
printf("%s\n", "Not a valid command.");
}
}
}

What is the reason I am getting: Socket operation on non-socket

I am writing c sockets the send a file from client to server. client() is called in main client program while the server() is called in the server program. send_file() is a helper function for client(). I want the server to wait for another client connection after it finishes getting data from the current client.
The first iteration is fine but I am getting error from accept in the SECOND iteration in the server: server: accept: Socket operation on non-socket
What causes the problem?
int send_file(int socket, char *path) {
int len;
char buf[BUF_SIZE];
char size[BUF_SIZE];
struct stat stbuf;
int fd = open(path, O_RDONLY);
fstat(fd, &stbuf);
sprintf(size, "%d", (int)stbuf.st_size);
write(socket, size, BUF_SIZE);
while((len = read(fd, buf, BUF_SIZE)) > 0) {
write(socket, buf, len);
}
close(fd);
return 1;
}
int client(char *src_path, char *dest_path, char *host_ip, int port) {
int sock_fd;
// Create the sock fd
sock_fd = socket(AF_INET, SOCK_STREAM, 0);
if (sock_fd < 0) {
perror("client: socket");
exit(1);
}
// Set the IP and port of the server to connect to.
struct sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons(port);
if (inet_pton(AF_INET, host_ip, &server.sin_addr) < 1) {
perror("client: inet_pton");
close(sock_fd);
exit(1);
}
// Connect to the server
if (connect(sock_fd, (struct sockaddr *)&server, sizeof(server)) == -1) {
perror("client: connect");
close(sock_fd);
exit(1);
}
send_file(sock_fd, src_path);
return 0;
}
int server(int port) {
printf("PORT: %d\n", port);
char buf[BUF_SIZE];
int sock_fd, client_fd;
int len;
// Create the socket FD.
sock_fd = socket(AF_INET, SOCK_STREAM, 0);
if (sock_fd < 0) {
perror("server: socket");
exit(1);
}
// Set information about the port (and IP) we want to be connected to.
struct sockaddr_in server, client;
server.sin_family = AF_INET;
server.sin_port = htons(PORT);
server.sin_addr.s_addr = INADDR_ANY;
memset(&server.sin_zero, 0, 8);
// Bind the selected port to the socket
if (bind(sock_fd, (struct sockaddr *)&server, sizeof(server)) < 0) {
perror("server: bind");
close(sock_fd);
exit(1);
}
// Announce willingness to accept connections on this socket
if (listen(sock_fd, MAX_BACKLOG) < 0) {
perror("server: listen");
close(sock_fd);
exit(1);
}
while(1) {
socklen_t client_size = sizeof(client);
if ((client_fd = accept(sock_fd, (struct sockaddr *)&client, &client_size)) < 0) {
perror("server: accept");
close(sock_fd);
exit(1);
}
read(client_fd, buf, BUF_SIZE);
int size = atoi(buf);
printf("Size: %d\n", size);
while ((size > 0) && ((len = read(client_fd, buf, BUF_SIZE)) > 0)) {
size -= len;
buf[len] = '\0';
printf("%s", buf);
}
close(client_fd);
}
close(sock_fd);
exit(1);
}
You have a buffer overflow in your read code on the server.
while ((size > 0) && ((len = read(client_fd, buf, BUF_SIZE)) > 0)) {
size -= len;
buf[len] = '\0';
// ^^^ Boom!!!
printf("%s", buf);
}
If you read BUF_SIZE bytes from the socket, len is BUF_SIZE and then you set the byte at buf[BUF_SIZE] to \0. This must be clobbering the socket file descriptor which is declared straight after the buffer.
I should add, the best way to fix it is probably to declare the buffer with size BUF_SIZE + 1 rather than read BUF_SIZE - 1 bytes because the IO will be a bit more efficient (you are writing in BUF_SIZE chunks).

Resources