Ejemplo n.º 1
0
size_t HardwareSerialX::write(uint8_t c)
{
  // If the output buffer is full, there's nothing for it other than to
  // wait for the interrupt handler to empty it a bit
  // ???: return 0 here instead?
  while (ring_isfull( _tx_buffer )) ;

  ring_put( _tx_buffer, c );

  sbi(*_ucsrb, _udrie);
  // clear the TXC bit -- "can be cleared by writing a one to its bit location"
  transmitting = true;
  sbi(*_ucsra, TXC0);

  return 1;
}
Ejemplo n.º 2
0
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;
}
Ejemplo n.º 3
0
static int8_t on_post_keys_response(int8_t cid, uint16_t status_code, GSwifi::GSREQUESTSTATE state) {
    HTTPLOG_PRINT(P("< P /k ")); HTTPLOG_PRINTLN(status_code);

    if (status_code != 200) {
        gs.bufferClear();
    }

    if (state != GSwifi::GSREQUESTSTATE_RECEIVED) {
        return 0;
    }

    gs.writeHead( post_keys_cid, status_code );

    switch (status_code) {
    case 200:
        while (! gs.bufferEmpty()) {
            char letter = gs.bufferGet();
            gs.write( letter );
        }
        gs.writeEnd();
        break;
    default:
        gs.writeEnd();
        break;
    }

    ring_put( &commands, COMMAND_CLOSE );
    ring_put( &commands, cid );
    ring_put( &commands, COMMAND_CLOSE );
    if (ring_isfull( &commands )) {
        HTTPLOG_PRINTLN("!E8");
        return -1;
    }
    ring_put( &commands, post_keys_cid );

    return 0;
}
Ejemplo n.º 4
0
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();
}
Ejemplo n.º 5
0
int
ring_ops(char *bfr,int bytes,enum ringbfract_t action,struct ringset *ring) {
    /*
     * Does ring buffer management. Actions can include
     *   RING_ALLOC, RING_DEALLOC, RING_INIT, RING_STORE, RING_RETR, RING_ISMT,
     *     RING_ISFULL, RING_ELEMENTS_FREE, RING_ELEMENTS_STORED,RING_VIEW, RING_DELETE
     * RING_ALLOC uses bytes to indicate the nuber of bytes to be stored in the ring.
     *   The buffer will be allocated to one more than this
     * RING_DEALLOC deallocates the ring buffer
     * RING_STORE, RING_VIEW, and RING_RETR both use the *bfr and bytes. Others do not and
     *   they can be set to zero.
     * RING_ISMT and RING_ISFULL, return 1 if true, 0 otherwise.
     * RING_RETR, RING_VIEW, and RING_STORE return -1 if the requested number of bytes is invalid
     * RING_ELEMENTS_FREE and RING_ELEMENTS_STORED return the number of bytes free and stored, repsectively.
     *
     * This should be called with the appropriate struct ringset *ring pointer to point to
     *  data from the appropriate thread.
    */
    int partial;

    switch (action) {
    case RING_ALLOC: // Allocate memory for the ring
        ring->ring = (char *)malloc(bytes+1);
        if(ring->ring == NULL)
            fail("ring_ops: Failed to allocate memory for ring buffer\n");
        ring->bfrsize = bytes + 1;
        ring->readptr = ring->writeptr = 0;
        writelog(2,"ring_ops: Successfully allocated ring buffer to hold %d bytes\n",bytes);
        break;
    case RING_DEALLOC: // Free the buffer
        writelog(2,"ring_ops: De-allocating ring buffer of %d bytes\n",ring->bfrsize);
        free(ring->ring);
        break;
    case RING_INIT: // Initialize
        writelog(5,"ring_ops: Initializing ring buffer of %d bytes\n",ring->bfrsize);
        ring->readptr = ring->writeptr = 0;
        break;
    case RING_STORE: // Store bytes from bfr to ring
        if(bytes > ring_bytes_free(ring)) {
            return -1;
        } else {
            // Copy in two parts if it will wrap.
            partial = ring->bfrsize - ring->writeptr;
            if(bytes > partial) {
                memcpy(&ring->ring[ring->writeptr],bfr,partial);
                memcpy(ring->ring,&bfr[partial],bytes - partial);
            } else {
                memcpy(&ring->ring[ring->writeptr],bfr,bytes);
            }
            ring->writeptr = ring_normalize(ring->writeptr + bytes,ring);
            writelog(7,"ring_ops: Stored %d bytes into ring. new readptr: %d  new writeptr: %d. "
                     "Ring now contains %d bytes\n",
                     bytes, ring->readptr,ring->writeptr, ring_bytes_stored(ring));
        }
        break;
    case RING_RETR: // Retrieve bytes from the ring to bfr
    case RING_VIEW: // Retrieve but don't update the ring->readptr pointer
        if((bytes > 0) && (bytes > ring_bytes_stored(ring))) {
            return -1;
        } else {
            partial = ring->bfrsize - ring->readptr;
            if(bytes > partial) {
                // Copy in two parts if it will wrap
                memcpy(bfr,&(ring->ring[ring->readptr]),partial);
                memcpy(&bfr[partial],ring->ring,bytes - partial);
            } else {
                memcpy(bfr,&(ring->ring[ring->readptr]),bytes);
            }
            // Update the readptring pointer if action == retrieve
            if(action == RING_RETR) {
                ring->readptr = ring_normalize(ring->readptr + bytes,ring);
                writelog(7,"ring_ops: Retrieved %d bytes from ring. new readptr: %d  new writeptr: %d. "
                         "Ring now contains %d bytes\n", bytes, ring->readptr,ring->writeptr,ring_bytes_stored(ring));
            }
        }
        break;
    case RING_DELETE: // Delete the given number of bytes from the readptr of the ring (update the ring->readptr).
        //  If bytes is out of range, do nothing but return -1.
        if((bytes > 0) && (bytes <= ring_bytes_stored(ring))) {
            ring->readptr = ring_normalize(ring->readptr + bytes,ring);
            writelog(7,"ring_ops: Deleted %d bytes from ring. new readptr: %d  new writeptr: %d. "
                     "Ring now contains %d bytes\n",
                     bytes, ring->readptr,ring->writeptr,ring_bytes_stored(ring));
        } else {
            return -1;
        }
        break;
    case RING_ISMT: // Is empty?
        return ring_isempty(ring);
        break;
    case RING_ISFULL: // Is full?
        return ring_isfull(ring);
        break;
    case RING_ELEMENTS_FREE: // REturns the number of free bytes
        return ring_bytes_free(ring);
        break;
    case RING_ELEMENTS_STORED: // REturns the number of bytes currently stored.
        return ring_bytes_stored(ring);
        break;
    default:
        fail("ring_ops: Illegal action passed to ring_ops: %d\n",action);
        break;
    }
    return 0;
}
Ejemplo n.º 6
0
// 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)
}