📄 server.c
字号:
#ifndef WIN32voidServerHandleSigchld(pid_t const pid) { ThreadHandleSigchld(pid);}#endifvoidServerUseSigchld(TServer * const serverP) { struct _TServer * const srvP = serverP->srvP; srvP->useSigchld = TRUE;}TThreadDoneFn destroySocket;static voiddestroyConnSocket(void * const userHandle) {/*---------------------------------------------------------------------------- This is a "connection done" function for the connection the server serves. It gets called some time after the connection has done its thing. Its job is to clean up stuff the server created for use by the connection, but the server can't clean up because the connection might be processed asynchronously in a background thread. To wit, we destroy the connection's socket.-----------------------------------------------------------------------------*/ TConn * const connectionP = userHandle; SocketDestroy(connectionP->socketP);}static void serverRun2(TServer * const serverP) { struct _TServer * const srvP = serverP->srvP; outstandingConnList * outstandingConnListP; createOutstandingConnList(&outstandingConnListP); while (!srvP->terminationRequested) { TConn * connectionP; abyss_bool connected; abyss_bool failed; TSocket * connectedSocketP; TIPAddr peerIpAddr; SocketAccept(srvP->listenSocketP, &connected, &failed, &connectedSocketP, &peerIpAddr); if (connected) { const char * error; freeFinishedConns(outstandingConnListP); waitForConnectionCapacity(outstandingConnListP); ConnCreate(&connectionP, serverP, connectedSocketP, &serverFunc, &destroyConnSocket, ABYSS_BACKGROUND, srvP->useSigchld, &error); if (!error) { addToOutstandingConnList(outstandingConnListP, connectionP); ConnProcess(connectionP); /* When connection is done (which could be later, courtesy of a background thread), destroyConnSocket() will destroy *connectedSocketP. */ } else { xmlrpc_strfree(error); SocketDestroy(connectedSocketP); } } else if (failed) TraceMsg("Socket Error=%d", SocketError(srvP->listenSocketP)); } waitForNoConnections(outstandingConnListP); destroyOutstandingConnList(outstandingConnListP);}void ServerRun(TServer * const serverP) { struct _TServer * const srvP = serverP->srvP; if (!srvP->socketBound) TraceMsg("This server is not set up to accept connections " "on its own, so you can't use ServerRun(). " "Try ServerRunConn() or ServerInit()"); else serverRun2(serverP);}static voidserverRunConn(TServer * const serverP, TSocket * const connectedSocketP) {/*---------------------------------------------------------------------------- Do the HTTP transaction on the TCP connection on the socket 'connectedSocketP'. (socket must be in connected state, with nothing having been read or written on the connection yet).-----------------------------------------------------------------------------*/ struct _TServer * const srvP = serverP->srvP; TConn * connectionP; const char * error; srvP->keepalivemaxconn = 1; ConnCreate(&connectionP, serverP, connectedSocketP, &serverFunc, NULL, ABYSS_FOREGROUND, srvP->useSigchld, &error); if (error) { TraceMsg("Couldn't create HTTP connection out of " "connected socket. %s", error); xmlrpc_strfree(error); } else { ConnProcess(connectionP); ConnWaitAndRelease(connectionP); }}voidServerRunConn2(TServer * const serverP, TSocket * const connectedSocketP, const char ** const errorP) {/*---------------------------------------------------------------------------- Do the HTTP transaction on the TCP connection on the socket 'connectedOsSocket'. (socket must be connected state, with nothing having been read or written on the connection yet).-----------------------------------------------------------------------------*/ struct _TServer * const srvP = serverP->srvP; if (srvP->serverAcceptsConnections) xmlrpc_asprintf(errorP, "This server is configured to accept connections on " "its own socket. " "Try ServerRun() or ServerCreateNoAccept()."); else { serverRunConn(serverP, connectedSocketP); *errorP = NULL; }}voidServerRunConn(TServer * const serverP, TOsSocket const connectedOsSocket) { TSocket * socketP; createSocketFromOsSocket(connectedOsSocket, &socketP); if (!socketP) TraceExit("Unable to use supplied socket"); else { const char * error; ServerRunConn2(serverP, socketP, &error); if (error) { TraceExit("Failed to run server on connection on file " "descriptor %d. %s", connectedOsSocket, error); xmlrpc_strfree(error); } SocketDestroy(socketP); }}voidServerRunOnce(TServer * const serverP) {/*---------------------------------------------------------------------------- Accept a connection from the listening socket and do the HTTP transaction that comes over it. If no connection is presently waiting on the listening socket, wait for one. But return immediately if we receive a signal during the wait.-----------------------------------------------------------------------------*/ struct _TServer * const srvP = serverP->srvP; if (!srvP->socketBound) TraceMsg("This server is not set up to accept connections " "on its own, so you can't use ServerRunOnce(). " "Try ServerRunConn() or ServerInit()"); else { abyss_bool connected; abyss_bool failed; TSocket * connectedSocketP; TIPAddr remoteAddr; srvP->keepalivemaxconn = 1; SocketAccept(srvP->listenSocketP, &connected, &failed, &connectedSocketP, &remoteAddr); if (connected) { serverRunConn(serverP, connectedSocketP); SocketDestroy(connectedSocketP); } else if (failed) TraceMsg("Socket Error=%d", SocketError(srvP->listenSocketP)); }}voidServerRunOnce2(TServer * const serverP, enum abyss_foreback const foregroundBackground ATTR_UNUSED) {/*---------------------------------------------------------------------------- This is a backward compatibility interface to ServerRunOnce(). 'foregroundBackground' is meaningless. We always process the connection in the foreground. The parameter exists because we once thought we could do them in the background, but we really can't do that in any clean way. If Caller wants background execution, he can spin his own thread or process to call us. It makes much more sense in Caller's context.-----------------------------------------------------------------------------*/ ServerRunOnce(serverP);}static voidsetGroups(void) {#ifdef HAVE_SETGROUPS if (setgroups(0, NULL) == (-1)) TraceExit("Failed to setup the group.");#endif}voidServerDaemonize(TServer * const serverP) {/*---------------------------------------------------------------------------- Turn Caller into a daemon (i.e. fork a child, then exit; the child returns to Caller). NOTE: It's ridiculous, but conventional, for us to do this. It's ridiculous because the task of daemonizing is not something particular to Abyss. It ought to be done by a higher level. In fact, it should be done before the Abyss server program is even execed. The user should run a "daemonize" program that creates a daemon which execs the Abyss server program.-----------------------------------------------------------------------------*/ struct _TServer * const srvP = serverP->srvP;#ifndef _WIN32 /* Become a daemon */ switch (fork()) { case 0: break; case -1: TraceExit("Unable to become a daemon"); default: /* We are the parent */ exit(0); } setsid(); /* Change the current user if we are root */ if (getuid()==0) { if (srvP->uid == (uid_t)-1) TraceExit("Can't run under root privileges. " "Please add a User option in your " "Abyss configuration file."); setGroups(); if (srvP->gid != (gid_t)-1) if (setgid(srvP->gid)==(-1)) TraceExit("Failed to change the group."); if (setuid(srvP->uid) == -1) TraceExit("Failed to change the user."); } if (srvP->pidfile != -1) { char z[16]; sprintf(z, "%d", getpid()); FileWrite(&srvP->pidfile, z, strlen(z)); FileClose(&srvP->pidfile); }#endif /* _WIN32 */}voidServerAddHandler2(TServer * const serverP, URIHandler2 * const handlerArgP, abyss_bool * const successP) { URIHandler2 * handlerP; MALLOCVAR(handlerP); if (handlerP == NULL) *successP = FALSE; else { *handlerP = *handlerArgP; if (handlerP->init == NULL) *successP = TRUE; else handlerP->init(handlerP, successP); if (*successP) *successP = ListAdd(&serverP->srvP->handlers, handlerP); if (!*successP) free(handlerP); }}static URIHandler2 *createHandler(URIHandler const function) { URIHandler2 * handlerP; MALLOCVAR(handlerP); if (handlerP != NULL) { handlerP->init = NULL; handlerP->term = NULL; handlerP->userdata = NULL; handlerP->handleReq2 = NULL; handlerP->handleReq1 = function; } return handlerP;}abyss_boolServerAddHandler(TServer * const serverP, URIHandler const function) { URIHandler2 * handlerP; abyss_bool success; handlerP = createHandler(function); if (handlerP == NULL) success = FALSE; else { success = ListAdd(&serverP->srvP->handlers, handlerP); if (!success) free(handlerP); } return success;}voidServerDefaultHandler(TServer * const serverP, URIHandler const handler) { serverP->srvP->defaulthandler = handler ? handler : ServerDefaultHandlerFunc;}voidLogWrite(TServer * const serverP, const char * const msg) { struct _TServer * const srvP = serverP->srvP; if (!srvP->logfileisopen && srvP->logfilename) logOpen(srvP); if (srvP->logfileisopen) { abyss_bool success; success = MutexLock(&srvP->logmutex); if (success) { const char * const lbr = "\n"; FileWrite(&srvP->logfile, msg, strlen(msg)); FileWrite(&srvP->logfile, lbr, strlen(lbr)); MutexUnlock(&srvP->logmutex); } }}/*********************************************************************************** server.c**** This file is part of the ABYSS Web server project.**** Copyright (C) 2000 by Moez Mahfoudh <mmoez@bigfoot.com>.** All rights reserved.**** Redistribution and use in source and binary forms, with or without** modification, are permitted provided that the following conditions** are met:** 1. Redistributions of source code must retain the above copyright** notice, this list of conditions and the following disclaimer.** 2. Redistributions in binary form must reproduce the above copyright** notice, this list of conditions and the following disclaimer in the** documentation and/or other materials provided with the distribution.** 3. The name of the author may not be used to endorse or promote products** derived from this software without specific prior written permission.** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF** SUCH DAMAGE.********************************************************************************/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -