I'm writing a project where you start the server in one terminal, and in other terminals that are clients you can send messages from one user to another using FIFO pipes. Server creates FIFO pipe that reads messages from clients. Client creates FIFO pipe to read messages from server.
In one terminal to start the server I type ./projectname --start
and in client i type ./projectname --login nickname
. When I close the client terminal my server receives segmentation fault(core dumped) error message. I tried to get rid of this in every possible way I know for x hours. How can it be fixed?
I have also tried to register users using the void verifyloginclient(char *login)
function but parent proccess is unable to receive information from child and is stuck in infinite while(1)
sending some message to server that also crashes server with segmentation fault so it's commented for now.
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
char userlist[10][30];
int succesfulllogin = 1;
void handler(int signum){
pid_t pid;
pid = wait(NULL);
succesfulllogin = 0;
printf("Parent knows child %d finished\n", (int)pid);
printf("Parent ending...\n");
}
void sig_handler_parent(int signum){
printf("signal response from child!\n");
succesfulllogin = 0;
exit(0);
}
void sig_handler_child(int signum){
printf("signal from parent\n");
succesfulllogin = 0;
exit(0);
}
void verifyloginclient(char *login)
{
int fd;
char buf[256];
char buf2[256];
snprintf(buf, sizeof buf, "%s%s", "fifopipes/","serwer.fifo");
if((fd = open(buf, O_WRONLY)) == -1){
perror("openFdloginclient");
exit(EXIT_FAILURE);
}
snprintf(buf2, sizeof buf2, "%s%s%s", login, " /login ",login);
if((write(fd, buf2, strlen(buf2))) == -1){
perror("writeloginclient");
}
close(fd);
}
int verifyloginserwer(char *login)
{
// check if login is on the userlist
int flagcmp = -1;
int x;
int indeks=0;
for(int i=0;i<10;i++){
x = strcmp(&userlist[i][0],login);
if(x==0){
flagcmp = i;
}
}
if(flagcmp == -1){ //if it doesnt exist we add him to first free slot
for(int i=0;i<10;i++){
if(userlist[i][0]=='\0'){
strcpy(userlist[i],login);
printf("userlist: %s\n", userlist[i]);
succesfulllogin = 1;
break;
}
else{
indeks++;
}
}
}
else if(flagcmp != -1 || indeks==10){
fprintf(stderr, "loggin error!\n");
succesfulllogin = 0;
return 2;
}
return 0;
}
int splitstring(char *source, int desiredlength, char **s1,char **s2)
{
int len;
len = strlen(source);
if (desiredlength > len)
return(0);
*s1 = (char *) malloc(sizeof(char) * desiredlength);
*s2 = (char *) malloc(sizeof(char) * len-desiredlength+1);
if(s1 ==NULL || s2 == NULL)
return 0;
strncpy(*s1,source,desiredlength);
strncpy(*s2,source+desiredlength, len-desiredlength);
return(1);
}
void startserwer()
{
int fdserwer;
int fdanuluj;
int fd;
char readbuf[80];
int read_bytes;
char buf[256]; //pipe server
char buf2[256]; //pipe client
char buf3[256]; // message to client
for(int i=0;i<10;i++){ // declare userlist
userlist[i][0] = '\0';
}
snprintf(buf, sizeof buf, "%s%s", "fifopipes/","serwer.fifo");
umask(0);
if(mkfifo(buf, 0777) == -1){
perror("mkfifoserwer");
exit(EXIT_FAILURE);
}
while(1){
if((fdserwer = open(buf, O_CREAT | O_RDONLY))== -1){
perror("openFdserwer");
exit(EXIT_FAILURE);
}
if((read_bytes = read(fdserwer, &readbuf, sizeof(readbuf)))== -1){
perror("readbytes");
}
else{
readbuf[read_bytes] = '\0';
//SENDER LOGIN
char senderlogin[80];
strcpy(senderlogin, readbuf);
char *token = strtok(senderlogin, " ");
printf("%s\n", token);
strcpy(senderlogin, token);
int b;
char *loginnadawcy;
char *resztakomendy;
b = splitstring(readbuf, (int) strlen(token)+1,&loginnadawcy,&resztakomendy);
if(b!=1){
printf("error in command\n");
}
else{
loginnadawcy[strlen(token)]='\0';
//COMMAND NAME AFTER SLASH /
char command[80];
strcpy(command, readbuf);
token = strtok(NULL, " ");
printf("%s\n",token);
strcpy(command, token);
int a;
char *komenda;
char *reszta;
a = splitstring(resztakomendy, (int)strlen(token)+1,&komenda,&reszta);
if(a!=1){
printf("error\n");
}
else{
komenda[strlen(token)]='\0';
if(strcmp(komenda,"/login")==0){
if(verifyloginserwer(senderlogin)==2){
//open client pipe
snprintf(buf2, sizeof buf2, "%s%s%s", "fifopipes/",senderlogin,".fifo");
if((fdanuluj = open(buf2, O_WRONLY)) == -1){
perror("openFdanuluj");
exit(EXIT_FAILURE);
}
//SEND MESSAGE TO CLIENT
snprintf(buf3, sizeof buf3, "%s%s", "serwer ", "end");
if((write(fdanuluj, buf3, strlen(buf3))) == -1){
perror("writeFdanuluj");
}
close(fdanuluj);
}
}
else if(strcmp(komenda,"/w")==0){
//RECEIVER LOGIN
char receiverlogin[80];
token = strtok(NULL, " ");
printf("%s\n",token);
strcpy(receiverlogin, token);
int r;
char *login;
char *message;
r = splitstring(reszta,(int)strlen(token)+1,&login,&message);
if(r!=1){
printf("error\n");
}
else{
//RECEIVE INFORMATION
login[strlen(receiverlogin)]='\0';
printf("from %s to %s: %s and length is %d \n", senderlogin, login, message, (int)strlen(message));
//OPEN CLIENT PIPE
snprintf(buf2, sizeof buf2, "%s%s%s", "fifopipes/",receiverlogin,".fifo");
if((fd = open(buf2, O_WRONLY))== -1){
perror("openFd");
exit(EXIT_FAILURE);
}
//SEND MESSAGE TO CLIENT
snprintf(buf3, sizeof buf3, "%s%s%s", senderlogin," ",message);
if( (write(fd, buf3, strlen(buf3) )) == -1){
perror("writeopenfd");
}
close(fd);
}
}
}
}
}
close(fdserwer);
}
unlink(buf);
}
void clientchild(char *login)
{
int fd;
char readbuf[80];
int read_bytes;
char buf[256];
snprintf(buf, sizeof buf, "%s%s%s", "fifopipes/",login,".fifo");
umask(0);
if(mkfifo(buf, 0777) == -1){
perror("mkfifoclient");
exit(EXIT_FAILURE);
}
while(1){
if((fd = open(buf, O_CREAT | O_RDONLY)) == -1){
perror("openFdchild");
exit(EXIT_FAILURE);
}
if((read_bytes = read(fd, &readbuf, sizeof(readbuf))) == -1){
perror("readfdchild");
}
else{
readbuf[read_bytes] = '\0';
//SENDER LOGIN
char nickname[80];
strcpy(nickname, readbuf);
char * token = strtok(nickname, " ");
//printf("%s\n",token);
int r;
char *login;
char *message;
r = splitstring(readbuf,(int)strlen(token)+1,&login,&message);
if(r!=1){
printf("blad\n");
}
else{
login[strlen(token)]='\0';
if(strcmp(login,"serwer")==0 && strcmp(message,"end")==0){
printf("Login error. Closing...\n");
close(fd);
break;
}
printf("%s: %s and length is %d \n", login, message, (int)strlen(message));
close(fd);
//printf("Received string: \"%s\" and length is %d \n", readbuf, (int)strlen(readbuf));
}
//free(login);
//free(message);
}
}
unlink(buf);
}
void clientparent(char *login)
{
signal(SIGQUIT,sig_handler_parent);
int fd;
int stringlen;
char readbuf[80];
char buf[256];
char buf2[256];
snprintf(buf, sizeof buf, "%s%s", "fifopipes/","serwer.fifo");
printf("FIFO_CLIENT: Send messages infinitely\n");
while(1){
if((fd = open(buf, O_WRONLY)) == -1){
perror("openFdparent");
exit(EXIT_FAILURE);
}
//printf("Enter string: ");
fgets(readbuf, sizeof(readbuf), stdin);
stringlen = strlen(readbuf);
readbuf[stringlen - 1] = '\0';
snprintf(buf2, sizeof buf2, "%s%s%s", login," ",readbuf);
if(strlen(login)+1 == strlen(buf2)){
printf("Error\n");
break;
}
else{
if((write(fd, buf2, strlen(buf2))) == -1){
perror("writeparent");
}
printf("Sent string: \"%s\" and string length is %d \n", buf2, (int)strlen(buf2));
}
}
close(fd);
}
void splitclient(char *login)
{
printf("login: %s\n", login);
pid_t pid = fork();
printf("fork returned: %d\n", (int) pid);
//signal(SIGCHLD, handler);
if (pid < 0){
perror("Fork failed");
}
else if (pid == 0){
signal(SIGQUIT,sig_handler_child);
printf("I am the child with pid %d\n", (int) getpid());
char buf[256];
snprintf(buf, sizeof buf, "%s%d", "Child ",(int) getpid());
//kod dziecka
clientchild(login);
//kill(getppid(),SIGQUIT);
exit(0);
}
else{
// We must be the parent
printf("I am the parent, waiting for child to end \n");
//kod rodzica
clientparent(login);
pid_t childpid = wait(NULL);
printf("Parent knows child %d finished\n", (int)childpid);
printf("Parent ending...\n");
}
}
int main(int argc, char **argv)
{
while(1)
{
int c;
int option_index = 0;
static struct option long_options[] =
{
{"start", no_argument, NULL, 's'},
{"login", required_argument, NULL, 'l'},
{0, 0, 0, 0}
};
c = getopt_long (argc, argv, "sl:", long_options, &option_index);
if (c == -1)
break;
switch (c)
{
case 's':
printf("start server\n");
startserwer();
break;
case 'l':
printf("login with option %s \n", optarg);
//verifyloginclient(optarg);
splitclient(optarg);
break;
case '?':
break;
default:
abort();
}
}
if (optind < argc)
{
printf("non-option ARGV-elements: ");
while (optind < argc)
printf("%s ", argv[optind++]);
putchar ('\n');
}
return 0;
}
From this piece in the code in startServer()
:
if((read_bytes = read(fdserwer, &readbuf, sizeof(readbuf)))== -1){
perror("readbytes");
}
else{
:
char *token = strtok(senderlogin, " ");
:
strcpy(senderlogin, token);
b = splitstring(readbuf, (int)
strlen(token)+1,&loginnadawcy,&resztakomendy);
You are not validating if token
is a non-NULL
pointer post tokenization. In the case the child exits, read()
would return a 0 (and not -1 as a failure), indicating EOF as the man tells:
RETURN VALUE
On success, the number of bytes read is returned (zero indicates end of file),
Thus the senderlogin
buffer would be empty and wouldn't yield any tokens. You need to factor in this case and have appropriate null checks in place. Adding a null chek will lead to a graceful exit of the server program.