Exemplo n.º 1
0
static void
bindSocketToAddr(SOCKET                     const winsock,
                 const struct sockaddr *    const addrP,
                 socklen_t                  const sockAddrLen,
                 const char **              const errorP) {
    
    int rc;

    rc = bind(winsock, (struct sockaddr *)addrP, sockAddrLen);

    if (rc != 0) {
        int const lastError = WSAGetLastError();
        xmlrpc_asprintf(errorP, "Unable to bind socket to the socket address.  "
                        "bind() failed with WSAERROR %i (%s)",
                        lastError, getWSAError(lastError));
    } else
        *errorP = NULL;
}
Exemplo n.º 2
0
void
SocketWinInit(const char ** const errorP) {

    WORD wVersionRequested;
    WSADATA wsaData;
    int err;
 
    wVersionRequested = MAKEWORD(1, 0);
 
    err = WSAStartup(wVersionRequested, &wsaData);

    if (err != 0) {
        int const lastError = WSAGetLastError();
        xmlrpc_asprintf(errorP, "WSAStartup() faild with error %d (%s)",
                        lastError, getWSAError(lastError));
    } else
        *errorP = NULL;
}
Exemplo n.º 3
0
static void
setSocketOptions(SOCKET        const fd,
                 const char ** const errorP) {

    int32_t const n = 1;

    int rc;

    rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&n, sizeof(n));

    if (rc != 0) {
        int const lastError = WSAGetLastError();
        xmlrpc_asprintf(errorP, "Failed to set socket options.  "
                        "setsockopt() failed with WSAERROR %d (%s)",
                        lastError, getWSAError(lastError));
    } else
        *errorP = NULL;
}
Exemplo n.º 4
0
static void
addAuthCookie(xmlrpc_env * const envP,
              TSession *   const abyssSessionP,
              const char * const authCookie) {

    const char * cookieResponse;
    
    xmlrpc_asprintf(&cookieResponse, "auth=%s", authCookie);
    
    if (xmlrpc_strnomem(cookieResponse))
        xmlrpc_faultf(envP, "Insufficient memory to generate cookie "
                      "response header.");
    else {
        ResponseAddField(abyssSessionP, "Set-Cookie", cookieResponse);
    
        xmlrpc_strfree(cookieResponse);
    }
}   
Exemplo n.º 5
0
static void
addAuthorizationHeader(xmlrpc_env *         const envP,
                       struct curl_slist ** const headerListP,
                       const char *         const hdrValue) {

    const char * authorizationHeader;
            
    xmlrpc_asprintf(&authorizationHeader, "Authorization: %s", hdrValue);
    
    if (authorizationHeader == xmlrpc_strsol)
        xmlrpc_faultf(envP, "Couldn't allocate memory for "
                      "Authorization header");
    else {
        addHeader(envP, headerListP, authorizationHeader);
        
        xmlrpc_strfree(authorizationHeader);
    }
}
Exemplo n.º 6
0
void
DateToLogString(time_t const datetime,
                const char **const dateStringP) {

    const char *tzo;
    struct tm tm;

    xmlrpc_localtime(datetime, &tm);

    tzo = tzOffsetStr(tm, datetime);

    xmlrpc_asprintf(dateStringP, "%02d/%s/%04d:%02d:%02d:%02d %s",
                    tm.tm_mday, _DateMonth[tm.tm_mon],
                    1900 + tm.tm_year, tm.tm_hour, tm.tm_min, tm.tm_sec,
                    tzo);

    xmlrpc_strfree(tzo);
}
Exemplo n.º 7
0
static void
makeChannelInfo(struct abyss_openssl_chaninfo ** const channelInfoPP,
                SSL *                            const sslP,
                const char **                    const errorP) {

    struct abyss_openssl_chaninfo * channelInfoP;

    MALLOCVAR(channelInfoP);
    
    if (channelInfoP == NULL)
        xmlrpc_asprintf(errorP, "Unable to allocate memory");
    else {
        
        *channelInfoPP = channelInfoP;

        *errorP = NULL;
    }
}
Exemplo n.º 8
0
static void
parseHttpHostPortPath(const char *const hostportpath,
                      const char **const hostP,
                      unsigned short *const portP,
                      const char **const pathP,
                      const char **const errorP) {

    const char *path;

    char *buffer;

    buffer = strdup(hostportpath);

    if (!buffer)
        xmlrpc_asprintf(errorP,
                        "Couldn't get memory for host/port/path buffer");
    else {
        char *const slashPos = strchr(buffer, '/');

        char *hostport;

        if (slashPos) {
            path = xmlrpc_strdupsol(slashPos); /* Includes the initial slash */

            *slashPos = '\0';  /* NUL termination for hostport */
        } else
            path = strdup("*");

        hostport = buffer;

        /* The following interprets the port field without taking into account
           any %HH encoding, as the RFC says may be there.  We ignore that
           remote possibility out of laziness.
        */
        parseHostPort(hostport, hostP, portP, errorP);

        if (*errorP)
            xmlrpc_strfree(path);
        else
            *pathP = path;

        free(buffer);
    }
}
Exemplo n.º 9
0
static void
waitForConnection(struct socketUnix * const listenSocketP,
                  bool *              const interruptedP,
                  const char **       const errorP) {
/*----------------------------------------------------------------------------
   Wait for the listening socket to have a connection ready to accept.

   We return before the requested condition holds if the process receives
   (and catches) a signal, but only if it receives that signal a certain
   time after we start running.  (That means this behavior isn't useful
   for most purposes).

   We furthermore return before the requested condition holds if someone sends
   a byte through the listening socket's interrupt pipe (or has sent one
   previously since the most recent time the pipe was drained).

   Return *interruptedP == true if we return before there is a connection
   ready to accept.
-----------------------------------------------------------------------------*/
    struct pollfd pollfds[2];
    int rc;

    pollfds[0].fd = listenSocketP->fd;
    pollfds[0].events = POLLIN;

    pollfds[1].fd = listenSocketP->interruptPipe.interrupteeFd;
    pollfds[1].events = POLLIN;
    
    rc = poll(pollfds, ARRAY_SIZE(pollfds), -1);

    if (rc < 0) {
        if (errno == EINTR) {
            *errorP       = NULL;
            *interruptedP = TRUE;
        } else {
            xmlrpc_asprintf(errorP, "poll() failed, errno = %d (%s)",
                            errno, strerror(errno));
            *interruptedP = FALSE; /* quiet compiler warning */
        }
    } else {
        *errorP       = NULL;
        *interruptedP = !(pollfds[0].revents & POLLIN);
    }
}
Exemplo n.º 10
0
void
xmlrpc_read_datetime_8601(xmlrpc_env *const envP,
                          const xmlrpc_value *const valueP,
                          const char **const iso8601ValueP) {
/*----------------------------------------------------------------------------
  Get the datetime in ISO 8601 format.

  ISO 8601 allows a variety of representations for each datetime.
  The particular one we return is as in the following example.

     19930214T131030,250000Z

  (13:10:30.25 on February 14, 1993)

  There are always 4 digits for the year.  There are always 6 digits after the
  comma (microseconds).  Midnight is hour 0, not 24.
-----------------------------------------------------------------------------*/
    validateDatetimeType(envP, valueP);
    if (!envP->fault_occurred) {
        xmlrpc_datetime dt;

        xmlrpc_read_datetime(envP, valueP, &dt);

        if (!envP->fault_occurred) {
            if (dt.Y > 9999)
                xmlrpc_faultf(envP, "Too far in future (year %u).  "
                        "ISO 8601 cannot "
                        "represent years after AD 9999", dt.Y);
            else {
                xmlrpc_asprintf(iso8601ValueP,
                                "%04u%02u%02uT%02u%02u%02u,%06uZ",
                                dt.Y, dt.M, dt.D, dt.h, dt.m, dt.s, dt.u);

                if (xmlrpc_strnomem(*iso8601ValueP))
                    xmlrpc_faultf(envP,
                                  "Unable to allocate memory "
                                          "for datetime string");

                if (envP->fault_occurred)
                    xmlrpc_strfree(*iso8601ValueP);
            }
        }
    }
}
Exemplo n.º 11
0
static void
addConnectionHeaderFld(TSession * const sessionP) {

    struct _TServer * const srvP = ConnServer(sessionP->connP)->srvP;

    if (HTTPKeepalive(sessionP)) {
        const char * keepaliveValue;
        
        ResponseAddField(sessionP, "Connection", "Keep-Alive");

        xmlrpc_asprintf(&keepaliveValue, "timeout=%u, max=%u",
                        srvP->keepalivetimeout, srvP->keepalivemaxconn);

        ResponseAddField(sessionP, "Keep-Alive", keepaliveValue);

        xmlrpc_strfree(keepaliveValue);
    } else
        ResponseAddField(sessionP, "Connection", "close");
}
Exemplo n.º 12
0
static void
initInterruptPipe(interruptPipe * const pipeP,
                  const char **   const errorP) {

    int pipeFd[2];
    int rc;

    rc = pipe(pipeFd);

    if (rc != 0)
        xmlrpc_asprintf(errorP, "Unable to create a pipe to use to interrupt "
                        "waits.  pipe() failed with errno %d (%s)",
                        errno, strerror(errno));
    else {
        *errorP = NULL;
        pipeP->interruptorFd = pipeFd[1];
        pipeP->interrupteeFd = pipeFd[0];
    }
}
Exemplo n.º 13
0
void
DateToString(time_t const datetime,
             const char **const dateStringP) {

    struct tm brokenTime;

    xmlrpc_gmtime(datetime, &brokenTime);

    if (mktime(&brokenTime) == (time_t) -1)
        *dateStringP = NULL;
    else
        xmlrpc_asprintf(dateStringP, "%s, %02u %s %04u %02u:%02u:%02u UTC",
                        _DateDay[brokenTime.tm_wday],
                        brokenTime.tm_mday,
                        _DateMonth[brokenTime.tm_mon],
                        1900 + brokenTime.tm_year,
                        brokenTime.tm_hour,
                        brokenTime.tm_min,
                        brokenTime.tm_sec);
}
Exemplo n.º 14
0
static void
makeChannelInfo(struct abyss_unix_chaninfo ** const channelInfoPP,
                struct sockaddr               const peerAddr,
                socklen_t                     const peerAddrLen,
                const char **                 const errorP) {

    struct abyss_unix_chaninfo * channelInfoP;

    MALLOCVAR(channelInfoP);
    
    if (channelInfoP == NULL)
        xmlrpc_asprintf(errorP, "Unable to allocate memory");
    else {
        channelInfoP->peerAddrLen = peerAddrLen;
        channelInfoP->peerAddr    = peerAddr;
        
        *errorP = NULL;
    }
    *channelInfoPP = channelInfoP;
}
Exemplo n.º 15
0
static void
bindSocketToPortInet6(int                     const fd,
                      uint16_t                const portNumber,
                      const char **           const errorP) {

    struct sockaddr_in6 name;
    int rc;

    name.sin6_family = AF_INET6;
    name.sin6_port   = htons(portNumber);
    name.sin6_addr = in6addr_any;

    rc = bind(fd, (struct sockaddr *)&name, sizeof(name));

    if (rc == -1)
        xmlrpc_asprintf(errorP, "Unable to bind IPv6 socket "
                        "to port number %hu.  "
                        "bind() failed with errno %d (%s)",
                        portNumber, errno, strerror(errno));
    else
        *errorP = NULL;
}
Exemplo n.º 16
0
static void
bindSocketToPort(int                     const fd,
                 const struct sockaddr * const sockAddrP,
                 socklen_t               const sockAddrLen,
                 const char **           const errorP) {
    
    int rc;

    rc = bind(fd, sockAddrP, sockAddrLen);

    if (rc == -1)
        xmlrpc_asprintf(errorP, "Unable to bind socket "
                        "to the socket address.  "
                        "bind() failed with errno %d (%s)",
                        errno, strerror(errno));
    else {
        *errorP = NULL;

        if (SwitchTraceIsActive)
            traceSocketBound(sockAddrP, sockAddrLen);
    }
}
Exemplo n.º 17
0
static void
createChanSwitch(struct _TServer * const srvP,
                 const char **     const errorP) {

    TChanSwitch * chanSwitchP;
    const char * error;
    
    /* Not valid to call this when channel switch already exists: */
    assert(srvP->chanSwitchP == NULL);

    createSwitchFromPortNum(srvP->port, &chanSwitchP, &error);

    if (error) {
        xmlrpc_asprintf(errorP,
                        "Can't create channel switch.  %s", error);
        xmlrpc_strfree(error);
    } else {
        *errorP = NULL;
        
        srvP->weCreatedChanSwitch = TRUE;
        srvP->chanSwitchP         = chanSwitchP;
    }
}
Exemplo n.º 18
0
void
ResponseError2(TSession *   const sessionP,
               const char * const explanation) {

    const char * errorDocument;

    ResponseAddField(sessionP, "Content-type", "text/html");

    ResponseWriteStart(sessionP);
    
    xmlrpc_asprintf(&errorDocument,
                    "<HTML><HEAD><TITLE>Error %d</TITLE></HEAD>"
                    "<BODY>"
                    "<H1>Error %d</H1>"
                    "<P>%s</P>" SERVER_HTML_INFO 
                    "</BODY>"
                    "</HTML>",
                    sessionP->status, sessionP->status, explanation);
    
    ConnWrite(sessionP->connP, errorDocument, strlen(errorDocument)); 

    xmlrpc_strfree(errorDocument);
}
Exemplo n.º 19
0
static void
chanSwitchListen(TChanSwitch * const chanSwitchP,
                 uint32_t      const backlog,
                 const char ** const errorP) {

    struct socketUnix * const socketUnixP = chanSwitchP->implP;

    int32_t const minus1 = -1;

    int rc;

    /* Disable the Nagle algorithm to make persistant connections faster */

    setsockopt(socketUnixP->fd, IPPROTO_TCP, TCP_NODELAY,
               &minus1, sizeof(minus1));

    rc = listen(socketUnixP->fd, backlog);

    if (rc == -1)
        xmlrpc_asprintf(errorP, "listen() failed with errno %d (%s)",
                        errno, strerror(errno));
    else
        *errorP = NULL;
}
Exemplo n.º 20
0
static void
addUserAgentHeader(xmlrpc_env *         const envP,
                   struct curl_slist ** const headerListP,
                   const char *         const userAgent) {

    if (userAgent) {
        /* Note: Curl has a CURLOPT_USERAGENT option that does some of this
           work.  We prefer to be totally in control, though, so we build
           the header explicitly.
        */
    
        curl_version_info_data * const curlInfoP =
            curl_version_info(CURLVERSION_NOW);
        char curlVersion[32];
        const char * userAgentHeader;
        
        snprintf(curlVersion, sizeof(curlVersion), "%u.%u.%u",
                (curlInfoP->version_num >> 16) && 0xff,
                (curlInfoP->version_num >>  8) && 0xff,
                (curlInfoP->version_num >>  0) && 0xff
            );
                  
        xmlrpc_asprintf(&userAgentHeader,
                        "User-Agent: %s Xmlrpc-c/%s Curl/%s",
                        userAgent, XMLRPC_C_VERSION, curlVersion);
        
        if (userAgentHeader == xmlrpc_strsol)
            xmlrpc_faultf(envP, "Couldn't allocate memory for "
                          "User-Agent header");
        else {
            addHeader(envP, headerListP, userAgentHeader);
            
            xmlrpc_strfree(userAgentHeader);
        }
    }
}
Exemplo n.º 21
0
static void
parseRequestUri(char *const requestUri,
                const char **const hostP,
                unsigned short *const portP,
                const char **const pathP,
                const char **const queryP,
                const char **const errorP) {
/*----------------------------------------------------------------------------
  Parse the request URI (in the request line
  "GET http://www.myserver.com:8080/myfile.cgi?parm HTTP/1.1",
  "http://www.myserver.com:8080/myfile.cgi?parm" is the request URI).

  Return as *hostP the "www.myserver.com" in the above example.  If
  that part of the URI doesn't exist, return *hostP == NULL.

  Return as *portP the 8080 in the above example.  If it doesn't exist,
  return 80.

  Return as *pathP the "/myfile.cgi" in the above example.  If it
  doesn't exist, return "*".

  Return as *queryP the "parm" in the above example.  If it doesn't
  exist, return *queryP == NULL.

  Return strings in newly malloc'ed storage.

  We can return syntactically invalid entities, e.g. a host name that
  contains "<", if 'requestUri' is similarly invalid.  We should fix that
  some day.  RFC 2396 lists a lot of characters as reserved for certain
  use in the URI, such as colon, and totally disallowed, such as space.
-----------------------------------------------------------------------------*/
    const char *requestUriNoQuery;
    /* The request URI with any query (the stuff marked by a question
       mark at the end of a request URI) chopped off.
    */
    const char *query;
    const char *path;
    const char *host;
    unsigned short port;

    splitUriQuery(requestUri, &query, &requestUriNoQuery, errorP);
    if (!*errorP) {
        if (requestUriNoQuery[0] == '/') {
            host = NULL;
            path = xmlrpc_strdupsol(requestUriNoQuery);
            port = 80;
            *errorP = NULL;
        } else {
            if (!xmlrpc_strneq(requestUriNoQuery, "http://", 7))
                xmlrpc_asprintf(errorP, "Scheme is not http://");
            else
                parseHttpHostPortPath(&requestUriNoQuery[7],
                                      &host, &port, &path, errorP);
        }

        if (!*errorP) {
            *portP = port;
            unescapeHostPathQuery(host, path, query,
                                  hostP, pathP, queryP, errorP);

            if (host)
                xmlrpc_strfree(host);
            if (path)
                xmlrpc_strfree(path);
        }

        if (query)
            xmlrpc_strfree(query);
        xmlrpc_strfree(requestUriNoQuery);
    }
}
Exemplo n.º 22
0
void
ConnCreate(TConn **            const connectionPP,
           TServer *           const serverP,
           TChannel *          const channelP,
           void *              const channelInfoP,
           TThreadProc *       const job,
           size_t              const jobStackSize,
           TThreadDoneFn *     const done,
           enum abyss_foreback const foregroundBackground,
           bool                const useSigchld,
           const char **       const errorP) {
/*----------------------------------------------------------------------------
   Create an HTTP connection.

   A connection carries one or more HTTP transactions (request/response).

   *channelP transports the requests and responses.

   The connection handles those HTTP requests.

   The connection handles the requests primarily by running the
   function 'job' once.  Some connections can do that autonomously, as
   soon as the connection is created.  Others don't until Caller
   subsequently calls ConnProcess.  Some connections complete the
   processing before ConnProcess return, while others may run the
   connection asynchronously to the creator, in the background, via a
   TThread thread.  'foregroundBackground' determines which.

   'job' calls methods of the connection to get requests and send
   responses.

   Some time after the HTTP transactions are all done, 'done' gets
   called in some context.

   'channelInfoP' == NULL means no channel info supplied.
-----------------------------------------------------------------------------*/
    TConn * connectionP;

    MALLOCVAR(connectionP);

    if (connectionP == NULL)
        xmlrpc_asprintf(errorP, "Unable to allocate memory for a connection "
                        "descriptor.");
    else {
        connectionP->server       = serverP;
        connectionP->channelP     = channelP;
        connectionP->channelInfoP = channelInfoP;
        connectionP->buffer.b[0]  = '\0';
        connectionP->buffersize   = 0;
        connectionP->bufferpos    = 0;
        connectionP->finished     = FALSE;
        connectionP->job          = job;
        connectionP->done         = done;
        connectionP->inbytes      = 0;
        connectionP->outbytes     = 0;
        connectionP->trace        = getenv("ABYSS_TRACE_CONN");

        makeThread(connectionP, foregroundBackground, useSigchld,
                   jobStackSize, errorP);
    }
    *connectionPP = connectionP;
}
Exemplo n.º 23
0
abyss_bool
RequestAuth(TSession *   const sessionP,
            const char * const credential,
            const char * const user,
            const char * const pass) {
/*----------------------------------------------------------------------------
   Authenticate requester, in a very simplistic fashion.

   If the request executing on session *sessionP specifies basic
   authentication (via Authorization header) with username 'user', password
   'pass', then return true.  Else, return false and set up an authorization
   failure response (HTTP response status 401) that says user must supply an
   identity in the 'credential' domain.

   When we return true, we also set the username in the request info for the
   session to 'user' so that a future SessionGetRequestInfo can get it.
-----------------------------------------------------------------------------*/
    bool authorized;
    const char * authValue;

    authValue = RequestHeaderValue(sessionP, "authorization");
    if (authValue) {
        char * const valueBuffer = malloc(strlen(authValue));
            /* A buffer we can mangle as we parse the authorization: value */

        if (!authValue)
            /* Should return error, but we have no way to do that */
            authorized = false;
        else {
            const char * authType;
            char * authHdrPtr;

            strcpy(valueBuffer, authValue);
            authHdrPtr = &valueBuffer[0];

            NextToken((const char **)&authHdrPtr);
            GetTokenConst(&authHdrPtr, &authType);
            if (authType) {
                if (xmlrpc_strcaseeq(authType, "basic")) {
                    const char * userPass;
                    char userPassEncoded[80];

                    NextToken((const char **)&authHdrPtr);

                    xmlrpc_asprintf(&userPass, "%s:%s", user, pass);
                    xmlrpc_base64Encode(userPass, userPassEncoded);
                    xmlrpc_strfree(userPass);

                    if (xmlrpc_streq(authHdrPtr, userPassEncoded)) {
                        sessionP->requestInfo.user = xmlrpc_strdupsol(user);
                        authorized = true;
                    } else
                        authorized = false;
                } else
                    authorized = false;
            } else
                authorized = false;

            free(valueBuffer);
        }
    } else
        authorized = false;

    if (!authorized) {
        const char * hdrValue;
        xmlrpc_asprintf(&hdrValue, "Basic realm=\"%s\"", credential);
        ResponseAddField(sessionP, "WWW-Authenticate", hdrValue);

        xmlrpc_strfree(hdrValue);

        ResponseStatus(sessionP, 401);
    }
    return authorized;
}
Exemplo n.º 24
0
static void
chanSwitchAccept(TChanSwitch * const chanSwitchP,
                 TChannel **   const channelPP,
                 void **       const channelInfoPP,
                 const char ** const errorP) {
/*----------------------------------------------------------------------------
   Accept a connection via the channel switch *chanSwitchP.  Return as
   *channelPP the channel for the accepted connection.

   If no connection is waiting at *chanSwitchP, wait until one is.

   If we receive a signal while waiting, return immediately with
   *channelPP == NULL.
-----------------------------------------------------------------------------*/
    struct socketWin * const listenSocketP = chanSwitchP->implP;
    HANDLE acceptEvent = WSACreateEvent();
    bool interrupted;
    TChannel * channelP;

    interrupted = FALSE; /* Haven't been interrupted yet */
    channelP    = NULL;  /* No connection yet */
    *errorP     = NULL;  /* No error yet */

    WSAEventSelect(listenSocketP->winsock, acceptEvent,
                   FD_ACCEPT | FD_CLOSE | FD_READ);

    while (!channelP && !*errorP && !interrupted) {
        HANDLE interrupts[2] = {acceptEvent, listenSocketP->interruptEvent};
        int rc;
        struct sockaddr peerAddr;
        socklen_t size = sizeof(peerAddr);

        rc = WaitForMultipleObjects(2, interrupts, FALSE, INFINITE);
        if (WAIT_OBJECT_0 + 1 == rc) {
            interrupted = TRUE;
            continue;
        };

        rc = accept(listenSocketP->winsock, &peerAddr, &size);

        if (rc >= 0) {
            int const acceptedWinsock = rc;

            createChannelForAccept(acceptedWinsock, peerAddr,
                                   &channelP, channelInfoPP, errorP);

            if (*errorP)
                closesocket(acceptedWinsock);
        } else {
            int const lastError = WSAGetLastError();

            if (lastError == WSAEINTR)
                interrupted = TRUE;
            else
                xmlrpc_asprintf(errorP,
                                "accept() failed, WSA error = %d (%s)",
                                lastError, getWSAError(lastError));
        }
    }
    *channelPP = channelP;
    CloseHandle(acceptEvent);
}
Exemplo n.º 25
0
void
ConnRead(TConn *       const connectionP,
         uint32_t      const timeout,
         bool *        const eofP,
         bool *        const timedOutP,
         const char ** const errorP) {
/*----------------------------------------------------------------------------
   Read some stuff on connection *connectionP from the channel.  Read it into
   the connection's buffer.

   Don't wait more than 'timeout' seconds for data to arrive.  If no data has
   arrived by then and 'timedOutP' is null, fail.  If 'timedOut' is non-null,
   return as *timedOutP whether 'timeout' seconds passed without any data
   arriving.

   Also, stop waiting upon any interruption and treat it the same as a
   timeout.  An interruption is either a signal received (and caught) at
   an appropriate time or a ChannelInterrupt() call before or during the
   wait.

   If 'eofP' is non-null, return *eofP == true, without reading anything, iff
   there will no more data forthcoming on the connection because client has
   closed the connection.  If 'eofP' is null, fail in that case.
-----------------------------------------------------------------------------*/
    uint32_t const timeoutMs = timeout * 1000;

    if (timeoutMs < timeout)
        /* Arithmetic overflow */
        xmlrpc_asprintf(errorP, "Timeout value is too large");
    else {
        bool const waitForRead  = TRUE;
        bool const waitForWrite = FALSE;

        bool readyForRead;
        bool failed;
            
        ChannelWait(connectionP->channelP, waitForRead, waitForWrite,
                    timeoutMs, &readyForRead, NULL, &failed);
            
        if (failed)
            xmlrpc_asprintf(errorP,
                            "Wait for stuff to arrive from client failed.");
        else {
            bool eof;
            if (readyForRead) {
                readFromChannel(connectionP, &eof, errorP);
            } else {
                /* Wait was interrupted, either by our requested timeout,
                   a (caught) signal, or a ChannelInterrupt().
                */
                traceReadTimeout(connectionP, timeout);
                *errorP = NULL;
                eof = FALSE;
            }
            if (!*errorP)
                dealWithReadTimeout(timedOutP, !readyForRead, timeout, errorP);
            if (!*errorP)
                dealWithReadEof(eofP, eof, errorP);
        }
    }
}
Exemplo n.º 26
0
void
ConnCreate(TConn **            const connectionPP,
           TServer *           const serverP,
           TSocket *           const connectedSocketP,
           TThreadProc *       const job,
           TThreadDoneFn *     const done,
           enum abyss_foreback const foregroundBackground,
           abyss_bool          const useSigchld,
           const char **       const errorP) {
    /*----------------------------------------------------------------------------
       Create an HTTP connection.

       A connection carries one or more HTTP transactions (request/response).

       'connectedSocketP' transports the requests and responses.

       The connection handles those HTTP requests.

       The connection handles the requests primarily by running the
       function 'job' once.  Some connections can do that autonomously, as
       soon as the connection is created.  Others don't until Caller
       subsequently calls ConnProcess.  Some connections complete the
       processing before ConnProcess return, while others may run the
       connection asynchronously to the creator, in the background, via a
       TThread thread.  'foregroundBackground' determines which.

       'job' calls methods of the connection to get requests and send
       responses.

       Some time after the HTTP transactions are all done, 'done' gets
       called in some context.
    -----------------------------------------------------------------------------*/
    TConn * connectionP;

    MALLOCVAR(connectionP);

    if (connectionP == NULL)
        xmlrpc_asprintf(errorP, "Unable to allocate memory for a connection "
                        "descriptor.");
    else {
        abyss_bool success;
        uint16_t peerPortNumber;

        connectionP->server     = serverP;
        connectionP->socketP    = connectedSocketP;
        connectionP->buffersize = 0;
        connectionP->bufferpos  = 0;
        connectionP->finished   = FALSE;
        connectionP->job        = job;
        connectionP->done       = done;
        connectionP->inbytes    = 0;
        connectionP->outbytes   = 0;
        connectionP->trace      = getenv("ABYSS_TRACE_CONN");
        connectionP->start      = time(NULL);

        SocketGetPeerName(connectedSocketP,
                          &connectionP->peerip, &peerPortNumber, &success);

        if (success)
            makeThread(connectionP, foregroundBackground, useSigchld, errorP);
        else
            xmlrpc_asprintf(errorP, "Failed to get peer name from socket.");
    }
    *connectionPP = connectionP;
}