Exemplo n.º 1
0
static void jswrap_waveform_start(JsVar *waveform, Pin pin, JsVarFloat freq, JsVar *options, bool isWriting) {
  bool running = jsvGetBoolAndUnLock(jsvObjectGetChild(waveform, "running", 0));
  if (running) {
    jsExceptionHere(JSET_ERROR, "Waveform is already running");
    return;
  }
  if (!jshIsPinValid(pin)) {
    jsExceptionHere(JSET_ERROR, "Invalid pin");
    return;
  }
  if (!isfinite(freq) || freq<0.001) {
    jsExceptionHere(JSET_ERROR, "Frequency must be above 0.001Hz");
    return;
  }

  JsSysTime startTime = jshGetSystemTime();
  bool repeat = false;
  if (jsvIsObject(options)) {
    JsVarFloat t = jsvGetFloatAndUnLock(jsvObjectGetChild(options, "time", 0));
    if (isfinite(t) && t>0)
       startTime = jshGetTimeFromMilliseconds(t*1000);
    repeat = jsvGetBoolAndUnLock(jsvObjectGetChild(options, "repeat", 0));
  } else if (!jsvIsUndefined(options)) {
    jsExceptionHere(JSET_ERROR, "Expecting options to be undefined or an Object, not %t", options);
  }

  bool is16Bit = false;
  JsVar *buffer = jswrap_waveform_getBuffer(waveform,0, &is16Bit);
  JsVar *buffer2 = jswrap_waveform_getBuffer(waveform,1,0);

  UtilTimerEventType eventType;

  if (is16Bit) {
    eventType = isWriting ? UET_WRITE_SHORT : UET_READ_SHORT;
  } else {
    eventType = isWriting ? UET_WRITE_BYTE : UET_READ_BYTE;
  }


  // And finally set it up
  if (!jstStartSignal(startTime, jshGetTimeFromMilliseconds(1000.0 / freq), pin, buffer, repeat?(buffer2?buffer2:buffer):0, eventType))
    jsWarn("Unable to schedule a timer");
  jsvUnLock(buffer);
  jsvUnLock(buffer2);

  jsvUnLock(jsvObjectSetChild(waveform, "running", jsvNewFromBool(true)));
  jsvUnLock(jsvObjectSetChild(waveform, "freq", jsvNewFromFloat(freq)));
  // Add to our list of active waveforms
  JsVar *waveforms = jsvObjectGetChild(execInfo.hiddenRoot, JSI_WAVEFORM_NAME, JSV_ARRAY);
  if (waveforms) {
    jsvArrayPush(waveforms, waveform);
    jsvUnLock(waveforms);
  }
}
Exemplo n.º 2
0
/*JSON{
  "type" : "function",
  "name" : "analogWrite",
  "generate" : "jswrap_io_analogWrite",
  "params" : [
    ["pin","pin",["The pin to use","You can find out which pins to use by looking at [your board's reference page](#boards) and searching for pins with the `PWM` or `DAC` markers."]],
    ["value","float","A value between 0 and 1"],
    ["options","JsVar",["An object containing options for analog output - see below"]]
  ]
}
Set the analog Value of a pin. It will be output using PWM.

Objects can contain:

* `freq` - pulse frequency in Hz, eg. ```analogWrite(A0,0.5,{ freq : 10 });``` - specifying a frequency will force PWM output, even if the pin has a DAC
* `soft` - boolean, If true software PWM is used if available.
* `forceSoft` - boolean, If true software PWM is used even

 **Note:** if you didn't call `pinMode` beforehand then this function will also reset pin's state to `"output"`
 */
void jswrap_io_analogWrite(Pin pin, JsVarFloat value, JsVar *options) {
  JsVarFloat freq = 0;
  JshAnalogOutputFlags flags = JSAOF_NONE;
  if (jsvIsObject(options)) {
    freq = jsvGetFloatAndUnLock(jsvObjectGetChild(options, "freq", 0));
    if (jsvGetBoolAndUnLock(jsvObjectGetChild(options, "forceSoft", 0)))
          flags |= JSAOF_FORCE_SOFTWARE;
    else if (jsvGetBoolAndUnLock(jsvObjectGetChild(options, "soft", 0)))
      flags |= JSAOF_ALLOW_SOFTWARE;
  }

  jshPinAnalogOutput(pin, value, freq, flags);
}
Exemplo n.º 3
0
// returns 0 on success and a (negative) error number on failure
int socketSendData(JsNetwork *net, JsVar *connection, int sckt, JsVar **sendData) {
    char *buf = alloca(net->chunkSize); // allocate on stack

    assert(!jsvIsEmptyString(*sendData));

    size_t bufLen = httpStringGet(*sendData, buf, net->chunkSize);
    int num = netSend(net, sckt, buf, bufLen);
    if (num < 0) return num; // an error occurred
    // Now cut what we managed to send off the beginning of sendData
    if (num > 0) {
        JsVar *newSendData = 0;
        if (num < (int)jsvGetStringLength(*sendData)) {
            // we didn't send all of it... cut out what we did send
            newSendData = jsvNewFromStringVar(*sendData, (size_t)num, JSVAPPENDSTRINGVAR_MAXLENGTH);
        } else {
            // we sent all of it! Issue a drain event, unless we want to close, then we shouldn't
            // callback for more data
            bool wantClose = jsvGetBoolAndUnLock(jsvObjectGetChild(connection,HTTP_NAME_CLOSE,0));
            if (!wantClose) {
                jsiQueueObjectCallbacks(connection, HTTP_NAME_ON_DRAIN, &connection, 1);
            }
            newSendData = jsvNewFromEmptyString();
        }
        jsvUnLock(*sendData);
        *sendData = newSendData;
    }

    return 0;
}
Exemplo n.º 4
0
/*JSON{
  "type" : "staticmethod",
  "class" : "fs",
  "name" : "pipe",
  "ifndef" : "SAVE_ON_FLASH",
  "generate" : "jswrap_pipe",
  "params" : [
    ["source","JsVar","The source file/stream that will send content."],
    ["destination","JsVar","The destination file/stream that will receive content from the source."],
    ["options","JsVar",["An optional object `{ chunkSize : int=64, end : bool=true, complete : function }`","chunkSize : The amount of data to pipe from source to destination at a time","complete : a function to call when the pipe activity is complete","end : call the 'end' function on the destination when the source is finished"]]
  ]
}*/
void jswrap_pipe(JsVar* source, JsVar* dest, JsVar* options) {
  if (!source || !dest) return;
  JsVar *pipe = jspNewObject(0, "Pipe");
  JsVar *arr = pipeGetArray(true);
  JsVar* position = jsvNewFromInteger(0);
  if (pipe && arr && position) {// out of memory?
    JsVar *readFunc = jspGetNamedField(source, "read", false);
    JsVar *writeFunc = jspGetNamedField(dest, "write", false);
    if(jsvIsFunction(readFunc)) {
      if(jsvIsFunction(writeFunc)) {
        JsVarInt chunkSize = 64;
        bool callEnd = true;
        // parse Options Object
        if (jsvIsObject(options)) {
          JsVar *c;
          c = jsvObjectGetChild(options, "complete", false);
          if (c) {
            jsvObjectSetChild(pipe, "#oncomplete", c);
            jsvUnLock(c);
          }
          c = jsvObjectGetChild(options, "end", false);
          if (c) callEnd = jsvGetBoolAndUnLock(c);
          c = jsvObjectGetChild(options, "chunkSize", false);
          if (c) {
            if (jsvIsNumeric(c) && jsvGetInteger(c)>0)
              chunkSize = jsvGetInteger(c);
            else
              jsWarn("chunkSize must be an integer > 0");
            jsvUnLock(c);
          }
        } else if (!jsvIsUndefined(options)) {
          jsWarn("'options' must be an object, or undefined");
        }
        // set up our event listeners
        jswrap_object_addEventListener(source, "close", jswrap_pipe_src_close_listener, JSWAT_VOID | (JSWAT_JSVAR << (JSWAT_BITS*1)));
        jswrap_object_addEventListener(dest, "drain", jswrap_pipe_drain_listener, JSWAT_VOID | (JSWAT_JSVAR << (JSWAT_BITS*1)));
        jswrap_object_addEventListener(dest, "close", jswrap_pipe_dst_close_listener, JSWAT_VOID | (JSWAT_JSVAR << (JSWAT_BITS*1)));
        // set up the rest of the pipe
        jsvUnLock(jsvObjectSetChild(pipe, "chunkSize", jsvNewFromInteger(chunkSize)));
        jsvUnLock(jsvObjectSetChild(pipe, "end", jsvNewFromBool(callEnd)));
        jsvUnLock(jsvAddNamedChild(pipe, position, "position"));
        jsvUnLock(jsvAddNamedChild(pipe, source, "source"));
        jsvUnLock(jsvAddNamedChild(pipe, dest, "destination"));
        // add the pipe to our list
        jsvArrayPush(arr, pipe);
      } else {
        jsExceptionHere(JSET_ERROR, "Destination object does not implement the required write(buffer, length, position) method.");
      }
    } else {
      jsExceptionHere(JSET_ERROR, "Source object does not implement the required read(buffer, length, position) method.");
    }
    jsvUnLock(readFunc);
    jsvUnLock(writeFunc);
  }
  jsvUnLock(arr);
  jsvUnLock(pipe);
  jsvUnLock(position);
}
Exemplo n.º 5
0
static NO_INLINE int i2c_get_address(JsVar *address, bool *sendStop) {
  *sendStop = true;
  if (jsvIsObject(address)) {
    JsVar *stopVar = jsvObjectGetChild(address, "stop", 0);
    if (stopVar) *sendStop = jsvGetBoolAndUnLock(stopVar);
    return jsvGetIntegerAndUnLock(jsvObjectGetChild(address, "address", 0));
  } else
    return jsvGetInteger(address);
}
Exemplo n.º 6
0
/*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
}
Exemplo n.º 7
0
/*JSON{ "type":"method", "class": "Waveform", "name" : "stop", "ifndef" : "SAVE_ON_FLASH",
         "description" : "Stop a waveform that is currently outputting",
         "generate" : "jswrap_waveform_stop"
}*/
void jswrap_waveform_stop(JsVar *waveform) {
  bool running = jsvGetBoolAndUnLock(jsvObjectGetChild(waveform, "running", 0));
  if (!running) {
    jsExceptionHere(JSET_ERROR, "Waveform is not running");
    return;
  }
  JsVar *buffer = jswrap_waveform_getBuffer(waveform,0,0);
  if (!jstStopBufferTimerTask(buffer)) {
    jsExceptionHere(JSET_ERROR, "Waveform couldn't be stopped");
  }
  jsvUnLock(buffer);
  // now run idle loop as this will issue the finish event and will clean up
  jswrap_waveform_idle();
}
Exemplo n.º 8
0
static bool handlePipe(JsVar *arr, JsvObjectIterator *it, JsVar* pipe) {
  bool paused = jsvGetBoolAndUnLock(jsvObjectGetChild(pipe,"drainWait",0));
  if (paused) return false;

  JsVar *position = jsvObjectGetChild(pipe,"position",0);
  JsVar *chunkSize = jsvObjectGetChild(pipe,"chunkSize",0);
  JsVar *source = jsvObjectGetChild(pipe,"source",0);
  JsVar *destination = jsvObjectGetChild(pipe,"destination",0);

  bool dataTransferred = false;
  if(source && destination && chunkSize && position) {
    JsVar *readFunc = jspGetNamedField(source, "read", false);
    JsVar *writeFunc = jspGetNamedField(destination, "write", false);
    if (jsvIsFunction(readFunc) && jsvIsFunction(writeFunc)) { // do the objects have the necessary methods on them?
      JsVar *buffer = jspExecuteFunction(readFunc, source, 1, &chunkSize);
      if(buffer) {
        JsVarInt bufferSize = jsvGetLength(buffer);
        if (bufferSize>0) {
          JsVar *response = jspExecuteFunction(writeFunc, destination, 1, &buffer);
          if (jsvIsBoolean(response) && jsvGetBool(response)==false) {
            // If boolean false was returned, wait for drain event (http://nodejs.org/api/stream.html#stream_writable_write_chunk_encoding_callback)
            jsvUnLock(jsvObjectSetChild(pipe,"drainWait",jsvNewFromBool(true)));
          }
          jsvUnLock(response);
          jsvSetInteger(position, jsvGetInteger(position) + bufferSize);
        }
        jsvUnLock(buffer);
        dataTransferred = true; // so we don't close the pipe if we get an empty string
      }
    } else {
      if(!jsvIsFunction(readFunc))
        jsExceptionHere(JSET_ERROR, "Source Stream does not implement the required read(length) method.");
      if(!jsvIsFunction(writeFunc))
        jsExceptionHere(JSET_ERROR, "Destination Stream does not implement the required write(buffer) method.");
    }
    jsvUnLock(readFunc);
    jsvUnLock(writeFunc);
  }

  if(!dataTransferred) { // when no more chunks are possible, execute the callback
    handlePipeClose(arr, it, pipe);
  }
  jsvUnLock(source);
  jsvUnLock(destination);
  jsvUnLock(chunkSize);
  jsvUnLock(position);
  return dataTransferred;
}
Exemplo n.º 9
0
static void handlePipeClose(JsVar *arr, JsvObjectIterator *it, JsVar* pipe) {
  jsiQueueObjectCallbacks(pipe, "#oncomplete", &pipe, 1);
  // also call 'end' if 'end' was passed as an initialisation option
  if (jsvGetBoolAndUnLock(jsvObjectGetChild(pipe,"end",0))) {
    // call destination.end if available
    JsVar *destination = jsvObjectGetChild(pipe,"destination",0);
    if (destination) {
      // remove our drain and close listeners.
      // TODO: This removes ALL listeners. Maybe we should just remove ours?
      jswrap_object_removeAllListeners_cstr(destination, "drain");
      jswrap_object_removeAllListeners_cstr(destination, "close");
      // execute the 'end' function
      JsVar *endFunc = jspGetNamedField(destination, "end", false);
      if (endFunc) {
        jsvUnLock(jspExecuteFunction(endFunc, destination, 0, 0));
        jsvUnLock(endFunc);
      }
      // execute the 'close' function
      JsVar *closeFunc = jspGetNamedField(destination, "close", false);
      if (closeFunc) {
        jsvUnLock(jspExecuteFunction(closeFunc, destination, 0, 0));
        jsvUnLock(closeFunc);
      }
      jsvUnLock(destination);
    }
    /* call source.close if available - probably not what node does
    but seems very sensible in this case. If you don't want it,
    set end:false */
    JsVar *source = jsvObjectGetChild(pipe,"source",0);
    if (source) {
      // TODO: This removes ALL listeners. Maybe we should just remove ours?
      jswrap_object_removeAllListeners_cstr(source, "close");
      // execute the 'close' function
      JsVar *closeFunc = jspGetNamedField(source, "close", false);
      if (closeFunc) {
        jsvUnLock(jspExecuteFunction(closeFunc, source, 0, 0));
        jsvUnLock(closeFunc);
      }
    }
    jsvUnLock(source);
  }
  JsVar *idx = jsvObjectIteratorGetKey(it);
  jsvRemoveChild(arr,idx);
  jsvUnLock(idx);
}
Exemplo n.º 10
0
/*JSON{ "type":"constructor", "class": "Waveform",  "name": "Waveform", "ifndef" : "SAVE_ON_FLASH",
         "description" : [ "Create a waveform class. This allows high speed input and output of waveforms. It has an internal variable called `buffer` (as well as `buffer2` when double-buffered - see `options` below) which contains the data to input/output.",
                           "When double-buffered, a 'buffer' event will be emitted each time a buffer is finished with (the argument is that buffer). When the recording stops, a 'finish' event will be emitted (with the first argument as the buffer)." ],
         "generate" : "jswrap_waveform_constructor",
         "params" : [ [ "samples", "int32", "The number of samples" ],
                      [ "options", "JsVar", "Optional options struct `{doubleBuffer:bool, bits : 8/16}` where: `doubleBuffer` is whether to allocate two buffers or not (default false), and bits is the amount of bits to use (default 8)." ] ],
         "return" : [ "JsVar", "An Waveform object" ]

}*/
JsVar *jswrap_waveform_constructor(int samples, JsVar *options) {
  if (samples<=0) {
    jsExceptionHere(JSET_ERROR, "Samples must be greater than 0");
    return 0;
  }

  bool doubleBuffer = false;
  bool use16bit = false;
  if (jsvIsObject(options)) {
    doubleBuffer = jsvGetBoolAndUnLock(jsvObjectGetChild(options, "doubleBuffer", 0));

    int bits = (int)jsvGetIntegerAndUnLock(jsvObjectGetChild(options, "bits", 0));
    if (bits!=0 && bits!=8 && bits!=16) {
      jsExceptionHere(JSET_ERROR, "Invalid number of bits");
      return 0;
    } else if (bits==16) use16bit = true;

  } else if (!jsvIsUndefined(options)) {
    jsExceptionHere(JSET_ERROR, "Expecting options to be undefined or an Object, not %t", options);
  }

  JsVar *arrayLength = jsvNewFromInteger(samples);
  JsVarDataArrayBufferViewType bufferType = use16bit ? ARRAYBUFFERVIEW_UINT16 : ARRAYBUFFERVIEW_UINT8;
  JsVar *arrayBuffer = jswrap_typedarray_constructor(bufferType, arrayLength, 0, 0);
  JsVar *arrayBuffer2 = 0;
  if (doubleBuffer) arrayBuffer2 = jswrap_typedarray_constructor(bufferType, arrayLength, 0, 0);
  jsvUnLock(arrayLength);
  JsVar *waveform = jspNewObject(0, "Waveform");


  if (!waveform || !arrayBuffer || (doubleBuffer && !arrayBuffer2)) {
    jsvUnLock(waveform);
    jsvUnLock(arrayBuffer); // out of memory
    jsvUnLock(arrayBuffer2);
    return 0;
  }
  jsvUnLock(jsvObjectSetChild(waveform, "buffer", arrayBuffer));
  if (arrayBuffer2) jsvUnLock(jsvObjectSetChild(waveform, "buffer2", arrayBuffer2));

  return waveform;
}
Exemplo n.º 11
0
// 'end' this connection
void clientRequestEnd(JsNetwork *net, JsVar *httpClientReqVar) {
    SocketType socketType = socketGetType(httpClientReqVar);
    if ((socketType&ST_TYPE_MASK) == ST_HTTP) {
        JsVar *finalData = 0;
        if (jsvGetBoolAndUnLock(jsvObjectGetChild(httpClientReqVar, HTTP_NAME_CHUNKED, 0))) {
            // If we were asked to send 'chunked' data, we need to finish up
            finalData = jsvNewFromString("");
        }
        // on HTTP, this actually means we connect
        // force sendData to be made
        clientRequestWrite(net, httpClientReqVar, finalData);
        jsvUnLock(finalData);
    } else {
        // on normal sockets, we actually request close after all data sent
        jsvObjectSetChildAndUnLock(httpClientReqVar, HTTP_NAME_CLOSE, jsvNewFromBool(true));
        // if we never sent any data, make sure we close 'now'
        JsVar *sendData = jsvObjectGetChild(httpClientReqVar, HTTP_NAME_SEND_DATA, 0);
        if (!sendData || jsvIsEmptyString(sendData))
            jsvObjectSetChildAndUnLock(httpClientReqVar, HTTP_NAME_CLOSENOW, jsvNewFromBool(true));
        jsvUnLock(sendData);
    }
}
Exemplo n.º 12
0
/*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);
  }
}
Exemplo n.º 13
0
/*JSON{
  "type" : "method",
  "class" : "WLAN",
  "name" : "connect",
  "generate" : "jswrap_wlan_connect",
  "params" : [
    ["ap","JsVar","Access point name"],
    ["key","JsVar","WPA2 key (or undefined for unsecured connection)"],
    ["callback","JsVar","Function to call back with connection status. It has one argument which is one of 'connect'/'disconnect'/'dhcp'"]
  ],
  "return" : ["bool","True if connection succeeded, false if it didn't."]
}
Connect to a wireless network
*/
bool jswrap_wlan_connect(JsVar *wlanObj, JsVar *vAP, JsVar *vKey, JsVar *callback) {
  if (!(jsvIsUndefined(callback) || jsvIsFunction(callback))) {
    jsError("Expecting callback Function but got %t", callback);
    return 0;
  }

  JsNetwork net;
  if (!networkGetFromVar(&net)) return false;

  // if previously completely disconnected, try and reconnect
  if (jsvGetBoolAndUnLock(jsvObjectGetChild(wlanObj,JS_HIDDEN_CHAR_STR"DIS",0))) {
    cc3000_initialise(wlanObj);
    jsvObjectSetChildAndUnLock(wlanObj,JS_HIDDEN_CHAR_STR"DIS", jsvNewFromBool(false));
  }

  if (jsvIsFunction(callback)) {
    jsvObjectSetChild(wlanObj, CC3000_ON_STATE_CHANGE, callback);
  }

  jsvObjectSetChild(wlanObj,JS_HIDDEN_CHAR_STR"AP", vAP); // no unlock intended
  jsvObjectSetChild(wlanObj,JS_HIDDEN_CHAR_STR"KEY", vKey); // no unlock intended

  char ap[32];
  char key[32];
  unsigned long security = WLAN_SEC_UNSEC;
  jsvGetString(vAP, ap, sizeof(ap));
  if (jsvIsString(vKey)) {
    security = WLAN_SEC_WPA2;
    jsvGetString(vKey, key, sizeof(key));
  }
  // might want to set wlan_ioctl_set_connection_policy
  bool connected =  wlan_connect(security, ap, (long)strlen(ap), NULL, (unsigned char*)key, (long)strlen(key))==0;

  networkFree(&net);
  // note that we're only online (for networkState) when DHCP succeeds
  return connected;
}
Exemplo n.º 14
0
/*JSON{
    "type" : "staticmethod",
    "class" : "NRF",
    "name" : "setServices",
    "generate" : "jswrap_nrf_bluetooth_setServices",
    "params" : [
      ["data","JsVar","The service (and characteristics) to advertise"]
    ]
}
BETA: This only partially works at the moment

Change the services and characteristics Espruino advertises.

```
NRF.setServices({
  0xBCDE : {
    0xABCD : {
      value : "Hello", // optional
      maxLen : 5, // optional (otherwise is length of initial value)
      broadcast : false, // optional, default is false
      readable : true,   // optional, default is false
      writable : true,   // optional, default is false
      onWrite : function(evt) { // optional
        console.log("Got ", evt.data);
      }
    }
    // more characteristics allowed
  }
  // more services allowed
});
```
*/
void jswrap_nrf_bluetooth_setServices(JsVar *data) {
  uint32_t err_code;

  // TODO: Reset services

  if (jsvIsObject(data)) {
    JsvObjectIterator it;
    jsvObjectIteratorNew(&it, data);
    while (jsvObjectIteratorHasValue(&it)) {
      ble_uuid_t ble_uuid;
      uint16_t service_handle;

      // Add the service
      BLE_UUID_BLE_ASSIGN(ble_uuid, jsvGetIntegerAndUnLock(jsvObjectIteratorGetKey(&it)));
      err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY,
                                              &ble_uuid,
                                              &service_handle);
      if (err_code) {
        jsExceptionHere(JSET_ERROR, "Got BLE error code %d in gatts_service_add", err_code);
        break;
      }
      // sd_ble_gatts_include_add ?

      // Now add characteristics
      JsVar *serviceVar = jsvObjectIteratorGetValue(&it);
      JsvObjectIterator serviceit;
      jsvObjectIteratorNew(&serviceit, serviceVar);
      while (jsvObjectIteratorHasValue(&serviceit)) {
        ble_uuid_t          char_uuid;
        ble_gatts_char_md_t char_md;
        ble_gatts_attr_t    attr_char_value;
        ble_gatts_attr_md_t attr_md;
        ble_gatts_char_handles_t  characteristic_handles;

        BLE_UUID_BLE_ASSIGN(char_uuid, jsvGetIntegerAndUnLock(jsvObjectIteratorGetKey(&serviceit)));
        JsVar *charVar = jsvObjectIteratorGetValue(&serviceit);

        memset(&char_md, 0, sizeof(char_md));
        if (jsvGetBoolAndUnLock(jsvObjectGetChild(charVar, "broadcast", 0)))
          char_md.char_props.broadcast = 1;
        if (jsvGetBoolAndUnLock(jsvObjectGetChild(charVar, "readable", 0)))
          char_md.char_props.read = 1;
        if (jsvGetBoolAndUnLock(jsvObjectGetChild(charVar, "writable", 0))) {
          char_md.char_props.write = 1;
          char_md.char_props.write_wo_resp = 1;
        }
        char_md.p_char_user_desc         = NULL;
        char_md.p_char_pf                = NULL;
        char_md.p_user_desc_md           = NULL;
        char_md.p_cccd_md                = NULL;
        char_md.p_sccd_md                = NULL;

        memset(&attr_md, 0, sizeof(attr_md));
        BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm);
        BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm);
        attr_md.vloc       = BLE_GATTS_VLOC_STACK;
        attr_md.rd_auth    = 0;
        attr_md.wr_auth    = 0;
        attr_md.vlen       = 1; // TODO: variable length?

        memset(&attr_char_value, 0, sizeof(attr_char_value));
        attr_char_value.p_uuid       = &char_uuid;
        attr_char_value.p_attr_md    = &attr_md;
        attr_char_value.init_len     = 0;
        attr_char_value.init_offs    = 0;
        attr_char_value.p_value      = 0;
        attr_char_value.max_len      = (uint16_t)jsvGetIntegerAndUnLock(jsvObjectGetChild(charVar, "maxLen", 0));
        if (attr_char_value.max_len==0) attr_char_value.max_len=1;

        // get initial data
        JsVar *charValue = jsvObjectGetChild(charVar, "value", 0);
        if (charValue) {
          JSV_GET_AS_CHAR_ARRAY(vPtr, vLen, charValue);
          if (vPtr && vLen) {
            attr_char_value.p_value = (uint8_t*)vPtr;
            attr_char_value.init_len = vLen;
            if (attr_char_value.init_len > attr_char_value.max_len)
              attr_char_value.max_len = attr_char_value.init_len;
          }
        }

        err_code = sd_ble_gatts_characteristic_add(service_handle,
                                                   &char_md,
                                                   &attr_char_value,
                                                   &characteristic_handles);

        jsvUnLock(charValue); // unlock here in case we were storing data in a flat string
        if (err_code) {
          jsExceptionHere(JSET_ERROR, "Got BLE error code %d in gatts_characteristic_add", err_code);
          break;
        }

        // Add Write callback
        JsVar *writeCb = jsvObjectGetChild(charVar, "onWrite", 0);
        if (writeCb) {
          char eventName[12];
          ble_handle_to_write_event_name(eventName, characteristic_handles.value_handle);
          jsvObjectSetChildAndUnLock(execInfo.root, eventName, writeCb);
        }

        jsvUnLock(charVar);
        /* We'd update the characteristic with:

    memset(&hvx_params, 0, sizeof(hvx_params));
    hvx_params.handle = characteristic_handle.value_handle;
    hvx_params.p_data = p_string;
    hvx_params.p_len  = &length;
    hvx_params.type   = BLE_GATT_HVX_NOTIFICATION;
    return sd_ble_gatts_hvx(p_nus->conn_handle, &hvx_params);

    Maybe we could find the handle out based on characteristic UUID, rather than having
    to store it?

    */

        jsvObjectIteratorNext(&serviceit);
      }
      jsvObjectIteratorFree(&serviceit);
      jsvUnLock(serviceVar);

      jsvObjectIteratorNext(&it);
    }
    jsvObjectIteratorFree(&it);



    } else if (!jsvIsUndefined(data)) {
      jsExceptionHere(JSET_TYPEERROR, "Expecting object or undefined, got %t", data);
    }
}
Exemplo n.º 15
0
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);
}
Exemplo n.º 16
0
bool socketServerConnectionsIdle(JsNetwork *net) {
    char buf[64];

    JsVar *arr = socketGetArray(HTTP_ARRAY_HTTP_SERVER_CONNECTIONS,false);
    if (!arr) return false;

    bool hadSockets = false;
    JsvObjectIterator it;
    jsvObjectIteratorNew(&it, arr);
    while (jsvObjectIteratorHasValue(&it)) {
        hadSockets = true;
        // Get connection, socket, and socket type
        // For normal sockets, socket==connection, but for HTTP we split it into a request and a response
        JsVar *connection = jsvObjectIteratorGetValue(&it);
        SocketType socketType = socketGetType(connection);
        JsVar *socket = (socketType==ST_HTTP) ? jsvObjectGetChild(connection,HTTP_NAME_RESPONSE_VAR,0) : jsvLockAgain(connection);

        int sckt = (int)jsvGetIntegerAndUnLock(jsvObjectGetChild(connection,HTTP_NAME_SOCKET,0))-1; // so -1 if undefined
        bool closeConnectionNow = jsvGetBoolAndUnLock(jsvObjectGetChild(connection, HTTP_NAME_CLOSENOW, false));

        if (!closeConnectionNow) {
            int num = net->recv(net, sckt, buf,sizeof(buf));
            if (num<0) {
                // we probably disconnected so just get rid of this
                closeConnectionNow = true;
            } else {
                // add it to our request string
                if (num>0) {
                    JsVar *receiveData = jsvObjectGetChild(connection,HTTP_NAME_RECEIVE_DATA,0);
                    JsVar *oldReceiveData = receiveData;
                    if (!receiveData) receiveData = jsvNewFromEmptyString();
                    if (receiveData) {
                        jsvAppendStringBuf(receiveData, buf, (size_t)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 *server = jsvObjectGetChild(connection,HTTP_NAME_SERVER_VAR,0);
                            JsVar *args[2] = { connection, socket };
                            jsiQueueObjectCallbacks(server, HTTP_NAME_ON_CONNECT, args, (socketType==ST_HTTP) ? 2 : 1);
                            jsvUnLock(server);
                        }
                        if (hadHeaders && !jsvIsEmptyString(receiveData)) {
                            // execute 'data' callback or save data
                            jswrap_stream_pushData(connection, receiveData);
                            // clear received data
                            jsvUnLock(receiveData);
                            receiveData = 0;
                        }
                        // if received data changed, update it
                        if (receiveData != oldReceiveData)
                            jsvObjectSetChild(connection,HTTP_NAME_RECEIVE_DATA,receiveData);
                        jsvUnLock(receiveData);
                    }
                }
            }

            // send data if possible
            JsVar *sendData = jsvObjectGetChild(socket,HTTP_NAME_SEND_DATA,0);
            if (sendData) {
                if (!socketSendData(net, socket, sckt, &sendData))
                    closeConnectionNow = true;
                jsvObjectSetChild(socket, HTTP_NAME_SEND_DATA, sendData); // socketSendData prob updated sendData
            }
            // only close if we want to close, have no data to send, and aren't receiving data
            if (jsvGetBoolAndUnLock(jsvObjectGetChild(socket,HTTP_NAME_CLOSE,0)) && !sendData && num<=0)
                closeConnectionNow = true;
            jsvUnLock(sendData);
        }
        if (closeConnectionNow) {
            // send out any data that we were POSTed
            JsVar *receiveData = jsvObjectGetChild(connection,HTTP_NAME_RECEIVE_DATA,0);
            bool hadHeaders = jsvGetBoolAndUnLock(jsvObjectGetChild(connection,HTTP_NAME_HAD_HEADERS,0));
            if (hadHeaders && !jsvIsEmptyString(receiveData)) {
                // execute 'data' callback or save data
                jswrap_stream_pushData(connection, receiveData);
            }
            jsvUnLock(receiveData);
            // fire the close listeners
            jsiQueueObjectCallbacks(connection, HTTP_NAME_ON_CLOSE, 0, 0);
            jsiQueueObjectCallbacks(socket, HTTP_NAME_ON_CLOSE, 0, 0);

            _socketConnectionKill(net, connection);
            JsVar *connectionName = jsvObjectIteratorGetKey(&it);
            jsvObjectIteratorNext(&it);
            jsvRemoveChild(arr, connectionName);
            jsvUnLock(connectionName);
        } else
            jsvObjectIteratorNext(&it);
        jsvUnLock(connection);
        jsvUnLock(socket);
    }
    jsvObjectIteratorFree(&it);
    jsvUnLock(arr);

    return hadSockets;
}
Exemplo n.º 17
0
bool socketClientConnectionsIdle(JsNetwork *net) {
    char buf[64];

    JsVar *arr = socketGetArray(HTTP_ARRAY_HTTP_CLIENT_CONNECTIONS,false);
    if (!arr) return false;

    bool hadSockets = false;
    JsvObjectIterator it;
    jsvObjectIteratorNew(&it, arr);
    while (jsvObjectIteratorHasValue(&it)) {
        hadSockets = true;
        // Get connection, socket, and socket type
        // For normal sockets, socket==connection, but for HTTP we split it into a request and a response
        JsVar *connection = jsvObjectIteratorGetValue(&it);
        SocketType socketType = socketGetType(connection);
        JsVar *socket = (socketType==ST_HTTP) ? jsvObjectGetChild(connection,HTTP_NAME_RESPONSE_VAR,0) : jsvLockAgain(connection);

        bool closeConnectionNow = jsvGetBoolAndUnLock(jsvObjectGetChild(connection, HTTP_NAME_CLOSENOW, false));
        int sckt = (int)jsvGetIntegerAndUnLock(jsvObjectGetChild(connection,HTTP_NAME_SOCKET,0))-1; // so -1 if undefined
        if (sckt<0) closeConnectionNow = true;
        bool hadHeaders = true;
        if (socketType==ST_HTTP)
            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)
            socketClientPushReceiveData(connection, socket, &receiveData);

        if (!closeConnectionNow) {
            JsVar *sendData = jsvObjectGetChild(connection,HTTP_NAME_SEND_DATA,0);
            // send data if possible
            if (sendData) {
                bool b = socketSendData(net, connection, sckt, &sendData);
                if (!b)
                    closeConnectionNow = true;
                jsvObjectSetChild(connection, HTTP_NAME_SEND_DATA, sendData); // _http_send prob updated sendData
            } else {
                if (jsvGetBoolAndUnLock(jsvObjectGetChild(connection, HTTP_NAME_CLOSE, false)))
                    closeConnectionNow = true;
            }
            // Now read data if possible
            int num = net->recv(net, sckt, buf, sizeof(buf));
            if (num<0) {
                // we probably disconnected so just get rid of this
                closeConnectionNow = true;
            } else {
                // 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, (size_t)num);
                        if (socketType==ST_HTTP && !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, 1);
                            }
                            jsvUnLock(resVar);
                            jsvObjectSetChild(connection, HTTP_NAME_RECEIVE_DATA, receiveData);
                        }
                    }
                }
            }
            jsvUnLock(sendData);
        }

        if (closeConnectionNow) {
            socketClientPushReceiveData(connection, socket, &receiveData);
            if (socketType != ST_HTTP)
                jsiQueueObjectCallbacks(socket, HTTP_NAME_ON_END, 0, 0);
            jsiQueueObjectCallbacks(socket, HTTP_NAME_ON_CLOSE, 0, 0);

            _socketConnectionKill(net, connection);
            JsVar *connectionName = jsvObjectIteratorGetKey(&it);
            jsvObjectIteratorNext(&it);
            jsvRemoveChild(arr, connectionName);
            jsvUnLock(connectionName);
        } else {
            jsvObjectIteratorNext(&it);
        }

        jsvUnLock(receiveData);
        jsvUnLock(connection);
        jsvUnLock(socket);
    }
    jsvUnLock(arr);

    return hadSockets;
}
Exemplo n.º 18
0
static void handlePipeClose(JsVar *arr, JsvObjectIterator *it, JsVar* pipe) {
  jsiQueueObjectCallbacks(pipe, "#oncomplete", &pipe, 1);
  // Check the source to see if there was more data... It may not be a stream,
  // but if it is and it has data it should have a a STREAM_BUFFER_NAME field
  JsVar *source = jsvObjectGetChild(pipe,"source",0);
  JsVar *destination = jsvObjectGetChild(pipe,"destination",0);
  if (source && destination) {
    JsVar *buffer = jsvObjectGetChild(source, STREAM_BUFFER_NAME, 0);
    if (buffer && jsvGetStringLength(buffer)) {
      jsvObjectSetChild(source, STREAM_BUFFER_NAME, 0); // remove outstanding data
      /* call write fn - we ignore drain/etc here because the source has
      just closed and we want to get this sorted quickly */
      JsVar *writeFunc = jspGetNamedField(destination, "write", false);
      if (jsvIsFunction(writeFunc)) // do the objects have the necessary methods on them?
        jsvUnLock(jspExecuteFunction(writeFunc, destination, 1, &buffer));
      jsvUnLock(writeFunc);
      // update position
      JsVar *position = jsvObjectGetChild(pipe,"position",0);
      jsvSetInteger(position, jsvGetInteger(position) + (JsVarInt)jsvGetStringLength(buffer));
      jsvUnLock(position);
    }
    jsvUnLock(buffer);
  }
  // also call 'end' if 'end' was passed as an initialisation option
  if (jsvGetBoolAndUnLock(jsvObjectGetChild(pipe,"end",0))) {
    // call destination.end if available
    if (destination) {
      // remove our drain and close listeners.
      // TODO: This removes ALL listeners. Maybe we should just remove ours?
      jswrap_object_removeAllListeners_cstr(destination, "drain");
      jswrap_object_removeAllListeners_cstr(destination, "close");
      // execute the 'end' function
      JsVar *endFunc = jspGetNamedField(destination, "end", false);
      if (endFunc) {
        jsvUnLock(jspExecuteFunction(endFunc, destination, 0, 0));
        jsvUnLock(endFunc);
      }
      // execute the 'close' function
      JsVar *closeFunc = jspGetNamedField(destination, "close", false);
      if (closeFunc) {
        jsvUnLock(jspExecuteFunction(closeFunc, destination, 0, 0));
        jsvUnLock(closeFunc);
      }
    }
    /* call source.close if available - probably not what node does
    but seems very sensible in this case. If you don't want it,
    set end:false */
    if (source) {
      // TODO: This removes ALL listeners. Maybe we should just remove ours?
      jswrap_object_removeAllListeners_cstr(source, "close");
      // execute the 'close' function
      JsVar *closeFunc = jspGetNamedField(source, "close", false);
      if (closeFunc) {
        jsvUnLock(jspExecuteFunction(closeFunc, source, 0, 0));
        jsvUnLock(closeFunc);
      }
    }
  }
  jsvUnLock(source);
  jsvUnLock(destination);
  JsVar *idx = jsvObjectIteratorGetKey(it);
  jsvRemoveChild(arr,idx);
  jsvUnLock(idx);
}
Exemplo n.º 19
0
bool socketServerConnectionsIdle(JsNetwork *net) {
    char *buf = alloca(net->chunkSize); // allocate on stack

    JsVar *arr = socketGetArray(HTTP_ARRAY_HTTP_SERVER_CONNECTIONS,false);
    if (!arr) return false;

    bool hadSockets = false;
    JsvObjectIterator it;
    jsvObjectIteratorNew(&it, arr);
    while (jsvObjectIteratorHasValue(&it)) {
        hadSockets = true;
        // Get connection, socket, and socket type
        // For normal sockets, socket==connection, but for HTTP we split it into a request and a response
        JsVar *connection = jsvObjectIteratorGetValue(&it);
        SocketType socketType = socketGetType(connection);
        JsVar *socket = ((socketType&ST_TYPE_MASK)==ST_HTTP) ? jsvObjectGetChild(connection,HTTP_NAME_RESPONSE_VAR,0) : jsvLockAgain(connection);

        int sckt = (int)jsvGetIntegerAndUnLock(jsvObjectGetChild(connection,HTTP_NAME_SOCKET,0))-1; // so -1 if undefined
        bool closeConnectionNow = jsvGetBoolAndUnLock(jsvObjectGetChild(connection, HTTP_NAME_CLOSENOW, false));
        int error = 0;

        if (!closeConnectionNow) {
            int num = netRecv(net, sckt, buf, net->chunkSize);
            if (num<0) {
                // we probably disconnected so just get rid of this
                closeConnectionNow = true;
                error = num;
            } else {
                // add it to our request string
                if (num>0) {
                    JsVar *receiveData = jsvObjectGetChild(connection,HTTP_NAME_RECEIVE_DATA,0);
                    JsVar *oldReceiveData = receiveData;
                    if (!receiveData) receiveData = jsvNewFromEmptyString();
                    if (receiveData) {
                        jsvAppendStringBuf(receiveData, buf, (size_t)num);
                        bool hadHeaders = jsvGetBoolAndUnLock(jsvObjectGetChild(connection,HTTP_NAME_HAD_HEADERS,0));
                        if (!hadHeaders && httpParseHeaders(&receiveData, connection, true)) {
                            hadHeaders = true;
                            jsvObjectSetChildAndUnLock(connection, HTTP_NAME_HAD_HEADERS, jsvNewFromBool(hadHeaders));
                            JsVar *server = jsvObjectGetChild(connection,HTTP_NAME_SERVER_VAR,0);
                            JsVar *args[2] = { connection, socket };
                            jsiQueueObjectCallbacks(server, HTTP_NAME_ON_CONNECT, args, ((socketType&ST_TYPE_MASK)==ST_HTTP) ? 2 : 1);
                            jsvUnLock(server);
                        }
                        if (hadHeaders && !jsvIsEmptyString(receiveData)) {
                            // Keep track of how much we received (so we can close once we have it)
                            if ((socketType&ST_TYPE_MASK)==ST_HTTP) {
                                jsvObjectSetChildAndUnLock(connection, HTTP_NAME_RECEIVE_COUNT,
                                                           jsvNewFromInteger(
                                                               jsvGetIntegerAndUnLock(jsvObjectGetChild(connection, HTTP_NAME_RECEIVE_COUNT, JSV_INTEGER)) +
                                                               jsvGetStringLength(receiveData)
                                                           ));
                            }
                            // execute 'data' callback or save data
                            if (jswrap_stream_pushData(connection, receiveData, false)) {
                                // clear received data
                                jsvUnLock(receiveData);
                                receiveData = 0;
                            }
                        }
                        // if received data changed, update it
                        if (receiveData != oldReceiveData)
                            jsvObjectSetChild(connection,HTTP_NAME_RECEIVE_DATA,receiveData);
                        jsvUnLock(receiveData);
                    }
                }
            }

            // send data if possible
            JsVar *sendData = jsvObjectGetChild(socket,HTTP_NAME_SEND_DATA,0);
            if (sendData && !jsvIsEmptyString(sendData)) {
                int sent = socketSendData(net, socket, sckt, &sendData);
                // FIXME? checking for errors is a bit iffy. With the esp8266 network that returns
                // varied error codes we'd want to skip SOCKET_ERR_CLOSED and let the recv side deal
                // with normal closing so we don't miss the tail of what's received, but other drivers
                // return -1 (which is the same value) for all errors. So we rely on the check ~12 lines
                // down if(num>0)closeConnectionNow=false instead.
                if (sent < 0) {
                    closeConnectionNow = true;
                    error = sent;
                }
                jsvObjectSetChild(socket, HTTP_NAME_SEND_DATA, sendData); // socketSendData prob updated sendData
            }
            // only close if we want to close, have no data to send, and aren't receiving data
            bool wantClose = jsvGetBoolAndUnLock(jsvObjectGetChild(socket,HTTP_NAME_CLOSE,0));
            if (wantClose && (!sendData || jsvIsEmptyString(sendData)) && num<=0) {
                bool reallyCloseNow = true;
                if ((socketType&ST_TYPE_MASK)==ST_HTTP) {
                    // Check if we had a Content-Length header - if so, we need to wait until we have received that amount
                    JsVar *headers = jsvObjectGetChild(connection,"headers",0);
                    if (headers) {
                        JsVarInt contentLength = jsvGetIntegerAndUnLock(jsvObjectGetChild(headers,"Content-Length",0));
                        JsVarInt contentReceived = jsvGetIntegerAndUnLock(jsvObjectGetChild(connection, HTTP_NAME_RECEIVE_COUNT, 0));
                        if (contentLength > contentReceived) {
                            reallyCloseNow = false;
                        }
                        jsvUnLock(headers);
                    }
                }
                closeConnectionNow = reallyCloseNow;
            } else if (num > 0)
                closeConnectionNow = false; // guarantee that anything received is processed
            jsvUnLock(sendData);
        }
        if (closeConnectionNow) {
            // send out any data that we were POSTed
            JsVar *receiveData = jsvObjectGetChild(connection,HTTP_NAME_RECEIVE_DATA,0);
            bool hadHeaders = jsvGetBoolAndUnLock(jsvObjectGetChild(connection,HTTP_NAME_HAD_HEADERS,0));
            if (hadHeaders && !jsvIsEmptyString(receiveData)) {
                // execute 'data' callback or save data
                jswrap_stream_pushData(connection, receiveData, true);
            }
            jsvUnLock(receiveData);

            // fire error events
            bool hadError = fireErrorEvent(error, connection, socket);

            // fire the close listeners
            JsVar *params[1] = { jsvNewFromBool(hadError) };
            jsiQueueObjectCallbacks(connection, HTTP_NAME_ON_CLOSE, params, 1);
            jsiQueueObjectCallbacks(socket, HTTP_NAME_ON_CLOSE, params, 1);
            jsvUnLock(params[0]);

            _socketConnectionKill(net, connection);
            JsVar *connectionName = jsvObjectIteratorGetKey(&it);
            jsvObjectIteratorNext(&it);
            jsvRemoveChild(arr, connectionName);
            jsvUnLock(connectionName);
        } else
            jsvObjectIteratorNext(&it);
        jsvUnLock2(connection, socket);
    }
    jsvObjectIteratorFree(&it);
    jsvUnLock(arr);

    return hadSockets;
}
Exemplo n.º 20
0
bool socketClientConnectionsIdle(JsNetwork *net) {
    char *buf = alloca(net->chunkSize); // allocate on stack

    JsVar *arr = socketGetArray(HTTP_ARRAY_HTTP_CLIENT_CONNECTIONS,false);
    if (!arr) return false;

    bool hadSockets = false;
    JsvObjectIterator it;
    jsvObjectIteratorNew(&it, arr);
    while (jsvObjectIteratorHasValue(&it)) {
        hadSockets = true;
        // Get connection, socket, and socket type
        // For normal sockets, socket==connection, but for HTTP connection is httpCRq and socket is httpCRs
        JsVar *connection = jsvObjectIteratorGetValue(&it);
        SocketType socketType = socketGetType(connection);
        JsVar *socket = ((socketType&ST_TYPE_MASK)==ST_HTTP) ? jsvObjectGetChild(connection,HTTP_NAME_RESPONSE_VAR,0) : jsvLockAgain(connection);
        bool socketClosed = false;
        JsVar *receiveData = 0;

        bool hadHeaders = false;
        int error = 0; // error code received from netXxxx functions
        bool isHttp = (socketType&ST_TYPE_MASK) == ST_HTTP;
        bool closeConnectionNow = jsvGetBoolAndUnLock(jsvObjectGetChild(connection, HTTP_NAME_CLOSENOW, false));
        bool alreadyConnected = jsvGetBoolAndUnLock(jsvObjectGetChild(connection, HTTP_NAME_CONNECTED, false));
        int sckt = (int)jsvGetIntegerAndUnLock(jsvObjectGetChild(connection,HTTP_NAME_SOCKET,0))-1; // so -1 if undefined
        if (sckt>=0) {
            if (isHttp)
                hadHeaders = jsvGetBoolAndUnLock(jsvObjectGetChild(connection,HTTP_NAME_HAD_HEADERS,0));
            else
                hadHeaders = true;
            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)
                socketClientPushReceiveData(connection, socket, &receiveData);

            JsVar *sendData = jsvObjectGetChild(connection,HTTP_NAME_SEND_DATA,0);
            if (!closeConnectionNow) {
                // send data if possible
                if (sendData && !jsvIsEmptyString(sendData)) {
                    // don't try to send if we're already in error state
                    int num = 0;
                    if (error == 0) num = socketSendData(net, connection, sckt, &sendData);
                    if (num > 0 && !alreadyConnected && !isHttp) { // whoa, we sent something, must be connected!
                        jsiQueueObjectCallbacks(connection, HTTP_NAME_ON_CONNECT, &connection, 1);
                        jsvObjectSetChildAndUnLock(connection, HTTP_NAME_CONNECTED, jsvNewFromBool(true));
                        alreadyConnected = true;
                    }
                    if (num < 0) {
                        closeConnectionNow = true;
                        error = num;
                    }
                    jsvObjectSetChild(connection, HTTP_NAME_SEND_DATA, sendData); // _http_send prob updated sendData
                } else {
                    // no data to send, do we want to close? do so.
                    if (jsvGetBoolAndUnLock(jsvObjectGetChild(connection, HTTP_NAME_CLOSE, false)))
                        closeConnectionNow = true;
                }
                // Now read data if possible (and we have space for it)
                if (!receiveData || !hadHeaders) {
                    int num = netRecv(net, sckt, buf, net->chunkSize);
                    //if (num != 0) printf("recv returned %d\r\n", num);
                    if (!alreadyConnected && num == SOCKET_ERR_NO_CONN) {
                        ; // ignore... it's just telling us we're not connected yet
                    } else if (num < 0) {
                        closeConnectionNow = true;
                        error = num;
                        // disconnected without headers? error.
                        if (!hadHeaders && error == SOCKET_ERR_CLOSED) error = SOCKET_ERR_NO_RESP;
                    } else {
                        // did we just get connected?
                        if (!alreadyConnected && !isHttp) {
                            jsiQueueObjectCallbacks(connection, HTTP_NAME_ON_CONNECT, &connection, 1);
                            jsvObjectSetChildAndUnLock(connection, HTTP_NAME_CONNECTED, jsvNewFromBool(true));
                            alreadyConnected = true;
                            // if we do not have any data to send, issue a drain event
                            if (!sendData || (int)jsvGetStringLength(sendData) == 0)
                                jsiQueueObjectCallbacks(connection, HTTP_NAME_ON_DRAIN, &connection, 1);
                        }
                        // got data add it to our receive buffer
                        if (num > 0) {
                            if (!receiveData) {
                                receiveData = jsvNewFromEmptyString();
                                jsvObjectSetChild(connection, HTTP_NAME_RECEIVE_DATA, receiveData);
                            }
                            if (receiveData) { // could be out of memory
                                jsvAppendStringBuf(receiveData, buf, (size_t)num);
                                if ((socketType&ST_TYPE_MASK)==ST_HTTP && !hadHeaders) {
                                    // for HTTP see whether we now have full response headers
                                    JsVar *resVar = jsvObjectGetChild(connection,HTTP_NAME_RESPONSE_VAR,0);
                                    if (httpParseHeaders(&receiveData, resVar, false)) {
                                        hadHeaders = true;
                                        jsvObjectSetChildAndUnLock(connection, HTTP_NAME_HAD_HEADERS, jsvNewFromBool(hadHeaders));
                                        jsiQueueObjectCallbacks(connection, HTTP_NAME_ON_CONNECT, &resVar, 1);
                                    }
                                    jsvUnLock(resVar);
                                    jsvObjectSetChild(connection, HTTP_NAME_RECEIVE_DATA, receiveData);
                                }
                            }
                        }
                    }
                }
                jsvUnLock(sendData);
            }
        }

        if (closeConnectionNow) {
            socketClientPushReceiveData(connection, socket, &receiveData);
            if (!receiveData) {
                if ((socketType&ST_TYPE_MASK) != ST_HTTP)
                    jsiQueueObjectCallbacks(socket, HTTP_NAME_ON_END, &socket, 1);

                // If we had data to send but the socket closed, this is an error
                JsVar *sendData = jsvObjectGetChild(connection,HTTP_NAME_SEND_DATA,0);
                if (sendData && jsvGetStringLength(sendData) > 0 && error == SOCKET_ERR_CLOSED)
                    error = SOCKET_ERR_UNSENT_DATA;
                jsvUnLock(sendData);

                _socketConnectionKill(net, connection);
                JsVar *connectionName = jsvObjectIteratorGetKey(&it);
                jsvObjectIteratorNext(&it);
                jsvRemoveChild(arr, connectionName);
                jsvUnLock(connectionName);
                socketClosed = true;

                // fire error event, if there is an error
                bool hadError = fireErrorEvent(error, connection, NULL);

                // close callback must happen after error callback
                JsVar *params[1] = { jsvNewFromBool(hadError) };
                jsiQueueObjectCallbacks(socket, HTTP_NAME_ON_CLOSE, params, 1);
                jsvUnLock(params[0]);
            }
        }


        if (!socketClosed) {
            jsvObjectIteratorNext(&it);
        }

        jsvUnLock3(receiveData, connection, socket);
    }
    jsvUnLock(arr);

    return hadSockets;
}
Exemplo n.º 21
0
void clientRequestWrite(JsNetwork *net, JsVar *httpClientReqVar, JsVar *data) {
    SocketType socketType = socketGetType(httpClientReqVar);
    // Append data to sendData
    JsVar *sendData = jsvObjectGetChild(httpClientReqVar, HTTP_NAME_SEND_DATA, 0);
    if (!sendData) {
        JsVar *options = 0;
        // Only append a header if we're doing HTTP AND we haven't already connected
        if ((socketType&ST_TYPE_MASK) == ST_HTTP)
            if (jsvGetIntegerAndUnLock(jsvObjectGetChild(httpClientReqVar, HTTP_NAME_SOCKET, 0))==0)
                options = jsvObjectGetChild(httpClientReqVar, HTTP_NAME_OPTIONS_VAR, 0);
        if (options) {
            // We're an HTTP client - make a header
            JsVar *method = jsvObjectGetChild(options, "method", 0);
            JsVar *path = jsvObjectGetChild(options, "path", 0);
            sendData = jsvVarPrintf("%v %v HTTP/1.0\r\nUser-Agent: Espruino "JS_VERSION"\r\nConnection: close\r\n", method, path);
            jsvUnLock2(method, path);
            JsVar *headers = jsvObjectGetChild(options, "headers", 0);
            bool hasHostHeader = false;
            if (jsvIsObject(headers)) {
                JsVar *hostHeader = jsvObjectGetChild(headers, "Host", 0);
                hasHostHeader = hostHeader!=0;
                jsvUnLock(hostHeader);
                httpAppendHeaders(sendData, headers);
                // if Transfer-Encoding:chunked was set, subsequent writes need to 'chunk' the data that is sent
                if (jsvIsStringEqualAndUnLock(jsvObjectGetChild(headers, "Transfer-Encoding", 0), "chunked")) {
                    jsvObjectSetChildAndUnLock(httpClientReqVar, HTTP_NAME_CHUNKED, jsvNewFromBool(true));
                }
            }
            jsvUnLock(headers);
            if (!hasHostHeader) {
                JsVar *host = jsvObjectGetChild(options, "host", 0);
                int port = (int)jsvGetIntegerAndUnLock(jsvObjectGetChild(options, "port", 0));
                if (port>0 && port!=80)
                    jsvAppendPrintf(sendData, "Host: %v:%d\r\n", host, port);
                else
                    jsvAppendPrintf(sendData, "Host: %v\r\n", host);
                jsvUnLock(host);
            }
            // finally add ending newline
            jsvAppendString(sendData, "\r\n");
        } else { // !options
            // We're not HTTP (or were already connected), so don't send any header
            sendData = jsvNewFromString("");
        }
        jsvObjectSetChild(httpClientReqVar, HTTP_NAME_SEND_DATA, sendData);
        jsvUnLock(options);
    }
    // We have data and aren't out of memory...
    if (data && sendData) {
        // append the data to what we want to send
        JsVar *s = jsvAsString(data, false);
        if (s) {
            if ((socketType&ST_TYPE_MASK) == ST_HTTP &&
                    jsvGetBoolAndUnLock(jsvObjectGetChild(httpClientReqVar, HTTP_NAME_CHUNKED, 0))) {
                // If we asked to send 'chunked' data, we need to wrap it up,
                // prefixed with the length
                jsvAppendPrintf(sendData, "%x\r\n%v\r\n", jsvGetStringLength(s), s);
            } else {
                jsvAppendStringVarComplete(sendData,s);
            }
            jsvUnLock(s);
        }
    }
    jsvUnLock(sendData);
    if ((socketType&ST_TYPE_MASK) == ST_HTTP) {
        // on HTTP we connect after the first write
        clientRequestConnect(net, httpClientReqVar);
    }
}
Exemplo n.º 22
0
/// if host=0, creates a server otherwise creates a client (and automatically connects). Returns >=0 on success
int net_linux_createsocket(JsNetwork *net, SocketType socketType, uint32_t host, unsigned short port, JsVar *options) {
  NOT_USED(net);
  int ippProto = socketType & ST_UDP ? IPPROTO_UDP : IPPROTO_TCP;
  int scktType = socketType & ST_UDP ? SOCK_DGRAM : SOCK_STREAM;
  int sckt = -1;

  if (host!=0) { // ------------------------------------------------- host (=client)

    sckt = socket(AF_INET, scktType, ippProto);
    if (sckt<0) {
      jsError("Socket creation failed");
      return sckt; // error
    }

    // turn on non-blocking mode
    #ifdef WIN_OS
    u_long n = 1;
    ioctlsocket(sckt,FIONBIO,&n);
    #endif

    if (scktType == SOCK_DGRAM) { // only for UDP
      // set broadcast
      int optval = 1;
      if (setsockopt(sckt,SOL_SOCKET,SO_BROADCAST,(const char *)&optval,sizeof(optval))<0)
        jsWarn("setsockopt(SO_BROADCAST) failed\n");
      return sckt;
    }

    sockaddr_in       sin;
    sin.sin_family = AF_INET;
    sin.sin_addr.s_addr = (in_addr_t)host;
    sin.sin_port = htons( port );

    int res = connect(sckt,(struct sockaddr *)&sin, sizeof(sockaddr_in) );

    if (res == SOCKET_ERROR) {
    #ifdef WIN_OS
     int err = WSAGetLastError();
    #else
     int err = errno;
    #endif
     if (err != EINPROGRESS &&
         err != EWOULDBLOCK) {
       jsError("Connect failed (err %d)", err);
       closesocket(sckt);
       return -1;
     }
    }

  } else { // ------------------------------------------------- no host (=server)

    sckt = socket(AF_INET, scktType, ippProto);
    if (sckt == INVALID_SOCKET) {
      jsError("Socket creation failed");
      return 0;
    }

    if (jsvGetBoolAndUnLock(jsvObjectGetChild(options, "reuseAddr", 0))) {
      int optval = 1;
      if (setsockopt(sckt,SOL_SOCKET,SO_REUSEADDR,(const char *)&optval,sizeof(optval)) < 0)
        jsWarn("setsockopt(SO_REUSADDR) failed\n");
#ifdef SO_REUSEPORT
      if (setsockopt(sckt,SOL_SOCKET,SO_REUSEPORT,(const char *)&optval,sizeof(optval)) < 0)
        jsWarn("setsockopt(SO_REUSPORT) failed\n");
#endif
    }

    int nret;
    sockaddr_in serverInfo;
    memset(&serverInfo, 0, sizeof(serverInfo));
    serverInfo.sin_family = AF_INET;
    //serverInfo.sin_addr.s_addr = htonl(INADDR_LOOPBACK); // allow only LOCAL clients to connect
    serverInfo.sin_addr.s_addr = INADDR_ANY; // allow anyone to connect
    serverInfo.sin_port = (unsigned short)htons((unsigned short)port); // port
    nret = bind(sckt, (struct sockaddr*)&serverInfo, sizeof(serverInfo));
    if (nret == SOCKET_ERROR) {
      jsError("Socket bind failed");
      closesocket(sckt);
      return -1;
    }

    // multicast support
    // FIXME: perhaps extend the JsNetwork with addmembership/removemembership instead of using options
    JsVar *mgrpVar = jsvObjectGetChild(options, "multicastGroup", 0);
    if (mgrpVar) {
        char ipStr[18];

        uint32_t grpip;
        jsvGetString(mgrpVar, ipStr, sizeof(ipStr));
        jsvUnLock(mgrpVar);
        net_linux_gethostbyname(net, ipStr, &grpip);

        JsVar *ipVar = jsvObjectGetChild(options, "multicastIp", 0);
        jsvGetString(ipVar, ipStr, sizeof(ipStr));
        jsvUnLock(ipVar);
        uint32_t ip;
        net_linux_gethostbyname(net, ipStr, &ip);

        struct ip_mreq mreq;
        mreq.imr_multiaddr = *(struct in_addr *)&grpip;
        mreq.imr_interface = *(struct in_addr *)&ip;
        setsockopt (sckt, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
    }

    if (scktType == SOCK_STREAM) { // only for TCP
      // Make the socket listen
      nret = listen(sckt, 10); // 10 connections (but this ignored on CC30000)
      if (nret == SOCKET_ERROR) {
        jsError("Socket listen failed");
        closesocket(sckt);
        return -1;
      }
    }
  }

#ifdef SO_NOSIGPIPE
  // disable SIGPIPE
  int optval = 1;
  if (setsockopt(sckt,SOL_SOCKET,SO_NOSIGPIPE,(const char *)&optval,sizeof(optval))<0)
    jsWarn("setsockopt(SO_NOSIGPIPE) failed\n");
#endif

  return sckt;
}
Exemplo n.º 23
0
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);
}