George Karanikas
George Karanikas

Reputation: 1244

read() from socket hangs when run from thread

I'm trying to write a proxy server and right now I want to implement pipelining. I came across a problem though and need assistance. I checked this question but I think it doesn't apply since I do have data to read from the socket.

The main idea is the following. For each connection I create a thread that handles it and for each request in this connection I want to create a thread that handles that request. So far I have managed to write the code for the first part and it works properly (the thread also handles all the requests of the connection).

Now when I'm trying to read from the socket, from a request handling thread, it hangs. The function that I use to read data is the same as before (in the working version).

void copydata(int from, int to, int len)
{
    char tbuff[BSIZ];
    int n;
    while (len > 0)
    {
        if ((n = read(from, tbuff, BSIZ)) <= 0) break;
        if (write(to, tbuff, n) < n) break;
        len -= n;
    }
}

The from, to and len variables have appropriate values (I checked them). Is there anything that can cause such behaviour?

PS: If more code is required for something please let me know.

EDIT

Here is how the len is acquired:

int contentlength(char *header)
{
    int len = INT_MAX;
    char line[MAX_LINE];

    if (HTTPheadervalue_case(header, "Content-Length", line)) sscanf(line, "%d", &len);
    return len;
}

Calling copydata (where activesocket is a function that opens the socket):

if ((srv = activesocket(host, portno)) < 0)
    {
        sprintf(reshead, "HTTP/1.1 503\r\nContent-Length: 12\r\nConnection: close\r\n\r\nNon-existent");
        write(cli, reshead, strlen(reshead));
    } else
    {
        sprintf(reqhead1, "%s %s HTTP/1.1\r\n", "GET", path);
        if (HTTPheadervalue_case(reqhead1, "Connection", result)) if (strcasecmp(result, "close") == 0) cli_terminate[cli] = TRUE;
        strcat(reqhead1, reqhead);
        write(srv, reqhead1, strlen(reqhead1));
        while (completed[cli] != id)
            ;
        copydata(cli, srv, contentlength(reqhead));
        parseResponse(&srv, cli);
        completed[cli] = (completed[cli] + 1) % ULONG_MAX;
    }

EDIT

One example request header is the following:

Host: www.google.com
User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.9.1.16) Gecko/20120421 Iceweasel/3.5.16 (like Firefox/3.5.16)
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-gb,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Proxy-Connection: keep-alive
Cookie: cookie content

I tried to also strip the keep-alive flag but still the same happens.

Upvotes: 1

Views: 1743

Answers (1)

Nikolai Fetissov
Nikolai Fetissov

Reputation: 84151

I am guessing this is your problem (from accept(2)):

On Linux, the new socket returned by accept() does not inherit file status flags such as O_NONBLOCK and O_ASYNC from the listening socket.

I.e. you need to explicitly make every new accepted socket non-blocking.

Upvotes: 2

Related Questions