Sergio
Sergio

Reputation: 275

Recv() function messing up other parts of my code

I am trying to execute cat|grep using a client server set-up, works as follows: client sends word to search for using grep, server executes cat|grep, sends results to client but the recv() function seems to be messing up with my code.

What's the problem?

Adding the recv() function makes other parts of my code not working, every puts() works until puts("test5"); which is where my code is stuck in the execution, putting the recv() function as a comment makes the code run fine.

Till now I am not using the word I send from the client in any way so the problem must be with the receive function itself, it's not giving an error and when I print the content I send it works fine.

Here is the relevant client part:

#include <stdio.h> 
#include <sys/socket.h> 
#include <arpa/inet.h> 
#include <unistd.h> 
#include <string.h> 
#include <stdlib.h>
#include<errno.h>

#define PORT 8080

int main(int argc, char const *argv[]) 
{ 
    int sock = 0, valread; 
    struct sockaddr_in serv_addr; 
    int buffer[1024];
    char buffer2[1024]={0};
    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) 
    { 
        printf("\n Socket creation error \n"); 
        return -1; 
     } 

    serv_addr.sin_family = AF_INET; 
    serv_addr.sin_port = htons(PORT);        

    if(inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr)<=0)  
    { 
        perror("Invalid address \n"); 
        return -1; 
    } 

    if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) 
    { 
        perror("Connection Failed \n"); 
        return -1; 
    } 

    int i, array[argc], countsize=0;
    if(argc>=2)
    {
        for(i=1; i<argc; i++)
        {
            int number=atoi(argv[i]);
            array[i-1]=number;
            countsize++;
        }

        if(send(sock, array, countsize*sizeof(int), 0)<0)
        {
            printf("Error in send! %s\n", strerror(errno));
           return -1; 
        }

        if(argc>=2)
        {
             int i=0;
             for(int i=0; i<argc; i++) 
            {
                if(atoi(argv[i])==6)
                {
                    puts("Please enter the name/word you want to search for in the history file: ");
                    char word[30];
                    fgets(word, 30, stdin); 
                    if(send(sock, &word , 30, 0)<0)
                        printf("Error in send! %s\n", strerror(errno));

                    valread = read( sock , buffer2, 1024); 
                    puts("The result cat|grep is:");
                    printf("%s\n", buffer2);
                }
            }  
        }
    }      
    return 0; 
} 

Here is the server's main method:

#include <stdio.h> 
#include <unistd.h> 
#include <sys/socket.h> 
#include <stdlib.h> 
#include <netinet/in.h> 
#include <string.h> 
#include<errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdbool.h>
#include <sys/wait.h>
#include<time.h> 
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <pthread.h>
#include <arpa/inet.h> 

#define PORT 8080
void *catgrep(void *);

int main() 
{ 
    int server_fd, new_socket;
    struct sockaddr_in address; 
    int opt = 1; 
    int addrlen = sizeof(address); 
    char buffer2[1024]={0};

    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) 
    { 
        perror("socket failed"); 
        exit(EXIT_FAILURE); 
    }        

    if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR , &opt, sizeof(opt))) 
    { 
        perror("setsockopt"); 
        exit(EXIT_FAILURE); 
    } 
    address.sin_family = AF_INET; 
    address.sin_addr.s_addr = INADDR_ANY; 
    address.sin_port = htons( PORT );       

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

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

        int arguments[10]={0};
        int n = recv(new_socket, arguments ,1024*sizeof(int),0);
    int j;

        int argumentsize=n/sizeof(int);
        for(j=0; j<argumentsize;j++)
        {
            if(arguments[j]==6)
            {
                pthread_t th5;
                pthread_attr_t attr5;
                pthread_attr_init(&attr5);

                if(pthread_create(&th5,&attr5, catgrep,&new_socket)!=0)
                {
                    printf("Error in pthread_create %s\n", strerror(errno));
                    return -1; 
                }
                pthread_join(th5, NULL);
               return -1; 
           }
        } 
        close(new_socket);
    }
    close(server_fd);
    return 1;
}

Here is my catgrep() method:

void *catgrep(void * param)
{
    int *sock = (int*) param;
    int new_sock = *sock;

    int fd[2];
    pipe(fd);
    pid_t pid = fork(); 
    char word[30];
    recv(new_sock, word ,30, 0); //when I put this line code 
    starts messing up. 
    puts(word);

    if(pid==0)
    {
        close(1);
        dup(fd[1]);
        close(fd[0]);
        close(fd[1]);
        char *cat_args[] = {"/bin/cat", "GameData.txt", NULL};
        if(execv(cat_args[0], cat_args)<0)
        {
            printf("Error in execv! %s\n", strerror(errno));
        }
       exit(0);
    }

    if(pid > 0)
    {
        close(0);
        dup(fd[0]);
        close (fd[1]);
        close(fd[0]);

        puts("test2");
        FILE *fp2;
        if ((fp2 = popen("grep -w tries", "r")) == NULL)
        {
            perror("popen failed");
            return NULL;
        }
        puts("test3");
        size_t str_size = 1024;
        char *stringts2 = malloc(str_size);
        if (!stringts2)
        {
            perror("stringts allocation failed");
            return NULL;
        }
        puts("test4");

        stringts2[0] = '\0';
        char buf[128];
        size_t n;
        puts("test5"); //when I use the recv() program gets stuck here. 

        while ((n = fread(buf, 1, sizeof(buf) - 1, fp2)) > 0)
        {
            puts("test10");
            buf[n] = '\0';
            size_t capacity = str_size - strlen(stringts2) - 1;
            while (n > capacity)
            {
                str_size *= 2;
                stringts2 = realloc(stringts2, str_size);
                if (!stringts2)
                {
                    perror("stringts realloation failed");
                    return NULL;
                }
                capacity = str_size - strlen(stringts2) - 1;
            }
            strcat(stringts2, buf);
        }

        puts("test6");

        if (pclose(fp2) != 0)
        {
            perror("pclose failed");
            return NULL;
        }
        puts("test7");

        if(send(new_sock, stringts2, 10000, 0)<0)
        {
            printf("Error in send! %s\n", strerror(errno));
        }
    }
    return NULL;
}

Few notes:

I am aware that in this particular piece of code I am not using the word sent by the client, hence why some lines are as comments, I will implement this when my problem gets fixed.

I am using popen() as I want to return the output of catgrep().

I isolated the problem and not it's only happening when I include the recv() function.

The word I am sending is being printed when I use recv() so the function isn't causing errors but it's messing up other parts.

UPDATE:

As suggested by someone in the comments I changed the way I receive the word sent by my client, I am now using the following:

int count = 0;
int total = 0;

while ((count = recv(new_sock, &word[total], sizeof word - count, 0)) > 0)
{
    total=total+count;
}
if (count==-1)
{
    perror("error in recv()");
}

Still having the same problem and same output.

Upvotes: 0

Views: 68

Answers (1)

Chris Dodd
Chris Dodd

Reputation: 126203

The basic problem is that you are confusing strings and byte streams -- they're not the same thing.

In your client, you send some data with:

        char word[30];
        fgets(word, 30, stdin); 
        if(send(sock, &word , 30, 0)<0)

This will read a line (including a newline) into the beginning of an on-stack buffer, and then send the entire buffer, including whatever garbage happens to be in it after the end of the string. You probably don't want the newline, maybe don't want the NUL terminator, and certainly don't want the garbage.

In addition, you don't check the return value of send for a short send -- in some (admittedly rare) situations, a send might not send all the data you request.

On the reading side you don't check the return value of recv to see how many bytes you got, which may be different from what you expect -- there's no guarentee that there will be 1:1 correspondence between send and recv calls on a connection. One send might get broken up and split across multiple recvs, and several sends might have their data combined and returned in one recv. So you always need to check the return value of recv to see how many bytes you actually got.

Upvotes: 2

Related Questions