Click here to Skip to main content
       

C / C++ / MFC

 
GeneralRe: how to unsigned int64 to two unsigned int32 values Pinmembervishalgpt9-Jan-13 23:32 
GeneralRe: how to unsigned int64 to two unsigned int32 values PinmemberJochen Arndt9-Jan-13 23:58 
GeneralRe: how to unsigned int64 to two unsigned int32 values Pinmembervishalgpt10-Jan-13 0:08 
AnswerRe: [SOLVED] how to unsigned int64 to two unsigned int32 values Pinmember«_Superman_»10-Jan-13 18:39 
GeneralRe: [SOLVED] how to unsigned int64 to two unsigned int32 values Pinmembervishalgpt14-Jan-13 15:25 
GeneralRe: [SOLVED] how to unsigned int64 to two unsigned int32 values Pinmember«_Superman_»14-Jan-13 17:55 
GeneralRe: [SOLVED] how to unsigned int64 to two unsigned int32 values Pinmembervishalgpt14-Jan-13 19:01 
QuestionHTTP server in C. How to implement Keep-Alive? Pinmemberjohanm_29-Jan-13 20:02 
I'm busy with my own http server implementation on an embedded platform. Technically the server is HTTP 1.0 compliant, and therefore it expects the the client to send the header "Connection: Keep-Alive" to keep the connection open.
 
The implementation looks like this. I removed the code that parses the HTTP header and performs the request, to keep the post as short as possible:
 

 
int Service_Request(int conn) {
    
        struct ReqInfo reqinfo;
        volatile int resource = 0;
        int retval = 0;
        Req_Result req_result = GOT_REQ;
        
        InitReqInfo(&reqinfo);
    
        /* while we still have HTTP requests to process */
        while (req_result == GOT_REQ)
        {
            
            /* Get HTTP request, there are 3 different return values:
             * GOT_REQ: we got a valid HTTP request
             * TIMEOUT_REQ we timed out waiting for a request
             * ERROR_REQ there was some error receiving from the socket
             * usually because the connection was closed by the peer*/
            req_result = Get_Request(conn, &reqinfo);
            if ( req_result == TIMEOUT_REQ)
            {
                /* timed out waiting for the client, exit */
                retval = 0;
                break;
            }
            else if (req_result == ERROR_REQ)
            {
                /* some error, exit */
                retval = -1;
                break;
            }
            /* Process the request GET, PUT and POST is supported*/
            if (reqinfo.method == GET)
            {
                /* code to handle GET*/
            }
            /* PUT and POST are handled in the same way */
            else if ((reqinfo.method == PUT) || (reqinfo.method == POST) )
            {
                /* Code to handle PUT and POST*/        
            }
            else
            {
                /* not supported, code should never get here */
                reqinfo.status = 501;
                Return_Error_Msg(conn, &reqinfo);
            }
            /*Diag_Msg("Client Request: \r\n");
            Diag_Msg(reqinfo.clientRequest);*/
            
            /*
             * the reqinfo.keep_alive flag will be set to 1 if the
             * "Connection: Keep-Alive" header was sent by the client
             */
            if(reqinfo.keep_alive == 0)
            {
                break;
            }
    
            reqinfo.keep_alive_max--;
            if(reqinfo.keep_alive_max <= 0 )
            {
                /*
                 * the connection has been reused for the maxmum amount of times, stop
                 */
                break;
            }
            /*
             * If we get here, we will clear the memory used for the client request
             * and go to the beginning of the while loop to receive another request
             */
            Writeline(conn,"\r\n",2);
            FreeReqInfo(&reqinfo);
            
        }
        FreeReqInfo(&reqinfo);
        return (retval);
    }
 

The Get_Request function looks like this:
 
Req_Result Get_Request(int conn, struct ReqInfo * reqinfo) {
    
        char buffer[MAX_REQ_LINE] = {0};
        int    rval;
        fd_set fds;
        struct timeval tv;
    
    
        /* Set timeout to 5 seconds if this is the first request since the client connected, wait 5 seconds
         * Otherwise, wait 5ms */
        if(reqinfo->first_request == 1)
        {
            tv.tv_sec = 5;
            tv.tv_usec = 0;
            reqinfo->first_request = 0;
        }
        else
        {
            tv.tv_sec = reqinfo->keep_alive_timeout;
            tv.tv_usec = 0;
        }
    
        /* Loop through request headers. If we have a simple request,
        then we will loop only once. Otherwise, we will loop until
        we receive a blank line which signifies the end of the headers,
        or until select() times out, whichever is sooner.                */
        do {
    
        /* Reset file descriptor set */
    
        FD_ZERO(&fds);
        FD_SET (conn, &fds);
    
    
        /* Wait until the timeout to see if input is ready */
    
        rval = select(conn + 1, &fds, NULL, NULL, &tv);
    
    
        /* Take appropriate action based on return from select() */
    
        if ( rval < 0 )
        {
          Diag_Msg("Error calling select() in get_request()");
          return (ERROR_REQ);
        }
        else if ( rval == 0 ) {
    
          /* input not ready after timeout */
    
          return (TIMEOUT_REQ);
    
        }
        else {
    
          /* We have an input line waiting, so retrieve it */
            memset(buffer,0,MAX_REQ_LINE - 1);
          if(Readline(conn, buffer, MAX_REQ_LINE - 1) == -1)
          {
                return (ERROR_REQ);
          }
          if(reqinfo->clientRequest == NULL)
          {
                reqinfo->clientRequest = calloc(MAX_REQ_LINE - 1, sizeof(char));
                strncpy(reqinfo->clientRequest,buffer,MAX_REQ_LINE - 1);
          }
          else
          {
                strncat(reqinfo->clientRequest,buffer,MAX_REQ_LINE - 1);
          }
          Trim(buffer);
    
          if ( buffer[0] == '\0' )
            break;
    
          if ( Parse_HTTP_Header(buffer, reqinfo) )
            break;
        }
        } while ( reqinfo->type != SIMPLE );
    
        return (GOT_REQ);
    }
 

 
To describe the workings of this server in English: The server receives the first request. It parses the headers, if it finds the "Connection: Keep-Alive" header, it sets a flag. The server proceeds to process this request. WHen it is done it checks the keep-alive flag. If it is cleared, the server closes the connection. If set the server performs a clean-up operation and the proceeds to wait for another request over the same connection. And so on.
 
I tested this with curl:
 
C:\curl>curl -v -H "Connection: Keep-Alive" --data-binary ( at )vid1.bin 10.84.67.129/s1p0:1/vid[1-2].bin
 
    [1/2]: 10.84.67.129/s1p0:1/vid1.bin --> <stdout>
    --_curl_--10.84.67.129/s1p0:1/vid1.bin
    * About to connect() to 10.84.67.129 port 80 (#0)
    * Trying 10.84.67.129...
    * connected
    * Connected to 10.84.67.129 (10.84.67.129) port 80 (#0)
    > POST /s1p0:1/vid1.bin HTTP/1.1
    > User-Agent: curl/7.28.1
    > Host: 10.84.67.129
    > Accept: */*
    > Connection: Keep-Alive
    > Content-Length: 51200
    > Content-Type: application/x-www-form-urlencoded
    > Expect: 100-continue
    >
    * HTTP 1.0, assume close after body
    < HTTP/1.0 100 Continue
    * HTTP 1.0, assume close after body
    < HTTP/1.0 200 OK
    < Server: DTSVU v0.1
    < Content-Type: text/html
    * HTTP/1.0 connection set to keep alive!
    < Connection: Keep-Alive
    < Keep-Alive: timeout=5, max=10
    <
    * Connection #0 to host 10.84.67.129 left intact
 
    [2/2]: 10.84.67.129/s1p0:1/vid2.bin --> <stdout>
    --_curl_--10.84.67.129/s1p0:1/vid2.bin
    * Connection #0 seems to be dead!
    * Closing connection #0
    * About to connect() to 10.84.67.129 port 80 (#0)
    * Trying 10.84.67.129...
    * connected
    * Connected to 10.84.67.129 (10.84.67.129) port 80 (#0)
    > POST /s1p0:1/vid2.bin HTTP/1.1
    > User-Agent: curl/7.28.1
    > Host: 10.84.67.129
    > Accept: */*
    > Connection: Keep-Alive
    > Content-Length: 51200
    > Content-Type: application/x-www-form-urlencoded
    > Expect: 100-continue
    >
    * HTTP 1.0, assume close after body
    < HTTP/1.0 100 Continue
    * HTTP 1.0, assume close after body
    < HTTP/1.0 200 OK
    < Server: DTSVU v0.1
    < Content-Type: text/html
    * HTTP/1.0 connection set to keep alive!
    < Connection: Keep-Alive
    < Keep-Alive: timeout=5, max=10
    <
    * Connection #0 to host 10.84.67.129 left intact
    * Closing connection #
 

 
As you can see, curl says: Connection #0 seems to be dead! after the first request is completed. It then proceeds to close the connection and opens a new one. I'm sure I implemented the HTTP 1.0 keep-alive functionality correctly. SO my question is: what does curl expect over the connection after the first request is completed? Why does it decide the connection is dead?
 
PS the above code was adapted from http://www.paulgriffiths.net/program/c/webserv.php
SuggestionRe: HTTP server in C. How to implement Keep-Alive? PinmvpRichard MacCutchan9-Jan-13 22:24 
GeneralRe: HTTP server in C. How to implement Keep-Alive? Pinmemberjohanm_210-Jan-13 1:17 
QuestionProblem loading non-default wab PinmemberMember 8689269-Jan-13 2:31 
AnswerRe: Problem loading non-default wab PinmemberCode-o-mat10-Jan-13 2:06 
GeneralRe: Problem loading non-default wab PinmemberMember 86892611-Jan-13 6:05 
GeneralRe: Problem loading non-default wab PinmemberCode-o-mat11-Jan-13 7:49 
GeneralRe: Problem loading non-default wab PinmemberMember 86892611-Jan-13 9:56 
GeneralRe: Problem loading non-default wab PinmemberCode-o-mat11-Jan-13 10:07 
GeneralRe: Problem loading non-default wab PinmemberCode-o-mat11-Jan-13 10:12 
GeneralRe: Problem loading non-default wab PinmemberMember 86892612-Jan-13 4:17 
GeneralRe: Problem loading non-default wab PinmemberCode-o-mat12-Jan-13 8:09 
QuestionRe: Problem loading non-default wab PinmvpRichard MacCutchan11-Jan-13 6:41 
AnswerRe: Problem loading non-default wab PinmemberMember 86892611-Jan-13 9:53 
GeneralRe: Problem loading non-default wab PinmvpRichard MacCutchan11-Jan-13 23:17 
GeneralRe: Problem loading non-default wab PinmemberMember 86892612-Jan-13 4:06 
GeneralRe: Problem loading non-default wab PinmvpRichard MacCutchan12-Jan-13 4:20 
QuestionHow do you get the file size for an open file? PinmemberMember 41945938-Jan-13 3:29 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.


Advertise | Privacy | Mobile
Web01 | 2.8.140916.1 | Last Updated 16 Sep 2014
Copyright © CodeProject, 1999-2014
All Rights Reserved. Terms of Service
Layout: fixed | fluid