📄 conn.c
字号:
/* Copyright information is at the end of the file. */#include <time.h>#include <string.h>#include <stdlib.h>#include <stdio.h>#include <ctype.h>#include <assert.h>#include "mallocvar.h"#include "xmlrpc-c/util_int.h"#include "xmlrpc-c/string_int.h"#include "xmlrpc-c/sleep_int.h"#include "xmlrpc-c/abyss.h"#include "socket.h"#include "server.h"#include "thread.h"#include "conn.h"/*********************************************************************** Conn*********************************************************************/static TThreadProc connJob;static voidconnJob(void * const userHandle) {/*---------------------------------------------------------------------------- This is the root function for a thread that processes a connection (performs HTTP transactions).-----------------------------------------------------------------------------*/ TConn * const connectionP = userHandle; (connectionP->job)(connectionP); connectionP->finished = TRUE; /* Note that if we are running in a forked process, setting connectionP->finished has no effect, because it's just our own copy of *connectionP. In this case, Parent must update his own copy based on a SIGCHLD signal that the OS will generate right after we exit. */ ThreadExit(0);}static voidconnDone(TConn * const connectionP) { /* In the forked case, this is designed to run in the parent process after the child has terminated. */ connectionP->finished = TRUE; if (connectionP->done) connectionP->done(connectionP);}static TThreadDoneFn threadDone;static voidthreadDone(void * const userHandle) { TConn * const connectionP = userHandle; connDone(connectionP);}static voidmakeThread(TConn * const connectionP, enum abyss_foreback const foregroundBackground, abyss_bool const useSigchld, const char ** const errorP) { switch (foregroundBackground) { case ABYSS_FOREGROUND: connectionP->hasOwnThread = FALSE; *errorP = NULL; break; case ABYSS_BACKGROUND: { const char * error; connectionP->hasOwnThread = TRUE; ThreadCreate(&connectionP->threadP, connectionP, &connJob, &threadDone, useSigchld, &error); if (error) { xmlrpc_asprintf(errorP, "Unable to create thread to " "process connection. %s", error); xmlrpc_strfree(error); } else *errorP = NULL; } break; } /* switch */} voidConnCreate(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"); 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;}abyss_boolConnProcess(TConn * const connectionP) {/*---------------------------------------------------------------------------- Drive the main processing of a connection -- run the connection's "job" function, which should read HTTP requests from the connection and send HTTP responses. If we succeed, we guarantee the connection's "done" function will get called some time after all processing is complete. It might be before we return or some time after. If we fail, we guarantee the "done" function will not be called.-----------------------------------------------------------------------------*/ abyss_bool retval; if (connectionP->hasOwnThread) { /* There's a background thread to handle this connection. Set it running. */ retval = ThreadRun(connectionP->threadP); } else { /* No background thread. We just handle it here while Caller waits. */ (connectionP->job)(connectionP); connDone(connectionP); retval = TRUE; } return retval;}voidConnWaitAndRelease(TConn * const connectionP) { if (connectionP->hasOwnThread) ThreadWaitAndRelease(connectionP->threadP); free(connectionP);}abyss_boolConnKill(TConn * connectionP) { connectionP->finished = TRUE; return ThreadKill(connectionP->threadP);}voidConnReadInit(TConn * const connectionP) { if (connectionP->buffersize>connectionP->bufferpos) { connectionP->buffersize -= connectionP->bufferpos; memmove(connectionP->buffer, connectionP->buffer+connectionP->bufferpos, connectionP->buffersize); connectionP->bufferpos = 0; } else connectionP->buffersize=connectionP->bufferpos = 0; connectionP->inbytes=connectionP->outbytes = 0;}static voidtraceBuffer(const char * const label, const char * const buffer, unsigned int const size) { unsigned int nonPrintableCount; unsigned int i; nonPrintableCount = 0; /* Initial value */ for (i = 0; i < size; ++i) { if (!isprint(buffer[i]) && buffer[i] != '\n' && buffer[i] != '\r') ++nonPrintableCount; } if (nonPrintableCount > 0) fprintf(stderr, "%s contains %u nonprintable characters.\n", label, nonPrintableCount); fprintf(stderr, "%s:\n", label); fprintf(stderr, "%.*s\n", (int)size, buffer);}static voidtraceSocketRead(TConn * const connectionP, unsigned int const size) { if (connectionP->trace) traceBuffer("READ FROM SOCKET:", connectionP->buffer + connectionP->buffersize, size);}static voidtraceSocketWrite(TConn * const connectionP, const char * const buffer, unsigned int const size, abyss_bool const failed) { if (connectionP->trace) { const char * const label = failed ? "FAILED TO WRITE TO SOCKET:" : "WROTE TO SOCKET"; traceBuffer(label, buffer, size); }}static uint32_tbufferSpace(TConn * const connectionP) { return BUFFER_SIZE - connectionP->buffersize;} abyss_boolConnRead(TConn * const connectionP, uint32_t const timeout) {/*---------------------------------------------------------------------------- Read some stuff on connection *connectionP from the socket. Don't wait more than 'timeout' seconds for data to arrive. Fail if nothing arrives within that time.-----------------------------------------------------------------------------*/ time_t const deadline = time(NULL) + timeout; abyss_bool cantGetData; abyss_bool gotData; cantGetData = FALSE; gotData = FALSE; while (!gotData && !cantGetData) { int const timeLeft = deadline - time(NULL); if (timeLeft <= 0) cantGetData = TRUE; else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -