コード例 #1
0
ファイル: ring.c プロジェクト: 111220187/chord
void ring_stabilise_all() {
  Node *current = NULL;
  Ring *ring = ring_get();
  int i = 0;
  int done_first = 0;
  
  /*
  current = ring->first_node;
  
  while (current != NULL) {
    i++;
*/
  for (i = 0; i < ring->size; i++) {
    current = ring->nodes[i];
    node_stabilise(current);
    node_fix_fingers(current);
    
    /*
    current = current->successor != current ? current->successor : NULL;
    
    if (done_first && current == ring->first_node) {
      current = NULL;
    }
    
    if (!done_first) {
      done_first = 1;
    }
     */
  }
}
コード例 #2
0
ファイル: ring.c プロジェクト: 111220187/chord
int ring_size() {
  Node *current = NULL;
  Ring *ring = ring_get();
  
  /*
  int size = 0;
  int done_first = 0;
  
  current = ring->first_node;
  
  while (current != NULL) {
    size++;
    current = current->successor != current ? current->successor : NULL;

    if (done_first && current == ring->first_node) {
      current = NULL;
    }
    
    if (!done_first) {
      done_first = 1;
    }
  }
   */
  
  return ring->size;
}
コード例 #3
0
ファイル: db.c プロジェクト: jlsandell/Craft
int db_worker_run(void *arg) {
    int running = 1;
    while (running) {
        RingEntry e;
        mtx_lock(&mtx);
        while (!ring_get(&ring, &e)) {
            cnd_wait(&cnd, &mtx);
        }
        mtx_unlock(&mtx);
        switch (e.type) {
        case BLOCK:
            _db_insert_block(e.p, e.q, e.x, e.y, e.z, e.w);
            break;
        case KEY:
            _db_set_key(e.p, e.q, e.key);
            break;
        case COMMIT:
            _db_commit();
            break;
        case EXIT:
            running = 0;
            break;
        }
    }
    return 0;
}
コード例 #4
0
ファイル: ring.c プロジェクト: promovicz/klingel
/* wait for an event */
int
waitevent()
{
  while(1) {
    /* ring button pressed? */
    if(ring_get()) {
      waitticks(DEBOUNCE);
      if(ring_get()) {
	waitticks(DEBOUNCE);
	if(ring_get()) {
	  while(ring_get());
	  return EVENT_RING;
	}
      }
    }

    /* sequence timeout or pending strobe activation? */
    if(firstpress) {
      tick_t time = gettick();
      if((time - firstpress) >= TIMEOUT) {
    	return EVENT_TIMEOUT;
      }
      if((time - lastpress) >= STROBEDELAY) {
        return EVENT_STROBE;
      }
    }

    /* command input? */
    char input;
    if(urx(&input)) {
      switch(input) {
      case 'O':
	return EVENT_CMD_OPEN;
      case 'L':
	return EVENT_CMD_LOCK;
      case 'U':
	return EVENT_CMD_UNLOCK;
      case 'S':
	return EVENT_CMD_STROBO_ENABLE;
      case 's':
	return EVENT_CMD_STROBO_DISABLE;
      }
    }
  }
}
コード例 #5
0
ファイル: ring.c プロジェクト: Aaron1011/Craft
void ring_grow(Ring *ring) {
    Ring new_ring;
    RingEntry entry;
    ring_alloc(&new_ring, ring->capacity * 2);
    while (ring_get(ring, &entry)) {
        ring_put(&new_ring, &entry);
    }
    free(ring->data);
    ring->capacity = new_ring.capacity;
    ring->start = new_ring.start;
    ring->end = new_ring.end;
    ring->data = new_ring.data;
}
コード例 #6
0
ファイル: ring.c プロジェクト: 111220187/chord
void ring_insert_before(Node *before_node, Node *node) {
  Ring *ring = ring_get();
  
  node->predecessor = before_node->predecessor;
  node->successor = before_node;
  if (before_node->predecessor == NULL) {
    ring->first_node = node;
  }
  else {
    before_node->predecessor->successor = node;
  }
  before_node->predecessor = node;
}
コード例 #7
0
ファイル: ring.c プロジェクト: 111220187/chord
void ring_insert_after(Node *after_node, Node *node) {
  Ring *ring = ring_get();
  
  node->predecessor = after_node;
  node->successor = after_node->successor;
  if (after_node->successor == NULL) {
    ring->last_node = node;
  }
  else {
    after_node->successor->predecessor = node;
  }
  after_node->successor = node;
}
コード例 #8
0
ファイル: ring.c プロジェクト: 111220187/chord
void ring_print_all() {
  Node *current = NULL;
  Ring *ring = ring_get();
  int i = 0; 
  
  printf("%-4s %-11s %-5s %-5s %-7s\n", "Key", "ID", "Pred", "Succ", "# Docs");
  printf("---- ----------- ----- ----- -------\n");
  
  for (i = 0; i < ring->size; i++) {
    current = ring->nodes[i];

    node_print(current);
  }
}
コード例 #9
0
ファイル: ring.c プロジェクト: 111220187/chord
void ring_insert(Node *node) {
  Node *current = NULL;
  Ring *ring = ring_get();
  
  if (ring->first_node == NULL) {
    ring->first_node = node;
    ring->last_node = node;
    
    node->predecessor = NULL;
    node->successor = NULL;
  }
  else {
    current = ring->first_node;
    /* insert the node into the doubly linked list
     * while maintaining sort order. First get the
     * node we will insert after.
     */
    while (current != NULL) {
      /* if there's no successor we're at the end, so add it here */
      if (current->successor == NULL) {
        if (node->key > current->key) {
          ring_insert_after(current, node);
        }
        else {
          ring_insert_before(current, node);
        }
        break;
      }
      else {
        /* if the successor node is less than the current, insert here */
        if ((node->key < current->successor->key) && (node->key > current->key)) {
          /* insert the node into the Ring */
          ring_insert_after(current, node);
          break;
        }
        /* if the node is less and current and greater than predecessor, insert here */
        else if ((node->key < current->key) 
                 && ((current->predecessor == NULL) 
                     || (node->key > current->predecessor->key))) {
                   /* insert the node into the Ring */
                   ring_insert_before(current, node);
                   break;
                 }
      }
      
      /* go to the successor node in the ring */
      current = current->successor != current ? current->successor : NULL;
    }
  }
}
コード例 #10
0
ファイル: GSwifi.cpp プロジェクト: pipoop/hobby-device
int8_t GSwifi::parseRequestLine (char *token, uint8_t token_size) {
    uint8_t i;
    for ( i = 0; i <= token_size; i++ ) {
        if (ring_isempty( _buf_cmd )) {
            return -1; // space didn't appear
        }
        ring_get( _buf_cmd, token+i, 1 );
        if (token[i] == ' ') {
            token[i] = '\0';
            break;
        }
    }
    if ( i == token_size + 1 ) {
        return -1; // couldnt detect token
    }
    return 0;
}
コード例 #11
0
int16_t ring_get_all(buffer_data_t *dest, buffer_index_t dest_size,
		volatile buffer_data_t *buffer, buffer_index_t buffer_size,
		volatile buffer_index_t *head, volatile buffer_index_t *tail)
{
	buffer_index_t count = 0;
	int16_t ret_val;
	buffer_data_t temp_value;
	do
	{
		ret_val = ring_get(&temp_value, buffer, buffer_size, head, tail);
		if (ERR_NONE != ret_val)
			break;
		dest[count++] = temp_value;
	} while ((count < dest_size));

	return count;
}
コード例 #12
0
ファイル: GSwifi.cpp プロジェクト: pipoop/hobby-device
int8_t GSwifi::parseHead2(uint8_t dat, int8_t cid) {
    if (dat == '\n') {
        continuous_newlines_ ++;
    }
    else if (dat == '\r') {
        // preserve
    }
    else {
        continuous_newlines_ = 0;
        if ( ! ring_isfull(_buf_cmd) ) {
            // ignore if overflowed
            ring_put( _buf_cmd, dat );
        }
    }
    if (continuous_newlines_ == 1) {
        // check "Content-Length: x" header
        // if it's non 0, wait for more body data
        // otherwise disconnect after handling response
        // GS splits HTTP requests/responses into multiple bulk messages,
        // 1st ends just after headers, and 2nd contains only response body
        // "Content-Length: "    .length = 16
        // "Content-Length: 9999".length = 20
        // "X-Requested-With: "  .length = 18
        char content_length_chars[21];
        memset( content_length_chars, 0, 21 );

        uint8_t copied = ring_get( _buf_cmd, content_length_chars, 20 );
        if ((copied >= 16) &&
            (strncmp(content_length_chars, "Content-Length: ", 16) == 0)) {
            content_length_chars[20] = 0;
            content_lengths_[ cid ] = atoi(&content_length_chars[16]);
        }
        if ((copied >= 18) &&
            (strncmp(content_length_chars, "X-Requested-With: ", 18) == 0)) {
            has_requested_with_ = true;
        }
        ring_clear(_buf_cmd);
    }
    if (continuous_newlines_ == 2) {
        // if detected double (\r)\n, switch to body mode
        ring_clear(_buf_cmd);
        return 0;
    }
    return -1;
}
コード例 #13
0
ファイル: HardwareSerialX.cpp プロジェクト: Tempfox/device
int HardwareSerialX::read(void)
{
  // if the head isn't ahead of the tail, we don't have any characters
  if (ring_isempty( _rx_buffer )) {
    return -1;
  }
  else {
    char c;
    ring_get( _rx_buffer, &c, 1 );

    if (is_limiting &&
        ring_used(_rx_buffer) < XONOFF_HYSTERESIS) {
        send_xon    = true;
        is_limiting = false;
        sbi(UCSR1B, UDRIE1);
    }

    return c;
  }
}
コード例 #14
0
ファイル: ring.c プロジェクト: 111220187/chord
void ring_print(int index, int with_fingers) {
  Node *current = NULL;
  Ring *ring = ring_get();
  int i = 0;
  int done_first = 0;
  
  
  current = ring->first_node;
  
  if (index) {
    printf("%-4s %-4s %-11s %-5s %-5s %-7s\n", "Idx", "Key", "ID", "Pred", "Succ", "# Docs");
    printf("---- ---- ----------- ----- ----- -------\n");
  }
  if (!index) {
    printf("%-4s %-11s %-5s %-5s %-7s\n", "Key", "ID", "Pred", "Succ", "# Docs");
    printf("---- ----------- ----- ----- -------\n");
  }
  
  while (current != NULL) {
    i++;
   
    if (index) {
      printf("%-4d ", i);
    }
    node_print(current);
    if (with_fingers) {
      node_print_finger_table(current);
    }
      
    current = current->successor != current ? current->successor : NULL;
    
    if (done_first && current == ring->first_node) {
      current = NULL;
    }
    
    if (!done_first) {
      done_first = 1;
    }
    
  }
}
コード例 #15
0
ファイル: GSwifi.cpp プロジェクト: pipoop/hobby-device
char GSwifi::bufferGet() {
    char letter;
    ring_get(_buf_cmd, &letter, 1);
    return letter;
}
コード例 #16
0
ファイル: test.c プロジェクト: Tempfox/device
int main() {
    ok( 1, "ok" );

    {
        struct RingBuffer buf_;
        struct RingBuffer *buf = &buf_;
        char data[65];
        ring_init( buf, data, 65 );
        ok( ring_used(buf) == 0, "0 used" );
        ok( ring_isempty(buf) == 1, "is empty" );

        ring_put(buf, 'a');
        ok( ring_used(buf) == 1, "1 used after put" );
        ok( ring_isfull(buf) == 0, "not full" );
        ok( ring_isempty(buf) == 0, "is empty" );

        char buf2[64];
        ring_get(buf, &buf2[0], 1);
        ok( buf2[0] == 'a', "get" );
        ok( ring_used(buf) == 0, "0 used after get" );
        ok( ring_isfull(buf) == 0, "not full" );
        ok( ring_isempty(buf) == 1, "is empty" );

        ring_put(buf, 'b');
        ring_clear(buf);

        ok( ring_used(buf) == 0, "0 used after clear" );
        ok( ring_isfull(buf) == 0, "not full" );
        ok( ring_isempty(buf) == 1, "is empty" );

        ring_put(buf, '0');        ring_put(buf, '1');        ring_put(buf, '2');        ring_put(buf, '3');
        ring_put(buf, '4');        ring_put(buf, '5');        ring_put(buf, '6');        ring_put(buf, '7');
        ring_put(buf, '8');        ring_put(buf, '9');        ring_put(buf, 'a');        ring_put(buf, 'b');
        ring_put(buf, 'c');        ring_put(buf, 'd');        ring_put(buf, 'e');        ring_put(buf, 'f');
        ring_put(buf, '0');        ring_put(buf, '1');        ring_put(buf, '2');        ring_put(buf, '3');
        ring_put(buf, '4');        ring_put(buf, '5');        ring_put(buf, '6');        ring_put(buf, '7');
        ring_put(buf, '8');        ring_put(buf, '9');        ring_put(buf, 'a');        ring_put(buf, 'b');
        ring_put(buf, 'c');        ring_put(buf, 'd');        ring_put(buf, 'e');        ring_put(buf, 'f');
        ring_put(buf, '0');        ring_put(buf, '1');        ring_put(buf, '2');        ring_put(buf, '3');
        ring_put(buf, '4');        ring_put(buf, '5');        ring_put(buf, '6');        ring_put(buf, '7');
        ring_put(buf, '8');        ring_put(buf, '9');        ring_put(buf, 'a');        ring_put(buf, 'b');
        ring_put(buf, 'c');        ring_put(buf, 'd');        ring_put(buf, 'e');        ring_put(buf, 'f');
        ring_put(buf, '0');        ring_put(buf, '1');        ring_put(buf, '2');        ring_put(buf, '3');
        ring_put(buf, '4');        ring_put(buf, '5');        ring_put(buf, '6');        ring_put(buf, '7');
        ring_put(buf, '8');        ring_put(buf, '9');        ring_put(buf, 'a');        ring_put(buf, 'b');
        ring_put(buf, 'c');        ring_put(buf, 'd');        ring_put(buf, 'e');        ring_put(buf, 'f');
        ok( ring_used(buf) == 64, "64 used after 64 puts" );
        ok( ring_isfull(buf) == 1, "is full" );
        ok( ring_isempty(buf) == 0, "is empty" );

        // dropped feature to protect buffer from overflow
        // ok( ring_put(buf, 'x') == -1, "can't put into full" );

        uint8_t fetched = ring_get(buf, &buf2[0], 64);
        ok( buf2[0] == '0', "get 1" );
        ok( buf2[1] == '1', "get 2" );
        ok( buf2[2] == '2', "get 3" );
        ok( buf2[3] == '3', "get 4" );
        ok( fetched == 64, "fetched all" );

        ok( ring_used(buf) == 0, "0 used after all get" );
        ok( ring_isfull(buf) == 0, "not full again" );
        ok( ring_isempty(buf) == 1, "is empty" );
    }

    done_testing();
}
コード例 #17
0
ファイル: GSwifi.cpp プロジェクト: pipoop/hobby-device
void GSwifi::parseLine () {
    static char buf[GS_CMD_SIZE];

    while (! ring_isempty(_buf_cmd)) {
        // received "\n"
        uint8_t i = 0;
        while ( (! ring_isempty(_buf_cmd)) &&
                (i < sizeof(buf) - 1) ) {
            ring_get( _buf_cmd, &buf[i], 1 );
            if (buf[i] == '\n') {
                break;
            }
            i ++;
        }
        if (i == 0) continue;
        buf[i] = 0;

        if ( (gs_mode_ == GSMODE_COMMAND) &&
             (gs_commandmode_ != GSCOMMANDMODE_NONE) ) {
            parseCmdResponse(buf);
        }

        if (strncmp(buf, P("CONNECT "), 8) == 0 && buf[8] >= '0' && buf[8] <= 'F' && buf[9] != 0) {
            // connect from client
            // CONNECT 0 1 192.168.2.1 63632
            // 1st cid is our http server's
            // 2nd cid is for client
            // next line will be "[ESC]Z10140GET / ..."

            int8_t cid = x2i(buf[10]); // 2nd cid = HTTP client cid
            ASSERT((0 <= cid) && (cid <= 16));

            setCidIsRequest(cid, true);
            content_lengths_[ cid ] = 0;

            // don't close other connections,
            // other connections close theirselves on their turn
            // ignore client's IP and port
        }
        else if (strncmp(buf, P("DISCONNECT "), 11) == 0) {
            int8_t cid = x2i(buf[11]);
            ASSERT((0 <= cid) && (cid <= 16));

            if (cid == server_cid_) {
                // if it's our server, this is fatal
                reset();
            }
            else if (! cidIsRequest(cid) ) {
                // request *from* us was disconnected (ex: polling)
                dispatchResponseHandler(cid, HTTP_STATUSCODE_DISCONNECT, GSREQUESTSTATE_ERROR);
            }
        }
        else if (strncmp(buf, P("DISASSOCIATED"), 13) == 0 ||
                 strncmp(buf, P("Disassociat"), 11) == 0) {
            // Disassociated
            // Disassociation Event
            clear();
            on_disconnect_();
            gs_failure_ = true;
        }
        else if (strncmp(buf, P("APP Reset"), 9) == 0 ||
                 strncmp(buf, P("Serial2WiFi APP"), 15) == 0) {
            // APP Reset-APP SW Reset
            // APP Reset-Wlan Except
            // Serial2Wifi APP
            on_reset_();
            gs_failure_ = true;
        }
        // else if (strncmp(buf, P("Out of StandBy-Timer"), 20) == 0 ||
        //          strncmp(buf, P("Out of StandBy-Alarm"), 20) == 0) {
        // }
        // else if (strncmp(buf, P("Out of Deep Sleep"), 17) == 0 ) {
        // }
    }
}
コード例 #18
0
ファイル: GSwifi.cpp プロジェクト: pipoop/hobby-device
// received a character from UART
void GSwifi::parseByte(uint8_t dat) {
    static uint8_t  next_token; // split each byte into tokens (cid,ip,port,length,data)
    static bool     escape = false;
    char temp[GS_MAX_PATH_LENGTH+1];

    if (dat == ESCAPE) {
        // 0x1B : Escape
        GSLOG_PRINT("e< ");
    }
    else { // if (next_token != NEXT_TOKEN_DATA) {
        GSLOG_WRITE(dat);
    }

    if (gs_mode_ == GSMODE_COMMAND) {
        if (escape) {
            // esc
            switch (dat) {
            case 'O':
            case 'F':
                // ignore
                break;
            case 'Z':
            case 'H':
                gs_mode_   = GSMODE_DATA_RX_BULK;
                next_token = NEXT_TOKEN_CID;
                break;
            default:
                // GSLOG_PRINT("!E1 "); GSLOG_PRINTLN2(dat,HEX);
                break;
            }
            escape = false;
        }
        else {
            if (dat == ESCAPE) {
                escape = true;
            }
            else if (dat == '\n') {
                // end of line
                parseLine();
            }
            else if (dat != '\r') {
                if ( ! ring_isfull(_buf_cmd) ) {
                    ring_put(_buf_cmd, dat);
                }
                else {
                    GSLOG_PRINTLN("!E2");
                }
            }
        }
        return;
    }
    else if (gs_mode_ != GSMODE_DATA_RX_BULK) {
        return;
    }

    static uint16_t       len;
    static char           len_chars[5];
    static int8_t         current_cid;
    static GSREQUESTSTATE request_state;

    if (next_token == NEXT_TOKEN_CID) {
        // dat is cid
        current_cid = x2i(dat);
        ASSERT((0 <= current_cid) && (current_cid <= 16));

        next_token  = NEXT_TOKEN_LENGTH;
        len         = 0;
    }
    else if (next_token == NEXT_TOKEN_LENGTH) {
        // Data Length is 4 ascii char represents decimal value i.e. 1400 byte (0x31 0x34 0x30 0x30)
        len_chars[ len ++ ] = dat;
        if (len >= 4) {
            len_chars[ len ] = 0;
            len        = atoi(len_chars); // length of data
            next_token = NEXT_TOKEN_DATA;

            if (content_lengths_[ current_cid ] > 0) {
                // this is our 2nd bulk message from GS for this response
                // we already swallowed HTTP response headers,
                // following should be body
                request_state = GSREQUESTSTATE_BODY;
            }
            else {
                request_state = GSREQUESTSTATE_HEAD1;
            }
            ring_clear( _buf_cmd ); // reuse _buf_cmd to store HTTP request
        }
    }
    else if (next_token == NEXT_TOKEN_DATA) {
        len --;

        if (cidIsRequest(current_cid)) { // request against us
            static uint16_t error_code;
            static int8_t   routeid;

            switch (request_state) {
            case GSREQUESTSTATE_HEAD1:
                if (dat != '\n') {
                    if ( ! ring_isfull(_buf_cmd) ) {
                        ring_put( _buf_cmd, dat );
                    }
                    // ignore overflowed
                }
                else {
                    // end of request line

                    // reuse "temp" buffer to parse method and path
                    int8_t  result  = parseRequestLine((char*)temp, 7);
                    GSMETHOD method = GSMETHOD_UNKNOWN;
                    if ( result == 0 ) {
                        method = x2method(temp);
                        result = parseRequestLine((char*)temp, GS_MAX_PATH_LENGTH);
                    }
                    if ( result != 0 ) {
                        // couldn't detect method or path
                        request_state = GSREQUESTSTATE_ERROR;
                        error_code    = 400;
                        ring_clear(_buf_cmd);
                        break;
                    }

                    routeid = router(method, temp);
                    if ( routeid < 0 ) {
                        request_state = GSREQUESTSTATE_ERROR;
                        error_code    = 404;
                        ring_clear(_buf_cmd);
                        break;
                    }
                    request_state                   = GSREQUESTSTATE_HEAD2;
                    continuous_newlines_            = 0;
                    content_lengths_[ current_cid ] = 0;
                    has_requested_with_             = false;
                    ring_clear(_buf_cmd);
                }
                break;
            case GSREQUESTSTATE_HEAD2:
                if(0 == parseHead2(dat, current_cid)) {
                    request_state = GSREQUESTSTATE_BODY;
                    // dispatched once, at start of body
                    dispatchRequestHandler(current_cid, routeid, GSREQUESTSTATE_BODY_START);
                }
                break;
            case GSREQUESTSTATE_BODY:
                if (content_lengths_[ current_cid ] > 0) {
                    content_lengths_[ current_cid ] --;
                }
                if (ring_isfull(_buf_cmd)) {
                    dispatchRequestHandler(current_cid, routeid, request_state); // POST, user callback should write()
                }
                ring_put(_buf_cmd, dat);
                break;
            case GSREQUESTSTATE_ERROR:
                // skip until received whole request
                break;
            case GSREQUESTSTATE_RECEIVED:
            default:
                break;
            }

            // end of bulk transfered data
            if (len == 0) {
                gs_mode_ = GSMODE_COMMAND;

                if ( request_state == GSREQUESTSTATE_ERROR ) {
                    writeHead( current_cid, error_code );
                    writeEnd();
                    ring_put( &commands, COMMAND_CLOSE );
                    ring_put( &commands, current_cid );
                }
                else {
                    if (content_lengths_[ current_cid ] == 0) {
                        // if Content-Length header was longer than <ESC>Z length,
                        // we wait til next bulk transfer
                        request_state = GSREQUESTSTATE_RECEIVED;
                    }
                    // user callback should write(), writeEnd() and close()
                    dispatchRequestHandler(current_cid, routeid, request_state);
                }
                ring_clear(_buf_cmd);
            }
        }
        else {
            // is request from us
            static uint16_t status_code;

            switch (request_state) {
            case GSREQUESTSTATE_HEAD1:
                if (dat != '\n') {
                    if ( ! ring_isfull(_buf_cmd) ) {
                        // ignore if overflowed
                        ring_put( _buf_cmd, dat );
                    }
                }
                else {
                    uint8_t i=0;

                    // skip 9 characters "HTTP/1.1 "
                    while (i++ < 9) {
                        ring_get( _buf_cmd, &temp[0], 1 );
                    }

                    // copy 3 numbers representing status code into temp buffer
                    temp[ 3 ] = 0;
                    int8_t count = ring_get( _buf_cmd, temp, 3 );
                    if (count != 3) {
                        // protocol error
                        // we should receive something like: "200 OK", "401 Unauthorized"
                        status_code   = 999;
                        request_state = GSREQUESTSTATE_ERROR;
                        break;
                    }
                    status_code                     = atoi(temp);
                    request_state                   = GSREQUESTSTATE_HEAD2;
                    continuous_newlines_            = 0;
                    content_lengths_[ current_cid ] = 0;
                    ring_clear(_buf_cmd);
                }
                break;
            case GSREQUESTSTATE_HEAD2:
                if(0 == parseHead2(dat, current_cid)) {
                    request_state = GSREQUESTSTATE_BODY;
                    // dispatched once, at start of body
                    dispatchResponseHandler(current_cid, status_code, GSREQUESTSTATE_BODY_START);
                }
                break;
            case GSREQUESTSTATE_BODY:
                if (content_lengths_[ current_cid ] > 0) {
                    content_lengths_[ current_cid ] --;
                }
                if (ring_isfull(_buf_cmd)) {
                    dispatchResponseHandler(current_cid, status_code, GSREQUESTSTATE_BODY);
                }
                ring_put(_buf_cmd, dat);
                break;
            case GSREQUESTSTATE_ERROR:
            case GSREQUESTSTATE_RECEIVED:
            default:
                break;
            }

            if (len == 0) {
                gs_mode_ = GSMODE_COMMAND;

                if ( request_state == GSREQUESTSTATE_ERROR ) {
                    dispatchResponseHandler(current_cid, status_code, request_state);
                }
                else {
                    if (content_lengths_[ current_cid ] == 0) {
                        // if Content-Length header was longer than <ESC>Z length,
                        // we wait til all response body received.
                        // we need to close our clientRequest before handling it.
                        // GS often locks when closing 2 connections in a row
                        // ex: POST /keys from iPhone (cid:1) -> POST /keys to server (cid:2)
                        //     response from server arrives -> close(1) -> close(2) -> lock!!
                        // the other way around: close(2) -> close(1) doesn't lock :(
                        request_state = GSREQUESTSTATE_RECEIVED;
                    }
                    dispatchResponseHandler(current_cid, status_code, request_state);
                }
                ring_clear( _buf_cmd );
            }
        } // is response
    } // (next_token == NEXT_TOKEN_DATA)
}