C TCP sockets, echo server with file sending, hangs up after sending a file
<p>I wanted to write a simple TCP echo server application. I managed to do the echo part, but have some problems with sending files between client and server. The idea is simple: despite sending ordinary messages, client can send a special command to server (\SENDFILE filename.txt), and after receiving such command, server should ask client for this file, and get the file from client. (Further I would like to get a file from one client, and later send it to another one). </p>

<p>I think "the protocol" here is simple, however, after typing \SENDFILE at client's side, client hangs up, and does not receive any further messages from server. Moreover (server and client are in different directories) at server's side there's only an empty file from client, with no content inside.</p>

<p>Any ideas what can be wrong here?</p>

<p><strong>client.c</strong></p>

<pre><code>#include&lt;stdio.h&gt; //printf
#include&lt;string.h&gt;    //
#include &lt;sys/stat.h&gt;
#include&lt;sys/socket.h&gt;    //socket
#include&lt;arpa/inet.h&gt; //inet_addr
#include &lt;fcntl.h&gt;
#define SERVER_PORT     9034
#define BUFF_SIZE       2000

int sendall(int s, char *buf, int len)
{
    int total = 0;
    int bytesleft = len;
    int n;

    while(total &lt; len)
    {
        n = send(s, buf+total, bytesleft, 0);
        if (n == -1)
            break;
        total += n;
        bytesleft -= n;
    }

    return n==-1?-1:0;
}

void SendMsgToSender(char *msg, int connfd)
{
    write(connfd, msg, strlen(msg));
    memset(msg, 0, BUFF_SIZE);
}

int main(int argc , char *argv[])
{
    int sock;
    struct sockaddr_in server;
    char bufferOUT[BUFF_SIZE] , bufferIN[BUFF_SIZE];
    struct stat file_stat;

    memset(bufferOUT, 0, BUFF_SIZE);
    memset(bufferIN, 0, BUFF_SIZE);

    //Create socket
    sock = socket(AF_INET , SOCK_STREAM , 0);
    if (sock == -1)
    {
        printf("Could not create socket");
    }
    //  puts("Socket created");

    server.sin_addr.s_addr = inet_addr("127.0.0.1");
    server.sin_family = AF_INET;
    server.sin_port = htons( SERVER_PORT );

    //Connect to remote server
    if (connect(sock , (struct sockaddr *)&amp;server , sizeof(server)) &lt; 0)
    {
        perror("Connect failed. Error");
        return 1;
    }

    // puts("Connected\n");
    int read_size = 10;

    //keep communicating with server
    while(1)
    {
        printf("&gt; ");
        fgets(bufferOUT, BUFF_SIZE, stdin);

        //Send some data
        if( send(sock , bufferOUT , BUFF_SIZE , 0) &lt; 0)
        {
            perror("Send failed");
            return 1;
        }

        //Receive a reply from the server
        if( (read_size = recv(sock , bufferIN , BUFF_SIZE , 0)) &lt; 0)
        {
            perror("Recv failed");
            break;
        }

        if(read_size == 0)
            break;

        if(bufferIN[0] == '\\')
        {
            char tmp[BUFF_SIZE], filename[BUFF_SIZE], *param;
            memset(filename, BUFF_SIZE, 0);
            strcpy(tmp, bufferIN);

            param = strtok(tmp, " ");
            if(param != NULL)
            {
                if(!strcmp(param, "\\GIVEMEFILE"))
                {
                    param = strtok(NULL, " ");
                    if(param != NULL)
                    {
                        strcpy(filename, param);
                        FILE * fp;
                        int nBytes;
                        char buffer[BUFF_SIZE], *s;
                        memset(buffer, 0, BUFF_SIZE);

                        fp = fopen(filename, "r");
                        if(fp == NULL)
                        {
                            perror("fopen");
                            fflush(stdout);
                            break;
                        }

                        int remain_data = file_stat.st_size;

                        do
                        {
                            s = fgets(buffer, BUFF_SIZE, fp);
                            if(s != NULL &amp;&amp; buffer[0] != EOF)
                            {
                                nBytes = sendall(sock, buffer, BUFF_SIZE);
                                remain_data -= nBytes;
                            }
                            else
                                break;
                        }
                        while((s != NULL) &amp;&amp; (nBytes &gt; 0) &amp;&amp; (remain_data &gt; 0));
                        fclose(fp);

                        memset(bufferOUT, 0, BUFF_SIZE);
                        memset(bufferIN, 0, BUFF_SIZE);

                        continue;
                    }
                }
            }
        }
        else
        {
            printf("%s\n", bufferIN);
            fflush(stdout);
        }

        memset(bufferOUT, 0, BUFF_SIZE);
        memset(bufferIN, 0, BUFF_SIZE);
    }

    close(sock);
    return 0;
}
</code></pre>

<p><strong>server.c</strong></p>

<pre><code>    #include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;
#include &lt;unistd.h&gt;
#include &lt;sys/types.h&gt;
#include &lt;sys/socket.h&gt;
#include &lt;netinet/in.h&gt;
#include &lt;arpa/inet.h&gt;
#include &lt;netdb.h&gt;
#include &lt;time.h&gt;
#include &lt;fcntl.h&gt;

#define SERVER_PORT     9034
#define BUFF_SIZE       2000

void StripNewline(char *s)
{
    while(*s != '\0')
    {
        if(*s == '\r' || *s == '\n')
        {
            *s = '\0';
        }
        s++;
    }
}

void SendMsgToSender(char *msg, int connfd)
{
    write(connfd, msg, strlen(msg));
    memset(msg, 0, BUFF_SIZE);
}

// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa)
{
    if (sa-&gt;sa_family == AF_INET)
    {
        return &amp;(((struct sockaddr_in*)sa)-&gt;sin_addr);
    }

    return &amp;(((struct sockaddr_in6*)sa)-&gt;sin6_addr);
}

int GetFileFromClient(int connfd, char *filename)
{
    FILE * fp = NULL;
    int bytes;
    char buffer[BUFF_SIZE];
    memset(buffer, 0, BUFF_SIZE);

    fp = fopen(filename, "w");
    if(fp == NULL)
        return 0;

    memset(buffer, 0, BUFF_SIZE);
    sprintf(buffer, "\\GIVEMEFILE %s \r\n", filename);
    SendMsgToSender(buffer, connfd);

    while(1)
    {
        memset(buffer ,0 , BUFF_SIZE);
        if((bytes =  recv(connfd , buffer , BUFF_SIZE , 0) ) &lt;= 0)
            return 0;
        else
            fprintf(fp, "%s\n", buffer);
    }

    fclose(fp);
    sleep(1);

    memset(buffer, 0, BUFF_SIZE);
    sprintf(buffer, "\r\n");
    SendMsgToSender(buffer, connfd);

    return 1;
}

int main(void)
{
    fd_set master;
    fd_set read_fds;
    int fdmax;

    int listener;
    int client_sock;
    struct sockaddr_storage remoteaddr;
    socklen_t addrlen;

    char bufferIN[BUFF_SIZE], bufferOUT[BUFF_SIZE], tmp[BUFF_SIZE], *datetime;
    int nbytes;

    char remoteIP[INET6_ADDRSTRLEN];

    int yes=1;
    int i, j, rv;

    struct addrinfo hints, *ai, *p;

    FD_ZERO(&amp;master);
    FD_ZERO(&amp;read_fds);

    memset(bufferIN, 0, BUFF_SIZE);
    memset(bufferOUT, 0, BUFF_SIZE);
    memset(tmp, 0, BUFF_SIZE);

    memset(&amp;hints, 0, sizeof hints);
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = AI_PASSIVE;

    char port[16] = "9034";
    if (getaddrinfo(NULL, port, &amp;hints, &amp;ai) &lt; 0)
    {
        fprintf(stderr, "selectserver: %s\n", gai_strerror(rv));
        exit(1);
    }

    for(p = ai; p != NULL; p = p-&gt;ai_next)
    {
        listener = socket(p-&gt;ai_family, p-&gt;ai_socktype, p-&gt;ai_protocol);
        if (listener &lt; 0)
        {
            continue;
        }

        setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &amp;yes, sizeof(int));

        if (bind(listener, p-&gt;ai_addr, p-&gt;ai_addrlen) &lt; 0)
            continue;

        break;
    }

    if (p == NULL)
        exit(2);

    freeaddrinfo(ai);

    if (listen(listener, 10) == -1)
    {
        perror("listen");
        exit(3);
    }

    FD_SET(listener, &amp;master);
    fdmax = listener;

    printf("Server is running ...\n\n");

    for(;;)
    {
        read_fds = master;
        if (select(fdmax+1, &amp;read_fds, NULL, NULL, NULL) == -1)
        {
            perror("select");
            exit(4);
        }

        for(i = 0; i &lt;= fdmax; i++)
        {
            if (FD_ISSET(i, &amp;read_fds))
            {
                if (i == listener)
                {
                    addrlen = sizeof remoteaddr;
                    client_sock = accept(listener,
                                         (struct sockaddr *)&amp;remoteaddr,
                                         &amp;addrlen);

                    if (client_sock == -1)
                    {
                        perror("accept");
                    }
                    else
                    {
                        FD_SET(client_sock, &amp;master);
                        if (client_sock &gt; fdmax)
                            fdmax = client_sock;
                    }
                }
                else
                {
                    if ((nbytes = recv(i, bufferIN, BUFF_SIZE, 0)) &lt;= 0)
                    {
                        if (nbytes == 0)
                            close(i);

                        else if(nbytes == -1)
                        {
                            perror("recv");
                            fflush(stdout);
                        }

                        close(i);
                        FD_CLR(i, &amp;master);
                    }
                    else
                    {
                        bufferIN[nbytes-1] = '\0';
                        StripNewline(bufferIN);
                        strcpy(tmp, bufferIN);

                        if(bufferIN[0] == '\\')
                        {
                            char *command, *param;
                            command = strtok(bufferIN, " ");

                            if(!strcmp(command, "\\QUIT"))
                            {
                                close(i);
                                FD_CLR(i, &amp;master);
                                break;
                            }

                            else if(!strcmp(command, "\\SENDFILE"))
                            {
                                param = strtok(tmp, " ");
                                if(param != NULL)
                                {
                                    param = strtok(NULL, " ");
                                    if(param != NULL)
                                    {
                                        printf("Client is sending me a file '%s'...\n", param);
                                        GetFileFromClient(i, param);
                                    }
                                }
                            }
                            else
                            {
                                SendMsgToSender(bufferIN, i);
                            }

                            memset(bufferIN, 0, BUFF_SIZE);
                            memset(bufferOUT, 0, BUFF_SIZE);
                        }
                        else
                        {
                            SendMsgToSender(bufferIN, i);
                        }
                    }
                } // END handle data from client
            } // END got new incoming connection
        } // END looping through file descriptors
    } // END for(;;)

    memset(bufferIN, 0, BUFF_SIZE);
    memset(bufferOUT, 0, BUFF_SIZE);

    return 0;
}
</code></pre>