LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   read socket problem (proxy server related) (https://www.linuxquestions.org/questions/programming-9/read-socket-problem-proxy-server-related-258308/)

jnusa 11-23-2004 06:28 AM

read socket problem (proxy server related)
 
I've moved the 'cheap http server problems...' into a new thread, because it wasn't really my thread :)

To sum up:

I'm coding a proxy server, and I'm having great difficulty reading the body, og a http request. I read once, and then read returns -1 (with errno: "Connection reset by peer). It only reads a fraktion of what it is supposed to do. I memset the buffer, it reads into, and I'm pretty sure, it's ok.

Here's the code:

Code:

int read_body(int fd, char *ptr, int length)
{       
        int        res = 0;
        int temp=1;
        int total = 0;

        if(ptr != NULL)
        {
                while(total < length )
                {       
                        res = (read(fd, ptr+total, length));
                        if(res != -1)
                                total += res;
                        if(res == 0)
                        {        puts("\n\n\nBREAK 0!!!!\n\n\n");
                                break;
                        }
                        if(res < 0)
                        {        puts("\n\n\nBREAK -1!!!\n\n\n");
                                break;
                        }
                        printf("\n Read: %d\tTotal read: %d\t Total length: %d\tfd: %d", res-temp, total, length, fd);
                }
                logit("\n", "content.log");
                logit(ptr, "content.log");
        }
        else
                logit("\nEvt. malloc error -> no error handeling!", "system.log");       
       
      close(fd);
      return res;
}


Output in terminal:

Code:

Status-code: 200
strlen(obj->body_content): 5548
Read: 2381    Total read: 2382        Total length: 5548    fd: 5

BREAK -1!!!
 
strlen(obj->body_content): 5548
Request end



If I read relative small sites (e.g. www.hootmail.dk, 2999b), there's no problem. If I read larger sites (e.g. www.leog.net), it only reads a fraktion (in one read cycle) and returns -1 (in the second read cycle).

Does anyone have any experience or have encountered the same problem? Or am I doing somethink wrong? Any info is greatly appriciated.

/Jnusa

rjlee 11-23-2004 07:35 AM

The -1 does not mean that no data was read. From the manpage:
Quote:

POSIX allows a read that is interrupted after reading some data to return -1 (with errno set to EINTR) or to return the number of bytes already read.
Also, to determine the value of errno, are you setting it to 0 before the call to read(), or could it be related to another I/O routine?

Cedrik 11-23-2004 07:54 AM

How do you open your socket ? Could you post the code that initialize fd ?

jnusa 11-23-2004 08:13 AM

No, i do not set errno = 0. Should I do this every time, I call a function that use errno?
Yes you're right about -1, not meaning that there's no more data. But I guess it means that there has been som kind of error (specified with errno).
Keep in mind, that I use the current filedescriptor to read the header og the server respons, and I'm having no problem there.

I pretty much followed the tutorial in "Internetworking with TCP/IP", by Comer:

Here's my code for opening my socket.

function call in main:

Code:

#define QLEN 32 //max connection queue length

int main(int argc, char *argv[])
{
        char *service = "http";
        ....
        msock = passiveTCP(service, QLEN);
        ...
       
                       
                       
return 0;       
}

Function I call in main:

Code:

int passiveTCP(const char *service, int qlen){
        return passivesock(service, "tcp", qlen);
}


Code:

int passivesock(const char *service, const char *transport, int qlen)
/*
 * Arguments:
 *      service  - service associated with the desired port
 *      transport - transport protocol to use ("tcp" or "udp")
 *      qlen      - maximum server request queue length
 */
{
        struct servent        *pse;        /* pointer to service information entry        */
        struct protoent *ppe;        /* pointer to protocol information entry*/
        struct sockaddr_in sin;        /* an Internet endpoint address                */
        int        s, type;        /* socket descriptor and socket type        */

        memset(&sin, 0, sizeof(sin));
        sin.sin_family = AF_INET;
        sin.sin_addr.s_addr = INADDR_ANY;

    /* Map service name to port number */
        if ( (pse = getservbyname(service, transport)) )
                sin.sin_port = htons(ntohs((unsigned short)pse->s_port)
                        + portbase);
        else if ((sin.sin_port=htons((unsigned short)atoi(service))) == 0)
                errexit("can't get \"%s\" service entry\n", service);

    /* Map protocol name to protocol number */
        if ( (ppe = getprotobyname(transport)) == 0)
                errexit("can't get \"%s\" protocol entry\n", transport);

    /* Use protocol to choose a socket type */
        if ( (strcmp(transport, "udp")) == 0)
                type = SOCK_DGRAM;
        else
                type = SOCK_STREAM;

    /* Allocate a socket */
        s = socket(PF_INET, type, ppe->p_proto);
        if (s < 0)
                errexit("can't create socket: %s\n", strerror(errno));

/*        int yes = 1;
        if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) == -1)
                puts("setsockopt SO_REUSEADDR");
*/       
        int status = 0;
        /* Bind the socket  - loop until port is ready/released*/
        while(status==0)
        {       
                if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) >= 0)
                        status = 1;
                if(status == 0) { puts("*"); (void)sleep(2); }
                /*errexit("can't bind to %s port: %s\n", service,
                        strerror(errno));*/       
        }
       
        if (type == SOCK_STREAM && listen(s, qlen) < 0)
                errexit("can't listen on %s port: %s\n", service,
                        strerror(errno));
        return s;
}


jnusa 11-24-2004 02:53 AM

I've tried setting errno to zero
Code:

errno = 0;
But still no go. It only reads once, returns -1 with errno message "Connection reset by peer". Does any have other solution to try or I'm I the first to encounter this problem.?

itsme86 11-24-2004 09:16 AM

It looks like you're doing a read() to get the header, then you're calling read_body(), but there's a good chance the body was already read in with the header and you've just somehow discarded that buffer. Once the HTTP server is done sending you the stuff it closes the connection (Connection reset by peer).

My guess is that you're going to find a big chunk of the body in the buffer with the header.

jnusa 11-24-2004 02:50 PM

Yeah, Im reading the header first. Since I only read 1 char at a time (until I reach body - is determined by CRLFCRLC), I'm certain that I'm not reading anymore data, than the header info. Also I can see in the 1k-2k bytes of body that I do read, that it's the beginning of the body (all the meta tags html start tag and so on). I'm trying to debug, by module testing my functions, and so far they work fine (read_body anyway, and som of the socket functions). I'm very puzzled about this. I've tried rearranging the read_body function, so it's reads the body faster, to avoid a timeout in the socket buffer. That wasn't the either. I've also tried declaring the buffer variable inside read_body, to see if the buffer pointer was messed up... that wasn't the case. Is there any socket options, that only will allow on read, pr connection or something like that?

itsme86 11-24-2004 03:32 PM

Check out man select. You can add the socket to the read set.

jnusa 11-24-2004 03:45 PM

hmm... well I'm doing that before I read the reply, to be sure that data is being transmitted. After I'm sure that data is being transmitted, I read the header, look at content (body length, status code, host name ect), and read the body content.
My select code:

Code:

        int maxfd = fd_request + 1;
        struct timeval tv;
        tv.tv_sec = 10;
        tv.tv_usec = 0;
        int i, res;
        http_headers http_obj;               
        http_headers *obj = &http_obj;
        fd_set fdset;                                //filedescriptor set               
        FD_ZERO(&fdset);                        //enables timeout
        FD_SET(fd_request, &fdset);        //
       
        if((res = select(maxfd, &fdset, NULL, NULL, &tv))<0)
                printf("\n###Error select: %s", strerror(errno));
        else if(res == 0)
                http_obj.status = -2;        //reply with error message to client.
       
        i = 0;
        if(FD_ISSET(fd_request, &fdset))
                if((i = read_reply(fd_request, &obj))<0)
                        printf("\nError readback: %s", strerror(errno));

Should I also select on filedescriptor when reading the body? I've tried to keep on reading, even though read() returns 0 and -1, to see if there were delays in the transmission. Of course that wasn't it either.

jnusa 11-25-2004 09:31 AM

Problem solved
 
The reson for the problem was, that I was sending a request from the client, to the server. When I calculated the length of the request, it was 100-300kb indstead of 200-300b! This length would be used when sending the data to the server (via : int write(int fd, char *data, int size). This somehow corrupted the memory or something. When I fixed the length, I could read the file descriptor more than once. I have no rational explaination for this.

Scenario:

Code:

-> Make mastersocket, and wait for connection
<- connection made by client -> make slave socket and fork()
-> read request and read hostname. Make request socket and connect to host.
-> send request to host (webserver), with wrong size
<- Read respons from server - total size e.g. 8500b:
                      ->Read once 2650b (200 status code, request succeded, and start of the webpage ok (<html><body>...))
                      ->Read second time -> return -1: errno =  "Connection reset by peer"

All the variables (except the request file descriptor), is initialized after the request is sent to the server. After I fixed the size of the request, in the parameter to write() everthing was working. Anyone have an explaination?


All times are GMT -5. The time now is 08:37 AM.