I'm having problem of segmentation fault while coding a multithreaded ftp protocol within a Linux environment. This segmentation is due to fclose() file function.
This is my code
Client code: it tests what ever the client writes as a command. For example, if he writes "put filename", it sends this file to the server by opening this file, reading it stream by stream into a buffer. These streams are sent via a socket to the server side.
#include <stdio.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#include <string.h>
#include <netinet/in.h> /* struct sockaddr_in, htons() */
#include <arpa/inet.h> /* inet_aton() */
#include <stdlib.h>
#define BUF_LENGTH 100
/*void getcmdstring(char ** args, char *cmd)
{
int i=0;
char * pch;
pch = strtok (cmd," ");
while (pch != NULL)
{
//args[i]=pch;
stpcpy(args[i],pch);
printf("%s,",args[i]);
//printf("%s,",pch);
pch = strtok (NULL, " ");
i++;
}
//args[i]=NULL;
//return argsVar;
}*/
int main(int argc, char ** argv)
{
int port;
int sock = -1;
struct sockaddr_in address;
//struct hostent * host;
int len;
//char ** args;
/* checking commandline parameter */
if (argc != 3)
{
printf("usage: %s hostIP port \n", argv[0]);
return -1;
}
/* obtain port number */
if (sscanf(argv[2], "%d", &port) <= 0)
{
fprintf(stderr, "%s: error: wrong parameter: port\n", argv[0]);
return -2;
}
// port = atoi(argv[2]);
/* create socket */
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock <= 0)
{
fprintf(stderr, "%s: error: cannot create socket\n", argv[0]);
return -3;
}
/* connect to server */
bzero(&address, sizeof(address));
address.sin_family = AF_INET;
address.sin_port = htons(port);
if(inet_aton(argv[1], &address.sin_addr) <=0){
fprintf(stderr,"inet_aton error for %s\n", argv[1]);
return -4;
}
/*host = gethostbyname(argv[1]);
if (!host)
{
fprintf(stderr, "%s: error: unknown host %s\n", argv[0], argv[1]);
return -4;
}
memcpy(&address.sin_addr, host->h_addr_list[0], host->h_length);*/
if (connect(sock, (struct sockaddr *)&address, sizeof(address))<0)
{
fprintf(stderr, "%s: error: cannot connect to host %s\n", argv[0], argv[1]);
return -5;
}
char cmd[4096], cmd2[4096];
char *fileS_path;
char cwd[2048];
char buf_S[BUF_LENGTH];
int varS;
char *fileR_path;
char cwd2[2048];
char buf_R[BUF_LENGTH];
int varR, varR2;
char ** res = NULL;
char * p = strtok (cmd2, " ");
int n_spaces = 0, i;
FILE *fileS;
while(1){
printf("ftp>");
fgets(cmd,4096,stdin);
strcpy(cmd2, cmd);
//printf("Cmd just after fgets: %s\n", cmd);
p = strtok (cmd2, " ");
n_spaces = 0;
if(cmd==NULL || strcmp(cmd, "")==0)
printf("Something wrong with reading the command from the screen\n");
else
{
/* split string and append tokens to 'res' */
while (p) {
res = realloc (res, sizeof (char*) * ++n_spaces);
if (res == NULL)
exit (-1); /* memory allocation failed */
res[n_spaces-1] = p;
p = strtok (NULL, " \n");
}
/* realloc one extra element for the last NULL */
res = realloc (res, sizeof (char*) * (n_spaces+1));
res[n_spaces] = 0;
/* print the result */
for (i = 0; i < (n_spaces+1); ++i)
printf ("res[%d] = %s\n", i, res[i]);
//printf("bar");
//printf("%s test before sending to socket\n", cmd);
//if(write(sock, cmd, 4096)<0)
//printf("problem with sending the socket command \n");
//else
//{
if(strcmp(res[0], "quit\n")==0)
break;
else if(res[0]!=NULL && res[1] !=NULL && strcmp(res[0], "put")==0)
{
if(write(sock, cmd, 4096)<0)
printf("problem with sending the socket command \n");
else{
// Sending file from the client to the server
printf("\n");
printf("****SENDING****\n");
if(getcwd(cwd,sizeof(cwd))!=NULL)
{
fileS_path=cwd;
strcat(fileS_path, "/");
strcat(fileS_path, res[1]);
}
printf("Sending the file %s to the server...\n", fileS_path);
printf("%s\n", fileS_path);
fileS = fopen(fileS_path, "r");
printf("OK apres creation file\n");
if(fileS==NULL)
fprintf(stderr, "File %s is not found. \n", fileS_path);
else
{
printf("else after creation file\n");
bzero(buf_S,BUF_LENGTH);
printf("bzero buffer1\n");
varS=-1;
printf("after initializing varS %d \n", varS);
while((varS=fread(buf_S, sizeof(char), BUF_LENGTH,fileS))>0)
{
printf("entering to the file loop %d \n", varS);
if(write(sock, buf_S, varS)<0){
printf("erreur");
fprintf(stderr, "Cannot send the file %s \n", fileS_path); exit;}
bzero(buf_S,BUF_LENGTH);
printf("bzero buffer2\n");
}
printf("The file was sent from the client to the server\n");
if(fileS!=NULL)
fclose(fileS);
printf("close fileS");
}
}
}
else if(res[0]!=NULL && res[1] !=NULL && strcmp(res[0], "get")==0)
{
if(write(sock, cmd, 4096)<0)
printf("problem with sending the socket command \n");
else{
printf("\n\n");
// Receiving file from the server to the client
printf("****RECEIVING****\n");
if(getcwd(cwd2,sizeof(cwd2))!=NULL){
fileR_path = cwd2;
strcat(fileR_path, "/");
strcat(fileR_path, res[1]);
}
printf("Receiving the file %s from the SERVER...\n", fileR_path);
FILE *fileR = fopen(fileR_path, "w");
if(!fileR)
fprintf(stderr, "File %s cannot be opened. \n", fileR_path);
else
{
bzero(buf_R,BUF_LENGTH);
varR =-1; varR2 =-1;
while((varR=read(sock, buf_R, BUF_LENGTH))>=0)
{
varR2=fwrite(buf_R, sizeof(char), varR,fileR);
if (varR2< varR)
fprintf(stderr, "Cannot write the file %s on the client \n", fileR_path);
bzero(buf_R,BUF_LENGTH);
if(varR == 0 || varR !=BUF_LENGTH)
break;
}
if(varR<0){
printf("Receiving failure while reading from the socket\n"); return -8;}
printf("The file was received from the SERVER to the CLIENT\n\n");
fclose(fileR);
}
}
}
else if( res[0]!=NULL && strcmp(res[0], "cd\n")==0)
{
if(write(sock, cmd, 4096)<0)
printf("Problem with sending the socket command \n");
if(read(sock, cwd, sizeof(cwd))<0)
printf("Problem reading the current working directory of the server \n");
else
printf("CWD of the server: %s",cwd);
}
else
{
printf("Wrong command, please try again\n");
}
//}
bzero(cmd, 4096);
printf("bzero cmd\n");
/* free the memory allocated */
free (res);
printf("free res\n");
}
}
/* close socket */
close(sock);
printf("exit now\n");
return 0;
}
The server side: try to catch the command via a socket. Then, it tests the command if it is a valid command. for example, if it is a put command, it reads the streams coming from client via the socket (read). Then, open a file and write into it the these streams.
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <sys/socket.h>
#include <linux/in.h>
#include <unistd.h>
//#include <netinet/in.h> /* struct sockaddr_in, htons() */
//#include <arpa/inet.h> /* inet_aton() */
#include <string.h>
#define BUF_LENGTH 100
#define MAXQ 10
typedef struct
{
int sock;
struct sockaddr address;
int addr_len;
} connection_t;
void * process(void * ptr)
{
char * buffer;
int len;
connection_t * conn;
long addr = 0;
char cmd[4096], cmd2[4096];
char ** res = NULL;
char * p = strtok (cmd2, " ");
int n_spaces = 0, i;
char *fileR_path;
char cwd[2048];
char buf_R[BUF_LENGTH];
FILE * fileR;
int varR, varR2;
if (!ptr) pthread_exit(0);
conn = (connection_t *)ptr;
while (1) // (strcmp(res[0],"exit")!=0)
{
printf("before reading the socket\n");
if(read(conn->sock, cmd, 4096)<0)
printf("Problem with reading the command from the server\n");
if (cmd ==NULL || strcmp(cmd, "")==0)
printf("receiving NULL command\n");
else
{
printf("After getting the command %s\n", cmd);
strcpy(cmd2, cmd);
p = strtok (cmd2, " ");
n_spaces = 0;
/* split string and append tokens to 'res' */
while (p) {
res = realloc (res, sizeof (char*) * ++n_spaces);
if (res == NULL)
exit (-1); /* memory allocation failed */
res[n_spaces-1] = p;
p = strtok (NULL, " \n");
}
/* realloc one extra element for the last NULL */
res = realloc (res, sizeof (char*) * (n_spaces+1));
res[n_spaces] = 0;
/* print the result */
for (i = 0; i < (n_spaces+1); ++i)
printf ("res[%d] = %s\n", i, res[i]);
printf("bar");
printf("%s test before sending to socket\n", cmd);
if((res[0] != NULL) && (res[1] != NULL) && strcmp(res[0],"put")==0)
{
/* Receiving File from the client in the server directory */
printf("\n****RECEIVING****\n");
if(getcwd(cwd,sizeof(cwd))!=NULL){
fileR_path = cwd;
strcat(fileR_path, "/");
strcat(fileR_path, res[1]);}
printf("Receiving the file %s from the client...\n", fileR_path);
fileR = fopen(fileR_path, "w");
if(fileR==NULL)
fprintf(stderr, "File %s cannot be opened. \n", fileR_path);
else
{
bzero(buf_R, BUF_LENGTH);
varR =-1 ; varR2=-1;
while((varR=read(conn->sock, buf_R, BUF_LENGTH))>=0)
{
varR2=fwrite(buf_R, sizeof(char), varR,fileR);
if (varR2< varR){
fprintf(stderr, "Cannot write the file %s on the server \n", fileR_path); exit;}
bzero(buf_R,BUF_LENGTH);
if((varR == 0 ) || (varR !=BUF_LENGTH)){
//printf("Something wrong with reading the socket \n");
break;
}
}
if(varR<0){
printf("Receiving failure due to error in reading socket\n");
//break;
exit;
}
printf("The file was received from the client to the server\n");
if(fileR!=NULL){
fclose(fileR);
printf("fileR closed\n");}
}
printf("\n");
}
else if ((res[0] != NULL) && (res[1] != NULL) && strcmp(res[0], "get")==0)
{
// Sending file from the server to the client
printf("\n****SENDING****\n");
char *fileS_path;
char cwd2[2048];
if(getcwd(cwd2,sizeof(cwd2))!=NULL){
fileS_path=cwd2;
strcat(fileS_path, "/");
strcat(fileS_path, res[1]);
}
char buf_S[BUF_LENGTH];
printf("Sending the file %s to the CLIENT...\n", fileS_path);
FILE *fileS = fopen(fileS_path, "r");
if(!fileS)
fprintf(stderr, "File %s is not found. \n", fileS_path);
else
{
bzero(buf_S,BUF_LENGTH);
int varS;
while((varS=fread(buf_S, sizeof(char), BUF_LENGTH,fileS))>0)
{
if(write(conn->sock, buf_S, varS)<0){
fprintf(stderr, "Cannot send the file %s \n", fileS_path); break;}
bzero(buf_S,BUF_LENGTH);
}
printf("The file was sent from the SERVER to the CLIENT\n\n");
fclose(fileS);
}
}
else if (res[0]!=NULL && strcmp(res[0], "cd\n")==0)
{
if(getcwd(cwd,sizeof(cwd))!=NULL){
if(write(conn->sock, cwd, sizeof(cwd))<0){
printf("Cannot send the current working directory \n");
}
}
}
else if (strcmp(res[0], "quit")==0)
exit; //break;
bzero(cmd, 4096);
printf("bzerocmd\n %s", cmd);
free(res);
printf("free res\n");
}
}
/* close socket and clean up */
close(conn->sock);
printf("socket closed\n");
free(conn);
printf("Connection free\n");
pthread_exit(0);
printf("Thread exit\n");
}
int main(int argc, char ** argv)
{
int sock = -1;
struct sockaddr_in address;
int port;
connection_t * connection;
pthread_t thread;
/* check for command line arguments */
if (argc != 2)
{
fprintf(stderr, "usage: %s port\n", argv[0]);
return -1;
}
/* obtain port number */
if (sscanf(argv[1], "%d", &port) <= 0)
{
fprintf(stderr, "%s: error: wrong parameter: port\n", argv[0]);
return -2;
}
/* create socket */
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock <= 0)
{
fprintf(stderr, "%s: error: cannot create socket\n", argv[0]);
return -3;
}
/* bind socket to port */
bzero(&address, sizeof(address));
address.sin_family = AF_INET;
address.sin_addr.s_addr = htonl(INADDR_ANY);
address.sin_port = htons(port);
if (bind(sock, (struct sockaddr *)&address, sizeof(struct sockaddr_in)) < 0)
{
fprintf(stderr, "%s: error: cannot bind socket to port %d\n", argv[0], port);
return -4;
}
/* listen on port */
if (listen(sock, MAXQ) < 0)
{
fprintf(stderr, "%s: error: cannot listen on port\n", argv[0]);
return -5;
}
printf("%s: ready and listening\n", argv[0]);
while (1)
{
/* accept incoming connections */
connection = (connection_t *)malloc(sizeof(connection_t));
connection->sock = accept(sock, &connection->address, &connection->addr_len);
if (connection->sock <= 0)
{
free(connection);
}
else
{
/* start a new thread but do not wait for it */
pthread_create(&thread, 0, process, (void *)connection);
pthread_detach(thread);
}
}
return 0;
}
The problem here, for the put command as an example (however, it is the same for the get command), in the first iteration everything is fine. The file is copied and the program looks fine. However, in the second iteration ( I mean when I enter the command secondly in the client terminal) the file is copied into the server side and segmentation fault is displayed in both sides (server and client). I tried to understand from where this segmentation fault is coming, so it was revealed that the program stops at the fclose function. I couldn't understand why? Any help?