⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 server.c

📁 一个很好用的解析
💻 C
📖 第 1 页 / 共 4 页
字号:
    assert(socketP);    createServer(&serverP->srvP, noAcceptFalse, socketP, 0, errorP);}static voidterminateHandlers(TList * const handlersP) {/*----------------------------------------------------------------------------   Terminate all handlers in the list '*handlersP'.   I.e. call each handler's terminate function.-----------------------------------------------------------------------------*/    if (handlersP->item) {        unsigned int i;        for (i = handlersP->size; i > 0; --i) {            URIHandler2 * const handlerP = handlersP->item[i-1];            if (handlerP->term)                handlerP->term(handlerP->userdata);        }    }}voidServerFree(TServer * const serverP) {    struct _TServer * const srvP = serverP->srvP;    if (srvP->weCreatedListenSocket)        SocketDestroy(srvP->listenSocketP);    xmlrpc_strfree(srvP->name);    xmlrpc_strfree(srvP->filespath);        ListFree(&srvP->defaultfilenames);    terminateHandlers(&srvP->handlers);    ListFree(&srvP->handlers);    logClose(srvP);    if (srvP->logfilename)        xmlrpc_strfree(srvP->logfilename);    free(srvP);}voidServerSetName(TServer *    const serverP,              const char * const name) {    xmlrpc_strfree(serverP->srvP->name);        serverP->srvP->name = strdup(name);}voidServerSetFilesPath(TServer *    const serverP,                   const char * const filesPath) {    xmlrpc_strfree(serverP->srvP->filespath);        serverP->srvP->filespath = strdup(filesPath);}voidServerSetLogFileName(TServer *    const serverP,                     const char * const logFileName) {        struct _TServer * const srvP = serverP->srvP;    if (srvP->logfilename)        xmlrpc_strfree(srvP->logfilename);        srvP->logfilename = strdup(logFileName);}voidServerSetKeepaliveTimeout(TServer * const serverP,                          uint32_t  const keepaliveTimeout) {    serverP->srvP->keepalivetimeout = keepaliveTimeout;}voidServerSetKeepaliveMaxConn(TServer * const serverP,                          uint32_t  const keepaliveMaxConn) {    serverP->srvP->keepalivemaxconn = keepaliveMaxConn;}voidServerSetTimeout(TServer * const serverP,                 uint32_t  const timeout) {    serverP->srvP->timeout = timeout;}voidServerSetAdvertise(TServer *  const serverP,                   abyss_bool const advertise) {    serverP->srvP->advertise = advertise;}voidServerSetMimeType(TServer *  const serverP,                  MIMEType * const MIMETypeP) {    serverP->srvP->mimeTypeP = MIMETypeP;}static voidrunUserHandler(TSession *        const sessionP,               struct _TServer * const srvP) {    abyss_bool handled;    int i;        for (i = srvP->handlers.size-1, handled = FALSE;         i >= 0 && !handled;         --i) {        URIHandler2 * const handlerP = srvP->handlers.item[i];                if (handlerP->handleReq2)            handlerP->handleReq2(handlerP, sessionP, &handled);        else if (handlerP->handleReq1)            handled = handlerP->handleReq1(sessionP);    }        if (!handled)        ((URIHandler)(srvP->defaulthandler))(sessionP);}static voidprocessDataFromClient(TConn *      const connectionP,                      abyss_bool   const lastReqOnConn,                      abyss_bool * const keepAliveP) {    TSession session;    RequestInit(&session, connectionP);    session.serverDeniesKeepalive = lastReqOnConn;            RequestRead(&session);    if (session.status == 0) {        if (session.version.major >= 2)            ResponseStatus(&session, 505);        else if (!RequestValidURI(&session))            ResponseStatus(&session, 400);        else            runUserHandler(&session, connectionP->server->srvP);    }    assert(session.status != 0);        if (session.responseStarted)        HTTPWriteEndChunk(&session);    else        ResponseError(&session);    *keepAliveP = HTTPKeepalive(&session);        SessionLog(&session);    RequestFree(&session);}static TThreadProc serverFunc;static voidserverFunc(void * const userHandle) {/*----------------------------------------------------------------------------   Do server stuff on one connection.  At its simplest, this means do   one HTTP request.  But with keepalive, it can be many requests.-----------------------------------------------------------------------------*/    TConn *           const connectionP = userHandle;    struct _TServer * const srvP = connectionP->server->srvP;    unsigned int requestCount;        /* Number of requests we've handled so far on this connection */    abyss_bool connectionDone;        /* No more need for this HTTP connection */    requestCount = 0;    connectionDone = FALSE;    while (!connectionDone) {        abyss_bool success;                /* Wait to read until timeout */        success = ConnRead(connectionP, srvP->keepalivetimeout);        if (!success)            connectionDone = TRUE;        else {            abyss_bool const lastReqOnConn =                requestCount + 1 >= srvP->keepalivemaxconn;            abyss_bool keepalive;                        processDataFromClient(connectionP, lastReqOnConn, &keepalive);                        ++requestCount;            if (!keepalive)                connectionDone = TRUE;                        /**************** Must adjust the read buffer *****************/            ConnReadInit(connectionP);        }    }}static voidcreateAndBindSocket(struct _TServer * const srvP) {    abyss_bool success;    success = SocketInit();    if (!success)        TraceMsg("Can't initialize TCP sockets");    else {        TSocket * socketP;                SocketUnixCreate(&socketP);                if (!socketP)            TraceMsg("Can't create a socket");        else {            abyss_bool success;                        success = SocketBind(socketP, NULL, srvP->port);                        if (!success)                TraceMsg("Failed to bind listening socket to port number %u",                         srvP->port);            else {                srvP->weCreatedListenSocket = TRUE;                srvP->socketBound = TRUE;                srvP->listenSocketP = socketP;            }            if (!success)                SocketDestroy(socketP);        }    }}voidServerInit(TServer * const serverP) {/*----------------------------------------------------------------------------   Initialize a server to accept connections.   Do not confuse this with creating the server -- ServerCreate().   Not necessary or valid with a server that doesn't accept connections (i.e.   user supplies the TCP connections).-----------------------------------------------------------------------------*/    struct _TServer * const srvP = serverP->srvP;    abyss_bool success;        if (!srvP->serverAcceptsConnections) {        TraceMsg("ServerInit() is not valid on a server that doesn't "                 "accept connections "                 "(i.e. created with ServerCreateNoAccept)");        success = FALSE;    } else {        if (!srvP->socketBound)            createAndBindSocket(srvP);        if (srvP->socketBound) {            success = SocketListen(srvP->listenSocketP, MAX_CONN);            if (!success)                TraceMsg("Failed to listen on bound socket.");        } else            success = FALSE;    }    if (!success)        exit(1);}/* We don't do any locking on the outstanding connections list, so    we must make sure that only the master thread (the one that listens   for connections) ever accesses it.   That's why when a thread completes, it places the connection in   "finished" status, but doesn't destroy the connection.*/typedef struct {    TConn * firstP;    unsigned int count;        /* Redundant with 'firstP', for quick access */} outstandingConnList;static voidcreateOutstandingConnList(outstandingConnList ** const listPP) {    outstandingConnList * listP;    MALLOCVAR_NOFAIL(listP);    listP->firstP = NULL;  /* empty list */    listP->count = 0;    *listPP = listP;}static voiddestroyOutstandingConnList(outstandingConnList * const listP) {    assert(listP->firstP == NULL);    assert(listP->count == 0);    free(listP);}static voidaddToOutstandingConnList(outstandingConnList * const listP,                         TConn *               const connectionP) {    connectionP->nextOutstandingP = listP->firstP;    listP->firstP = connectionP;    ++listP->count;}static voidfreeFinishedConns(outstandingConnList * const listP) {/*----------------------------------------------------------------------------   Garbage-collect the resources associated with connections that are   finished with their jobs.  Thread resources, connection pool   descriptor, etc.-----------------------------------------------------------------------------*/    TConn ** pp;    pp = &listP->firstP;    while (*pp) {        TConn * const connectionP = (*pp);        ThreadUpdateStatus(connectionP->threadP);                if (connectionP->finished) {            /* Take it out of the list */            *pp = connectionP->nextOutstandingP;            --listP->count;                        ConnWaitAndRelease(connectionP);        } else {            /* Move to next connection in list */            pp = &connectionP->nextOutstandingP;        }    }}static voidwaitForConnectionFreed(outstandingConnList * const outstandingConnListP                       ATTR_UNUSED) {/*----------------------------------------------------------------------------  Wait for a connection descriptor in 'connectionPool' to be probably  freed.-----------------------------------------------------------------------------*/    /* TODO: We should do something more sophisticated here.  For pthreads,       we can have a thread signal us by semaphore when it terminates.       For fork, we might be able to use the "done" handler argument       to ConnCreate() to get interrupted when the death of a child       signal happens.    */    xmlrpc_millisecond_sleep(2000);}static voidwaitForNoConnections(outstandingConnList * const outstandingConnListP) {    while (outstandingConnListP->firstP) {        freeFinishedConns(outstandingConnListP);            if (outstandingConnListP->firstP)            waitForConnectionFreed(outstandingConnListP);    }}static voidwaitForConnectionCapacity(outstandingConnList * const outstandingConnListP) {/*----------------------------------------------------------------------------   Wait until there are fewer than the maximum allowed connections in   progress.-----------------------------------------------------------------------------*/    while (outstandingConnListP->count >= MAX_CONN) {        freeFinishedConns(outstandingConnListP);        if (outstandingConnListP->firstP)            waitForConnectionFreed(outstandingConnListP);    }}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -