void KPR_MQTTClient(xsMachine* the) { FskErr err; KPR_MQTTClientRecord *self = NULL; xsIntegerValue c = xsToInteger(xsArgc); KprMQTTClient client = NULL; char clientIdentifier[kKprMQTTClientIdentifierMaxLength + 1]; Boolean cleanSession = true; if (c >= 1) { char *arg = xsToString(xsArg(0)); UInt32 len = FskStrLen(arg); if (len < 1 || len > kKprMQTTClientIdentifierMaxLength) xsThrowIfFskErr(kFskErrBadData); FskStrCopy(clientIdentifier, arg); } else { char hex[9]; FskStrNumToHex(FskRandom(), hex, 8); FskStrCopy(clientIdentifier, kKprMQTTClientIdentifierPrefix); FskStrCat(clientIdentifier, hex); } if (c >= 2) { cleanSession = xsToBoolean(xsArg(1)); } bailIfError(FskMemPtrNewClear(sizeof(KPR_MQTTClientRecord), &self)); bailIfError(KprMQTTClientNew(&client, clientIdentifier, cleanSession, self)); client->connectCallback = KPR_mqttclient_onConnect; client->subscribeCallback = KPR_mqttclient_onSubscribe; client->unsubscribeCallback = KPR_mqttclient_onUnsubscribe; client->publishCallback = KPR_mqttclient_onPublish; client->messageCallback = KPR_mqttclient_onMessage; client->disconnectCallback = KPR_mqttclient_onDisconnect; client->errorCallback = KPR_mqttclient_onError; self->client = client; self->the = the; self->slot = xsThis; self->code = the->code; xsSetHostData(self->slot, self); // xsCall1(xsGet(xsGlobal, xsID_Object), xsID_seal, self->slot); xsRemember(self->slot); bail: if (err) { KprMQTTClientDispose(client); FskMemPtrDispose(self); xsThrowIfFskErr(err); } }
char *FskUUIDtoString(FskUUID uuid) { // uppercase 000000000000-0000-0000-000000000000 char *str = NULL; if (kFskErrNone == FskMemPtrNewClear(36, &str)) { UInt32 u32; UInt16 u16; UInt8 *ptr = uuid->value; u32 = *(UInt32 *)(ptr + 0); FskStrNumToHex(FskEndianU32_NtoB(u32), &str[0], 8); u16 = *(UInt16 *)(ptr + 4); FskStrNumToHex(FskEndianU16_NtoB(u16), &str[8], 4); str[12] = '-'; u16 = *(UInt16 *)(ptr + 6); FskStrNumToHex(FskEndianU16_NtoB(u16), &str[13], 4); str[17] = '-'; u16 = *(UInt16 *)(ptr + 8); FskStrNumToHex(FskEndianU16_NtoB(u16), &str[18], 4); str[22] = '-'; u16 = *(UInt16 *)(ptr + 10); FskStrNumToHex(FskEndianU16_NtoB(u16), &str[23], 4); u32 = *(UInt32 *)(ptr + 12); FskStrNumToHex(FskEndianU32_NtoB(u32), &str[27], 8); } return str; }
char *FskUUIDtoString_844412(FskUUID uuid) { // lowercase 00000000-0000-0000-0000-000000000000 char *str = NULL; if (kFskErrNone == FskMemPtrNewClear(37, &str)) { UInt32 u32; UInt16 u16; UInt8 *ptr = uuid->value; u32 = *(UInt32 *)(ptr + 0); FskStrNumToHex(FskEndianU32_NtoB(u32), &str[0], 8); str[8] = '-'; u16 = *(UInt16 *)(ptr + 4); FskStrNumToHex(FskEndianU16_NtoB(u16), &str[9], 4); str[13] = '-'; u16 = *(UInt16 *)(ptr + 6); FskStrNumToHex(FskEndianU16_NtoB(u16), &str[14], 4); str[18] = '-'; u16 = *(UInt16 *)(ptr + 8); FskStrNumToHex(FskEndianU16_NtoB(u16), &str[19], 4); str[23] = '-'; u16 = *(UInt16 *)(ptr + 10); FskStrNumToHex(FskEndianU16_NtoB(u16), &str[24], 4); u32 = *(UInt32 *)(ptr + 12); FskStrNumToHex(FskEndianU32_NtoB(u32), &str[28], 8); for (u16 = 0; u16 < 36; u16++) str[u16] = tolower(str[u16]); //@@ should use portable function } return str; }
void printInterfaces() { FskNetInterfaceRecord *nir; char str[32], mac[32]; nir = gNetworkInterfaces; while (nir) { FskNetIPandPortToString(nir->ip, 0, str); FskStrNumToHex(nir->MAC[0], mac, 2); mac[2] = ':'; FskStrNumToHex(nir->MAC[1], &mac[3], 2); mac[5] = ':'; FskStrNumToHex(nir->MAC[2], &mac[6], 2); mac[8] = ':'; FskStrNumToHex(nir->MAC[3], &mac[9], 2); mac[11] = ':'; FskStrNumToHex(nir->MAC[4], &mac[12], 2); mac[14] = ':'; FskStrNumToHex(nir->MAC[5], &mac[15], 2); mac[17] = '\0'; FskInstrumentedTypePrintfDebug(&gNetInterfaceNotifierTypeInstrumentation, "IFC: %s -- %s -- %s", nir->name, str, mac); nir = nir->next; } }
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); } } }