void ape_ws_write(ape_socket *socket_client, unsigned char *data, size_t len, ape_socket_data_autorelease data_type) { unsigned char payload_head[32] = { 0x81 }; size_t payload_length = 0; if (len <= 125) { payload_head[1] = (unsigned char)len & 0x7F; payload_length = 2; } else if (len <= 65535) { unsigned short int s = htons(len); payload_head[1] = 126; memcpy(&payload_head[2], &s, 2); payload_length = 4; } else if (len <= 0xFFFFFFFF) { unsigned int s = htonl(len); payload_head[1] = 127; payload_head[2] = 0; payload_head[3] = 0; payload_head[4] = 0; payload_head[5] = 0; memcpy(&payload_head[6], &s, 4); payload_length = 10; } printf("Writting WS to %d\n", socket_client->s.fd); PACK_TCP(socket_client->s.fd); APE_socket_write(socket_client, payload_head, payload_length, APE_DATA_STATIC); APE_socket_write(socket_client, data, len, data_type); FLUSH_TCP(socket_client->s.fd); }
/* Send queue to socket */ int send_raws(subuser *user, acetables *g_ape) { int finish = 1, state = 0; struct _raw_pool *pool; struct _transport_properties *properties; if (user->raw_pools.nraw == 0) { return 1; } PACK_TCP(user->client->fd); /* Activate TCP_CORK */ properties = transport_get_properties(user->user->transport, g_ape); if (!user->headers.sent) { user->headers.sent = 1; switch(user->user->transport) { case TRANSPORT_XHRSTREAMING: finish &= http_send_headers(user->headers.content, HEADER_XHR, HEADER_XHR_LEN, user->client, g_ape); break; case TRANSPORT_SSE_LONGPOLLING: finish &= http_send_headers(user->headers.content, HEADER_SSE, HEADER_SSE_LEN, user->client, g_ape); break; case TRANSPORT_WEBSOCKET: case TRANSPORT_WEBSOCKET_IETF: break; default: finish &= http_send_headers(user->headers.content, HEADER_DEFAULT, HEADER_DEFAULT_LEN, user->client, g_ape); break; } } if (properties != NULL && properties->padding.left.val != NULL) { finish &= sendbin(user->client->fd, properties->padding.left.val, properties->padding.left.len, 0, g_ape); } if (user->raw_pools.high.nraw) { pool = user->raw_pools.high.rawfoot->prev; } else { pool = user->raw_pools.low.rawhead; state = 1; } if (user->user->transport == TRANSPORT_WEBSOCKET_IETF) { char payload_head[32] = { 0x84 }; int payload_size = raws_size(user); /* TODO: fragmentation? */ int payload_length = 0; if (payload_size <= 125) { payload_head[1] = (unsigned char)payload_size & 0x7F; payload_length = 2; } else if (payload_size <= 65535) { unsigned short int s = htons(payload_size); payload_head[1] = 126; memcpy(&payload_head[2], &s, 2); payload_length = 4; } else if (payload_size <= 0xFFFFFFFF) { unsigned int s = htonl(payload_size); payload_head[1] = 127; payload_head[2] = 0; payload_head[3] = 0; payload_head[4] = 0; payload_head[5] = 0; memcpy(&payload_head[6], &s, 4); payload_length = 10; } finish &= sendbin(user->client->fd, payload_head, payload_length, 0, g_ape); } finish &= sendbin(user->client->fd, "[", 1, 0, g_ape); while (pool->raw != NULL) { struct _raw_pool *pool_next = (state ? pool->next : pool->prev); finish &= sendbin(user->client->fd, pool->raw->data, pool->raw->len, 0, g_ape); if ((pool_next != NULL && pool_next->raw != NULL) || (!state && user->raw_pools.low.nraw)) { finish &= sendbin(user->client->fd, ",", 1, 0, g_ape); } else { finish &= sendbin(user->client->fd, "]", 1, 0, g_ape); if (properties != NULL && properties->padding.right.val != NULL) { finish &= sendbin(user->client->fd, properties->padding.right.val, properties->padding.right.len, 0, g_ape); } } free_raw(pool->raw); pool->raw = NULL; pool = pool_next; if ((pool == NULL || pool->raw == NULL) && !state) { pool = user->raw_pools.low.rawhead; state = 1; } } user->raw_pools.high.nraw = 0; user->raw_pools.low.nraw = 0; user->raw_pools.nraw = 0; user->raw_pools.high.rawfoot = user->raw_pools.high.rawhead; user->raw_pools.low.rawfoot = user->raw_pools.low.rawhead; FLUSH_TCP(user->client->fd); return finish; }
static void process_websocket_frame(ape_socket *co, acetables *g_ape) { ape_buffer *buffer = &co->buffer_in; websocket_state *websocket = co->parser.data; ape_parser *parser = &co->parser; unsigned char *pData; for (pData = (unsigned char *)&buffer->data[websocket->offset]; websocket->offset < buffer->length; websocket->offset++, pData++) { switch(websocket->step) { case WS_STEP_KEY: /* Copy the xor key (32 bits) */ websocket->key.val[websocket->key.pos] = *pData; if (++websocket->key.pos == 4) { websocket->step = WS_STEP_DATA; } break; case WS_STEP_START: /* Contain fragmentaiton infos & opcode (+ reserved bits) */ websocket->frame_payload.start = *pData; websocket->step = WS_STEP_LENGTH; break; case WS_STEP_LENGTH: /* Check for MASK bit */ if (!(*pData & 0x80)) { return; } switch (*pData & 0x7F) { /* 7bit length */ case 126: /* Following 16bit are length */ websocket->step = WS_STEP_SHORT_LENGTH; break; case 127: /* Following 64bit are length */ websocket->step = WS_STEP_EXTENDED_LENGTH; break; default: /* We have the actual length */ websocket->frame_payload.extended_length = *pData & 0x7F; websocket->step = WS_STEP_KEY; break; } break; case WS_STEP_SHORT_LENGTH: memcpy(((char *)&websocket->frame_payload)+(websocket->frame_pos), pData, 1); if (websocket->frame_pos == 3) { websocket->frame_payload.extended_length = ntohs(websocket->frame_payload.short_length); websocket->step = WS_STEP_KEY; } break; case WS_STEP_EXTENDED_LENGTH: memcpy(((char *)&websocket->frame_payload)+(websocket->frame_pos), pData, 1); if (websocket->frame_pos == 9) { websocket->frame_payload.extended_length = ntohl(websocket->frame_payload.extended_length >> 32); websocket->step = WS_STEP_KEY; } break; case WS_STEP_DATA: if (websocket->data_pos == 0) { websocket->data_pos = websocket->offset; } *pData ^= websocket->key.val[(websocket->frame_pos - websocket->data_pos) % 4]; if (--websocket->frame_payload.extended_length == 0) { unsigned char saved; websocket->data = &buffer->data[websocket->data_pos]; websocket->step = WS_STEP_START; websocket->frame_pos = -1; websocket->frame_payload.extended_length = 0; websocket->data_pos = 0; websocket->key.pos = 0; switch(websocket->frame_payload.start & 0x0F) { case 0x8: { /* Close frame Reply by a close response */ char payload_head[2] = { 0x88, 0x00 }; sendbin(co->fd, payload_head, 2, 0, g_ape); return; } case 0x9: { int body_length = &buffer->data[websocket->offset+1] - websocket->data; char payload_head[2] = { 0x8a, body_length & 0x7F }; /* All control frames MUST be 125 bytes or less */ if (body_length > 125) { payload_head[0] = 0x88; payload_head[1] = 0x00; sendbin(co->fd, payload_head, 2, 1, g_ape); return; } PACK_TCP(co->fd); sendbin(co->fd, payload_head, 2, 0, g_ape); if (body_length) { sendbin(co->fd, websocket->data, body_length, 0, g_ape); } FLUSH_TCP(co->fd); break; } case 0xA: /* Never called as long as we never ask for pong */ break; default: /* Data frame */ saved = buffer->data[websocket->offset+1]; buffer->data[websocket->offset+1] = '\0'; parser->onready(parser, g_ape); buffer->data[websocket->offset+1] = saved; break; } if (websocket->offset+1 == buffer->length) { websocket->offset = 0; buffer->length = 0; websocket->frame_pos = 0; websocket->key.pos = 0; return; } } break; default: break; } websocket->frame_pos++; }
subuser *checkrecv(ape_socket *co, acetables *g_ape) { unsigned int op; http_state *http = co->parser.data; subuser *user = NULL; clientget cget; if (http->host == NULL) { shutdown(co->fd, 2); return NULL; } if (gettransport(http->uri) == TRANSPORT_WEBSOCKET) { char *origin = get_header_line(http->hlines, "Origin"); websocket_state *websocket; if (origin == NULL) { shutdown(co->fd, 2); return NULL; } PACK_TCP(co->fd); sendbin(co->fd, CONST_STR_LEN(WEBSOCKET_HARDCODED_HEADERS), 0, g_ape); sendbin(co->fd, CONST_STR_LEN("WebSocket-Origin: "), 0, g_ape); sendbin(co->fd, origin, strlen(origin), 0, g_ape); sendbin(co->fd, CONST_STR_LEN("\r\nWebSocket-Location: ws://"), 0, g_ape); sendbin(co->fd, http->host, strlen(http->host), 0, g_ape); sendbin(co->fd, http->uri, strlen(http->uri), 0, g_ape); sendbin(co->fd, CONST_STR_LEN("\r\n\r\n"), 0, g_ape); FLUSH_TCP(co->fd); co->parser = parser_init_stream(co); websocket = co->parser.data; websocket->http = http; /* keep http data */ return NULL; } if (http->data == NULL) { sendbin(co->fd, HEADER_DEFAULT, HEADER_DEFAULT_LEN, 0, g_ape); sendbin(co->fd, CONST_STR_LEN(CONTENT_NOTFOUND), 0, g_ape); safe_shutdown(co->fd, g_ape); return NULL; } cget.client = co; cget.ip_get = co->ip_client; cget.get = http->data; cget.host = http->host; cget.hlines = http->hlines; op = checkcmd(&cget, gettransport(http->uri), &user, g_ape); switch (op) { case CONNECT_SHUTDOWN: safe_shutdown(co->fd, g_ape); break; case CONNECT_KEEPALIVE: break; } return user; }