void httpKill() { // shut down connections { JsVar *arr = httpGetArray(HTTP_ARRAY_HTTP_SERVER_CONNECTIONS,false); if (arr) { JsArrayIterator it; jsvArrayIteratorNew(&it, arr); while (jsvArrayIteratorHasElement(&it)) { JsVar *connection = jsvArrayIteratorGetElement(&it); _httpServerConnectionKill(connection); jsvUnLock(connection); jsvArrayIteratorNext(&it); } jsvArrayIteratorFree(&it); jsvRemoveAllChildren(arr); jsvUnLock(arr); } } { JsVar *arr = httpGetArray(HTTP_ARRAY_HTTP_CLIENT_CONNECTIONS,false); if (arr) { JsArrayIterator it; jsvArrayIteratorNew(&it, arr); while (jsvArrayIteratorHasElement(&it)) { JsVar *connection = jsvArrayIteratorGetElement(&it); _httpClientConnectionKill(connection); jsvUnLock(connection); jsvArrayIteratorNext(&it); } jsvArrayIteratorFree(&it); jsvRemoveAllChildren(arr); jsvUnLock(arr); } } // shut down our listeners, unlock objects, free data { JsVar *arr = httpGetArray(HTTP_ARRAY_HTTP_SERVERS,false); if (arr) { JsArrayIterator it; jsvArrayIteratorNew(&it, arr); while (jsvArrayIteratorHasElement(&it)) { JsVar *connection = jsvArrayIteratorGetElement(&it); SOCKET socket = (SOCKET)jsvGetIntegerAndUnLock(jsvObjectGetChild(connection,HTTP_NAME_SOCKET,0))-1; // so -1 if undefined if (socket!=INVALID_SOCKET) closesocket(socket); jsvUnLock(connection); jsvArrayIteratorNext(&it); } jsvArrayIteratorFree(&it); jsvRemoveAllChildren(arr); jsvUnLock(arr); } } #ifdef WIN32 // Shutdown Winsock WSACleanup(); #endif }
/*JSON{ "type":"method", "class": "Function", "name" : "apply", "description" : ["This executes the function with the supplied 'this' argument and parameters"], "generate" : "jswrap_function_apply", "params" : [ [ "this", "JsVar", "The value to use as the 'this' argument when executing the function"], [ "args", "JsVar", "Optional Array of Aruments"] ], "return" : [ "JsVar", "The return value of executing this function" ] }*/ JsVar *jswrap_function_apply(JsVar *parent, JsVar *thisArg, JsVar *argsArray) { unsigned int i; JsVar **args = 0; size_t argC = 0; if (jsvIsArray(argsArray)) { argC = (size_t)jsvGetArrayLength(argsArray); if (argC>64) argC=64; // sanity args = (JsVar**)alloca((size_t)argC * sizeof(JsVar*)); for (i=0;i<argC;i++) args[i] = 0; JsvArrayIterator it; jsvArrayIteratorNew(&it, argsArray); while (jsvArrayIteratorHasElement(&it)) { JsVarInt idx = jsvGetIntegerAndUnLock(jsvArrayIteratorGetIndex(&it)); if (idx>=0 && idx<(int)argC) { assert(!args[idx]); // just in case there were dups args[idx] = jsvArrayIteratorGetElement(&it); } jsvArrayIteratorNext(&it); } jsvArrayIteratorFree(&it); } else if (!jsvIsUndefined(argsArray)) { jsWarn("Second argument to Function.apply must be an array"); } JsVar *r = jspeFunctionCall(parent, 0, thisArg, false, (int)argC, args); for (i=0;i<argC;i++) jsvUnLock(args[i]); return r; }
void httpIdle() { if (networkState != NETWORKSTATE_ONLINE) return; JsVar *arr = httpGetArray(HTTP_ARRAY_HTTP_SERVERS,false); if (arr) { JsArrayIterator it; jsvArrayIteratorNew(&it, arr); while (jsvArrayIteratorHasElement(&it)) { JsVar *server = jsvArrayIteratorGetElement(&it); SOCKET socket = (SOCKET)jsvGetIntegerAndUnLock(jsvObjectGetChild(server,HTTP_NAME_SOCKET,0))-1; // so -1 if undefined #ifndef USE_CC3000 // TODO: look for unreffed servers? fd_set s; FD_ZERO(&s); FD_SET(socket,&s); // check for waiting clients struct timeval timeout; timeout.tv_sec = 0; timeout.tv_usec = 0; int n = select(socket+1,&s,NULL,NULL,&timeout); #else /* CC3000 works a different way - we set accept as nonblocking, * and then we just call it and see if it works or not... */ int n=1; #endif while (n-->0) { // we have a client waiting to connect... int theClient = accept(socket,NULL,NULL); // try and connect if (theClient > -1) { JsVar *req = jspNewObject(jsiGetParser(), 0, "httpSRq"); JsVar *res = jspNewObject(jsiGetParser(), 0, "httpSRs"); if (res && req) { // out of memory? JsVar *arr = httpGetArray(HTTP_ARRAY_HTTP_SERVER_CONNECTIONS, true); if (arr) { jsvArrayPush(arr, req); jsvUnLock(arr); } jsvObjectSetChild(req, HTTP_NAME_RESPONSE_VAR, res); jsvObjectSetChild(req, HTTP_NAME_SERVER_VAR, server); jsvUnLock(jsvObjectSetChild(req, HTTP_NAME_SOCKET, jsvNewFromInteger(theClient+1))); // on response jsvUnLock(jsvObjectSetChild(res, HTTP_NAME_CODE, jsvNewFromInteger(200))); jsvUnLock(jsvObjectSetChild(res, HTTP_NAME_HEADERS, jsvNewWithFlags(JSV_OBJECT))); } jsvUnLock(req); jsvUnLock(res); //add(new CNetworkConnect(theClient, this)); // add to service queue } } jsvUnLock(server); jsvArrayIteratorNext(&it); } jsvArrayIteratorFree(&it); jsvUnLock(arr); } httpServerConnectionsIdle(); httpClientConnectionsIdle(); }
/*JSON{ "type":"idle", "generate" : "jswrap_waveform_idle", "ifndef" : "SAVE_ON_FLASH" }*/ bool jswrap_waveform_idle() { JsVar *waveforms = jsvObjectGetChild(execInfo.hiddenRoot, JSI_WAVEFORM_NAME, 0); if (waveforms) { JsvArrayIterator it; jsvArrayIteratorNew(&it, waveforms); while (jsvArrayIteratorHasElement(&it)) { JsVar *waveform = jsvArrayIteratorGetElement(&it); bool running = jsvGetBoolAndUnLock(jsvObjectGetChild(waveform, "running", 0)); if (running) { JsVar *buffer = jswrap_waveform_getBuffer(waveform,0,0); UtilTimerTask task; // Search for a timer task if (!jstGetLastBufferTimerTask(buffer, &task)) { // if the timer task is now gone... JsVar *arrayBuffer = jsvObjectGetChild(waveform, "buffer", 0); jsiQueueObjectCallbacks(waveform, "#onfinish", &arrayBuffer, 1); jsvUnLock(arrayBuffer); running = false; jsvUnLock(jsvObjectSetChild(waveform, "running", jsvNewFromBool(running))); } else { // If the timer task is still there... if (task.data.buffer.nextBuffer && task.data.buffer.nextBuffer != task.data.buffer.currentBuffer) { // if it is a double-buffered task int currentBuffer = (jsvGetRef(buffer)==task.data.buffer.currentBuffer) ? 0 : 1; JsVar *oldBuffer = jsvObjectGetChild(waveform, "currentBuffer", JSV_INTEGER); if (jsvGetInteger(oldBuffer) !=currentBuffer) { // buffers have changed - fire off a 'buffer' event with the buffer that needs to be filled jsvSetInteger(oldBuffer, currentBuffer); JsVar *arrayBuffer = jsvObjectGetChild(waveform, (currentBuffer==0) ? "buffer" : "buffer2", 0); jsiQueueObjectCallbacks(waveform, "#onbuffer", &arrayBuffer, 1); jsvUnLock(arrayBuffer); } jsvUnLock(oldBuffer); } } jsvUnLock(buffer); } jsvUnLock(waveform); // if not running, remove waveform from this list if (!running) jsvArrayIteratorRemoveAndGotoNext(&it, waveforms); else jsvArrayIteratorNext(&it); } jsvArrayIteratorFree(&it); jsvUnLock(waveforms); } return false; // no need to stay awake - an IRQ will wake us }
/*JSON{ "type":"staticmethod", "class" : "Math", "name" : "max", "generate_full" : "jswrap_math_minmax(args, true)", "description" : "Find the maximum of a series of numbers", "params" : [ [ "args", "JsVarArray", "A floating point value to clip"] ], "return" : ["float", "The maximum of the supplied values"] }*/ JsVarFloat jswrap_math_minmax(JsVar *args, bool isMax) { JsVarFloat v = isMax ? -INFINITY : INFINITY; JsvArrayIterator it; jsvArrayIteratorNew(&it, args); while (jsvArrayIteratorHasElement(&it)) { JsVarFloat arg = jsvGetFloatAndUnLock(jsvArrayIteratorGetElement(&it)); if ((isMax && arg > v) || (!isMax && arg < v) || isnan(arg)) v = arg; jsvArrayIteratorNext(&it); } jsvArrayIteratorFree(&it); return v; }
/*JSON{ "type":"staticmethod", "class":"console", "name" : "log", "description" : "Print the supplied string(s)", "generate" : "jswrap_interface_print", "params" : [ [ "text", "JsVarArray", "One or more arguments to print"] ] }*/ void jswrap_interface_print(JsVar *v) { assert(jsvIsArray(v)); JsArrayIterator it; jsvArrayIteratorNew(&it, v); while (jsvArrayIteratorHasElement(&it)) { JsVar *v = jsvAsString(jsvArrayIteratorGetElement(&it), true); jsiConsoleRemoveInputLine(); jsiConsolePrintStringVar(v); jsvUnLock(v); jsvArrayIteratorNext(&it); if (jsvArrayIteratorHasElement(&it)) jsiConsolePrint(" "); } jsvArrayIteratorFree(&it); jsiConsolePrint("\n"); }
/*JSON{ "type":"method", "class": "Array", "name" : "push", "description" : "Push a new value onto the end of this array'", "generate" : "jswrap_array_push", "params" : [ [ "arguments", "JsVarArray", "One or more arguments to add"] ], "return" : ["int", "The new size of the array"] }*/ JsVarInt jswrap_array_push(JsVar *parent, JsVar *args) { if (!jsvIsArray(parent)) return -1; JsVarInt len = -1; JsvArrayIterator it; jsvArrayIteratorNew(&it, args); while (jsvArrayIteratorHasElement(&it)) { JsVar *el = jsvArrayIteratorGetElement(&it); len = jsvArrayPush(parent, el); jsvUnLock(el); jsvArrayIteratorNext(&it); } jsvArrayIteratorFree(&it); if (len<0) len = jsvGetArrayLength(parent); return len; }
/*JSON{ "type":"staticmethod", "class": "String", "name" : "fromCharCode", "description" : "Return the character(s) represented by the given character code(s).", "generate" : "jswrap_string_fromCharCode", "params" : [ [ "code", "JsVarArray", "One or more character codes to create a string from (range 0-255)."] ], "return" : ["JsVar", "The character"] }*/ JsVar *jswrap_string_fromCharCode(JsVar *arr) { assert(jsvIsArray(arr)); JsVar *r = jsvNewFromEmptyString(); if (!r) return 0; JsvArrayIterator it; jsvArrayIteratorNew(&it, arr); while (jsvArrayIteratorHasElement(&it)) { char ch = (char)jsvGetIntegerAndUnLock(jsvArrayIteratorGetElement(&it)); jsvAppendStringBuf(r, &ch, 1); jsvArrayIteratorNext(&it); } jsvArrayIteratorFree(&it); return r; }
JsVar *jswrap_typedarray_constructor(JsVarDataArrayBufferViewType type, JsVar *arr, JsVarInt byteOffset, JsVarInt length) { JsVar *arrayBuffer = 0; if (jsvIsArrayBuffer(arr)) { arrayBuffer = jsvLockAgain(arr); } else if (jsvIsInt(arr)) { length = jsvGetInteger(arr); byteOffset = 0; arrayBuffer = jswrap_arraybuffer_constructor(JSV_ARRAYBUFFER_GET_SIZE(type)*length); } else if (jsvIsArray(arr)) { length = jsvGetArrayLength(arr); byteOffset = 0; arrayBuffer = jswrap_arraybuffer_constructor(JSV_ARRAYBUFFER_GET_SIZE(type)*length); // later on we'll populate this } if (!arrayBuffer) { jsError("Unsupported first argument\n"); return 0; } if (length<=0) length = (JsVarInt)jsvGetArrayBufferLength(arrayBuffer) / JSV_ARRAYBUFFER_GET_SIZE(type); JsVar *typedArr = jsvNewWithFlags(JSV_ARRAYBUFFER); if (typedArr) { typedArr->varData.arraybuffer.type = type; typedArr->varData.arraybuffer.byteOffset = (unsigned short)byteOffset; typedArr->varData.arraybuffer.length = (unsigned short)length; typedArr->firstChild = jsvGetRef(jsvRef(arrayBuffer)); if (jsvIsArray(arr)) { // if we were given an array, populate this ArrayBuffer JsvArrayIterator it; jsvArrayIteratorNew(&it, arr); while (jsvArrayIteratorHasElement(&it)) { JsVar *idx = jsvArrayIteratorGetIndex(&it); if (jsvIsInt(idx)) { JsVar *val = jsvArrayIteratorGetElement(&it); jsvArrayBufferSet(typedArr, jsvGetInteger(idx), val); jsvUnLock(val); } jsvUnLock(idx); jsvArrayIteratorNext(&it); } jsvArrayIteratorFree(&it); } } jsvUnLock(arrayBuffer); return typedArr; }
/*JSON{ "type":"kill", "generate" : "jswrap_file_kill" }*/ void jswrap_file_kill() { { JsVar *arr = fsGetArray(false); if (arr) { JsvArrayIterator it; jsvArrayIteratorNew(&it, arr); while (jsvArrayIteratorHasElement(&it)) { JsVar *file = jsvArrayIteratorGetElement(&it); jswrap_file_close(file); jsvUnLock(file); jsvArrayIteratorNext(&it); } jsvArrayIteratorFree(&it); jsvRemoveAllChildren(arr); jsvUnLock(arr); } } }
/*JSON{ "type":"staticmethod", "class":"console", "name" : "log", "description" : [ "Print the supplied string(s) to the console", "**Note:** If you're connected to a computer (not a wall adaptor) via USB but **you are not running a terminal app** then when you print data Espruino may pause execution and wait until the computer requests the data it is trying to print." ], "generate" : "jswrap_interface_print", "params" : [ [ "text", "JsVarArray", "One or more arguments to print"] ] }*/ void jswrap_interface_print(JsVar *v) { assert(jsvIsArray(v)); jsiConsoleRemoveInputLine(); JsvArrayIterator it; jsvArrayIteratorNew(&it, v); while (jsvArrayIteratorHasElement(&it)) { JsVar *v = jsvArrayIteratorGetElement(&it); if (jsvIsString(v)) jsiConsolePrintStringVar(v); else jsfPrintJSON(v, JSON_PRETTY | JSON_NEWLINES); jsvUnLock(v); jsvArrayIteratorNext(&it); if (jsvArrayIteratorHasElement(&it)) jsiConsolePrint(" "); } jsvArrayIteratorFree(&it); jsiConsolePrint("\n"); }
/*JSON{ "type":"kill", "generate" : "jswrap_waveform_kill", "ifndef" : "SAVE_ON_FLASH" }*/ void jswrap_waveform_kill() { // be sure to remove all waveforms... JsVar *waveforms = jsvObjectGetChild(execInfo.hiddenRoot, JSI_WAVEFORM_NAME, 0); if (waveforms) { JsvArrayIterator it; jsvArrayIteratorNew(&it, waveforms); while (jsvArrayIteratorHasElement(&it)) { JsVar *waveform = jsvArrayIteratorGetElement(&it); bool running = jsvGetBoolAndUnLock(jsvObjectGetChild(waveform, "running", 0)); if (running) { JsVar *buffer = jswrap_waveform_getBuffer(waveform,0,0); if (!jstStopBufferTimerTask(buffer)) { jsExceptionHere(JSET_ERROR, "Waveform couldn't be stopped"); } jsvUnLock(buffer); } jsvUnLock(waveform); // if not running, remove waveform from this list jsvArrayIteratorRemoveAndGotoNext(&it, waveforms); } jsvArrayIteratorFree(&it); jsvUnLock(waveforms); } }
/*JSON{ "type":"method", "class": "Array", "name" : "splice", "description" : "Both remove and add items to an array", "generate" : "jswrap_array_splice", "params" : [ [ "index", "int", "Index at which to start changing the array. If negative, will begin that many elements from the end"], [ "howMany", "JsVar", "An integer indicating the number of old array elements to remove. If howMany is 0, no elements are removed."], [ "element1", "JsVar", "A new item to add (optional)" ], [ "element2", "JsVar", "A new item to add (optional)" ], [ "element3", "JsVar", "A new item to add (optional)" ], [ "element4", "JsVar", "A new item to add (optional)" ], [ "element5", "JsVar", "A new item to add (optional)" ], [ "element6", "JsVar", "A new item to add (optional)" ] ], "return" : ["JsVar", "An array containing the removed elements. If only one element is removed, an array of one element is returned."] }*/ JsVar *jswrap_array_splice(JsVar *parent, JsVarInt index, JsVar *howManyVar, JsVar *element1, JsVar *element2, JsVar *element3, JsVar *element4, JsVar *element5, JsVar *element6) { JsVarInt len = jsvGetArrayLength(parent); if (index<0) index+=len; if (index<0) index=0; if (index>len) index=len; JsVarInt howMany = len; // how many to delete! if (jsvIsInt(howManyVar)) howMany = jsvGetInteger(howManyVar); if (howMany > len-index) howMany = len-index; JsVarInt newItems = 0; if (element1) newItems++; if (element2) newItems++; if (element3) newItems++; if (element4) newItems++; if (element5) newItems++; if (element6) newItems++; JsVarInt shift = newItems-howMany; bool needToAdd = false; JsVar *result = jsvNewWithFlags(JSV_ARRAY); JsArrayIterator it; jsvArrayIteratorNew(&it, parent); while (jsvArrayIteratorHasElement(&it) && !needToAdd) { bool goToNext = true; JsVar *idxVar = jsvArrayIteratorGetIndex(&it); if (idxVar && jsvIsInt(idxVar)) { JsVarInt idx = jsvGetInteger(idxVar); if (idx<index) { // do nothing... } else if (idx<index+howMany) { // must delete if (result) { // append to result array JsVar *el = jsvArrayIteratorGetElement(&it); jsvArrayPush(result, el); jsvUnLock(el); } // delete goToNext = false; JsVar *toRemove = jsvArrayIteratorGetIndex(&it); jsvArrayIteratorNext(&it); jsvRemoveChild(parent, toRemove); jsvUnLock(toRemove); } else { // we're greater than the amount we need to remove now needToAdd = true; goToNext = false; } } jsvUnLock(idxVar); if (goToNext) jsvArrayIteratorNext(&it); } // now we add everything JsVar *beforeIndex = jsvArrayIteratorGetIndex(&it); if (element1) jsvArrayInsertBefore(parent, beforeIndex, element1); if (element2) jsvArrayInsertBefore(parent, beforeIndex, element2); if (element3) jsvArrayInsertBefore(parent, beforeIndex, element3); if (element4) jsvArrayInsertBefore(parent, beforeIndex, element4); if (element5) jsvArrayInsertBefore(parent, beforeIndex, element5); if (element6) jsvArrayInsertBefore(parent, beforeIndex, element6); jsvUnLock(beforeIndex); // And finally renumber while (jsvArrayIteratorHasElement(&it)) { JsVar *idxVar = jsvArrayIteratorGetIndex(&it); if (idxVar && jsvIsInt(idxVar)) { jsvSetInteger(idxVar, jsvGetInteger(idxVar)+shift); } jsvUnLock(idxVar); jsvArrayIteratorNext(&it); } // free jsvArrayIteratorFree(&it); return result; }
void httpClientConnectionsIdle() { char buf[64]; JsVar *arr = httpGetArray(HTTP_ARRAY_HTTP_CLIENT_CONNECTIONS,false); if (!arr) return; JsArrayIterator it; jsvArrayIteratorNew(&it, arr); while (jsvArrayIteratorHasElement(&it)) { JsVar *connection = jsvArrayIteratorGetElement(&it); bool closeConnectionNow = jsvGetBoolAndUnLock(jsvObjectGetChild(connection, HTTP_NAME_CLOSENOW, false)); SOCKET sckt = (SOCKET)jsvGetIntegerAndUnLock(jsvObjectGetChild(connection,HTTP_NAME_SOCKET,0))-1; // so -1 if undefined bool hadHeaders = jsvGetBoolAndUnLock(jsvObjectGetChild(connection,HTTP_NAME_HAD_HEADERS,0)); JsVar *receiveData = jsvObjectGetChild(connection,HTTP_NAME_RECEIVE_DATA,0); /* We do this up here because we want to wait until we have been once * around the idle loop (=callbacks have been executed) before we run this */ if (hadHeaders && receiveData) { JsVar *resVar = jsvObjectGetChild(connection,HTTP_NAME_RESPONSE_VAR,0); jsiQueueObjectCallbacks(resVar, HTTP_NAME_ON_DATA, receiveData, 0); jsvUnLock(resVar); // clear - because we have issued a callback jsvObjectSetChild(connection,HTTP_NAME_RECEIVE_DATA,0); } if (sckt!=INVALID_SOCKET) { JsVar *sendData = jsvObjectGetChild(connection,HTTP_NAME_SEND_DATA,0); // send data if possible if (sendData) { // this will wait to see if we can write any more, but ALSO // will wait for connection fd_set writefds; FD_ZERO(&writefds); FD_SET(sckt, &writefds); struct timeval time; time.tv_sec = 0; time.tv_usec = 0; int n = select(sckt+1, 0, &writefds, 0, &time); if (n==SOCKET_ERROR ) { // we probably disconnected so just get rid of this closeConnectionNow = true; } else if (FD_ISSET(sckt, &writefds)) { if (!_http_send(sckt, &sendData)) closeConnectionNow = true; jsvObjectSetChild(connection, HTTP_NAME_SEND_DATA, sendData); // _http_send prob updated sendData } #ifdef USE_CC3000 } else { // When in CC3000, write then read (FIXME) #else } // When in Linux, just read and write at the same time { #endif // Now receive data fd_set s; FD_ZERO(&s); FD_SET(sckt,&s); // check for waiting clients struct timeval timeout; timeout.tv_sec = 0; #ifdef USE_CC3000 timeout.tv_usec = 5000; // 5 millisec #else timeout.tv_usec = 0; #endif int n = select(sckt+1,&s,NULL,NULL,&timeout); if (n==SOCKET_ERROR) { // we probably disconnected so just get rid of this closeConnectionNow = true; } else if (n>0) { // receive data int num = (int)recv(sckt,buf,sizeof(buf),0); // add it to our request string if (num>0) { if (!receiveData) { receiveData = jsvNewFromEmptyString(); jsvObjectSetChild(connection, HTTP_NAME_RECEIVE_DATA, receiveData); } if (receiveData) { // could be out of memory jsvAppendStringBuf(receiveData, buf, num); if (!hadHeaders) { JsVar *resVar = jsvObjectGetChild(connection,HTTP_NAME_RESPONSE_VAR,0); if (httpParseHeaders(&receiveData, resVar, false)) { hadHeaders = true; jsvUnLock(jsvObjectSetChild(connection, HTTP_NAME_HAD_HEADERS, jsvNewFromBool(hadHeaders))); jsiQueueObjectCallbacks(connection, HTTP_NAME_ON_CONNECT, resVar, 0); } jsvUnLock(resVar); jsvObjectSetChild(connection, HTTP_NAME_RECEIVE_DATA, receiveData); } } } else if (num==0) { // select says data, but recv says 0 means connection is closed closeConnectionNow = true; } } else { #ifdef USE_CC3000 // Nothing to send or receive, and closed if (!sendData && cc3000_socket_has_closed(sckt)) closeConnectionNow = true; #endif } } jsvUnLock(sendData); } jsvUnLock(receiveData); if (closeConnectionNow) { JsVar *resVar = jsvObjectGetChild(connection,HTTP_NAME_RESPONSE_VAR,0); jsiQueueObjectCallbacks(resVar, HTTP_NAME_ON_CLOSE, 0, 0); jsvUnLock(resVar); _httpClientConnectionKill(connection); JsVar *connectionName = jsvArrayIteratorGetIndex(&it); jsvArrayIteratorNext(&it); jsvRemoveChild(arr, connectionName); jsvUnLock(connectionName); } else jsvArrayIteratorNext(&it); jsvUnLock(connection); } jsvUnLock(arr); }
void httpServerConnectionsIdle() { char buf[64]; JsVar *arr = httpGetArray(HTTP_ARRAY_HTTP_SERVER_CONNECTIONS,false); if (!arr) return; JsArrayIterator it; jsvArrayIteratorNew(&it, arr); while (jsvArrayIteratorHasElement(&it)) { JsVar *connection = jsvArrayIteratorGetElement(&it); JsVar *connectReponse = jsvObjectGetChild(connection,HTTP_NAME_RESPONSE_VAR,0); SOCKET sckt = (SOCKET)jsvGetIntegerAndUnLock(jsvObjectGetChild(connection,HTTP_NAME_SOCKET,0))-1; // so -1 if undefined bool closeConnectionNow = jsvGetBoolAndUnLock(jsvObjectGetChild(connection, HTTP_NAME_CLOSENOW, false)); bool hadData = false; // TODO: look for unreffed connections? fd_set s; FD_ZERO(&s); FD_SET(sckt,&s); // check for waiting clients struct timeval timeout; timeout.tv_sec = 0; timeout.tv_usec = 0; int n = select(sckt+1,&s,NULL,NULL,&timeout); if (n==SOCKET_ERROR) { // we probably disconnected so just get rid of this closeConnectionNow = true; } else if (n>0) { hadData = true; // receive data int num = (int)recv(sckt,buf,sizeof(buf),0); // add it to our request string if (num>0) { JsVar *receiveData = jsvObjectGetChild(connection,HTTP_NAME_RECEIVE_DATA,0); if (!receiveData) { receiveData = jsvNewFromEmptyString(); jsvObjectSetChild(connection,HTTP_NAME_RECEIVE_DATA,receiveData); } if (receiveData) { jsvAppendStringBuf(receiveData, buf, num); bool hadHeaders = jsvGetBoolAndUnLock(jsvObjectGetChild(connection,HTTP_NAME_HAD_HEADERS,0)); if (!hadHeaders && httpParseHeaders(&receiveData, connection, true)) { hadHeaders = true; jsvUnLock(jsvObjectSetChild(connection, HTTP_NAME_HAD_HEADERS, jsvNewFromBool(hadHeaders))); JsVar *resVar = jsvObjectGetChild(connection,HTTP_NAME_RESPONSE_VAR,0); JsVar *server = jsvObjectGetChild(connection,HTTP_NAME_SERVER_VAR,0); jsiQueueObjectCallbacks(server, HTTP_NAME_ON_CONNECT, connection, resVar); jsvUnLock(server); jsvUnLock(resVar); } jsvUnLock(receiveData); } } } // send data if possible JsVar *sendData = jsvObjectGetChild(connectReponse,HTTP_NAME_SEND_DATA,0); if (sendData) { fd_set writefds; FD_ZERO(&writefds); FD_SET(sckt, &writefds); struct timeval time; time.tv_sec = 0; time.tv_usec = 0; int n = select(sckt+1, 0, &writefds, 0, &time); if (n==SOCKET_ERROR ) { // we probably disconnected so just get rid of this closeConnectionNow = true; } else if (FD_ISSET(sckt, &writefds)) { if (!_http_send(sckt, &sendData)) closeConnectionNow = true; } jsvObjectSetChild(connectReponse, HTTP_NAME_SEND_DATA, sendData); // _http_send prob updated sendData } else { #ifdef USE_CC3000 // nothing to send, nothing to receive, and closed... if (!hadData && cc3000_socket_has_closed(sckt)) closeConnectionNow = true; #endif } if (jsvGetBoolAndUnLock(jsvObjectGetChild(connectReponse,HTTP_NAME_CLOSE,0)) && !sendData) closeConnectionNow = true; jsvUnLock(sendData); if (closeConnectionNow) { JsVar *resVar = jsvObjectGetChild(connection,HTTP_NAME_RESPONSE_VAR,0); jsiQueueObjectCallbacks(resVar, HTTP_NAME_ON_CLOSE, 0, 0); jsvUnLock(resVar); _httpServerConnectionKill(connection); JsVar *connectionName = jsvArrayIteratorGetIndex(&it); jsvArrayIteratorNext(&it); jsvRemoveChild(arr, connectionName); jsvUnLock(connectionName); } else jsvArrayIteratorNext(&it); jsvUnLock(connection); jsvUnLock(connectReponse); } jsvArrayIteratorFree(&it); jsvUnLock(arr); }