Exemplo n.º 1
0
void xs_gpio_repeat(xsMachine* the)
{
    FskGPIO gpio = xsGetHostData(xsThis);

    if (gpio) {
        if (in != gpio->direction)
            xsThrowDiagnosticIfFskErr(kFskErrUnimplemented, "Digital pin %d cannot repeat on output pin", (int)gpio->pinNum);

        if (gpio->poller)
            FskListRemove(&gGPIOPollers, gpio);
        
        gpio->poller = (xsTest(xsArg(0))) ? xsGetHostData(xsArg(0)) : NULL;

        if (gpio->poller) {
            FskListAppend(&gGPIOPollers, gpio);
            gpio->pollerValue = -1;     // won't match
            if (NULL == gGPIOPoller) {
                FskTimeCallbackNew(&gGPIOPoller);
                FskTimeCallbackScheduleNextRun(gGPIOPoller, gpioPoller, NULL);
            }
        }
        else if ((NULL == gGPIOPollers) && (NULL != gGPIOPoller)) {
            FskTimeCallbackDispose(gGPIOPoller);
            gGPIOPoller = NULL;
        }
    }
}
Exemplo n.º 2
0
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;
}
Exemplo n.º 3
0
static void
xs_handshake_finished_callback(xsMachine *the)
{
	FskSSL *fssl = xsGetHostData(xsGet(xsThis, xsID("_hostData")));
	int ac = xsToInteger(xsArgc);
	FskSocket skt = ac > 0 && xsTest(xsArg(0)) ? (FskSocket)xsGetHostData(xsArg(0)): NULL;
	FskErr err = ac > 1 && xsTypeOf(xsArg(0)) == xsIntegerType ? (FskErr)xsToInteger(xsArg(1)): kFskErrNone;

	if (fssl->socketCallback == NULL)
		return;	/* callback is the only way to get a socket so no callback no socket */

	fssl->skt = skt;
	if (skt != NULL) {
		skt->lastErr = (err == kFskErrNone) ? kFskErrNone : kFskErrSSLHandshakeFailed;	// ignore the detailed error
		skt->fssl = fssl;
	}
	/* it is possible that the callback calls FskSSLDispose which destroys not only all objects but the VM, so we need to be free from VM when the callback is called */
	FskTimeCallbackNew(&fssl->timer);
	FskTimeCallbackScheduleNextRun(fssl->timer, time_callback, fssl);
}
Exemplo n.º 4
0
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);
		}
	}

}
Exemplo n.º 5
0
FskErr FskHTTPServerRequestResume(FskHTTPServerRequest request)
{
    request->state = request->suspendedState;
	FskTimeCallbackScheduleNextRun(request->cycleCallback, httpServerTimeCycle, request);
    return kFskErrNone;
}