FskErr FskHTTPServerStart(FskHTTPServer http) { if (!http) return kFskErrInvalidParameter; if (http->stopped) { FskInstrumentedItemSendMessage(http, kFskHTTPInstrMsgServerStart, http); http->stopped = false; FskTimeGetNow(&http->stats.serverStarted); } else { FskInstrumentedItemSendMessage(http, kFskHTTPInstrMsgServerStartedAlready, http); } return kFskErrNone; }
FskErr FskSemaphoreNew_(FskSemaphore *sem, UInt32 value, FSK_SYNCHRONIZATION_DEBUG_ARGS) #endif { FskErr err; err = FskMemPtrNewClear(sizeof(FskSemaphoreRecord), (FskMemPtr *)sem); BAIL_IF_ERR(err); err = KplSemaphoreNew((KplSemaphore*)&(*sem)->kplSem, value); BAIL_IF_ERR(err); FskInstrumentedItemNew(*sem, NULL, &gFskSemaphoreTypeInstrumentation); #if SUPPORT_INSTRUMENTATION && SUPPORT_SYNCHRONIZATION_DEBUG if (FskInstrumentedItemHasListeners(*sem)) { FskSynchronizationInstrMsgRecord msg; msg.file = file; msg.line = line; msg.function = function; FskInstrumentedItemSendMessage(*sem, kFskSynchronizationInstrMsgSemaphoreNew, &msg); } #endif bail: if ((err != kFskErrNone) && (*sem != NULL)) { KplSemaphoreDispose((*sem)->kplSem); FskMemPtrDispose(*sem); *sem = NULL; } return err; }
FskErr FskHTTPServerStop(FskHTTPServer http, Boolean flush) { if (!http) return kFskErrInvalidParameter; if (http->stopped == false) { FskHTTPServerRequest request = http->activeRequests; http->stopped = true; FskTimeGetNow(&http->stats.serverStopped); // -- should we kill off live requests here? no. can restart. // -- should we kill off active sessions here? yes when waiting on a keep alive. while (request) { if (request->state == kHTTPReadRequestHeaders) { request->state = kHTTPClose; FskHTTPServerRequestCycle(request); request = http->activeRequests; } else request = request->next; } } else { FskInstrumentedItemSendMessage(http, kFskHTTPInstrMsgServerStoppedAlready, http); } return kFskErrNone; }
// --------------------------------------------------------------------- void sNotifyInterfaceNotifiers(FskNetInterfaceRecord *iface, UInt32 status) { FskNetInterfaceNotifier callback = NULL, next; FskThread thread = FskThreadGetCurrent(); callback = (FskNetInterfaceNotifier)FskListMutexGetNext(interfaceChangeCBList, NULL); while (callback) { next = (FskNetInterfaceNotifier)FskListMutexGetNext(interfaceChangeCBList, callback); #if 0 && SUPPORT_INSTRUMENTATION if (FskInstrumentedItemHasListeners(callback)) { FskNetInterfaceRecord *iface = (FskNetInterfaceRecord *)FskNetInterfaceFindByName(ifcName); FskInterfaceInstrData data; data.notf = callback; data.ifc = iface; data.status = status; FskInstrumentedItemSendMessage(callback, kFskNetInstrMsgInterfaceNotify, &data); } #endif /* SUPPORT_INSTRUMENTATION */ if (callback->thread != thread) { FskNetInterfaceRecord *interFace; if (kFskErrNone == FskMemPtrNewFromData(sizeof(FskNetInterfaceRecord), iface, &interFace)) { interFace->next = NULL; interFace->name = FskStrDoCopy(iface->name); // POST notify FskInstrumentedTypePrintfDebug(&gNetInterfaceNotifierTypeInstrumentation, " - posting callback to thread %s for interface %s", callback->thread->name, iface->name); FskThreadPostCallback(callback->thread, doNetIfcCallback, (void*)callback->callback, (void*)interFace, (void*)status, (void*)callback->param); } } else { FskInstrumentedTypePrintfDebug(&gNetInterfaceNotifierTypeInstrumentation, "callback->thread %s - call", callback->thread->name); (callback->callback)(iface, status, callback->param); } callback = next; } }
FskHTTPServerListener FskHTTPServerListenerNew(FskHTTPServer http, int port, char *interfaceName) { FskHTTPServerListener listener; FskErr err; FskSocket skt; FskNetInterfaceRecord *ifc = NULL; FskInstrumentedTypePrintfDebug(&gFskHTTPServerTypeInstrumentation, "httpServerListenerNew - interfaceName: %s\n", interfaceName); err = FskMemPtrNewClear(sizeof(FskHTTPServerListenerRecord), (FskMemPtr*)&listener); BAIL_IF_ERR(err); listener->http = http; listener->port = port; listener->ifcName = FskStrDoCopy(interfaceName); err = FskNetSocketNewTCP(&skt, true, "HTTP Server"); if (err) { FskInstrumentedItemSendMessage(listener->http, kFskHTTPInstrMsgErrString, "listener socket create failed."); FskInstrumentedTypePrintfDebug(&gFskHTTPServerTypeInstrumentation, "httpServerListenerNew - creating socket failed: %d\n", err); BAIL(kFskErrNoMoreSockets); } FskNetSocketReuseAddress(skt); ifc = FskNetInterfaceFindByName(listener->ifcName); if ((NULL == ifc) || (kFskErrNone != (err = FskNetSocketBind(skt, ifc->ip, listener->port)))) { FskNetSocketClose(skt); FskInstrumentedTypePrintfDebug(&gFskHTTPServerTypeInstrumentation, "httpServerListenerNew - bind failed: %d port: %d\n", err, listener->port); listener->http->stats.connectionsAborted++; if (listener->http->callbacks) err = doCallCondition(listener->http->callbacks->serverCondition, listener->http, kFskHTTPConditionNoSocket, listener->http->refCon); goto bail; } listener->skt = skt; FskNetSocketMakeNonblocking(skt); FskListAppend((FskList*)&listener->http->listeners, listener); FskInstrumentedTypePrintfDebug(&gFskHTTPServerTypeInstrumentation, "httpServerListenerNew - about to listen\n"); FskNetSocketListen(skt); FskThreadAddDataHandler(&listener->dataHandler, (FskThreadDataSource)skt, (FskThreadDataReadyCallback)httpServerListenerAcceptNewConnection, true, false, listener); FskInstrumentedItemSendMessage(listener->http, kFskHTTPInstrMsgNowListening, listener); bail: FskNetInterfaceDescriptionDispose(ifc); if (err) { FskInstrumentedItemSendMessage(listener->http, kFskHTTPInstrMsgFailedListener, listener); FskMemPtrDisposeAt((void**)&listener); } return listener; }
FskErr FskSemaphoreAcquire_(FskSemaphore sem, FSK_SYNCHRONIZATION_DEBUG_ARGS) #endif { #if SUPPORT_INSTRUMENTATION #if SUPPORT_SYNCHRONIZATION_DEBUG if (FskInstrumentedItemHasListeners(sem)) { FskSynchronizationInstrMsgRecord msg; msg.file = file; msg.line = line; msg.function = function; FskInstrumentedItemSendMessage(sem, kFskSynchronizationInstrMsgSemaphoreAcquire, &msg); } #else FskInstrumentedItemSendMessage(sem, kFskSynchronizationInstrMsgSemaphoreAcquire, sem); #endif #endif WaitForSingleObject(sem->hSem, INFINITE); return kFskErrNone; }
FskErr FskSemaphoreRelease_(FskSemaphore sem, FSK_SYNCHRONIZATION_DEBUG_ARGS) #endif { #if SUPPORT_INSTRUMENTATION #if SUPPORT_SYNCHRONIZATION_DEBUG if (FskInstrumentedItemHasListeners(sem)) { FskSynchronizationInstrMsgRecord msg; msg.file = file; msg.line = line; msg.function = function; FskInstrumentedItemSendMessage(sem, kFskSynchronizationInstrMsgSemaphoreRelease, &msg); } #else FskInstrumentedItemSendMessage(sem, kFskSynchronizationInstrMsgSemaphoreRelease, sem); #endif #endif ReleaseSemaphore(sem->hSem, 1, NULL); return kFskErrNone; }
FskErr FskMutexRelease_(FskMutex mutex, FSK_SYNCHRONIZATION_DEBUG_ARGS) #endif { #if SUPPORT_INSTRUMENTATION #if SUPPORT_SYNCHRONIZATION_DEBUG if (FskInstrumentedItemHasListeners(mutex)) { FskSynchronizationInstrMsgRecord msg; msg.name = mutex->name; msg.file = file; msg.line = line; msg.function = function; FskInstrumentedItemSendMessage(mutex, kFskSynchronizationInstrMsgMutexRelease, &msg); } #else FskInstrumentedItemSendMessage(mutex, kFskSynchronizationInstrMsgMutexRelease, mutex); #endif #endif KplMutexRelease(mutex->kplMutex); return kFskErrNone; }
static FskErr httpServerListenerStart(FskHTTPServerListener listener, FskSocket skt) { FskErr err = kFskErrNone; FskHTTPServerRequest request; if (listener->http->stopped) { FskInstrumentedItemSendMessage(listener->http, kFskHTTPInstrMsgConnectionRefusedStopped, listener); listener->http->stats.connectionsRefused++; FskNetSocketClose(skt); goto bail; } err = FskMemPtrNewClear(sizeof(FskHTTPServerRequestRecord), (FskMemPtr*)&request); BAIL_IF_ERR(err); sFskHTTPServerRequestUpUse(request); request->http = listener->http; request->skt = skt; FskNetSocketGetRemoteAddress(skt, (UInt32 *)&request->requesterAddress, &request->requesterPort); FskNetSocketMakeNonblocking(request->skt); err = FskHeaderStructNew(&request->requestHeaders); BAIL_IF_ERR(err); err = FskHeaderStructNew(&request->responseHeaders); BAIL_IF_ERR(err); request->in.bufferSize = request->http->defaultBufferSize; request->out.bufferSize = request->http->defaultBufferSize; err = FskMemPtrNew(request->in.bufferSize, (FskMemPtr*)&request->in.buf); BAIL_IF_ERR(err); err = FskMemPtrNew(request->out.bufferSize, (FskMemPtr*)&request->out.buf); BAIL_IF_ERR(err); FskListAppend((FskList*)&request->http->activeRequests, request); FskTimeCallbackNew(&request->cycleCallback); FskTimeCallbackNew(&request->keepAliveKillCallback); listener->http->stats.connectionsMade++; request->state = kHTTPNewSession; FskInstrumentedItemNew(request, NULL, &gFskHTTPServerRequestTypeInstrumentation); FskInstrumentedItemSetOwner(request, request->http); FskTimeCallbackScheduleNextRun(request->cycleCallback, httpServerTimeCycle, request); doCallCondition(request->http->callbacks->requestCondition, request, kFskHTTPConditionConnectionInitialized, request->refCon); FskTimeCallbackNew(&request->timer); FskTimeCallbackScheduleFuture(request->timer, 1, 0, KprHTTPServerTimerCallback, request); bail: if (err) FskHTTPServerRequestDispose(request); return err; }
FskErr FskHTTPServerStop(FskHTTPServer http, Boolean flush) { if (!http) return kFskErrInvalidParameter; if (http->stopped == false) { http->stopped = true; FskTimeGetNow(&http->stats.serverStopped); // -- should we kill off live requests here? no. can restart. // -- should we kill off active sessions here? } else { FskInstrumentedItemSendMessage(http, kFskHTTPInstrMsgServerStoppedAlready, http); } return kFskErrNone; }
FskErr FskHTTPServerDispose(FskHTTPServer http) { FskInstrumentedTypePrintfDebug(&gFskHTTPServerTypeInstrumentation, "FskHTTPServerDispose %p - useCount: %d\n", http, http ? http->useCount : 0); if (http) { // remove existing requests while (http->activeRequests) { FskHTTPServerRequest request = http->activeRequests; FskInstrumentedItemSendMessage(request, kFskHTTPInstrMsgRequestRemainsOnClose, request); if (kFskErrNone != doCallCondition(http->callbacks->requestCondition, request, kFskHTTPConditionConnectionTerminating, request->refCon)) FskHTTPServerRequestDispose(request); } FskNetInterfaceRemoveNotifier(http->interfaceNotifier); while (http->listeners) FskHTTPServerListenerDispose(http->listeners); sFskHTTPServerDownUse(http); } return kFskErrNone; }
FskErr FskMutexNew_(FskMutex *mutex, const char *name, FSK_SYNCHRONIZATION_DEBUG_ARGS) #endif { FskMutex mtx = NULL; FskErr err; err = FskMemPtrNewClear(sizeof(FskMutexRecord), (FskMemPtr *)&mtx); BAIL_IF_ERR(err); err = KplMutexNew((KplMutex*)&mtx->kplMutex); BAIL_IF_ERR(err); #if SUPPORT_INSTRUMENTATION mtx->name = FskStrDoCopy_Untracked(name); FskInstrumentedItemNew(mtx, mtx->name, &gFskMutexTypeInstrumentation); #if SUPPORT_SYNCHRONIZATION_DEBUG if (FskInstrumentedItemHasListeners(mtx)) { FskSynchronizationInstrMsgRecord msg; msg.name = name; msg.file = file; msg.line = line; msg.function = function; FskInstrumentedItemSendMessage(mtx, kFskSynchronizationInstrMsgMutexNew, &msg); } #endif #endif bail: if ((err != kFskErrNone) && (mtx != NULL)) { KplMutexDispose(mtx->kplMutex); #if SUPPORT_INSTRUMENTATION FskMemPtrDispose_Untracked((void*)mtx->name); #endif FskMemPtrDispose(mtx); mtx = NULL; } *mutex = mtx; return err; }
FskErr FskSemaphoreDispose_(FskSemaphore sem, FSK_SYNCHRONIZATION_DEBUG_ARGS) #endif { if (sem) { #if SUPPORT_INSTRUMENTATION && SUPPORT_SYNCHRONIZATION_DEBUG if (FskInstrumentedItemHasListeners(sem)) { FskSynchronizationInstrMsgRecord msg; msg.file = file; msg.line = line; msg.function = function; FskInstrumentedItemSendMessage(sem, kFskSynchronizationInstrMsgSemaphoreDispose, &msg); } #endif CloseHandle(sem->hSem); FskInstrumentedItemDispose(sem); FskMemPtrDispose(sem); } return kFskErrNone; }
FskErr FskMutexNew_(FskMutex *mutex, const char *name, FSK_SYNCHRONIZATION_DEBUG_ARGS) #endif { FskErr err; pthread_mutexattr_t attr; err = FskMemPtrNewClear(sizeof(FskMutexRecord), (FskMemPtr *)mutex); BAIL_IF_ERR(err); if ((pthread_mutexattr_init(&attr) != 0) || (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE) != 0) || (pthread_mutex_init(&(*mutex)->mutex, &attr) != 0)) { BAIL(kFskErrOperationFailed); } #if SUPPORT_INSTRUMENTATION (*mutex)->name = FskStrDoCopy_Untracked(name); FskInstrumentedItemNew(*mutex, NULL, &gFskMutexTypeInstrumentation); #if SUPPORT_SYNCHRONIZATION_DEBUG if (FskInstrumentedItemHasListeners(*mutex)) { FskSynchronizationInstrMsgRecord msg; msg.name = name; msg.file = file; msg.line = line; msg.function = function; FskInstrumentedItemSendMessage(*mutex, kFskSynchronizationInstrMsgMutexNew, &msg); } #endif #endif bail: pthread_mutexattr_destroy(&attr); if ((err != kFskErrNone) && (*mutex != NULL)) { #if SUPPORT_INSTRUMENTATION FskMemPtrDispose((FskMemPtr)(*mutex)->name); #endif FskMemPtrDispose(*mutex); *mutex = NULL; } return err; }
FskErr FskSemaphoreNew_(FskSemaphore *sem, UInt32 value, FSK_SYNCHRONIZATION_DEBUG_ARGS) #endif { FskErr err; err = FskMemPtrNewClear(sizeof(FskSemaphoreRecord), (FskMemPtr *)sem); BAIL_IF_ERR(err); #if TARGET_OS_MAC { FskSemaphore s = *sem; snprintf(s->name, sizeof(s->name)-1, "/tmp/sem%lx", (unsigned long)s); if ((s->hSem = sem_open(s->name, O_CREAT|O_EXCL, 666, value)) == NULL) { BAIL(kFskErrOperationFailed); } } #else if (sem_init(&(*sem)->hSem, 0, value) != 0) { BAIL(kFskErrOperationFailed); } #endif FskInstrumentedItemNew(*sem, NULL, &gFskSemaphoreTypeInstrumentation); #if SUPPORT_INSTRUMENTATION && SUPPORT_SYNCHRONIZATION_DEBUG if (FskInstrumentedItemHasListeners(*sem)) { FskSynchronizationInstrMsgRecord msg; msg.file = file; msg.line = line; msg.function = function; FskInstrumentedItemSendMessage(*sem, kFskSynchronizationInstrMsgSemaphoreNew, &msg); } #endif bail: if ((err != kFskErrNone) && (*sem != NULL)) { FskMemPtrDispose(*sem); *sem = NULL; } return err; }
FskErr FskMutexNew_(FskMutex *mutex, const char *name, FSK_SYNCHRONIZATION_DEBUG_ARGS) #endif { FskErr err; err = FskMemPtrNewClear(sizeof(FskMutexRecord), (FskMemPtr *)mutex); BAIL_IF_ERR(err); InitializeCriticalSection(&(*mutex)->cs); #if SUPPORT_INSTRUMENTATION (*mutex)->name = FskStrDoCopy_Untracked(name); FskInstrumentedItemNew(*mutex, (*mutex)->name, &gFskMutexTypeInstrumentation); #if SUPPORT_SYNCHRONIZATION_DEBUG if (FskInstrumentedItemHasListeners(*mutex)) { FskSynchronizationInstrMsgRecord msg; msg.name = name; msg.file = file; msg.line = line; msg.function = function; FskInstrumentedItemSendMessage(*mutex, kFskSynchronizationInstrMsgMutexNew, &msg); } #endif #endif bail: if ((err != kFskErrNone) && (*mutex != NULL)) { #if SUPPORT_INSTRUMENTATION FskMemPtrDispose_Untracked((*mutex)->name); #endif FskMemPtrDispose(*mutex); *mutex = NULL; } return err; }
FskErr FskMutexDispose_(FskMutex mutex, FSK_SYNCHRONIZATION_DEBUG_ARGS) #endif { if (mutex) { #if SUPPORT_INSTRUMENTATION && SUPPORT_SYNCHRONIZATION_DEBUG if (FskInstrumentedItemHasListeners(mutex)) { FskSynchronizationInstrMsgRecord msg; msg.name = mutex->name; msg.file = file; msg.line = line; msg.function = function; FskInstrumentedItemSendMessage(mutex, kFskSynchronizationInstrMsgMutexDispose, &msg); } #endif KplMutexDispose(mutex->kplMutex); FskInstrumentedItemDispose(mutex); #if SUPPORT_INSTRUMENTATION FskMemPtrDispose_Untracked((void*)mutex->name); #endif FskMemPtrDispose(mutex); } return kFskErrNone; }
UInt32 FskMutexTrylock_(FskMutex mutex, FSK_SYNCHRONIZATION_DEBUG_ARGS) #endif { #if SUPPORT_INSTRUMENTATION int ret; #if SUPPORT_SYNCHRONIZATION_DEBUG FskSynchronizationInstrMsgRecord msg; if (FskInstrumentedItemHasListeners(mutex)) { msg.name = mutex->name; msg.file = file; msg.line = line; msg.function = function; FskInstrumentedItemSendMessage(mutex, kFskSynchronizationInstrMsgMutexTrylock, &msg); } #else FskInstrumentedItemSendMessage(mutex, kFskSynchronizationInstrMsgMutexTrylock, mutex); #endif ret = KplMutexTrylock(mutex->kplMutex); if (0 == ret) { #if SUPPORT_SYNCHRONIZATION_DEBUG FskInstrumentedItemSendMessage(mutex, kFskSynchronizationInstrMsgMutexTrylockSucceeded, &msg); #else FskInstrumentedItemSendMessage(mutex, kFskSynchronizationInstrMsgMutexTrylockSucceeded, mutex); #endif } else { #if SUPPORT_SYNCHRONIZATION_DEBUG FskInstrumentedItemSendMessage(mutex, kFskSynchronizationInstrMsgMutexTrylockFailed, &msg); #else FskInstrumentedItemSendMessage(mutex, kFskSynchronizationInstrMsgMutexTrylockFailed, mutex); #endif } return ret; #else return KplMutexTrylock(mutex->kplMutex); #endif }
static void httpServerEngineCycle(void *param) { FskErr err = kFskErrNone, retVal = kFskErrNeedMoreTime; FskHTTPServerRequest request = (FskHTTPServerRequest)param; int amt, ret, chunkSize = 0; UInt32 chunkSizeL; char *s, *p; Boolean readSomeMore, needsDispose = false; FskThreadRemoveDataHandler(&request->dataHandler); switch (request->state) { case kHTTPNewSession: FskInstrumentedItemSendMessage(request, kFskHTTPInstrMsgRequestState, request); FskTimeGetNow(&request->stats.requestStarted); request->state = kHTTPReadRequestHeaders; case kHTTPReadRequestHeaders: FskInstrumentedItemSendMessage(request, kFskHTTPInstrMsgRequestState, request); shoveBuffer(request->in); amt = request->in.bufferSize - request->in.max; if (amt) { err = FskNetSocketRecvTCP(request->skt, &request->in.buf[request->in.max], amt, &ret); switch (err) { case kFskErrNone: #if SUPPORT_INSTRUMENTATION if (FskInstrumentedItemHasListeners(request)) { FskHTTPInstrMsgDataRecord msg; msg.buffer = &request->in.buf[request->in.max]; msg.amt = ret; FskInstrumentedItemSendMessage(request, kFskHTTPInstrMsgRequestRecvData, &msg); } #endif request->http->stats.requestsStarted += 1; request->in.max += ret; request->state = kHTTPProcessRequestHeaders; request->stats.bytesReceived += ret; request->http->stats.bytesReceived += ret; break; case kFskErrNoData: retVal = kFskErrNoData; break; case kFskErrConnectionClosed: if (request->stats.bytesReceived) { request->state = kHTTPSocketError; } else { request->state = kHTTPDone; } break; default: FskInstrumentedItemSendMessage(request, kFskHTTPInstrMsgErrString, "kHTTPReadRequestHeaders: RecvTCP - error"); request->state = kHTTPSocketError; break; } } else request->state = kHTTPProcessRequestHeaders; if (request->state != kHTTPProcessRequestHeaders) break; case kHTTPProcessRequestHeaders: FskInstrumentedItemSendMessage(request, kFskHTTPInstrMsgRequestState, request); amt = request->in.max - request->in.pos; if (amt) { ret = FskHeadersParseChunk(&request->in.buf[request->in.pos], amt, kFskHeaderTypeRequest, request->requestHeaders); if (ret < 0) { err = kFskErrBadData; request->state = kHTTPSocketError; break; } request->in.pos += ret; if (request->requestHeaders->headersParsed) { httpProcessRequestHeaders(request); } else if (ret != amt) { // odd case - we didn't consume all the data, but // the header parsing isn't complete. request->state = kHTTPServerError; } } else request->state = kHTTPReadRequestHeaders; if (request->state != kHTTPReadRequestBody) break; case kHTTPReadRequestBody: FskInstrumentedItemSendMessage(request, kFskHTTPInstrMsgRequestState, request); readSomeMore = false; amt = request->in.max - request->in.pos; if (request->requestBodyContentLength > 0) { if (amt) { request->state = kHTTPProcessRequestBody; } else { request->in.max = 0; request->in.pos = 0; readSomeMore = true; } } else if (request->requestBodyChunked) { // chunked if (amt == 0) { readSomeMore = true; } else { p = &request->in.buf[request->in.pos]; while ((amt > 1) && lineEnd(p)) { // consume line-ends amt -= 2; request->in.pos += 2; p += 2; } while ((amt > 1) && !lineEnd(p)) { // scan for chunk size amt--; p++; } if ((amt > 1) && lineEnd(p)) { // convert the chunksize s = &request->in.buf[request->in.pos]; chunkSize = FskStrHexToNum(s, p-s); p += 2; //lineend request->requestBodyContentLength = chunkSize; request->in.pos += (p-s); request->state = kHTTPReadRequestBody; if (0 == chunkSize) { // we've read the end indicator (0) if ((amt > 1) && lineEnd(p)) request->in.pos += 2; // consume last cr/lf } request->requestBodyChunked = false; } } else { readSomeMore = true; } } } else { // we're done reading chunks // we're done reading the request request->state = kHTTPPrepareResponse; doCallCondition(request->http->callbacks->requestCondition, request, kFskHTTPConditionRequestRequestFinished, request->refCon); } if (readSomeMore) { shoveBuffer(request->in); err = FskNetSocketRecvTCP(request->skt, &request->in.buf[request->in.max], request->in.bufferSize - request->in.max, &ret); switch (err) { case kFskErrNone: #if SUPPORT_INSTRUMENTATION if (FskInstrumentedItemHasListeners(request)) { FskHTTPInstrMsgDataRecord msg; msg.buffer = &request->in.buf[request->in.max]; msg.amt = ret; FskInstrumentedItemSendMessage(request, kFskHTTPInstrMsgRequestRecvData, &msg); } #endif request->in.max += ret; if (request->requestBodyChunked) // chunked? request->state = kHTTPReadRequestBody; else request->state = kHTTPProcessRequestBody; request->stats.bytesReceived += ret; request->http->stats.bytesReceived += ret; break; case kFskErrNoData: retVal = kFskErrNoData; break; default: FskInstrumentedItemSendMessage(request, kFskHTTPInstrMsgErrString, "kHTTPReadRequestBody: RecvTCP - error"); request->http->stats.requestsFailed += 1; request->state = kHTTPSocketError; break; } } if (request->state != kHTTPProcessRequestBody) break; case kHTTPProcessRequestBody: FskInstrumentedItemSendMessage(request, kFskHTTPInstrMsgRequestState, request); amt = request->in.max - request->in.pos; if (amt > request->requestBodyContentLength) { if (false == request->requestBodyChunked) request->requestBodyContentLength = amt; else amt = request->requestBodyContentLength; } chunkSizeL = (UInt32)chunkSize; err = doDataCallback(request->http->callbacks->requestReceiveRequest, request, &request->in.buf[request->in.pos], amt, &chunkSizeL, request->refCon); chunkSize = (int)chunkSizeL; if (kFskErrNone == err) { if (chunkSize) { request->in.pos += chunkSize; request->requestBodyContentLength -= chunkSize; request->stats.requestBodyReceived += chunkSize; if (false == request->requestBodyChunked) { if (0 == request->requestBodyContentLength) request->state = kHTTPPrepareResponse; else request->state = kHTTPReadRequestBody; } else request->state = kHTTPReadRequestBody; } else { // data callback wants to suspend the session and not // consume the chunk, it can do so if (request->state != kHTTPSessionSuspend) request->state = kHTTPServerError; } } else { // the data callback returned an error. if (request->state != kHTTPSessionSuspend) request->state = kHTTPServerError; } if (request->state != kHTTPPrepareResponse) break; doCallCondition(request->http->callbacks->requestCondition, request, kFskHTTPConditionRequestRequestFinished, request->refCon); if (request->state != kHTTPPrepareResponse) break; case kHTTPPrepareResponse: FskInstrumentedItemSendMessage(request, kFskHTTPInstrMsgRequestState, request); request->state = kHTTPProcessResponse; err = doCallCondition(request->http->callbacks->requestCondition, request, kFskHTTPConditionRequestGenerateResponseHeaders, request->refCon); if (err == kFskErrNeedMoreTime) request->state = kHTTPSessionSuspend; else if (err) request->responseHeaders->responseCode = 500; if (request->state != kHTTPProcessResponse) break; case kHTTPProcessResponse: request->state = kHTTPGetDataChunk; httpPrepareResponseHeaders(request); if (request->state != kHTTPGetDataChunk) break; case kHTTPGetDataChunk: FskInstrumentedItemSendMessage(request, kFskHTTPInstrMsgRequestState, request); if (0 == FskStrCompare(kFskStrHEAD, FskHeaderMethod(request->requestHeaders))) { request->state = kHTTPSendDataChunk; request->nextState = kHTTPSetupNextRequest; break; } p = &request->out.buf[request->out.max]; if (request->transferEncoding == kFskTransferEncodingChunked) { request->out.max += 6; } chunkSize = 0; amt = (request->out.bufferSize - request->out.max) - 2; // fetch response data from callback chunkSizeL = (UInt32)chunkSize; err = doDataCallback(request->http->callbacks->requestGenerateResponseBody, request, &request->out.buf[request->out.max], amt, &chunkSizeL, request->refCon); chunkSize = (int)chunkSizeL; FskInstrumentedTypePrintfDebug(&gFskHTTPServerTypeInstrumentation, "doDataCallback returns err: %d, chunkSize: %d\n", err, chunkSize); if ((kFskErrNone != err) && (kFskErrEndOfFile != err)) { FskInstrumentedTypePrintfDebug(&gFskHTTPServerTypeInstrumentation, "about to doCallCondition -requestResponseFinished - FAIL\n"); doCallCondition(request->http->callbacks->requestCondition, request, kFskHTTPConditionRequestResponseFinished, request->refCon); request->http->stats.requestsFailed += 1; request->state = kHTTPServerError; break; } request->out.max += chunkSize; if ((0 == chunkSize) && (request->state == kHTTPSessionSuspend)) { if (kFskTransferEncodingChunked == request->transferEncoding) request->out.max -= 6; break; } request->state = kHTTPSendDataChunk; if ((chunkSize == 0) || (kFskErrEndOfFile == err)) { request->nextState = kHTTPSetupNextRequest; } else request->nextState = kHTTPGetDataChunk; if (request->transferEncoding == kFskTransferEncodingChunked) { FskStrNumToHex(chunkSize, p, 4); p += 4; *p++ = kFskCR; *p++ = kFskLF; if (chunkSize) p += chunkSize; *p++ = kFskCR; *p++ = kFskLF; request->out.max += 2; } request->stats.bodyBytesSent += chunkSize; if (request->state != kHTTPSendDataChunk) break; case kHTTPSendDataChunk: FskInstrumentedItemSendMessage(request, kFskHTTPInstrMsgRequestState, request); FskInstrumentedTypePrintfDebug(&gFskHTTPServerTypeInstrumentation, " - request->out.max %d - request->out.pos %d\n", request->out.max, request->out.pos); amt = request->out.max - request->out.pos; if (0 == amt) { FskInstrumentedTypePrintfDebug(&gFskHTTPServerTypeInstrumentation, "amt is zero now - transition to next state.\n"); request->state = request->nextState; break; } err = FskNetSocketSendTCP(request->skt, &request->out.buf[request->out.pos], amt, &ret); switch (err) { case kFskErrNone: #if SUPPORT_INSTRUMENTATION if (FskInstrumentedItemHasListeners(request)) { FskHTTPInstrMsgDataRecord msg; msg.buffer = &request->out.buf[request->out.pos]; msg.amt = ret; FskInstrumentedItemSendMessage(request, kFskHTTPInstrMsgRequestSendData, &msg); } #endif request->out.pos += ret; request->stats.bytesSent += ret; request->http->stats.bytesSent += ret; if (request->transferEncoding == kFskTransferEncodingChunked) { request->stats.bytesSent -= 8; } if (request->out.pos == request->out.max) { request->out.pos = 0; request->out.max = 0; request->state = request->nextState; } break; case kFskErrNoData: retVal = kFskErrSocketFull; break; default: FskInstrumentedItemSendMessage(request, kFskHTTPInstrMsgErrString, "kHTTPSendDataChunk: SendTCP - error"); request->state = kHTTPSocketError; request->http->stats.requestsFailed += 1; break; } if (request->state != kHTTPSetupNextRequest) break; case kHTTPSetupNextRequest: FskInstrumentedItemSendMessage(request, kFskHTTPInstrMsgRequestState, request); FskTimeGetNow(&request->stats.requestStopped); request->http->stats.requestsFinished += 1; doCallCondition(request->http->callbacks->requestCondition, request, kFskHTTPConditionRequestResponseFinished, request->refCon); request->state = kHTTPDone; if (request->keepAlive && !request->http->stopped) { if ((request->in.max - request->in.pos) > 0) { FskHeaderStructDispose(request->requestHeaders); FskHeaderStructDispose(request->responseHeaders); FskHeaderStructNew(&request->requestHeaders); FskHeaderStructNew(&request->responseHeaders); request->keepAlive = false; request->out.max = 0; request->out.pos = 0; FskMemSet(&request->stats, 0, sizeof(request->stats)); FskTimeGetNow(&request->stats.requestStarted); request->state = kHTTPProcessRequestHeaders; } } if (request->state != kHTTPDone) break; case kHTTPDone: FskInstrumentedItemSendMessage(request, kFskHTTPInstrMsgRequestState, request); if (request->keepAlive && !request->http->stopped) { FskHeaderStructDispose(request->requestHeaders); FskHeaderStructDispose(request->responseHeaders); FskHeaderStructNew(&request->requestHeaders); FskHeaderStructNew(&request->responseHeaders); request->keepAlive = false; request->in.max = 0; request->in.pos = 0; request->out.max = 0; request->out.pos = 0; FskMemSet(&request->stats, 0, sizeof(request->stats)); retVal = kFskErrNoData; // will cause data handler to be installed request->state = kHTTPNewSession; } else { request->state = kHTTPClose; retVal = kFskErrNeedMoreTime; } break; case kHTTPFulfillExpectation: FskInstrumentedItemSendMessage(request, kFskHTTPInstrMsgRequestState, request); request->state = kHTTPSendDataChunk; request->nextState = kHTTPReadRequestBody; request->out.max += snprintf(request->out.buf, request->out.bufferSize, "%s %d %s\r\n\r\n", httpProtocolVersionString(request), 100, FskFindResponse(100)); break; case kHTTPDenyExpectation: FskInstrumentedItemSendMessage(request, kFskHTTPInstrMsgRequestState, request); request->state = kHTTPSendDataChunk; request->nextState = kHTTPDone; request->out.max += snprintf(request->out.buf, request->out.bufferSize, "%s %d %s\r\n\r\n", httpProtocolVersionString(request), 417, FskFindResponse(417)); break; case kHTTPServerError: FskInstrumentedItemSendMessage(request, kFskHTTPInstrMsgRequestState, request); request->state = kHTTPSocketError; // fall through case kHTTPSocketError: FskInstrumentedItemSendMessage(request, kFskHTTPInstrMsgRequestState, request); request->http->stats.connectionsAborted++; doCallCondition(request->http->callbacks->requestCondition, request, kFskHTTPConditionRequestErrorAbort, request->refCon); request->state = kHTTPClose; // fall through case kHTTPClose: FskInstrumentedItemSendMessage(request, kFskHTTPInstrMsgRequestState, request); request->state = kHTTPRequestComplete; needsDispose = true; break; case kHTTPRequestComplete: FskInstrumentedItemSendMessage(request, kFskHTTPInstrMsgRequestState, request); retVal = kFskErrNone; // request is finished, don't call back break; case kHTTPSessionSuspend: FskInstrumentedItemSendMessage(request, kFskHTTPInstrMsgRequestState, request); retVal = kFskErrNone; // do nothing in suspend state break; default: FskInstrumentedItemSendMessage(request, kFskHTTPInstrMsgRequestState, request); request->state = kHTTPClose; // unknown state break; ; } if ((request->state == kHTTPServerError) || (request->state == kHTTPSocketError) || (request->state == kHTTPDone) || (request->state == kHTTPClose)) retVal = kFskErrNeedMoreTime; if (retVal == kFskErrNoData) { FskThreadAddDataHandler(&request->dataHandler, (FskThreadDataSource)request->skt, httpServerDataHandler, true, false, request); } else if (retVal == kFskErrSocketFull) { FskThreadAddDataHandler(&request->dataHandler, (FskThreadDataSource)request->skt, httpServerDataHandler, false, true, request); } else if (retVal == kFskErrNeedMoreTime) { FskTimeCallbackScheduleNextRun(request->cycleCallback, httpServerTimeCycle, request); } else if (retVal == kFskErrNone) { // nothing doin } else { FskInstrumentedTypePrintfDebug(&gFskHTTPServerTypeInstrumentation, "httpCycle - weird retVal %d\n", retVal); } if (needsDispose) { FskListRemove((FskList*)&request->http->activeRequests, request); FskTimeCallbackDispose(request->keepAliveKillCallback); request->keepAliveKillCallback = NULL; if (kFskErrNone != doCallCondition(request->http->callbacks->requestCondition, request, kFskHTTPConditionConnectionTerminating, request->refCon)) FskHTTPServerRequestDispose(request); } else { if ((retVal == kFskErrNeedMoreTime) || ((retVal != kFskErrNone) && request->keepAlive)) { FskTimeCallbackScheduleFuture(request->keepAliveKillCallback, FskHTTPServerRequestGetKeepAliveTimeout(request), 0, httpKillKeepAlive, request); } } }
static void httpKillKeepAlive(FskTimeCallBack cb, const FskTime when, void *param) { FskHTTPServerRequest request = (FskHTTPServerRequest)param; FskInstrumentedItemSendMessage(request, kFskHTTPInstrMsgRequestKillIdle, request); request->state = kHTTPClose; httpServerEngineCycle(param); }