Home > Software engineering >  thread function doesn't terminate until Enter is pressed
thread function doesn't terminate until Enter is pressed

Time:05-23

The following code (in the end) represents thread function which takes in ls command from remote client and send current working directory to that client.

It successfully sends but there is one issue: When it stops sending completely, I want it to start listening again. At line:

printf("Enter 1 if you want to exit or 0 if you don't: "); 
                 fgets(exit_status,MAX_SIZE,stdin);

It gets stuck and it is terminated (and starts another thread) when I press Enter

Which I don't understand why? and while I was debugging I saw above print statement executes after pressing Enter despite the debugger being at the end of function (means it passed this print statement).

I want it to start listening again automatically when it finish sending data.

If anyone wants to look at my full code here is the link:https://pastebin.com/9UmTkPge

void  *server_socket_ls(void *arg) {
    int* exit_status = (int*)malloc(sizeof(int));
    *exit_status = 0;   
    while (*exit_status == 0) {
    //socket code is here
        
    //code for ls
        
    char buffer[BUFFSIZE];
    int received = -1;
    char data[MAX];
    memset(data,0,MAX);
       // this will make server wait for another command to run until it receives exit
        data[0] = '\0';
        if((received = recv(new_socket, buffer,BUFFSIZE,0))<0){
    
            perror("Failed");
        }
    
        buffer[received] = '\0';
    
        strcat (data,  buffer);
        if (strcmp(data, "exit")==0) // this will force the code to exit
            exit(0);
    
        puts (data);
            char *args[100];
            setup(data,args,0);
            int pipefd[2],lenght;
    
            if(pipe(pipefd))
                perror("Failed to create pipe");
    
            pid_t pid = fork();
            char path[MAX];
    
            if(pid==0)
            {
                close(1); // close the original stdout
                dup2(pipefd[1],1); // duplicate pipfd[1] to stdout
                close(pipefd[0]); // close the readonly side of the pipe
                close(pipefd[1]); // close the original write side of the pipe
                execvp(args[0],args); // finally execute the command
            }
            else
                if(pid>0)
                {
                    close(pipefd[1]);
                    memset(path,0,MAX);
    
                    while(lenght=read(pipefd[0],path,MAX-1)){
                        printf("Data read so far %s\n", path);
                        if(send(new_socket,path,strlen(path),0) != strlen(path) ){
                            perror("Failed");
                        }
                        //fflush(NULL);
                        printf("Data sent so far %s\n", path);
                        memset(path,0,MAX);
                        
                    }
    
                    close(pipefd[0]);
                    //removed so server will not terminate
                              
                }
                else 
                {
                    printf("Error !\n");
                    exit(0);
                }
                 printf("Enter 1 if you want to exit or 0 if you don't: "); 
                 fgets(exit_status,MAX_SIZE,stdin);    
                
        }
    
    }

CodePudding user response:

There are many bugs:

  1. In terminal_thread, input_command is allocated on each loop iteration -- a memory leak
  2. Code to strip newline is broken
  3. With .l, not specifying an IP address causes a segfault because token is NULL
  4. The port number in terminal_thread for .l is 5126 which does not match the 9191 in the corresponding server code
  5. After connecting, server_socket_file does not do anything.
  6. In server_socket_ls, it loops on socket, bind, listen, and accept. The loop should start after the listen (i.e. only do accept in the loop and reuse the listening socket).
  7. Other bugs marked in the code

I had to refactor the code and add some debug. It is annotated with the bugs. I use cpp conditionals to denote old vs. new code:

#if 0
// old code
#else
// new code
#endif

#if 1
// new code
#endif

Here is the code. I got minimal .l (remote ls) working:

#include <netinet/in.h>
#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <stdbool.h>
#include <stdarg.h>

#define BACKLOG 10
#define MAX_SIZE 200
#define BACKLOG 10
#define BUFFSIZE 2048
#define MAXPENDING 5
#define MAX 2048

__thread char *tid;
__thread char dbgstrbuf[1000];

FILE *xfdbg;

typedef struct server_arg {
    int portNum;
} server_arg;
typedef struct server_arg1 {
    int portNum;
} server_arg1;

void
dbgprt(const char *fmt,...)
{
    va_list ap;
    char msg[1000];
    char *bp = msg;

    bp  = sprintf(bp,"%4s ",tid);
    va_start(ap,fmt);
    bp  = vsprintf(bp,fmt,ap);
    va_end(ap);

    fputs(msg,xfdbg);
}

const char *
dbgstr(const char *str)
{
    char *bp = dbgstrbuf;

    bp  = sprintf(bp,"'");

    for (int chr = *str  ;  chr != 0;  chr = *str  ) {
        if ((chr > 0x20) && (chr <= 0x7E))
            bp  = sprintf(bp,"%c",chr);
        else
            bp  = sprintf(bp,"{%2.2X}",chr);
    }

    bp  = sprintf(bp,"'");

    return dbgstrbuf;
}

void
setup(char inputBuffer[], char *args[], int *background)
{
    const char s[4] = " \t\n";
    char *token;

    token = strtok(inputBuffer, s);
    int i = 0;

    while (token != NULL) {
        args[i] = token;
        i  ;
        // printf("%s\n", token);
        token = strtok(NULL, s);
    }
    args[i] = NULL;
}

void *
terminal_thread(void *arg)
{
// NOTE/FIX: do this _once_
#if 1
    char *input_command = malloc(MAX_SIZE);
#endif

    tid = "term";

    while (1) {
        dbgprt("term: PROMPT\n");

        printf(">> ");
//memset(input_command,0,strlen(str));
// NOTE/BUG: this is a memory leak
#if 0
        char *input_command = malloc(MAX_SIZE);
#endif

        dbgprt("term: FGETS\n");
        fgets(input_command, MAX_SIZE, stdin);

// NOTE/BUG: code is broken to strip newline
#if 0
        if ((strlen(input_command) > 0) &&
            (input_command[strlen(input_command) - 1] == '\n'))
            input_command[strlen(input_command) - 1] = '\0';
#else
        input_command[strcspn(input_command,"\n")] = 0;
#endif

        dbgprt("term: COMMAND %s\n",dbgstr(input_command));

        char list[] = "ls";
        char cp[] = "cp";

#if 0
        char s[100];
        printf("%s\n", getcwd(s,100));
        chdir("Desktop");
        printf("%s\n", getcwd(s,100));
#endif

        if (strcmp(input_command, list) == 0) {
            // ls code will run here

        }

        if (strchr(input_command, '.') != NULL &&
            strchr(input_command, 'l') != NULL) {

            printf("remote ls\n");
            char ip[20];
            const char c[2] = " ";

            // strcpy(str,input_command);
            char *token;

            // get the first token
            token = strtok(input_command, c);

            // walk through other tokens
            int i = 0;

            while (token != NULL && i != -1) {
                token = strtok(NULL, c);
                i--;
            }
// NOTE/FIX: after the loop token _must_ be
#if 1
            if (token == NULL) {
                token = "127.0.0.1";
                printf("no IP address found -- using %s\n",token);
            }
#endif
            strcpy(ip, token);

            int sock;
            struct sockaddr_in echoserver;
            char buffer[BUFFSIZE];
            unsigned int echolen;
            int received = 0;

            if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
                perror("Failed to create socket");
                exit(1);
            }
            int enable = 1;

            if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &enable,
                sizeof(int)) < 0) {
                perror("error");
            }
            memset(&echoserver, 0, sizeof(echoserver));
            echoserver.sin_family = AF_INET;
            echoserver.sin_addr.s_addr = inet_addr(ip);

// NOTE/BUG: this port number does _not_ match any server port
#if 0
            echoserver.sin_port = htons(5126);
#else
            unsigned short port = 9191;
            dbgprt("term: port=%u\n",port);
            echoserver.sin_port = htons(port);
#endif

            if (connect(sock, (struct sockaddr *) &echoserver,
                sizeof(echoserver)) < 0) {
                perror("Failed to connect with server");
                exit(1);
            }
            char s[100];

            // while(1) { // to repeat the whole process until exit is typed
            strcpy(s, "ls");

// NOTE/BUG: this blows away the "s" in "ls" because s is _set_ with strcpy
#if 0
            s[strlen(s) - 1] = '\0';    // fgets doesn't automatically discard '\n'
#endif
            echolen = strlen(s);

            /* send() from client; */
            if (send(sock, s, echolen, 0) != echolen) {
                perror("Mismatch in number of sent bytes");
            }

            fprintf(stdout, "Message from server: ");

            int bytes = 0;

            /* recv() from server; */
            if ((bytes = recv(sock, buffer, echolen, 0)) < 1) {
                perror("Failed to receive bytes from server");
            }
            received  = bytes;
            buffer[bytes] = '\0';
            /* Assure null terminated string */
            fprintf(stdout, buffer);

            bytes = 0;
// this d {...} while block will receive the buffer sent by server
            do {
                buffer[bytes] = '\0';
                printf("%s\n", buffer);
            } while ((bytes = recv(sock, buffer, BUFFSIZE - 1, 0)) >= BUFFSIZE - 1);
            buffer[bytes] = '\0';
            printf("%s\n", buffer);
            printf("\n");

            continue;
        }
    }
}

void *
server_socket_ls(void *arg)
{
    int *exit_status = (int *) malloc(sizeof(int));

    tid = "ls";

    dbgprt("ls: ENTER\n");

    *exit_status = 0;
    while (*exit_status == 0) {
        server_arg *s = (server_arg *) arg;
        int server_fd, new_socket;
        struct sockaddr_in address;
        int addrlen = sizeof(address);

        dbgprt("ls: SOCKET\n");

        // Creating socket file descriptor
        if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
            perror("socket failed");
            exit(EXIT_FAILURE);
        }
        int enable = 1;

        if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &enable,
            sizeof(int)) < 0) {
            perror("error");
        }

        address.sin_family = AF_INET;
        address.sin_addr.s_addr = INADDR_ANY;
        address.sin_port = htons(s->portNum);

        dbgprt("ls: BIND prtNum=%u\n",s->portNum);
        if (bind(server_fd, (struct sockaddr *) &address, sizeof(address))
            < 0) {
            perror("bind failed");
        }

        dbgprt("ls: LISTEN\n");
        if (listen(server_fd, 3) < 0) {
            perror("listen");
        }

        if ((new_socket = accept(server_fd, (struct sockaddr *) &address,
            (socklen_t *) & addrlen)) < 0) {
            perror("accept");
        }

        dbgprt("ls: ACCEPTED\n");
        printf("Server Connected\n");

//code for ls

        char buffer[BUFFSIZE];
        int received = -1;
        char data[MAX];

        memset(data, 0, MAX);
        // this will make server wait for another command to run until it
        // receives exit
        data[0] = '\0';

        if ((received = recv(new_socket, buffer, BUFFSIZE, 0)) < 0) {
            perror("Failed");
        }

        buffer[received] = '\0';

        strcat(data, buffer);
        dbgstr(data);
        if (strcmp(data, "exit") == 0)  // this will force the code to exit
            exit(0);

        puts(data);
        char *args[100];

        setup(data, args, 0);
        int pipefd[2],
         lenght;

        if (pipe(pipefd))
            perror("Failed to create pipe");

        pid_t pid = fork();
        char path[MAX];

        if (pid == 0) {
// NOTE/BUG: no need to close before dup2
#if 0
            close(1);                   // close the original stdout
#endif
            dup2(pipefd[1], 1);         // duplicate pipfd[1] to stdout
            close(pipefd[0]);           // close the readonly side of the pipe
            close(pipefd[1]);           // close the original write side of the pipe
            execvp(args[0], args);      // finally execute the command
        }
        else if (pid > 0) {
            close(pipefd[1]);
            memset(path, 0, MAX);

// NOTE/BUG: read does _not_ terminate buffer with EOS (0x00)
#if 0
            while (lenght = read(pipefd[0], path, MAX - 1)) {
                printf("Data read so far %s\n", path);
                if (send(new_socket, path, strlen(path), 0) != strlen(path)) {
                    perror("Failed");
                }
                // fflush(NULL);
                printf("Data sent so far %s\n", path);
                memset(path, 0, MAX);
            }
#else
            while (lenght = read(pipefd[0], path, MAX - 1)) {
                printf("Data read so far ", path);
                fwrite(path,1,lenght,stdout);
                printf("\n");

                if (send(new_socket, path, lenght, 0) != lenght) {
                    perror("Failed");
                }

                // fflush(NULL);
                printf("Data send so far ", path);
                fwrite(path,1,lenght,stdout);
                printf("\n");

                memset(path, 0, MAX);
            }
#endif

            // close(pipefd[0]);
            // removed so server will not terminate
// NOTE/BUG: child needs to terminate -- otherwise, _both_ parent and child
// will prompt user below
#if 1
            exit(0);
#endif

        }
        else {
            printf("Error !\n");
            exit(0);
        }

        printf("Enter 1 if you want to exit or 0 if you don't: ");
// NOTE/BUG: need to pass buffer
// NOTE/BUG: exit_status is an int pointer
#if 0
        fgets(exit_status, MAX_SIZE, stdin);
#else
        char exit_buf[100];
        fgets(exit_buf,sizeof(exit_buf),stdin);
        *exit_status = atoi(exit_buf);
#endif
    }

}

void *
server_socket_file(void *arg)
{

    tid = "file";

    dbgprt("file: ENTER\n");

    server_arg1 *s1 = (server_arg1 *) arg;
    int server_fd, new_socket;
    struct sockaddr_in address;
    int addrlen = sizeof(address);

    // Creating socket file descriptor
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
        perror("socket failed");
        exit(EXIT_FAILURE);
    }
    int enable = 1;

    if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int))
        < 0) {
        perror("error");
    }

    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(s1->portNum);

    dbgprt("file: BIND portNum=%u\n",s1->portNum);

    if (bind(server_fd, (struct sockaddr *) &address, sizeof(address)) < 0) {
        perror("bind failed");

    }
    if (listen(server_fd, 3) < 0) {
        perror("listen");
    }

    if ((new_socket = accept(server_fd, (struct sockaddr *) &address,
        (socklen_t *) & addrlen)) < 0) {
        perror("accept");
    }

    printf("Server Connected\n");
}

int
main(int argc, char const *argv[])
{

    tid = "main";

    server_arg *s = (server_arg *) malloc(sizeof(server_arg));
    server_arg1 *s1 = (server_arg1 *) malloc(sizeof(server_arg1));
    pthread_t id_1;
    pthread_t id_2;
    pthread_t id_3;

    xfdbg = fopen("debug.txt","w");
    setlinebuf(xfdbg);

    if (pthread_create(&id_3, NULL, terminal_thread, NULL) != 0) {
        perror("pthread_create");
    }

// NOTE/BUG: this port (or the one below) doesn't match the client code
// port of 5126
    s->portNum = 9191;
    pthread_create(&id_1, NULL, server_socket_ls, s);

    s1->portNum = 6123;
    pthread_create(&id_2, NULL, server_socket_file, s1);

    pthread_join(id_1, NULL);
    pthread_join(id_2, NULL);
    pthread_join(id_3, NULL);

// NOTE/BUG: pthread_exit in main thread is wrong
#if 0
    pthread_exit(0);
#else
    return 0;
#endif
}

Here is the program output (for .l):

>> remote ls
no IP address found -- using 127.0.0.1
Message from server: Server Connected
ls
Data read so far debug.txt
orig
orig.c
orig.txt
out

Data send so far debug.txt
orig
orig.c
orig.txt
out

bug.txt
orig
orig.c
orig.txt
out

Here is the debug.txt output:

term term: PROMPT
term term: FGETS
  ls ls: ENTER
  ls ls: SOCKET
file file: ENTER
  ls ls: BIND prtNum=9191
file file: BIND portNum=6123
  ls ls: LISTEN
term term: COMMAND '.l'
term term: port=9191
  ls ls: ACCEPTED
term term: PROMPT

This program is exiting as soon as its stops sending data at exit(0) and so doesn't ask for exit_status. Is there a way somehow to make it not stop and instead the terminal prompt reappears along with servers listening at the back? – Dragut

Because I sensed the urgency, I erred on the side of a partial solution now is better than a perfect solution too late.

I may have introduced a bug with an extraneous exit call in the ls server parent process (now fixed).

But, there are other issues ...

The main issue is that the server (for ls) is prompting the user whether to continue or not (on stdout/stdin). This doesn't work too well.

It's the client (i.e. terminal_thread) that should prompt the user. Or, as I've done it, the client will see exit at the command prompt, then send a packet with "exit" in it to the server, and terminate. Then, the server will see this command and terminate.

I refactored as much as I could without completely redoing everything.

I split off some code into functions. Some of the can/could be reused to implement the "file" server.

But, I'd put both functions into a single server thread. I'd have the server look at the "command" it gets and do either of the actions based on the command. Since there's no code for actually doing something in the "file" server [yet] it's difficult to rework.

One thing to fix [which I did not have time for]:

The .l command is of the form: .l [ip_address]. The default for ip_address is 127.0.0.1. But, this should be split into two commands (e.g.):

  1. attach [ip_address]
  2. ls [ls arguments]

Anyway, here's the updated code. I had to move a bit quickly, so it's not quite as clean as I'd like.

#include <netinet/in.h>
#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <stdbool.h>
#include <stdarg.h>

#if 1
#include <time.h>
#endif

#define BACKLOG 10
#define MAX_SIZE 200
#define BACKLOG 10
#define BUFFSIZE 2048
#define MAXPENDING 5
#define MAX 2048

__thread char *tid;
__thread char dbgstrbuf[1000];

FILE *xfdbg;
double tsczero = 0.0;

typedef struct server_arg {
    int portNum;
} server_arg;
typedef struct server_arg1 {
    int portNum;
} server_arg1;

double
tscgetf(void)
{
    struct timespec ts;
    double sec;

    clock_gettime(CLOCK_MONOTONIC,&ts);

    sec = ts.tv_nsec;
    sec /= 1e9;
    sec  = ts.tv_sec;

    sec -= tsczero;

    return sec;
}

void
dbgprt(const char *fmt,...)
{
    va_list ap;
    char msg[1000];
    char *bp = msg;

    bp  = sprintf(bp,"[%.9f/%4s] ",tscgetf(),tid);
    va_start(ap,fmt);
    bp  = vsprintf(bp,fmt,ap);
    va_end(ap);

    fputs(msg,xfdbg);
}

const char *
dbgstr(const char *str,int len)
{
    char *bp = dbgstrbuf;

    if (len < 0)
        len = strlen(str);

    bp  = sprintf(bp,"'");

    for (int i = 0;  i < len;    i) {
        int chr = str[i];
        if ((chr > 0x20) && (chr <= 0x7E))
            bp  = sprintf(bp,"%c",chr);
        else
            bp  = sprintf(bp,"{%2.2X}",chr);
    }

    bp  = sprintf(bp,"'");

    return dbgstrbuf;
}

void
setup(char inputBuffer[], char *args[], int *background)
{
    const char s[4] = " \t\n";
    char *token;

    token = strtok(inputBuffer, s);
    int i = 0;

    while (token != NULL) {
        args[i] = token;
        i  ;
        // printf("%s\n", token);
        token = strtok(NULL, s);
    }
    args[i] = NULL;
}

int
open_remote(const char *ip,unsigned short port)
{
    int sock;
    struct sockaddr_in echoserver;

    dbgprt("open_remote: ENTER ip=%s port=%u\n",dbgstr(ip,-1),port);

    if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
        perror("Failed to create socket");
        exit(1);
    }
    int enable = 1;

    if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &enable,
        sizeof(int)) < 0) {
        perror("error");
    }
    memset(&echoserver, 0, sizeof(echoserver));
    echoserver.sin_family = AF_INET;
    echoserver.sin_addr.s_addr = inet_addr(ip);

// NOTE/BUG: this port number does _not_ match any server port
#if 0
    echoserver.sin_port = htons(5126);
#else
    dbgprt("term: port=%u\n",port);
    echoserver.sin_port = htons(port);
#endif

    if (connect(sock, (struct sockaddr *) &echoserver,
        sizeof(echoserver)) < 0) {
        perror("Failed to connect with server");
        exit(1);
    }

    dbgprt("open_remote: EXIT sock=%d\n",sock);

    return sock;
}

void *
terminal_thread(void *arg)
{
// NOTE/FIX: do this _once_
#if 1
    char *input_command = malloc(MAX_SIZE);
#endif

    tid = "term";

    char buffer[BUFFSIZE];
    int sock_ls = -1;

    while (1) {
        dbgprt("term: PROMPT\n");

        printf(">> ");
//memset(input_command,0,strlen(str));
// NOTE/BUG: this is a memory leak
#if 0
        char *input_command = malloc(MAX_SIZE);
#endif

        dbgprt("term: FGETS\n");
        fgets(input_command, MAX_SIZE, stdin);

// NOTE/BUG: code is broken to strip newline
#if 0
        if ((strlen(input_command) > 0) &&
            (input_command[strlen(input_command) - 1] == '\n'))
            input_command[strlen(input_command) - 1] = '\0';
#else
        input_command[strcspn(input_command,"\n")] = 0;
#endif

        dbgprt("term: COMMAND %s\n",dbgstr(input_command,-1));

        char list[] = "ls";
        char cp[] = "cp";

#if 0
        char s[100];
        printf("%s\n", getcwd(s,100));
        chdir("Desktop");
        printf("%s\n", getcwd(s,100));
#endif

        // exit program (and exit server)
        if (strcmp(input_command,"exit") == 0) {
            if (sock_ls >= 0) {
                dbgprt("term: SENDEXIT\n");
                if (send(sock_ls,"exit",4,0) < 0) {
                    perror("send/exit");
                    exit(1);
                }
                break;
            }
        }

        if (strcmp(input_command, list) == 0) {
            // ls code will run here

        }

        if ((input_command[0] == '.') && (input_command[1] == 'l')) {
            printf("remote ls\n");
            char ip[20];
            const char c[2] = " ";

            // strcpy(str,input_command);
            char *token;

            // get the first token
            token = strtok(input_command, c);

            // walk through other tokens
            int i = 0;

            while (token != NULL && i != -1) {
                token = strtok(NULL, c);
                i--;
            }

#if 1
            if (token == NULL) {
                token = "127.0.0.1";
                printf("no IP address found -- using %s\n",token);
            }
#endif

            if (sock_ls < 0)
                sock_ls = open_remote(token,9191);

            char s[100];

            strcpy(s, "ls");

// NOTE/BUG: this blows away the "s" in "ls" because s is _set_ with strcpy
#if 0
            s[strlen(s) - 1] = '\0';    // fgets doesn't automatically discard '\n'
#endif
            unsigned int echolen;
            echolen = strlen(s);

            int received = 0;

            /* send() from client; */
            if (send(sock_ls, s, echolen, 0) != echolen) {
                perror("Mismatch in number of sent bytes");
            }

            fprintf(stdout, "Message from server: ");

            int bytes = 0;

            /* recv() from server; */
            if ((bytes = recv(sock_ls, buffer, echolen, 0)) < 1) {
                perror("Failed to receive bytes from server");
            }
            received  = bytes;
            buffer[bytes] = '\0';
            /* Assure null terminated string */
            fprintf(stdout, buffer);

            bytes = 0;
// this d {...} while block will receive the buffer sent by server
            do {
                buffer[bytes] = '\0';
                printf("%s\n", buffer);
            } while ((bytes = recv(sock_ls, buffer, BUFFSIZE - 1, 0)) >= BUFFSIZE - 1);
            buffer[bytes] = '\0';
            printf("%s\n", buffer);
            printf("\n");

            continue;
        }
    }

    dbgprt("term: EXIT\n");

    return (void *) 0;
}

int
ls_loop(int new_socket)
{

    dbgprt("ls_loop: ENTER new_socket=%d\n",new_socket);

//code for ls

    char buffer[BUFFSIZE];
    int received = -1;
    char data[MAX];

    int stop = 0;

    while (1) {
        memset(data, 0, MAX);
        // this will make server wait for another command to run until it
        // receives exit
        data[0] = '\0';

        if ((received = recv(new_socket, buffer, BUFFSIZE, 0)) < 0) {
            perror("Failed");
        }
        buffer[received] = '\0';

        strcpy(data, buffer);
        dbgprt("ls_loop: COMMAND %s\n",dbgstr(data,-1));

        // this will force the code to exit
#if 0
        if (strcmp(data, "exit") == 0)
            exit(0);
        puts(data);
#else
        if (strncmp(data, "exit", 4) == 0) {
            dbgprt("ls_loop: EXIT/COMMAND\n");
            stop = 1;
            break;
        }
#endif

        char *args[100];

        setup(data, args, 0);
        int pipefd[2], length;

        if (pipe(pipefd))
            perror("Failed to create pipe");

        pid_t pid = fork();
        char path[MAX];

        if (pid == 0) {
// NOTE/BUG: no need to close before dup2
#if 0
            close(1);                   // close the original stdout
#endif
            dup2(pipefd[1], 1);         // duplicate pipfd[1] to stdout
            close(pipefd[0]);           // close the readonly side of the pipe
            close(pipefd[1]);           // close the original write side of the pipe
            execvp(args[0], args);      // finally execute the command
            exit(1);
        }

        if (pid < 0) {
            perror("fork");
            exit(1);
        }

        dbgprt("ls_loop: PARENT\n");
        close(pipefd[1]);

        while (length = read(pipefd[0], path, MAX - 1)) {
            dbgprt("ls_loop: DATAREAD %s\n",dbgstr(path,length));

            if (send(new_socket, path, length, 0) != length) {
                perror("Failed");
            }

            memset(path, 0, MAX);
        }

        close(pipefd[0]);
    }

    dbgprt("ls_loop: EXIT stop=%d\n",stop);
}

void *
server_socket_ls(void *arg)
{

    tid = "ls";

    dbgprt("lsmain: ENTER\n");

    do {
        server_arg *s = (server_arg *) arg;
        int server_fd, new_socket;
        struct sockaddr_in address;
        int addrlen = sizeof(address);

        dbgprt("lsmain: SOCKET\n");

        // Creating socket file descriptor
        if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
            perror("socket failed");
            exit(EXIT_FAILURE);
        }
        int enable = 1;

        if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &enable,
            sizeof(int)) < 0) {
            perror("error");
        }

        address.sin_family = AF_INET;
        address.sin_addr.s_addr = INADDR_ANY;
        address.sin_port = htons(s->portNum);

        dbgprt("lsmain: BIND prtNum=%u\n",s->portNum);
        if (bind(server_fd, (struct sockaddr *) &address, sizeof(address))
            < 0) {
            perror("bind failed");
        }

        dbgprt("lsmain: LISTEN\n");
        if (listen(server_fd, 3) < 0) {
            perror("listen");
        }

        while (1) {
            if ((new_socket = accept(server_fd, (struct sockaddr *) &address,
                (socklen_t *) & addrlen)) < 0) {
                perror("accept");
            }

            dbgprt("lsmain: ACCEPTED\n");

            int stop = ls_loop(new_socket);
            close(new_socket);

            if (stop) {
                dbgprt("lsmain: STOP\n");
                break;
            }
        }
    } while (0);

    dbgprt("lsmain: EXIT\n");

    return (void *) 0;
}

void *
server_socket_file(void *arg)
{

    tid = "file";

    dbgprt("file: ENTER\n");

    server_arg1 *s1 = (server_arg1 *) arg;
    int server_fd, new_socket;
    struct sockaddr_in address;
    int addrlen = sizeof(address);

    // Creating socket file descriptor
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
        perror("socket failed");
        exit(EXIT_FAILURE);
    }
    int enable = 1;

    if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int))
        < 0) {
        perror("error");
    }

    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(s1->portNum);

    dbgprt("file: BIND portNum=%u\n",s1->portNum);

    if (bind(server_fd, (struct sockaddr *) &address, sizeof(address)) < 0) {
        perror("bind failed");

    }
    if (listen(server_fd, 3) < 0) {
        perror("listen");
    }

    if ((new_socket = accept(server_fd, (struct sockaddr *) &address,
        (socklen_t *) & addrlen)) < 0) {
        perror("accept");
    }

    printf("Server Connected\n");
}

int
main(int argc, char const *argv[])
{

    tid = "main";

    tsczero = tscgetf();

    server_arg *s = (server_arg *) malloc(sizeof(server_arg));
    server_arg1 *s1 = (server_arg1 *) malloc(sizeof(server_arg1));
    pthread_t id_1;
    pthread_t id_2;
    pthread_t id_3;

    xfdbg = fopen("debug.txt","w");
    setlinebuf(xfdbg);

    if (pthread_create(&id_3, NULL, terminal_thread, NULL) != 0) {
        perror("pthread_create");
    }

// NOTE/BUG: this port (or the one below) doesn't match the client code
// port of 5126
    s->portNum = 9191;
    pthread_create(&id_1, NULL, server_socket_ls, s);

    s1->portNum = 6123;
    if (0)
        pthread_create(&id_2, NULL, server_socket_file, s1);

    pthread_join(id_1, NULL);
    if (0)
        pthread_join(id_2, NULL);
    pthread_join(id_3, NULL);

// NOTE/BUG: pthread_exit in main thread is wrong
#if 0
    pthread_exit(0);
#else

    fclose(xfdbg);

    return 0;
#endif
}

Here's the debug output:

[0.000170689/  ls] lsmain: ENTER
[0.000240819/  ls] lsmain: SOCKET
[0.000281554/  ls] lsmain: BIND prtNum=9191
[0.000207250/term] term: PROMPT
[0.000312276/term] term: FGETS
[0.000372488/  ls] lsmain: LISTEN
[2.367264029/term] term: COMMAND '.l'
[2.367295218/term] open_remote: ENTER ip='127.0.0.1' port=9191
[2.367346382/term] term: port=9191
[2.367434666/term] open_remote: EXIT sock=6
[2.367439573/  ls] lsmain: ACCEPTED
[2.367455805/  ls] ls_loop: ENTER new_socket=5
[2.367467511/  ls] ls_loop: COMMAND 'ls'
[2.367636543/  ls] ls_loop: PARENT
[2.369013467/  ls] ls_loop: DATAREAD 'debug.txt{0A}fix1{0A}fix1.c{0A}orig{0A}orig.c{0A}orig.txt{0A}out{0A}'
[2.369206789/term] term: PROMPT
[2.369222828/term] term: FGETS
[20.551357125/term] term: COMMAND 'exit'
[20.551378790/term] term: SENDEXIT
[20.551452423/term] term: EXIT
[20.551586028/  ls] ls_loop: COMMAND 'exit'
[20.551609143/  ls] ls_loop: EXIT/COMMAND
[20.551615857/  ls] ls_loop: EXIT stop=1
[20.551649125/  ls] lsmain: STOP
[20.551656969/  ls] lsmain: EXIT
  • Related