[CODING] Netchat-cli - A TCP Socket Client in C


Welcome back friends , In this post i am going to build a simple socket client in C. This project isn’t possible without this beautiful post C Sockets Example. You can learn more about sockets there.

Full code is available in my github repo netchat-cli.

I had to use MultiThreading in this program , because in the example code recieve function is after send function. So if the other client send message to us and we are writing message , then we can only see recieved message after sending the message we have been writing. Thats not how clients like netcat works , with MultiThreading this problem is solved.

Threads are popular way to improve application through parallelism.

In C , thread library can be included using #include <pthread.h>.

Creating a thread is really simple. I will use netchat source code as example.


// thread function for listening
void *listen_sock(void *argp);

... inside main()

pthread_t listen_thread;

pthread_create(&listen_thread, NULL, listen_sock, NULL);

...

void *listen_sock(void *argp) {
    char reply[2048];
    while(1) {
        // receive data 
        if(recv(sock, reply, 2048, 0) < 0) {
            printf("Failed to recieve message \n");
            exit(1);
        }
        printf("%s", reply);
        // reset contents of reply
        memset(reply, 0, 2048);
    }
}

I have declared listen_sock function with type void*. This function is executed when thread is created. Then inside main() declared a variable with type pthread_t.

pthread_create() once this function is called , Code inside listen_sock is executed in the background.

There is also another useful function to handle threads , pthread_join(thread_var, NULL). This function block the calling thread and wait till the called thread terminate. Since we need both threads run at same time (main thread and listen_thread) i didn’t used this function.


Edited on 21/02/2022

The above function was straight forward, i didn’t do any security check on that. Today my friend B[] did code audit on it and shown me a possible vulnerability.

If a malicious user send a string that is not NULL terminated, so reply does not end in NULL character . In that case, printf doesn’t know how long the string is supposed to be and causes a segmentation fault during print

Rewrite of the function :-

// MAX_SIZE is defined at the top and its value is 2048

void *listen_sock(void *argp) {
    char reply[MAX_SIZE + 1];
    while(1) {
        // receive data 
        size_t r = recv(sock, reply, MAX_SIZE, 0);
        if(r <= 0 || r > MAX_SIZE) {
            fprintf(stderr, "Failed to recieve message \n");
            exit(1);
        } else {
            // NULL terminate string ( clear buffer and prevent String Termination Error)
            reply[r] = '\0';
            printf("%s", reply);
        }
    }
}

Final result :-