You've already forked qlg.tsgz.moe
Init Repo
This commit is contained in:
365
vendor/swoole/src/protocol/Base.c
vendored
Executable file
365
vendor/swoole/src/protocol/Base.c
vendored
Executable file
@ -0,0 +1,365 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| Swoole |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 2012-2017 The Swoole Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 2.0 of the Apache license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.apache.org/licenses/LICENSE-2.0.html |
|
||||
| If you did not receive a copy of the Apache2.0 license and are unable|
|
||||
| to obtain it through the world-wide-web, please send a note to |
|
||||
| license@swoole.com so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Author: Tianfeng Han <mikan.tenny@gmail.com> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#include "swoole.h"
|
||||
#include "Connection.h"
|
||||
|
||||
/**
|
||||
* return the package total length
|
||||
*/
|
||||
int swProtocol_get_package_length(swProtocol *protocol, swConnection *conn, char *data, uint32_t size)
|
||||
{
|
||||
uint16_t length_offset = protocol->package_length_offset;
|
||||
int32_t body_length;
|
||||
/**
|
||||
* no have length field, wait more data
|
||||
*/
|
||||
if (size < length_offset + protocol->package_length_size)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
body_length = swoole_unpack(protocol->package_length_type, data + length_offset);
|
||||
//Length error
|
||||
//Protocol length is not legitimate, out of bounds or exceed the allocated length
|
||||
if (body_length < 0)
|
||||
{
|
||||
swWarn("invalid package, remote_addr=%s:%d, length=%d, size=%d.", swConnection_get_ip(conn), swConnection_get_port(conn), body_length, size);
|
||||
return SW_ERR;
|
||||
}
|
||||
//total package length
|
||||
return protocol->package_body_offset + body_length;
|
||||
}
|
||||
|
||||
static sw_inline int swProtocol_split_package_by_eof(swProtocol *protocol, swConnection *conn, swString *buffer)
|
||||
{
|
||||
#if SW_LOG_TRACE_OPEN > 0
|
||||
static int count;
|
||||
count++;
|
||||
#endif
|
||||
|
||||
int eof_pos;
|
||||
if (buffer->length - buffer->offset < protocol->package_eof_len)
|
||||
{
|
||||
eof_pos = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
eof_pos = swoole_strnpos(buffer->str + buffer->offset, buffer->length - buffer->offset, protocol->package_eof, protocol->package_eof_len);
|
||||
}
|
||||
|
||||
swTraceLog(SW_TRACE_EOF_PROTOCOL, "#[0] count=%d, length=%ld, size=%ld, offset=%ld.", count, buffer->length, buffer->size, (long)buffer->offset);
|
||||
|
||||
//waiting for more data
|
||||
if (eof_pos < 0)
|
||||
{
|
||||
buffer->offset = buffer->length - protocol->package_eof_len;
|
||||
return buffer->length;
|
||||
}
|
||||
|
||||
uint32_t length = buffer->offset + eof_pos + protocol->package_eof_len;
|
||||
swTraceLog(SW_TRACE_EOF_PROTOCOL, "#[4] count=%d, length=%d", count, length);
|
||||
if (protocol->onPackage(conn, buffer->str, length) < 0)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
if (conn->removed)
|
||||
{
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
//there are remaining data
|
||||
if (length < buffer->length)
|
||||
{
|
||||
uint32_t remaining_length = buffer->length - length;
|
||||
char *remaining_data = buffer->str + length;
|
||||
swTraceLog(SW_TRACE_EOF_PROTOCOL, "#[5] count=%d, remaining_length=%d", count, remaining_length);
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (remaining_length < protocol->package_eof_len)
|
||||
{
|
||||
goto wait_more_data;
|
||||
}
|
||||
eof_pos = swoole_strnpos(remaining_data, remaining_length, protocol->package_eof, protocol->package_eof_len);
|
||||
if (eof_pos < 0)
|
||||
{
|
||||
wait_more_data:
|
||||
swTraceLog(SW_TRACE_EOF_PROTOCOL, "#[1] count=%d, remaining_length=%d, length=%d", count, remaining_length, length);
|
||||
memmove(buffer->str, remaining_data, remaining_length);
|
||||
buffer->length = remaining_length;
|
||||
buffer->offset = 0;
|
||||
return SW_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
length = eof_pos + protocol->package_eof_len;
|
||||
if (protocol->onPackage(conn, remaining_data, length) < 0)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
if (conn->removed)
|
||||
{
|
||||
return SW_OK;
|
||||
}
|
||||
swTraceLog(SW_TRACE_EOF_PROTOCOL, "#[2] count=%d, remaining_length=%d, length=%d", count, remaining_length, length);
|
||||
remaining_data += length;
|
||||
remaining_length -= length;
|
||||
}
|
||||
}
|
||||
}
|
||||
swTraceLog(SW_TRACE_EOF_PROTOCOL, "#[3] length=%ld, size=%ld, offset=%ld", buffer->length, buffer->size, (long)buffer->offset);
|
||||
swString_clear(buffer);
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return SW_ERR: close the connection
|
||||
* @return SW_OK: continue
|
||||
*/
|
||||
int swProtocol_recv_check_length(swProtocol *protocol, swConnection *conn, swString *buffer)
|
||||
{
|
||||
int package_length;
|
||||
uint32_t recv_size;
|
||||
char swap[SW_BUFFER_SIZE_STD];
|
||||
|
||||
if (conn->skip_recv)
|
||||
{
|
||||
conn->skip_recv = 0;
|
||||
goto do_get_length;
|
||||
}
|
||||
|
||||
do_recv:
|
||||
if (conn->active == 0)
|
||||
{
|
||||
return SW_OK;
|
||||
}
|
||||
if (buffer->offset > 0)
|
||||
{
|
||||
recv_size = buffer->offset - buffer->length;
|
||||
}
|
||||
else
|
||||
{
|
||||
recv_size = protocol->package_length_offset + protocol->package_length_size;
|
||||
}
|
||||
|
||||
int n = swConnection_recv(conn, buffer->str + buffer->length, recv_size, 0);
|
||||
if (n < 0)
|
||||
{
|
||||
switch (swConnection_error(errno))
|
||||
{
|
||||
case SW_ERROR:
|
||||
swSysError("recv(%d, %d) failed.", conn->fd, recv_size);
|
||||
return SW_OK;
|
||||
case SW_CLOSE:
|
||||
conn->close_errno = errno;
|
||||
return SW_ERR;
|
||||
default:
|
||||
return SW_OK;
|
||||
}
|
||||
}
|
||||
else if (n == 0)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer->length += n;
|
||||
|
||||
if (conn->recv_wait)
|
||||
{
|
||||
if (buffer->length >= buffer->offset)
|
||||
{
|
||||
do_dispatch:
|
||||
if (protocol->onPackage(conn, buffer->str, buffer->offset) < 0)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
if (conn->removed)
|
||||
{
|
||||
return SW_OK;
|
||||
}
|
||||
conn->recv_wait = 0;
|
||||
|
||||
int remaining_length = buffer->length - buffer->offset;
|
||||
if (remaining_length > 0)
|
||||
{
|
||||
assert(remaining_length < sizeof(swap));
|
||||
memcpy(swap, buffer->str + buffer->offset, remaining_length);
|
||||
memcpy(buffer->str, swap, remaining_length);
|
||||
buffer->offset = 0;
|
||||
buffer->length = remaining_length;
|
||||
goto do_get_length;
|
||||
}
|
||||
else
|
||||
{
|
||||
swString_clear(buffer);
|
||||
goto do_recv;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return SW_OK;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
do_get_length: package_length = protocol->get_package_length(protocol, conn, buffer->str, buffer->length);
|
||||
//invalid package, close connection.
|
||||
if (package_length < 0)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
//no length
|
||||
else if (package_length == 0)
|
||||
{
|
||||
return SW_OK;
|
||||
}
|
||||
else if (package_length > protocol->package_max_length)
|
||||
{
|
||||
swWarn("package is too big, remote_addr=%s:%d, length=%d.", swConnection_get_ip(conn), swConnection_get_port(conn), package_length);
|
||||
return SW_ERR;
|
||||
}
|
||||
//get length success
|
||||
else
|
||||
{
|
||||
if (buffer->size < package_length)
|
||||
{
|
||||
if (swString_extend(buffer, package_length) < 0)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
}
|
||||
conn->recv_wait = 1;
|
||||
buffer->offset = package_length;
|
||||
|
||||
if (buffer->length >= package_length)
|
||||
{
|
||||
goto do_dispatch;
|
||||
}
|
||||
else
|
||||
{
|
||||
goto do_recv;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return SW_ERR: close the connection
|
||||
* @return SW_OK: continue
|
||||
*/
|
||||
int swProtocol_recv_check_eof(swProtocol *protocol, swConnection *conn, swString *buffer)
|
||||
{
|
||||
int recv_again = SW_FALSE;
|
||||
int buf_size;
|
||||
|
||||
recv_data: buf_size = buffer->size - buffer->length;
|
||||
char *buf_ptr = buffer->str + buffer->length;
|
||||
|
||||
if (buf_size > SW_BUFFER_SIZE_STD)
|
||||
{
|
||||
buf_size = SW_BUFFER_SIZE_STD;
|
||||
}
|
||||
|
||||
int n = swConnection_recv(conn, buf_ptr, buf_size, 0);
|
||||
if (n < 0)
|
||||
{
|
||||
switch (swConnection_error(errno))
|
||||
{
|
||||
case SW_ERROR:
|
||||
swSysError("recv from socket#%d failed.", conn->fd);
|
||||
return SW_OK;
|
||||
case SW_CLOSE:
|
||||
conn->close_errno = errno;
|
||||
return SW_ERR;
|
||||
default:
|
||||
return SW_OK;
|
||||
}
|
||||
}
|
||||
else if (n == 0)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer->length += n;
|
||||
|
||||
if (buffer->length < protocol->package_eof_len)
|
||||
{
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
if (protocol->split_by_eof)
|
||||
{
|
||||
if (swProtocol_split_package_by_eof(protocol, conn, buffer) == 0)
|
||||
{
|
||||
return SW_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
recv_again = SW_TRUE;
|
||||
}
|
||||
}
|
||||
else if (memcmp(buffer->str + buffer->length - protocol->package_eof_len, protocol->package_eof, protocol->package_eof_len) == 0)
|
||||
{
|
||||
if (protocol->onPackage(conn, buffer->str, buffer->length) < 0)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
if (conn->removed)
|
||||
{
|
||||
return SW_OK;
|
||||
}
|
||||
swString_clear(buffer);
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
//over max length, will discard
|
||||
if (buffer->length == protocol->package_max_length)
|
||||
{
|
||||
swWarn("Package is too big. package_length=%d", (int )buffer->length);
|
||||
return SW_ERR;
|
||||
}
|
||||
|
||||
//buffer is full, may have not read data
|
||||
if (buffer->length == buffer->size)
|
||||
{
|
||||
recv_again = SW_TRUE;
|
||||
if (buffer->size < protocol->package_max_length)
|
||||
{
|
||||
uint32_t extend_size = swoole_size_align(buffer->size * 2, SwooleG.pagesize);
|
||||
if (extend_size > protocol->package_max_length)
|
||||
{
|
||||
extend_size = protocol->package_max_length;
|
||||
}
|
||||
if (swString_extend(buffer, extend_size) < 0)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
}
|
||||
}
|
||||
//no eof
|
||||
if (recv_again)
|
||||
{
|
||||
goto recv_data;
|
||||
}
|
||||
}
|
||||
return SW_OK;
|
||||
}
|
133
vendor/swoole/src/protocol/Base64.c
vendored
Executable file
133
vendor/swoole/src/protocol/Base64.c
vendored
Executable file
@ -0,0 +1,133 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| Swoole |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 2012-2017 The Swoole Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 2.0 of the Apache license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.apache.org/licenses/LICENSE-2.0.html |
|
||||
| If you did not receive a copy of the Apache2.0 license and are unable|
|
||||
| to obtain it through the world-wide-web, please send a note to |
|
||||
| license@swoole.com so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Author: Tianfeng Han <mikan.tenny@gmail.com> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "base64.h"
|
||||
|
||||
/* BASE 64 encode table */
|
||||
static char base64en[] =
|
||||
{ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
|
||||
'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
|
||||
't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/', };
|
||||
|
||||
#define BASE64_PAD '='
|
||||
#define BASE64DE_FIRST '+'
|
||||
#define BASE64DE_LAST 'z'
|
||||
|
||||
/* ASCII order for BASE 64 decode, -1 in unused character */
|
||||
static signed char base64de[] = {
|
||||
/* '+', ',', '-', '.', '/', '0', '1', '2', */
|
||||
62, -1, -1, -1, 63, 52, 53, 54,
|
||||
/* '3', '4', '5', '6', '7', '8', '9', ':', */
|
||||
55, 56, 57, 58, 59, 60, 61, -1,
|
||||
/* ';', '<', '=', '>', '?', '@', 'A', 'B', */
|
||||
-1, -1, -1, -1, -1, -1, 0, 1,
|
||||
/* 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', */
|
||||
2, 3, 4, 5, 6, 7, 8, 9,
|
||||
/* 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', */
|
||||
10, 11, 12, 13, 14, 15, 16, 17,
|
||||
/* 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', */
|
||||
18, 19, 20, 21, 22, 23, 24, 25,
|
||||
/* '[', '\', ']', '^', '_', '`', 'a', 'b', */
|
||||
-1, -1, -1, -1, -1, -1, 26, 27,
|
||||
/* 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', */
|
||||
28, 29, 30, 31, 32, 33, 34, 35,
|
||||
/* 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', */
|
||||
36, 37, 38, 39, 40, 41, 42, 43,
|
||||
/* 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', */
|
||||
44, 45, 46, 47, 48, 49, 50, 51,
|
||||
};
|
||||
|
||||
int swBase64_encode(unsigned char *in, int inlen, char *out)
|
||||
{
|
||||
int i, j;
|
||||
for (i = j = 0; i < inlen; i++)
|
||||
{
|
||||
int s = i % 3; /* from 6/gcd(6, 8) */
|
||||
switch (s)
|
||||
{
|
||||
case 0:
|
||||
out[j++] = base64en[(in[i] >> 2) & 0x3F];
|
||||
continue;
|
||||
case 1:
|
||||
out[j++] = base64en[((in[i - 1] & 0x3) << 4) + ((in[i] >> 4) & 0xF)];
|
||||
continue;
|
||||
case 2:
|
||||
out[j++] = base64en[((in[i - 1] & 0xF) << 2) + ((in[i] >> 6) & 0x3)];
|
||||
out[j++] = base64en[in[i] & 0x3F];
|
||||
}
|
||||
}
|
||||
/* move back */
|
||||
i -= 1;
|
||||
/* check the last and add padding */
|
||||
if ((i % 3) == 0)
|
||||
{
|
||||
out[j++] = base64en[(in[i] & 0x3) << 4];
|
||||
out[j++] = BASE64_PAD;
|
||||
out[j++] = BASE64_PAD;
|
||||
}
|
||||
else if ((i % 3) == 1)
|
||||
{
|
||||
out[j++] = base64en[(in[i] & 0xF) << 2];
|
||||
out[j++] = BASE64_PAD;
|
||||
}
|
||||
return BASE64_OK;
|
||||
}
|
||||
|
||||
int swBase64_decode(char *in, int inlen, unsigned char *out)
|
||||
{
|
||||
int i, j;
|
||||
for (i = j = 0; i < inlen; i++)
|
||||
{
|
||||
int c;
|
||||
int s = i % 4; /* from 8/gcd(6, 8) */
|
||||
|
||||
if (in[i] == '=')
|
||||
{
|
||||
return BASE64_OK;
|
||||
}
|
||||
|
||||
if (in[i] < BASE64DE_FIRST || in[i] > BASE64DE_LAST || (c = base64de[in[i] - BASE64DE_FIRST]) == -1)
|
||||
{
|
||||
return BASE64_INVALID;
|
||||
}
|
||||
|
||||
switch (s)
|
||||
{
|
||||
case 0:
|
||||
out[j] = c << 2;
|
||||
continue;
|
||||
case 1:
|
||||
out[j++] += (c >> 4) & 0x3;
|
||||
/* if not last char with padding */
|
||||
if (i < (inlen - 3) || in[inlen - 2] != '=')
|
||||
out[j] = (c & 0xF) << 4;
|
||||
continue;
|
||||
case 2:
|
||||
out[j++] += (c >> 2) & 0xF;
|
||||
/* if not last char with padding */
|
||||
if (i < (inlen - 2) || in[inlen - 1] != '=')
|
||||
out[j] = (c & 0x3) << 6;
|
||||
continue;
|
||||
case 3:
|
||||
out[j++] += c;
|
||||
}
|
||||
}
|
||||
return BASE64_OK;
|
||||
}
|
302
vendor/swoole/src/protocol/Http.c
vendored
Executable file
302
vendor/swoole/src/protocol/Http.c
vendored
Executable file
@ -0,0 +1,302 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| Swoole |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 2.0 of the Apache license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.apache.org/licenses/LICENSE-2.0.html |
|
||||
| If you did not receive a copy of the Apache2.0 license and are unable|
|
||||
| to obtain it through the world-wide-web, please send a note to |
|
||||
| license@swoole.com so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Author: Tianfeng Han <mikan.tenny@gmail.com> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
#include "swoole.h"
|
||||
#include "http.h"
|
||||
#include "http2.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
|
||||
static const char *method_strings[] =
|
||||
{
|
||||
"DELETE", "GET", "HEAD", "POST", "PUT", "PATCH", "CONNECT", "OPTIONS", "TRACE", "COPY", "LOCK", "MKCOL", "MOVE",
|
||||
"PROPFIND", "PROPPATCH", "UNLOCK", "REPORT", "MKACTIVITY", "CHECKOUT", "MERGE", "M-SEARCH", "NOTIFY",
|
||||
"SUBSCRIBE", "UNSUBSCRIBE", "PRI",
|
||||
};
|
||||
|
||||
int swHttp_get_method(const char *method_str, int method_len)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < HTTP_PRI; i++)
|
||||
{
|
||||
if (strncasecmp(method_strings[i], method_str, method_len) == 0)
|
||||
{
|
||||
return i + 1;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
const char* swHttp_get_method_string(int method)
|
||||
{
|
||||
if (method < 0 || method > HTTP_PRI)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
return method_strings[method - 1];
|
||||
}
|
||||
|
||||
/**
|
||||
* only GET/POST
|
||||
*/
|
||||
int swHttpRequest_get_protocol(swHttpRequest *request)
|
||||
{
|
||||
char *buf = request->buffer->str;
|
||||
char *pe = buf + request->buffer->length;
|
||||
|
||||
if (request->buffer->length < 16)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
|
||||
//http method
|
||||
if (memcmp(buf, "GET", 3) == 0)
|
||||
{
|
||||
request->method = HTTP_GET;
|
||||
request->offset = 4;
|
||||
buf += 4;
|
||||
}
|
||||
else if (memcmp(buf, "POST", 4) == 0)
|
||||
{
|
||||
request->method = HTTP_POST;
|
||||
request->offset = 5;
|
||||
buf += 5;
|
||||
}
|
||||
else if (memcmp(buf, "PUT", 3) == 0)
|
||||
{
|
||||
request->method = HTTP_PUT;
|
||||
request->offset = 4;
|
||||
buf += 4;
|
||||
}
|
||||
else if (memcmp(buf, "PATCH", 5) == 0)
|
||||
{
|
||||
request->method = HTTP_PATCH;
|
||||
request->offset = 6;
|
||||
buf += 6;
|
||||
}
|
||||
else if (memcmp(buf, "DELETE", 6) == 0)
|
||||
{
|
||||
request->method = HTTP_DELETE;
|
||||
request->offset = 7;
|
||||
buf += 7;
|
||||
}
|
||||
else if (memcmp(buf, "HEAD", 4) == 0)
|
||||
{
|
||||
request->method = HTTP_HEAD;
|
||||
request->offset = 5;
|
||||
buf += 5;
|
||||
}
|
||||
else if (memcmp(buf, "OPTIONS", 7) == 0)
|
||||
{
|
||||
request->method = HTTP_OPTIONS;
|
||||
request->offset = 8;
|
||||
buf += 8;
|
||||
}
|
||||
#ifdef SW_USE_HTTP2
|
||||
//HTTP2 Connection Preface
|
||||
else if (memcmp(buf, "PRI", 3) == 0)
|
||||
{
|
||||
request->method = HTTP_PRI;
|
||||
if (memcmp(buf, SW_HTTP2_PRI_STRING, sizeof(SW_HTTP2_PRI_STRING) - 1) == 0)
|
||||
{
|
||||
request->buffer->offset = sizeof(SW_HTTP2_PRI_STRING) - 1;
|
||||
return SW_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
goto _excepted;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
_excepted: request->excepted = 1;
|
||||
return SW_ERR;
|
||||
}
|
||||
|
||||
//http version
|
||||
char *p;
|
||||
char state = 0;
|
||||
for (p = buf; p < pe; p++)
|
||||
{
|
||||
switch(state)
|
||||
{
|
||||
case 0:
|
||||
if (isspace(*p))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
state = 1;
|
||||
request->url_offset = p - request->buffer->str;
|
||||
break;
|
||||
case 1:
|
||||
if (isspace(*p))
|
||||
{
|
||||
state = 2;
|
||||
request->url_length = p - request->buffer->str - request->url_offset;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (isspace(*p))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (pe - p < 8)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
if (memcmp(p, "HTTP/1.1", 8) == 0)
|
||||
{
|
||||
request->version = HTTP_VERSION_11;
|
||||
goto end;
|
||||
}
|
||||
else if (memcmp(p, "HTTP/1.0", 8) == 0)
|
||||
{
|
||||
request->version = HTTP_VERSION_10;
|
||||
goto end;
|
||||
}
|
||||
else
|
||||
{
|
||||
goto _excepted;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
end: p += 8;
|
||||
request->buffer->offset = p - request->buffer->str;
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
void swHttpRequest_free(swConnection *conn)
|
||||
{
|
||||
swHttpRequest *request = conn->object;
|
||||
if (!request)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (request->buffer)
|
||||
{
|
||||
swString_free(request->buffer);
|
||||
}
|
||||
bzero(request, sizeof(swHttpRequest));
|
||||
sw_free(request);
|
||||
conn->object = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* POST content-length
|
||||
*/
|
||||
int swHttpRequest_get_content_length(swHttpRequest *request)
|
||||
{
|
||||
swString *buffer = request->buffer;
|
||||
char *buf = buffer->str + buffer->offset;
|
||||
int len = buffer->length - buffer->offset;
|
||||
|
||||
char *pe = buf + len;
|
||||
char *p;
|
||||
char *eol;
|
||||
|
||||
for (p = buf; p < pe; p++)
|
||||
{
|
||||
if (*p == '\r' && pe - p > sizeof("Content-Length"))
|
||||
{
|
||||
if (strncasecmp(p, SW_STRL("\r\nContent-Length") - 1) == 0)
|
||||
{
|
||||
//strlen("\r\n") + strlen("Content-Length")
|
||||
p += (2 + (sizeof("Content-Length:") - 1));
|
||||
//skip space
|
||||
if (*p == ' ')
|
||||
{
|
||||
p++;
|
||||
}
|
||||
eol = strstr(p, "\r\n");
|
||||
if (eol == NULL)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
request->content_length = atoi(p);
|
||||
return SW_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return SW_ERR;
|
||||
}
|
||||
|
||||
#ifdef SW_HTTP_100_CONTINUE
|
||||
int swHttpRequest_has_expect_header(swHttpRequest *request)
|
||||
{
|
||||
swString *buffer = request->buffer;
|
||||
//char *buf = buffer->str + buffer->offset;
|
||||
char *buf = buffer->str;
|
||||
//int len = buffer->length - buffer->offset;
|
||||
int len = buffer->length;
|
||||
|
||||
char *pe = buf + len;
|
||||
char *p;
|
||||
|
||||
for (p = buf; p < pe; p++)
|
||||
{
|
||||
if (*p == '\r' && pe - p > sizeof("\r\nExpect"))
|
||||
{
|
||||
p += 2;
|
||||
if (strncasecmp(p, SW_STRL("Expect") - 1) == 0)
|
||||
{
|
||||
p += sizeof("Expect: ") - 1;
|
||||
if (strncasecmp(p, SW_STRL("100-continue") - 1) == 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
p++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* header-length
|
||||
*/
|
||||
int swHttpRequest_get_header_length(swHttpRequest *request)
|
||||
{
|
||||
swString *buffer = request->buffer;
|
||||
char *buf = buffer->str + buffer->offset;
|
||||
int len = buffer->length - buffer->offset;
|
||||
|
||||
char *pe = buf + len;
|
||||
char *p;
|
||||
|
||||
for (p = buf; p < pe; p++)
|
||||
{
|
||||
if (*p == '\r' && p + 4 <= pe && memcmp(p, "\r\n\r\n", 4) == 0)
|
||||
{
|
||||
//strlen(header) + strlen("\r\n\r\n")
|
||||
request->header_length = p - buffer->str + 4;
|
||||
return SW_OK;
|
||||
}
|
||||
}
|
||||
return SW_ERR;
|
||||
}
|
142
vendor/swoole/src/protocol/Http2.c
vendored
Executable file
142
vendor/swoole/src/protocol/Http2.c
vendored
Executable file
@ -0,0 +1,142 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| Swoole |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 2012-2017 The Swoole Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 2.0 of the Apache license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.apache.org/licenses/LICENSE-2.0.html |
|
||||
| If you did not receive a copy of the Apache2.0 license and are unable|
|
||||
| to obtain it through the world-wide-web, please send a note to |
|
||||
| license@swoole.com so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Author: Tianfeng Han <mikan.tenny@gmail.com> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#include "swoole.h"
|
||||
#include "Connection.h"
|
||||
#include "http2.h"
|
||||
|
||||
int swHttp2_parse_frame(swProtocol *protocol, swConnection *conn, char *data, uint32_t length)
|
||||
{
|
||||
int wait_body = 0;
|
||||
int package_length = 0;
|
||||
|
||||
while (length > 0)
|
||||
{
|
||||
if (wait_body)
|
||||
{
|
||||
if (length >= package_length)
|
||||
{
|
||||
protocol->onPackage(conn, data, package_length);
|
||||
wait_body = 0;
|
||||
data += package_length;
|
||||
length -= package_length;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
package_length = protocol->get_package_length(protocol, conn, data, length);
|
||||
if (package_length < 0)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
else if (package_length == 0)
|
||||
{
|
||||
return SW_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
wait_body = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
int swHttp2_send_setting_frame(swProtocol *protocol, swConnection *conn)
|
||||
{
|
||||
char setting_frame[SW_HTTP2_FRAME_HEADER_SIZE + SW_HTTP2_SETTING_OPTION_SIZE * 3];
|
||||
char *p = setting_frame;
|
||||
uint16_t id;
|
||||
uint32_t value;
|
||||
|
||||
swHttp2_set_frame_header(p, SW_HTTP2_TYPE_SETTINGS, SW_HTTP2_SETTING_OPTION_SIZE * 3, 0, 0);
|
||||
p += SW_HTTP2_FRAME_HEADER_SIZE;
|
||||
|
||||
id = htons(SW_HTTP2_SETTINGS_MAX_CONCURRENT_STREAMS);
|
||||
memcpy(p, &id, sizeof(id));
|
||||
value = htonl(SW_HTTP2_MAX_CONCURRENT_STREAMS);
|
||||
memcpy(p + 2, &value, sizeof(value));
|
||||
p += SW_HTTP2_SETTING_OPTION_SIZE;
|
||||
|
||||
id = htons(SW_HTTP2_SETTINGS_INIT_WINDOW_SIZE);
|
||||
memcpy(p, &id, sizeof(id));
|
||||
value = htonl(SW_HTTP2_MAX_WINDOW);
|
||||
memcpy(p + 2, &value, sizeof(value));
|
||||
p += SW_HTTP2_SETTING_OPTION_SIZE;
|
||||
|
||||
id = htons(SW_HTTP2_SETTINGS_MAX_FRAME_SIZE);
|
||||
memcpy(p, &id, sizeof(id));
|
||||
value = htonl(SW_HTTP2_MAX_FRAME_SIZE);
|
||||
memcpy(p + 2, &value, sizeof(value));
|
||||
|
||||
return swConnection_send(conn, setting_frame, sizeof(setting_frame), 0);
|
||||
}
|
||||
|
||||
/**
|
||||
+-----------------------------------------------+
|
||||
| Length (24) |
|
||||
+---------------+---------------+---------------+
|
||||
| Type (8) | Flags (8) |
|
||||
+-+-------------+---------------+-------------------------------+
|
||||
|R| Stream Identifier (31) |
|
||||
+=+=============================================================+
|
||||
| Frame Payload (0...) ...
|
||||
+---------------------------------------------------------------+
|
||||
*/
|
||||
int swHttp2_get_frame_length(swProtocol *protocol, swConnection *conn, char *buf, uint32_t length)
|
||||
{
|
||||
if (length < SW_HTTP2_FRAME_HEADER_SIZE)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return swHttp2_get_length(buf) + SW_HTTP2_FRAME_HEADER_SIZE;
|
||||
}
|
||||
|
||||
char* swHttp2_get_type(int type)
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case SW_HTTP2_TYPE_DATA:
|
||||
return "DATA";
|
||||
case SW_HTTP2_TYPE_HEADERS:
|
||||
return "HEADERS";
|
||||
case SW_HTTP2_TYPE_PRIORITY:
|
||||
return "PRIORITY";
|
||||
case SW_HTTP2_TYPE_RST_STREAM:
|
||||
return "RST_STREAM";
|
||||
case SW_HTTP2_TYPE_SETTINGS:
|
||||
return "SETTINGS";
|
||||
case SW_HTTP2_TYPE_PUSH_PROMISE:
|
||||
return "PUSH_PROMISE";
|
||||
case SW_HTTP2_TYPE_PING:
|
||||
return "PING";
|
||||
case SW_HTTP2_TYPE_GOAWAY:
|
||||
return "GOAWAY";
|
||||
case SW_HTTP2_TYPE_WINDOW_UPDATE:
|
||||
return "WINDOW_UPDATE";
|
||||
case SW_HTTP2_TYPE_CONTINUATION:
|
||||
return "CONTINUATION";
|
||||
default:
|
||||
return "UNKOWN";
|
||||
}
|
||||
}
|
131
vendor/swoole/src/protocol/MimeTypes.c
vendored
Executable file
131
vendor/swoole/src/protocol/MimeTypes.c
vendored
Executable file
@ -0,0 +1,131 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| Swoole |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 2012-2015 The Swoole Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 2.0 of the Apache license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.apache.org/licenses/LICENSE-2.0.html |
|
||||
| If you did not receive a copy of the Apache2.0 license and are unable|
|
||||
| to obtain it through the world-wide-web, please send a note to |
|
||||
| license@swoole.com so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Author: Tianfeng Han <mikan.tenny@gmail.com> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#include "swoole.h"
|
||||
|
||||
char* swoole_get_mimetype(char *file)
|
||||
{
|
||||
char *dot;
|
||||
dot = strrchr(file, '.');
|
||||
if (dot == NULL)
|
||||
{
|
||||
return "text/plain";
|
||||
}
|
||||
if (strcasecmp(dot, ".html") == 0 || strcasecmp(dot, ".htm") == 0)
|
||||
{
|
||||
return "text/html";
|
||||
}
|
||||
else if (strcasecmp(dot, ".xml") == 0)
|
||||
{
|
||||
return "text/xml";
|
||||
}
|
||||
else if (strcasecmp(dot, ".css") == 0)
|
||||
{
|
||||
return "text/css";
|
||||
}
|
||||
else if (strcasecmp(dot, ".text") == 0 || strcasecmp(dot, ".txt") == 0)
|
||||
{
|
||||
return "text/plain";
|
||||
}
|
||||
else if (strcasecmp(dot, ".jpeg") == 0 || strcasecmp(dot, ".jpg") == 0)
|
||||
{
|
||||
return "image/jpeg";
|
||||
}
|
||||
else if (strcasecmp(dot, ".png") == 0)
|
||||
{
|
||||
return "image/png";
|
||||
}
|
||||
else if (strcasecmp(dot, ".gif") == 0)
|
||||
{
|
||||
return "image/gif";
|
||||
}
|
||||
else if (strcasecmp(dot, ".json") == 0)
|
||||
{
|
||||
return "application/json";
|
||||
}
|
||||
else if (strcasecmp(dot, ".js") == 0)
|
||||
{
|
||||
return "application/javascript";
|
||||
}
|
||||
else if (strcasecmp(dot, ".pdf") == 0)
|
||||
{
|
||||
return "application/pdf";
|
||||
}
|
||||
else if (strcasecmp(dot, ".doc") == 0)
|
||||
{
|
||||
return "application/msword";
|
||||
}
|
||||
else if (strcasecmp(dot, ".xls") == 0)
|
||||
{
|
||||
return "application/vnd.ms-excel";
|
||||
}
|
||||
else if (strcasecmp(dot, ".ppt") == 0)
|
||||
{
|
||||
return "application/vnd.ms-powerpoint";
|
||||
}
|
||||
else if (strcasecmp(dot, ".docx") == 0)
|
||||
{
|
||||
return "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
|
||||
}
|
||||
else if (strcasecmp(dot, ".xlsx") == 0)
|
||||
{
|
||||
return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
|
||||
}
|
||||
else if (strcasecmp(dot, ".pptx") == 0)
|
||||
{
|
||||
return "application/vnd.openxmlformats-officedocument.presentationml.presentation";
|
||||
}
|
||||
else if (strcasecmp(dot, ".swf") == 0)
|
||||
{
|
||||
return "application/x-shockwave-flash";
|
||||
}
|
||||
else if (strcasecmp(dot, ".zip") == 0)
|
||||
{
|
||||
return "application/zip";
|
||||
}
|
||||
else if (strcasecmp(dot, ".mp3") == 0)
|
||||
{
|
||||
return "audio/mpeg";
|
||||
}
|
||||
else if (strcasecmp(dot, ".mp4") == 0)
|
||||
{
|
||||
return "video/mp4";
|
||||
}
|
||||
else if (strcasecmp(dot, ".mpeg") == 0 || strcasecmp(dot, ".mpg") == 0)
|
||||
{
|
||||
return "video/mpeg";
|
||||
}
|
||||
else if (strcasecmp(dot, ".mov") == 0)
|
||||
{
|
||||
return "video/quicktime";
|
||||
}
|
||||
else if (strcasecmp(dot, ".flv") == 0)
|
||||
{
|
||||
return "video/x-flv";
|
||||
}
|
||||
else if (strcasecmp(dot, ".wmv") == 0)
|
||||
{
|
||||
return "video/x-ms-wmv";
|
||||
}
|
||||
else if (strcasecmp(dot, ".avi") == 0)
|
||||
{
|
||||
return "video/x-msvideo";
|
||||
}
|
||||
return "application/octet-stream";
|
||||
}
|
||||
|
70
vendor/swoole/src/protocol/Mqtt.c
vendored
Executable file
70
vendor/swoole/src/protocol/Mqtt.c
vendored
Executable file
@ -0,0 +1,70 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| Swoole |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 2012-2015 The Swoole Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 2.0 of the Apache license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.apache.org/licenses/LICENSE-2.0.html |
|
||||
| If you did not receive a copy of the Apache2.0 license and are unable|
|
||||
| to obtain it through the world-wide-web, please send a note to |
|
||||
| license@swoole.com so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Author: Tianfeng Han <mikan.tenny@gmail.com> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#include "mqtt.h"
|
||||
|
||||
void swMqtt_print_package(swMqtt_package *pkg)
|
||||
{
|
||||
printf("type=%d, length=%d\n", pkg->type, pkg->length);
|
||||
}
|
||||
|
||||
static sw_inline int swMqtt_get_length(char *data, uint32_t size, int *count)
|
||||
{
|
||||
uint8_t byte;
|
||||
int mul = 1;
|
||||
int length = 0;
|
||||
|
||||
*count = 0;
|
||||
do
|
||||
{
|
||||
byte = data[*count + 1];
|
||||
length += (byte & 127) * mul;
|
||||
mul *= 128;
|
||||
(*count)++;
|
||||
} while ((byte & 128) != 0);
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
//int swMqtt_unpack(swMqtt_package *pkg, char *data, uint32_t size)
|
||||
//{
|
||||
// uint8_t byte = data[0];
|
||||
// off_t offset;
|
||||
//
|
||||
// pkg->type = (byte & 0xF0) >> 4;
|
||||
// pkg->dup = (byte & 0x08) >> 3;
|
||||
// pkg->qos = (byte & 0x06) >> 1;
|
||||
// pkg->retain = byte & 0x01;
|
||||
//
|
||||
// offset += 1;
|
||||
//
|
||||
// int count = 0;
|
||||
// pkg->length = swMqtt_get_length(data, size, &count);
|
||||
// offset += count + 1;
|
||||
//}
|
||||
|
||||
int swMqtt_get_package_length(swProtocol *protocol, swConnection *conn, char *data, uint32_t size)
|
||||
{
|
||||
if (size < SW_MQTT_MIN_LENGTH)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
int count = 0;
|
||||
int length = swMqtt_get_length(data, size, &count);
|
||||
return length + count + 1;
|
||||
}
|
182
vendor/swoole/src/protocol/Redis.c
vendored
Executable file
182
vendor/swoole/src/protocol/Redis.c
vendored
Executable file
@ -0,0 +1,182 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| Swoole |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 2012-2015 The Swoole Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 2.0 of the Apache license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.apache.org/licenses/LICENSE-2.0.html |
|
||||
| If you did not receive a copy of the Apache2.0 license and are unable|
|
||||
| to obtain it through the world-wide-web, please send a note to |
|
||||
| license@swoole.com so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Author: Tianfeng Han <mikan.tenny@gmail.com> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#include "swoole.h"
|
||||
#include "redis.h"
|
||||
#include "Connection.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t state;
|
||||
|
||||
int n_lines_total;
|
||||
int n_lines_received;
|
||||
|
||||
int n_bytes_total;
|
||||
int n_bytes_received;
|
||||
|
||||
int offset;
|
||||
|
||||
} swRedis_request;
|
||||
|
||||
int swRedis_recv(swProtocol *protocol, swConnection *conn, swString *buffer)
|
||||
{
|
||||
char *p, *pe;
|
||||
int ret;
|
||||
char *buf_ptr;
|
||||
size_t buf_size;
|
||||
|
||||
swRedis_request *request;
|
||||
|
||||
if (conn->object == NULL)
|
||||
{
|
||||
request = sw_malloc(sizeof(swRedis_request));
|
||||
bzero(request, sizeof(swRedis_request));
|
||||
conn->object = request;
|
||||
}
|
||||
else
|
||||
{
|
||||
request = (swRedis_request *) conn->object;
|
||||
}
|
||||
|
||||
recv_data: buf_ptr = buffer->str + buffer->length;
|
||||
buf_size = buffer->size - buffer->length;
|
||||
|
||||
int n = swConnection_recv(conn, buf_ptr, buf_size, 0);
|
||||
if (n < 0)
|
||||
{
|
||||
switch (swConnection_error(errno))
|
||||
{
|
||||
case SW_ERROR:
|
||||
swSysError("recv from socket#%d failed.", conn->fd);
|
||||
return SW_OK;
|
||||
case SW_CLOSE:
|
||||
conn->close_errno = errno;
|
||||
return SW_ERR;
|
||||
default:
|
||||
return SW_OK;
|
||||
}
|
||||
}
|
||||
else if (n == 0)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer->length += n;
|
||||
|
||||
if (strncmp(buffer->str + buffer->length - SW_CRLF_LEN, SW_CRLF, SW_CRLF_LEN) != 0)
|
||||
{
|
||||
if (buffer->size < protocol->package_max_length)
|
||||
{
|
||||
uint32_t extend_size = swoole_size_align(buffer->size * 2, SwooleG.pagesize);
|
||||
if (extend_size > protocol->package_max_length)
|
||||
{
|
||||
extend_size = protocol->package_max_length;
|
||||
}
|
||||
if (swString_extend(buffer, extend_size) < 0)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
}
|
||||
else if (buffer->length == buffer->size)
|
||||
{
|
||||
package_too_big:
|
||||
swWarn("Package is too big. package_length=%ld.", buffer->length);
|
||||
return SW_ERR;
|
||||
}
|
||||
goto recv_data;
|
||||
}
|
||||
|
||||
p = buffer->str;
|
||||
pe = p + buffer->length;
|
||||
|
||||
do
|
||||
{
|
||||
switch(request->state)
|
||||
{
|
||||
case SW_REDIS_RECEIVE_TOTAL_LINE:
|
||||
if (*p == '*' && (p = swRedis_get_number(p, &ret)))
|
||||
{
|
||||
request->n_lines_total = ret;
|
||||
request->state = SW_REDIS_RECEIVE_LENGTH;
|
||||
break;
|
||||
}
|
||||
/* no break */
|
||||
|
||||
case SW_REDIS_RECEIVE_LENGTH:
|
||||
if (*p == '$' && (p = swRedis_get_number(p, &ret)))
|
||||
{
|
||||
if (ret < 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (ret + (p - buffer->str) > protocol->package_max_length)
|
||||
{
|
||||
goto package_too_big;
|
||||
}
|
||||
request->n_bytes_total = ret;
|
||||
request->state = SW_REDIS_RECEIVE_STRING;
|
||||
break;
|
||||
}
|
||||
//integer
|
||||
else if (*p == ':' && (p = swRedis_get_number(p, &ret)))
|
||||
{
|
||||
break;
|
||||
}
|
||||
/* no break */
|
||||
|
||||
case SW_REDIS_RECEIVE_STRING:
|
||||
if (pe - p < request->n_bytes_total - request->n_bytes_received)
|
||||
{
|
||||
request->n_bytes_received += pe - p;
|
||||
return SW_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
p += request->n_bytes_total + SW_CRLF_LEN;
|
||||
request->n_bytes_total = 0;
|
||||
request->n_lines_received++;
|
||||
request->state = SW_REDIS_RECEIVE_LENGTH;
|
||||
|
||||
if (request->n_lines_received == request->n_lines_total)
|
||||
{
|
||||
if (protocol->onPackage(conn, buffer->str, buffer->length) < 0)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
if (conn->removed)
|
||||
{
|
||||
return SW_OK;
|
||||
}
|
||||
swString_clear(buffer);
|
||||
bzero(request, sizeof(swRedis_request));
|
||||
return SW_OK;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
goto failed;
|
||||
}
|
||||
} while(p < pe);
|
||||
}
|
||||
failed:
|
||||
swWarn("redis protocol error.");
|
||||
return SW_ERR;
|
||||
}
|
1160
vendor/swoole/src/protocol/SSL.c
vendored
Executable file
1160
vendor/swoole/src/protocol/SSL.c
vendored
Executable file
File diff suppressed because it is too large
Load Diff
150
vendor/swoole/src/protocol/Sha1.c
vendored
Executable file
150
vendor/swoole/src/protocol/Sha1.c
vendored
Executable file
@ -0,0 +1,150 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| Swoole |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 2.0 of the Apache license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.apache.org/licenses/LICENSE-2.0.html |
|
||||
| If you did not receive a copy of the Apache2.0 license and are unable|
|
||||
| to obtain it through the world-wide-web, please send a note to |
|
||||
| license@swoole.com so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Author: Tianfeng Han <mikan.tenny@gmail.com> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
#include <string.h>
|
||||
|
||||
#include "sha1.h"
|
||||
|
||||
#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
|
||||
|
||||
/* blk0() and blk() perform the initial expand. */
|
||||
/* I got the idea of expanding during the round function from SSLeay */
|
||||
|
||||
#ifdef LITTLE_ENDIAN
|
||||
#define blk0(i) (block->l[i] = (rol(block->l[i],24)&(sha1_quadbyte)0xFF00FF00) \
|
||||
|(rol(block->l[i],8)&(sha1_quadbyte)0x00FF00FF))
|
||||
#else
|
||||
#define blk0(i) block->l[i]
|
||||
#endif
|
||||
|
||||
#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
|
||||
^block->l[(i+2)&15]^block->l[i&15],1))
|
||||
|
||||
/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
|
||||
#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
|
||||
#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
|
||||
#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
|
||||
#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
|
||||
#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
|
||||
|
||||
typedef union _BYTE64QUAD16 {
|
||||
sha1_byte c[64];
|
||||
sha1_quadbyte l[16];
|
||||
} BYTE64QUAD16;
|
||||
static void swSha1_transform(sha1_quadbyte state[5], sha1_byte buffer[64]);
|
||||
/* Hash a single 512-bit block. This is the core of the algorithm. */
|
||||
static void swSha1_transform(sha1_quadbyte state[5], sha1_byte buffer[64]) {
|
||||
sha1_quadbyte a, b, c, d, e;
|
||||
BYTE64QUAD16 src;
|
||||
BYTE64QUAD16 *block;
|
||||
|
||||
/* slow but cast-align */
|
||||
memcpy(src.c, buffer, sizeof(sha1_byte) * 64);
|
||||
block = &src;
|
||||
/* Copy context->state[] to working vars */
|
||||
a = state[0];
|
||||
b = state[1];
|
||||
c = state[2];
|
||||
d = state[3];
|
||||
e = state[4];
|
||||
/* 4 rounds of 20 operations each. Loop unrolled. */
|
||||
R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
|
||||
R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
|
||||
R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
|
||||
R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
|
||||
R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
|
||||
R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
|
||||
R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
|
||||
R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
|
||||
R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
|
||||
R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
|
||||
R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
|
||||
R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
|
||||
R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
|
||||
R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
|
||||
R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
|
||||
R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
|
||||
R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
|
||||
R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
|
||||
R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
|
||||
R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
|
||||
/* Add the working vars back into context.state[] */
|
||||
state[0] += a;
|
||||
state[1] += b;
|
||||
state[2] += c;
|
||||
state[3] += d;
|
||||
state[4] += e;
|
||||
/* Wipe variables */
|
||||
a = b = c = d = e = 0;
|
||||
}
|
||||
|
||||
|
||||
/* swSha1_init - Initialize new context */
|
||||
void swSha1_init(SHA_CTX* context) {
|
||||
/* SHA1 initialization constants */
|
||||
context->state[0] = 0x67452301;
|
||||
context->state[1] = 0xEFCDAB89;
|
||||
context->state[2] = 0x98BADCFE;
|
||||
context->state[3] = 0x10325476;
|
||||
context->state[4] = 0xC3D2E1F0;
|
||||
context->count[0] = context->count[1] = 0;
|
||||
}
|
||||
|
||||
/* Run your data through this. */
|
||||
void swSha1_update(SHA_CTX *context, sha1_byte *data, unsigned int len) {
|
||||
unsigned int i, j;
|
||||
|
||||
j = (context->count[0] >> 3) & 63;
|
||||
if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++;
|
||||
context->count[1] += (len >> 29);
|
||||
if ((j + len) > 63) {
|
||||
memcpy(&context->buffer[j], data, (i = 64-j));
|
||||
swSha1_transform(context->state, context->buffer);
|
||||
for ( ; i + 63 < len; i += 64) {
|
||||
swSha1_transform(context->state, &data[i]);
|
||||
}
|
||||
j = 0;
|
||||
}
|
||||
else i = 0;
|
||||
memcpy(&context->buffer[j], &data[i], len - i);
|
||||
}
|
||||
|
||||
|
||||
/* Add padding and return the message digest. */
|
||||
void swSha1_final(sha1_byte digest[SHA1_DIGEST_LENGTH], SHA_CTX *context) {
|
||||
sha1_quadbyte i, j;
|
||||
sha1_byte finalcount[8];
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
finalcount[i] = (sha1_byte)((context->count[(i >= 4 ? 0 : 1)]
|
||||
>> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */
|
||||
}
|
||||
swSha1_update(context, (sha1_byte *)"\200", 1);
|
||||
while ((context->count[0] & 504) != 448) {
|
||||
swSha1_update(context, (sha1_byte *)"\0", 1);
|
||||
}
|
||||
/* Should cause a swSha1_Transform() */
|
||||
swSha1_update(context, finalcount, 8);
|
||||
for (i = 0; i < SHA1_DIGEST_LENGTH; i++) {
|
||||
digest[i] = (sha1_byte)
|
||||
((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
|
||||
}
|
||||
/* Wipe variables */
|
||||
i = j = 0;
|
||||
memset(context->buffer, 0, SHA1_BLOCK_LENGTH);
|
||||
memset(context->state, 0, SHA1_DIGEST_LENGTH);
|
||||
memset(context->count, 0, 8);
|
||||
memset(&finalcount, 0, 8);
|
||||
}
|
154
vendor/swoole/src/protocol/Socks5.c
vendored
Executable file
154
vendor/swoole/src/protocol/Socks5.c
vendored
Executable file
@ -0,0 +1,154 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| Swoole |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 2012-2017 The Swoole Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 2.0 of the Apache license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.apache.org/licenses/LICENSE-2.0.html |
|
||||
| If you did not receive a copy of the Apache2.0 license and are unable|
|
||||
| to obtain it through the world-wide-web, please send a note to |
|
||||
| license@swoole.com so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Author: Tianfeng Han <mikan.tenny@gmail.com> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#include "swoole.h"
|
||||
#include "Client.h"
|
||||
#include "socks5.h"
|
||||
|
||||
char* swSocks5_strerror(int code)
|
||||
{
|
||||
switch (code)
|
||||
{
|
||||
case 0x01:
|
||||
return "General failure";
|
||||
case 0x02:
|
||||
return "Connection not allowed by ruleset";
|
||||
case 0x03:
|
||||
return "Network unreachable";
|
||||
case 0x04:
|
||||
return "Host unreachable";
|
||||
case 0x05:
|
||||
return "Connection refused by destination host";
|
||||
case 0x06:
|
||||
return "TTL expired";
|
||||
case 0x07:
|
||||
return "command not supported / protocol error";
|
||||
case 0x08:
|
||||
return "address type not supported";
|
||||
default:
|
||||
return "Unknown error";
|
||||
}
|
||||
}
|
||||
|
||||
int swSocks5_connect(swClient *cli, char *recv_data, int length)
|
||||
{
|
||||
swSocks5 *ctx = cli->socks5_proxy;
|
||||
char *buf = ctx->buf;
|
||||
|
||||
if (ctx->state == SW_SOCKS5_STATE_HANDSHAKE)
|
||||
{
|
||||
uchar version = recv_data[0];
|
||||
uchar method = recv_data[1];
|
||||
if (version != SW_SOCKS5_VERSION_CODE)
|
||||
{
|
||||
swoole_error_log(SW_LOG_NOTICE, SW_ERROR_SOCKS5_UNSUPPORT_VERSION, "SOCKS version is not supported.");
|
||||
return SW_ERR;
|
||||
}
|
||||
if (method != ctx->method)
|
||||
{
|
||||
swoole_error_log(SW_LOG_NOTICE, SW_ERROR_SOCKS5_UNSUPPORT_METHOD, "SOCKS authentication method not supported.");
|
||||
return SW_ERR;
|
||||
}
|
||||
//authenticate request
|
||||
if (method == SW_SOCKS5_METHOD_AUTH)
|
||||
{
|
||||
buf[0] = 0x01;
|
||||
buf[1] = ctx->l_username;
|
||||
|
||||
buf += 2;
|
||||
memcpy(buf, ctx->username, ctx->l_username);
|
||||
buf += ctx->l_username;
|
||||
buf[0] = ctx->l_password;
|
||||
memcpy(buf + 1, ctx->password, ctx->l_password);
|
||||
|
||||
ctx->state = SW_SOCKS5_STATE_AUTH;
|
||||
|
||||
return cli->send(cli, ctx->buf, ctx->l_username + ctx->l_password + 3, 0);
|
||||
}
|
||||
//send connect request
|
||||
else
|
||||
{
|
||||
send_connect_request:
|
||||
buf[0] = SW_SOCKS5_VERSION_CODE;
|
||||
buf[1] = 0x01;
|
||||
buf[2] = 0x00;
|
||||
|
||||
ctx->state = SW_SOCKS5_STATE_CONNECT;
|
||||
|
||||
if (ctx->dns_tunnel)
|
||||
{
|
||||
buf[3] = 0x03;
|
||||
buf[4] = ctx->l_target_host;
|
||||
buf += 5;
|
||||
memcpy(buf, ctx->target_host, ctx->l_target_host);
|
||||
buf += ctx->l_target_host;
|
||||
*(uint16_t *) buf = htons(ctx->target_port);
|
||||
return cli->send(cli, ctx->buf, ctx->l_target_host + 7, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
buf[3] = 0x01;
|
||||
buf += 4;
|
||||
*(uint32_t *) buf = htons(ctx->l_target_host);
|
||||
buf += 4;
|
||||
*(uint16_t *) buf = htons(ctx->target_port);
|
||||
return cli->send(cli, ctx->buf, ctx->l_target_host + 7, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (ctx->state == SW_SOCKS5_STATE_AUTH)
|
||||
{
|
||||
uchar version = recv_data[0];
|
||||
uchar status = recv_data[1];
|
||||
if (version != 0x01)
|
||||
{
|
||||
swoole_error_log(SW_LOG_NOTICE, SW_ERROR_SOCKS5_UNSUPPORT_VERSION, "SOCKS version is not supported.");
|
||||
return SW_ERR;
|
||||
}
|
||||
if (status != 0)
|
||||
{
|
||||
swoole_error_log(SW_LOG_NOTICE, SW_ERROR_SOCKS5_AUTH_FAILED, "SOCKS username/password authentication failed.");
|
||||
return SW_ERR;
|
||||
}
|
||||
goto send_connect_request;
|
||||
}
|
||||
else if (ctx->state == SW_SOCKS5_STATE_CONNECT)
|
||||
{
|
||||
uchar version = recv_data[0];
|
||||
if (version != SW_SOCKS5_VERSION_CODE)
|
||||
{
|
||||
swoole_error_log(SW_LOG_NOTICE, SW_ERROR_SOCKS5_UNSUPPORT_VERSION, "SOCKS version is not supported.");
|
||||
return SW_ERR;
|
||||
}
|
||||
uchar result = recv_data[1];
|
||||
// uchar reg = recv_data[2];
|
||||
// uchar type = recv_data[3];
|
||||
// uint32_t ip = *(uint32_t *) (recv_data + 4);
|
||||
// uint16_t port = *(uint16_t *) (recv_data + 8);
|
||||
if (result == 0)
|
||||
{
|
||||
ctx->state = SW_SOCKS5_STATE_READY;
|
||||
}
|
||||
else
|
||||
{
|
||||
swoole_error_log(SW_LOG_NOTICE, SW_ERROR_SOCKS5_SERVER_ERROR, "Socks5 server error, reason :%s.", swSocks5_strerror(result));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return SW_OK;
|
||||
}
|
312
vendor/swoole/src/protocol/WebSocket.c
vendored
Executable file
312
vendor/swoole/src/protocol/WebSocket.c
vendored
Executable file
@ -0,0 +1,312 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| Swoole |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 2.0 of the Apache license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.apache.org/licenses/LICENSE-2.0.html |
|
||||
| If you did not receive a copy of the Apache2.0 license and are unable|
|
||||
| to obtain it through the world-wide-web, please send a note to |
|
||||
| license@swoole.com so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Author: Tianfeng Han <mikan.tenny@gmail.com> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#include "swoole.h"
|
||||
#include "Server.h"
|
||||
#include "websocket.h"
|
||||
#include "Connection.h"
|
||||
|
||||
#include <sys/time.h>
|
||||
|
||||
/* The following is websocket data frame:
|
||||
+-+-+-+-+-------+-+-------------+-------------------------------+
|
||||
0 1 2 3 |
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 |
|
||||
+-+-+-+-+-------+-+-------------+-------------------------------+
|
||||
|F|R|R|R| opcode|M| Payload len | Extended payload length |
|
||||
|I|S|S|S| (4) |A| (7) | (16/64) |
|
||||
|N|V|V|V| |S| | (if payload len==126/127) |
|
||||
| |1|2|3| |K| | |
|
||||
+-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
|
||||
| Extended payload length continued, if payload len == 127 |
|
||||
+ - - - - - - - - - - - - - - - +-------------------------------+
|
||||
| |Masking-key, if MASK set to 1 |
|
||||
+-------------------------------+-------------------------------+
|
||||
| Masking-key (continued) | Payload Data |
|
||||
+-------------------------------- - - - - - - - - - - - - - - - +
|
||||
: Payload Data continued ... :
|
||||
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
|
||||
| Payload Data continued ... |
|
||||
+---------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
int swWebSocket_get_package_length(swProtocol *protocol, swConnection *conn, char *buf, uint32_t length)
|
||||
{
|
||||
//need more data
|
||||
if (length < SW_WEBSOCKET_HEADER_LEN)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
char mask = (buf[1] >> 7) & 0x1;
|
||||
//0-125
|
||||
uint64_t payload_length = buf[1] & 0x7f;
|
||||
int header_length = SW_WEBSOCKET_HEADER_LEN;
|
||||
buf += SW_WEBSOCKET_HEADER_LEN;
|
||||
|
||||
//uint16_t, 2byte
|
||||
if (payload_length == 0x7e)
|
||||
{
|
||||
if (length < 4)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
payload_length = ntohs(*((uint16_t *) buf));
|
||||
header_length += sizeof(uint16_t);
|
||||
buf += sizeof(uint16_t);
|
||||
}
|
||||
//uint64_t, 8byte
|
||||
else if (payload_length > 0x7e)
|
||||
{
|
||||
if (length < 10)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
payload_length = swoole_ntoh64(*((uint64_t *) buf));
|
||||
header_length += sizeof(uint64_t);
|
||||
buf += sizeof(uint64_t);
|
||||
}
|
||||
if (mask)
|
||||
{
|
||||
if (length < header_length + 4)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
header_length += SW_WEBSOCKET_MASK_LEN;
|
||||
}
|
||||
swTrace("header_length=%d, payload_length=%d", (int)header_length, (int)payload_length);
|
||||
return header_length + payload_length;
|
||||
}
|
||||
|
||||
void swWebSocket_encode(swString *buffer, char *data, size_t length, char opcode, int finish, int mask)
|
||||
{
|
||||
int pos = 0;
|
||||
char frame_header[16];
|
||||
|
||||
/**
|
||||
* frame header
|
||||
*/
|
||||
frame_header[pos++] = FRAME_SET_FIN(finish) | FRAME_SET_OPCODE(opcode);
|
||||
if (length < 126)
|
||||
{
|
||||
frame_header[pos++] = FRAME_SET_MASK(mask) | FRAME_SET_LENGTH(length, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (length < 65536)
|
||||
{
|
||||
frame_header[pos++] = FRAME_SET_MASK(mask) | 126;
|
||||
}
|
||||
else
|
||||
{
|
||||
frame_header[pos++] = FRAME_SET_MASK(mask) | 127;
|
||||
frame_header[pos++] = FRAME_SET_LENGTH(length, 7);
|
||||
frame_header[pos++] = FRAME_SET_LENGTH(length, 6);
|
||||
frame_header[pos++] = FRAME_SET_LENGTH(length, 5);
|
||||
frame_header[pos++] = FRAME_SET_LENGTH(length, 4);
|
||||
frame_header[pos++] = FRAME_SET_LENGTH(length, 3);
|
||||
frame_header[pos++] = FRAME_SET_LENGTH(length, 2);
|
||||
}
|
||||
frame_header[pos++] = FRAME_SET_LENGTH(length, 1);
|
||||
frame_header[pos++] = FRAME_SET_LENGTH(length, 0);
|
||||
}
|
||||
swString_append_ptr(buffer, frame_header, pos);
|
||||
|
||||
/**
|
||||
* frame body
|
||||
*/
|
||||
if (data && length > 0)
|
||||
{
|
||||
if (mask)
|
||||
{
|
||||
char *_mask_data = SW_WEBSOCKET_MASK_DATA;
|
||||
swString_append_ptr(buffer, _mask_data, SW_WEBSOCKET_MASK_LEN);
|
||||
|
||||
char *_data = buffer->str + buffer->length;
|
||||
swString_append_ptr(buffer, data, length);
|
||||
|
||||
int i;
|
||||
for (i = 0; i < length; i++)
|
||||
{
|
||||
_data[i] ^= _mask_data[i % SW_WEBSOCKET_MASK_LEN];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
swString_append_ptr(buffer, data, length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void swWebSocket_decode(swWebSocket_frame *frame, swString *data)
|
||||
{
|
||||
memcpy(frame, data->str, SW_WEBSOCKET_HEADER_LEN);
|
||||
|
||||
//0-125
|
||||
size_t payload_length = frame->header.LENGTH;
|
||||
uint8_t header_length = SW_WEBSOCKET_HEADER_LEN;
|
||||
char *buf = data->str + SW_WEBSOCKET_HEADER_LEN;
|
||||
|
||||
//uint16_t, 2byte
|
||||
if (frame->header.LENGTH == 0x7e)
|
||||
{
|
||||
payload_length = ntohs(*((uint16_t *) buf));
|
||||
header_length += 2;
|
||||
}
|
||||
//uint64_t, 8byte
|
||||
else if (frame->header.LENGTH > 0x7e)
|
||||
{
|
||||
payload_length = swoole_ntoh64(*((uint64_t *) buf));
|
||||
header_length += 8;
|
||||
}
|
||||
|
||||
if (frame->header.MASK)
|
||||
{
|
||||
char *mask_key = frame->mask_key;
|
||||
memcpy(mask_key, data->str + header_length, SW_WEBSOCKET_MASK_LEN);
|
||||
header_length += SW_WEBSOCKET_MASK_LEN;
|
||||
buf = data->str + header_length;
|
||||
int i;
|
||||
for (i = 0; i < payload_length; i++)
|
||||
{
|
||||
buf[i] ^= mask_key[i % SW_WEBSOCKET_MASK_LEN];
|
||||
}
|
||||
}
|
||||
frame->payload_length = payload_length;
|
||||
frame->header_length = header_length;
|
||||
frame->payload = data->str + header_length;
|
||||
}
|
||||
|
||||
void swWebSocket_print_frame(swWebSocket_frame *frame)
|
||||
{
|
||||
printf("FIN: %x, RSV1: %d, RSV2: %d, RSV3: %d, opcode: %d, MASK: %d, length: %ld\n", frame->header.FIN,
|
||||
frame->header.RSV1, frame->header.RSV2, frame->header.RSV3, frame->header.OPCODE, frame->header.MASK,
|
||||
frame->payload_length);
|
||||
|
||||
if (frame->payload_length)
|
||||
{
|
||||
printf("payload: %s\n", frame->payload);
|
||||
}
|
||||
}
|
||||
|
||||
int swWebSocket_dispatch_frame(swConnection *conn, char *data, uint32_t length)
|
||||
{
|
||||
swString frame;
|
||||
bzero(&frame, sizeof(frame));
|
||||
frame.str = data;
|
||||
frame.length = length;
|
||||
|
||||
swString send_frame;
|
||||
bzero(&send_frame, sizeof(send_frame));
|
||||
char buf[128];
|
||||
send_frame.str = buf;
|
||||
send_frame.size = sizeof(buf);
|
||||
|
||||
swWebSocket_frame ws;
|
||||
swWebSocket_decode(&ws, &frame);
|
||||
|
||||
swString *frame_buffer;
|
||||
int frame_length;
|
||||
swListenPort *port;
|
||||
|
||||
size_t offset;
|
||||
switch (ws.header.OPCODE)
|
||||
{
|
||||
case WEBSOCKET_OPCODE_CONTINUATION_FRAME:
|
||||
frame_buffer = conn->websocket_buffer;
|
||||
if (frame_buffer == NULL)
|
||||
{
|
||||
swWarn("bad frame[opcode=0]. remote_addr=%s:%d.", swConnection_get_ip(conn), swConnection_get_port(conn));
|
||||
return SW_ERR;
|
||||
}
|
||||
offset = length - ws.payload_length;
|
||||
frame_length = length - offset;
|
||||
port = swServer_get_port(SwooleG.serv, conn->fd);
|
||||
//frame data overflow
|
||||
if (frame_buffer->length + frame_length > port->protocol.package_max_length)
|
||||
{
|
||||
swWarn("websocket frame is too big, remote_addr=%s:%d.", swConnection_get_ip(conn), swConnection_get_port(conn));
|
||||
return SW_ERR;
|
||||
}
|
||||
//merge incomplete data
|
||||
swString_append_ptr(frame_buffer, data + offset, frame_length);
|
||||
//frame is finished, do dispatch
|
||||
if (ws.header.FIN)
|
||||
{
|
||||
swReactorThread_dispatch(conn, frame_buffer->str, frame_buffer->length);
|
||||
swString_free(frame_buffer);
|
||||
conn->websocket_buffer = NULL;
|
||||
}
|
||||
break;
|
||||
|
||||
case WEBSOCKET_OPCODE_TEXT_FRAME:
|
||||
case WEBSOCKET_OPCODE_BINARY_FRAME:
|
||||
offset = length - ws.payload_length - SW_WEBSOCKET_HEADER_LEN;
|
||||
data[offset] = 1;
|
||||
data[offset + 1] = ws.header.OPCODE;
|
||||
if (!ws.header.FIN)
|
||||
{
|
||||
if (conn->websocket_buffer)
|
||||
{
|
||||
swWarn("merging incomplete frame, bad request. remote_addr=%s:%d.", swConnection_get_ip(conn), swConnection_get_port(conn));
|
||||
return SW_ERR;
|
||||
}
|
||||
conn->websocket_buffer = swString_dup(data + offset, length - offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
swReactorThread_dispatch(conn, data + offset, length - offset);
|
||||
}
|
||||
break;
|
||||
|
||||
case WEBSOCKET_OPCODE_PING:
|
||||
if (length >= (sizeof(buf) - SW_WEBSOCKET_HEADER_LEN))
|
||||
{
|
||||
swWarn("ping frame application data is too big. remote_addr=%s:%d.", swConnection_get_ip(conn), swConnection_get_port(conn));
|
||||
return SW_ERR;
|
||||
}
|
||||
else if (length == SW_WEBSOCKET_HEADER_LEN)
|
||||
{
|
||||
swWebSocket_encode(&send_frame, NULL, 0, WEBSOCKET_OPCODE_PONG, 1, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
offset = ws.header.MASK ? SW_WEBSOCKET_HEADER_LEN + SW_WEBSOCKET_MASK_LEN : SW_WEBSOCKET_HEADER_LEN;
|
||||
swWebSocket_encode(&send_frame, data += offset, length - offset, WEBSOCKET_OPCODE_PONG, 1, 0);
|
||||
}
|
||||
swConnection_send(conn, send_frame.str, send_frame.length, 0);
|
||||
break;
|
||||
|
||||
case WEBSOCKET_OPCODE_PONG:
|
||||
break;
|
||||
|
||||
case WEBSOCKET_OPCODE_CONNECTION_CLOSE:
|
||||
if (0x7d < (length - 2))
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
send_frame.str[0] = 0x88;
|
||||
send_frame.str[1] = 0x00;
|
||||
send_frame.length = 2;
|
||||
swConnection_send(conn, send_frame.str, 2, 0);
|
||||
return SW_ERR;
|
||||
|
||||
default:
|
||||
swWarn("unknown opcode [%d].", ws.header.OPCODE);
|
||||
break;
|
||||
}
|
||||
return SW_OK;
|
||||
}
|
Reference in New Issue
Block a user