📄 server.c
字号:
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 + -