int swString_append(swString *str, swString *append_str) { int new_size = str->size + append_str->length; if(new_size > str->size) { if(swString_extend(str, new_size) < 0) { return SW_ERR; } } memcpy(str->str + str->length, append_str->str, append_str->length); return SW_OK; }
int swString_append(swString *str, swString *append_str) { int new_size = str->length + append_str->length; if (new_size > str->size) { if (swString_extend(str, swoole_size_align(new_size * 2, sysconf(_SC_PAGESIZE))) < 0) { return SW_ERR; } } memcpy(str->str + str->length, append_str->str, append_str->length); str->length += append_str->length; return SW_OK; }
static PHP_METHOD(swoole_buffer, expand) { long size = -1; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &size) == FAILURE) { RETURN_FALSE; } swString *buffer = swoole_get_object(getThis()); if (size <= buffer->size) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "new size must more than %ld", buffer->size); RETURN_FALSE; } zend_update_property_long(swoole_buffer_class_entry_ptr, getThis(), ZEND_STRL("capacity"), size TSRMLS_CC); SW_CHECK_RETURN(swString_extend(buffer, size)); }
int swString_append_int(swString *str, int value) { char buf[16]; int s_len = swoole_itoa(buf, value); int new_size = str->length + s_len; if (new_size > str->size) { if (swString_extend(str, swoole_size_align(new_size * 2, sysconf(_SC_PAGESIZE))) < 0) { return SW_ERR; } } memcpy(str->str + str->length, buf, s_len); str->length += s_len; return SW_OK; }
int swString_write_ptr(swString *str, off_t offset, char *write_str, int length) { int new_length = offset + length; if (new_length > str->size) { if (swString_extend(str, swoole_size_align(new_length * 2, sysconf(_SC_PAGESIZE))) < 0) { return SW_ERR; } } memcpy(str->str + offset, write_str, length); if (new_length > str->length) { str->length = new_length; } return SW_OK; }
static int swClient_onStreamRead(swReactor *reactor, swEvent *event) { int n; swClient *cli = event->socket->object; char *buf = cli->buffer->str; long buf_size = cli->buffer->size; #ifdef SW_USE_OPENSSL if (cli->open_ssl && cli->socket->ssl_state == SW_SSL_STATE_WAIT_STREAM) { if (swClient_ssl_handshake(cli) < 0) { return cli->close(cli); } if (cli->socket->ssl_state != SW_SSL_STATE_READY) { return SW_OK; } //ssl handshake sucess else if (cli->onConnect) { cli->onConnect(cli); } } #endif if (cli->open_eof_check || cli->open_length_check) { swConnection *conn = cli->socket; swProtocol *protocol = &cli->protocol; if (cli->open_eof_check) { n = swProtocol_recv_check_eof(protocol, conn, cli->buffer); } else { n = swProtocol_recv_check_length(protocol, conn, cli->buffer); } if (n < 0) { return cli->close(cli); } else { return SW_OK; } } //packet mode else if (cli->packet_mode == 1) { uint32_t len_tmp = 0; n = swConnection_recv(event->socket, &len_tmp, 4, 0); if (n <= 0) { return cli->close(cli); } else { buf_size = ntohl(len_tmp); if (buf_size > cli->buffer->size) { swString_extend(cli->buffer, buf_size); } } } #ifdef SW_CLIENT_RECV_AGAIN recv_again: #endif n = swConnection_recv(event->socket, buf, buf_size, 0); if (n < 0) { switch (swConnection_error(errno)) { case SW_ERROR: swSysError("Read from socket[%d] failed.", event->fd); return SW_OK; case SW_CLOSE: goto close_fd; case SW_WAIT: return SW_OK; default: return SW_OK; } } else if (n == 0) { close_fd: return cli->close(cli); } else { cli->onReceive(cli, buf, n); #ifdef SW_CLIENT_RECV_AGAIN if (n == buf_size) { goto recv_again; } #endif return SW_OK; } return SW_OK; }
/** * For Http Protocol */ static int swPort_onRead_http(swReactor *reactor, swListenPort *port, swEvent *event) { swConnection *conn = event->socket; if (conn->websocket_status >= WEBSOCKET_STATUS_HANDSHAKE) { if (conn->http_upgrade == 0) { swHttpRequest_free(conn); conn->websocket_status = WEBSOCKET_STATUS_ACTIVE; conn->http_upgrade = 1; } return swPort_onRead_check_length(reactor, port, event); } #ifdef SW_USE_HTTP2 if (conn->http2_stream) { return swPort_onRead_check_length(reactor, port, event); } #endif int n = 0; char *buf; int buf_len; swHttpRequest *request = NULL; swProtocol *protocol = &port->protocol; //new http request if (conn->object == NULL) { request = sw_malloc(sizeof(swHttpRequest)); bzero(request, sizeof(swHttpRequest)); conn->object = request; } else { request = (swHttpRequest *) conn->object; } if (!request->buffer) { request->buffer = swString_new(SW_HTTP_HEADER_MAX_SIZE); //alloc memory failed. if (!request->buffer) { swReactorThread_onClose(reactor, event); return SW_ERR; } } swString *buffer = request->buffer; recv_data: buf = buffer->str + buffer->length; buf_len = buffer->size - buffer->length; n = swConnection_recv(conn, buf, buf_len, 0); if (n < 0) { switch (swConnection_error(errno)) { case SW_ERROR: swSysError("recv from connection#%d failed.", event->fd); return SW_OK; case SW_CLOSE: conn->close_errno = errno; goto close_fd; default: return SW_OK; } } else if (n == 0) { close_fd: swHttpRequest_free(conn); swReactorThread_onClose(reactor, event); return SW_OK; } else { buffer->length += n; if (request->method == 0 && swHttpRequest_get_protocol(request) < 0) { if (request->buffer->length < SW_HTTP_HEADER_MAX_SIZE) { return SW_OK; } swWarn("get protocol failed."); #ifdef SW_HTTP_BAD_REQUEST if (swConnection_send(conn, SW_STRL(SW_HTTP_BAD_REQUEST) - 1, 0) < 0) { swSysError("send() failed."); } #endif goto close_fd; } if (request->method > HTTP_PRI) { swWarn("method no support"); goto close_fd; } #ifdef SW_USE_HTTP2 else if (request->method == HTTP_PRI) { conn->http2_stream = 1; swHttp2_send_setting_frame(protocol, conn); if (n == sizeof(SW_HTTP2_PRI_STRING) - 1) { swHttpRequest_free(conn); return SW_OK; } swHttp2_parse_frame(protocol, conn, buf + (sizeof(SW_HTTP2_PRI_STRING) - 1), n - (sizeof(SW_HTTP2_PRI_STRING) - 1)); swHttpRequest_free(conn); return SW_OK; } #endif if (request->content_length == 0) { if (swHttpRequest_get_content_length(request) < 0) { if (memcmp(buffer->str + buffer->length - 4, "\r\n\r\n", 4) == 0) { swReactorThread_dispatch(conn, buffer->str, buffer->length); swHttpRequest_free(conn); return SW_OK; } else if (buffer->size == buffer->length) { swWarn("[0]http header is too long."); goto close_fd; } //wait more data else { goto recv_data; } } else if (request->content_length > (protocol->package_max_length - SW_HTTP_HEADER_MAX_SIZE)) { swWarn("Content-Length is too big, MaxSize=[%d].", protocol->package_max_length - SW_HTTP_HEADER_MAX_SIZE); goto close_fd; } } //http header is not the end if (request->header_length == 0) { if (swHttpRequest_get_header_length(request) < 0) { if (buffer->size == buffer->length) { swWarn("[2]http header is too long."); goto close_fd; } else { goto recv_data; } } } //total length uint32_t request_size = request->content_length + request->header_length; if (request_size > buffer->size && swString_extend(buffer, request_size) < 0) { goto close_fd; } //discard the redundant data if (buffer->length > request_size) { buffer->length = request_size; } if (buffer->length == request_size) { swReactorThread_dispatch(conn, buffer->str, buffer->length); swHttpRequest_free(conn); } else { #ifdef SW_HTTP_100_CONTINUE //Expect: 100-continue if (swHttpRequest_has_expect_header(request)) { swSendData _send; _send.data = "HTTP/1.1 100 Continue\r\n\r\n"; _send.length = strlen(_send.data); int send_times = 0; direct_send: n = swConnection_send(conn, _send.data, _send.length, 0); if (n < _send.length) { _send.data += n; _send.length -= n; send_times++; if (send_times < 10) { goto direct_send; } else { swWarn("send http header failed"); } } } else { swTrace("PostWait: request->content_length=%d, buffer->length=%zd, request->header_length=%d\n", request->content_length, buffer->length, request->header_length); } #endif goto recv_data; } } 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) { buf_size = SW_BUFFER_SIZE; } int n = swConnection_recv(conn, buf_ptr, buf_size, 0); //swNotice("ReactorThread: recv[len=%d]", n); if (n < 0) { switch (swConnection_error(errno)) { case SW_ERROR: swSysError("recv from socket#%d failed.", conn->fd); return SW_OK; case SW_CLOSE: return SW_ERR; default: return SW_OK; } } else if (n == 0) { return SW_ERR; } else { conn->last_time = SwooleGS->now; 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) { protocol->onPackage(conn, buffer->str, buffer->length); 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; }
/** * @return SW_ERR: close the connection * @return SW_OK: continue */ int swProtocol_recv_check_length(swProtocol *protocol, swConnection *conn, swString *buffer) { char *recvbuf; uint32_t recvbuf_size; do_recv: recvbuf = buffer->str + buffer->length; recvbuf_size = buffer->offset > 0 ? buffer->offset - buffer->length : protocol->package_length_offset + protocol->package_length_size; int n = swConnection_recv(conn, recvbuf, recvbuf_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: return SW_ERR; default: return SW_OK; } } else if (n == 0) { return SW_ERR; } else { conn->last_time = SwooleGS->now; buffer->length += n; if (conn->recv_wait) { if (buffer->length == buffer->offset) { protocol->onPackage(conn, buffer->str, buffer->length); conn->recv_wait = 0; swString_clear(buffer); } return SW_OK; } else { int 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; } //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 + buffer->length; goto do_recv; } } } return SW_OK; }
static int process_stream_onRead(swReactor *reactor, swEvent *event) { SWOOLE_GET_TSRMLS; process_stream *ps = event->socket->object; char *buf = ps->buffer->str + ps->buffer->length; size_t len = ps->buffer->size - ps->buffer->length; int ret = read(event->fd, buf, len); if (ret > 0) { ps->buffer->length += ret; if (ps->buffer->length == ps->buffer->size) { swString_extend(ps->buffer, ps->buffer->size * 2); } return SW_OK; } else if (ret < 0) { swSysError("read() failed."); return SW_OK; } zval *retval = NULL; zval **args[2]; zval *zdata; SW_MAKE_STD_ZVAL(zdata); SW_ZVAL_STRINGL(zdata, ps->buffer->str, ps->buffer->length, 1); SwooleG.main_reactor->del(SwooleG.main_reactor, ps->fd); swString_free(ps->buffer); args[0] = &zdata; int status; zval *zstatus; SW_MAKE_STD_ZVAL(zstatus); pid_t pid = swWaitpid(ps->pid, &status, WNOHANG); if (pid > 0) { array_init(zstatus); add_assoc_long(zstatus, "code", WEXITSTATUS(status)); add_assoc_long(zstatus, "signal", WTERMSIG(status)); } else { ZVAL_FALSE(zstatus); } args[1] = &zstatus; zval *zcallback = ps->callback; if (zcallback) { if (sw_call_user_function_ex(EG(function_table), NULL, zcallback, &retval, 2, args, 0, NULL TSRMLS_CC) == FAILURE) { swoole_php_fatal_error(E_WARNING, "swoole_async: onAsyncComplete handler error"); } sw_zval_free(zcallback); } else { #ifdef SW_COROUTINE php_context *context = ps->context; sw_zval_add_ref(&zdata); add_assoc_zval(zstatus, "output", zdata); int ret = coro_resume(context, zstatus, &retval); if (ret == CORO_END && retval) { sw_zval_ptr_dtor(&retval); } efree(context); #else return SW_OK; #endif } if (EG(exception)) { zend_exception_error(EG(exception), E_ERROR TSRMLS_CC); } if (retval != NULL) { sw_zval_ptr_dtor(&retval); } sw_zval_ptr_dtor(&zdata); sw_zval_ptr_dtor(&zstatus); close(ps->fd); efree(ps); return SW_OK; }
static int swoole_mysql_onRead(swReactor *reactor, swEvent *event) { #if PHP_MAJOR_VERSION < 7 TSRMLS_FETCH_FROM_CTX(sw_thread_ctx ? sw_thread_ctx : NULL); #endif mysql_client *client = event->socket->object; int sock = event->fd; zval *zobject = client->object; swString *buffer = client->buffer; int ret; zval **args[2]; zval *callback = NULL; zval *retval = NULL; zval *result = NULL; while(1) { ret = recv(sock, buffer->str + buffer->length, buffer->size - buffer->length, 0); if (ret < 0) { if (errno == EINTR) { continue; } else { switch (swConnection_error(errno)) { case SW_ERROR: swSysError("Read from socket[%d] failed.", event->fd); return SW_ERR; case SW_CLOSE: goto close_fd; case SW_WAIT: goto parse_response; default: return SW_ERR; } } } else if (ret == 0) { close_fd: if (client->state == SW_MYSQL_STATE_READ_END) { goto parse_response; } sw_zend_call_method_with_0_params(&zobject, swoole_mysql_class_entry_ptr, NULL, "close", &retval); if (retval) { sw_zval_ptr_dtor(&retval); } if (client->callback) { args[0] = &zobject; args[1] = &result; SW_ALLOC_INIT_ZVAL(result); ZVAL_BOOL(result, 0); callback = client->callback; if (sw_call_user_function_ex(EG(function_table), NULL, callback, &retval, 2, args, 0, NULL TSRMLS_CC) != SUCCESS) { swoole_php_fatal_error(E_WARNING, "swoole_async_mysql callback[2] handler error."); } if (result) { sw_zval_ptr_dtor(&result); } sw_zval_ptr_dtor(&callback); client->callback = NULL; client->state = SW_MYSQL_STATE_QUERY; if (retval) { sw_zval_ptr_dtor(&retval); } } return SW_OK; } else { buffer->length += ret; //recv again if (buffer->length == buffer->size) { if (swString_extend(buffer, buffer->size * 2) < 0) { swoole_php_fatal_error(E_ERROR, "malloc failed."); reactor->del(SwooleG.main_reactor, event->fd); } continue; } parse_response: if (mysql_response(client) < 0) { return SW_OK; } //remove from eventloop reactor->del(reactor, event->fd); zend_update_property_long(swoole_mysql_class_entry_ptr, zobject, ZEND_STRL("affected_rows"), client->response.affected_rows TSRMLS_CC); zend_update_property_long(swoole_mysql_class_entry_ptr, zobject, ZEND_STRL("insert_id"), client->response.insert_id TSRMLS_CC); client->state = SW_MYSQL_STATE_QUERY; args[0] = &zobject; //OK if (client->response.response_type == 0) { SW_ALLOC_INIT_ZVAL(result); ZVAL_BOOL(result, 1); } //ERROR else if (client->response.response_type == 255) { SW_ALLOC_INIT_ZVAL(result); ZVAL_BOOL(result, 0); zend_update_property_string(swoole_mysql_class_entry_ptr, zobject, ZEND_STRL("error"), client->response.server_msg TSRMLS_CC); zend_update_property_long(swoole_mysql_class_entry_ptr, zobject, ZEND_STRL("errno"), client->response.error_code TSRMLS_CC); } //ResultSet else { result = client->response.result_array; } args[1] = &result; callback = client->callback; if (sw_call_user_function_ex(EG(function_table), NULL, callback, &retval, 2, args, 0, NULL TSRMLS_CC) != SUCCESS) { swoole_php_fatal_error(E_WARNING, "swoole_async_mysql callback[2] handler error."); reactor->del(SwooleG.main_reactor, event->fd); } /* free memory */ if (retval) { sw_zval_ptr_dtor(&retval); } if (result) { sw_zval_ptr_dtor(&result); #if PHP_MAJOR_VERSION > 5 efree(result); #endif } //free callback object sw_zval_ptr_dtor(&callback); //clear buffer swString_clear(client->buffer); if (client->response.columns) { efree(client->response.columns); } if (client->object) { sw_zval_ptr_dtor(&client->object); } #if PHP_MAJOR_VERSION > 5 if (client->response.result_array) { efree(client->response.result_array); } #endif bzero(&client->response, sizeof(client->response)); return SW_OK; } } return SW_OK; }
/** * For Http Protocol */ static int swPort_onRead_http(swReactor *reactor, swListenPort *port, swEvent *event) { swConnection *conn = event->socket; #ifdef SW_USE_OPENSSL if (swPort_check_ssl_state(port, conn) < 0) { goto close_fd; } #endif if (conn->websocket_status >= WEBSOCKET_STATUS_HANDSHAKE) { if (conn->object != NULL) { swHttpRequest_free(conn); conn->websocket_status = WEBSOCKET_STATUS_ACTIVE; } return swPort_onRead_check_length(reactor, port, event); } int n = 0; char *buf; int buf_len; swHttpRequest *request = NULL; swProtocol *protocol = &port->protocol; //new http request if (conn->object == NULL) { request = sw_malloc(sizeof(swHttpRequest)); bzero(request, sizeof(swHttpRequest)); conn->object = request; } else { request = (swHttpRequest *) conn->object; } if (!request->buffer) { request->buffer = swString_new(SW_HTTP_HEADER_MAX_SIZE); //alloc memory failed. if (!request->buffer) { swReactorThread_onClose(reactor, event); return SW_ERR; } } swString *buffer = request->buffer; recv_data: buf = buffer->str + buffer->length; buf_len = buffer->size - buffer->length; n = swConnection_recv(conn, buf, buf_len, 0); if (n < 0) { switch (swConnection_error(errno)) { case SW_ERROR: swSysError("recv from connection#%d failed.", event->fd); return SW_OK; case SW_CLOSE: goto close_fd; default: return SW_OK; } } else if (n == 0) { close_fd: swHttpRequest_free(conn); swReactorThread_onClose(reactor, event); return SW_OK; } else { conn->last_time = SwooleGS->now; buffer->length += n; if (request->method == 0 && swHttpRequest_get_protocol(request) < 0) { if (request->buffer->length < SW_HTTP_HEADER_MAX_SIZE) { return SW_OK; } swWarn("get protocol failed."); #ifdef SW_HTTP_BAD_REQUEST if (swConnection_send(conn, SW_STRL(SW_HTTP_BAD_REQUEST) - 1, 0) < 0) { swSysError("send() failed."); } #endif goto close_fd; } swTrace("request->method=%d", request->method); //DELETE if (request->method == HTTP_DELETE) { if (request->content_length == 0 && swHttpRequest_have_content_length(request) == SW_FALSE) { goto http_no_entity; } else { goto http_entity; } } //GET HEAD OPTIONS else if (request->method == HTTP_GET || request->method == HTTP_HEAD || request->method == HTTP_OPTIONS) { http_no_entity: if (memcmp(buffer->str + buffer->length - 4, "\r\n\r\n", 4) == 0) { swReactorThread_dispatch(conn, buffer->str, buffer->length); swHttpRequest_free(conn); } else if (buffer->size == buffer->length) { swWarn("http header is too long."); goto close_fd; } //wait more data else { goto recv_data; } } //POST PUT HTTP_PATCH else if (request->method == HTTP_POST || request->method == HTTP_PUT || request->method == HTTP_PATCH) { http_entity: if (request->content_length == 0) { if (swHttpRequest_get_content_length(request) < 0) { if (buffer->size == buffer->length) { swWarn("http header is too long."); goto close_fd; } else { goto recv_data; } } else if (request->content_length > protocol->package_max_length) { swWarn("content-length more than the package_max_length[%d].", protocol->package_max_length); goto close_fd; } } uint32_t request_size = 0; //http header is not the end if (request->header_length == 0) { if (buffer->size == buffer->length) { swWarn("http header is too long."); goto close_fd; } if (swHttpRequest_get_header_length(request) < 0) { goto recv_data; } request_size = request->content_length + request->header_length; } else { request_size = request->content_length + request->header_length; } if (request_size > buffer->size && swString_extend(buffer, request_size) < 0) { goto close_fd; } //discard the redundant data if (buffer->length > request_size) { buffer->length = request_size; } if (buffer->length == request_size) { swReactorThread_dispatch(conn, buffer->str, buffer->length); swHttpRequest_free(conn); } else { #ifdef SW_HTTP_100_CONTINUE //Expect: 100-continue if (swHttpRequest_has_expect_header(request)) { swSendData _send; _send.data = "HTTP/1.1 100 Continue\r\n\r\n"; _send.length = strlen(_send.data); int send_times = 0; direct_send: n = swConnection_send(conn, _send.data, _send.length, 0); if (n < _send.length) { _send.data += n; _send.length -= n; send_times++; if (send_times < 10) { goto direct_send; } else { swWarn("send http header failed"); } } } else { swTrace("PostWait: request->content_length=%d, buffer->length=%zd, request->header_length=%d\n", request->content_length, buffer->length, request->header_length); } #endif goto recv_data; } } else { swWarn("method no support"); goto close_fd; } } 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]; do_recv: if (buffer->offset > 0) { recv_size = buffer->offset - buffer->length; } else { recv_size = protocol->package_length_offset + protocol->package_length_size; } int ret = swConnection_recv(conn, buffer->str + buffer->length, recv_size, 0); if (ret < 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 (ret == 0) { return SW_ERR; } else { buffer->length += ret; if (conn->recv_wait) { if (buffer->length >= buffer->offset) { do_dispatch: ret = protocol->onPackage(conn, buffer->str, buffer->offset); 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); return ret; } } 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) { int retval = swProtocol_split_package_by_eof(protocol, conn, buffer); if (retval == SW_CONTINUE) { recv_again = SW_TRUE; } else if (retval == SW_CLOSE) { return SW_ERR; } else { return SW_OK; } } 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); #ifdef SW_USE_OPENSSL if (conn->ssl && SSL_pending(conn->ssl) > 0) { goto recv_data; } #endif 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; }
/** * @return SW_ERR: close the connection * @return SW_OK: continue */ int swProtocol_recv_check_length(swProtocol *protocol, swConnection *conn, swString *buffer) { int package_length; uint8_t package_length_size = protocol->get_package_length_size ? protocol->get_package_length_size(conn) : protocol->package_length_size; uint32_t recv_size; 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 + 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) { memmove(buffer->str, buffer->str + buffer->offset, remaining_length); buffer->offset = 0; buffer->length = remaining_length; goto do_get_length; } else { swString_clear(buffer); #ifdef SW_USE_OPENSSL if (conn->ssl) { goto do_recv; } #endif } } 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; }
/** * For Http Protocol */ static int swPort_onRead_http(swReactor *reactor, swListenPort *port, swEvent *event) { swConnection *conn = event->socket; swServer *serv = reactor->ptr; if (conn->websocket_status >= WEBSOCKET_STATUS_HANDSHAKE) { if (conn->http_upgrade == 0) { swHttpRequest_free(conn); conn->websocket_status = WEBSOCKET_STATUS_ACTIVE; conn->http_upgrade = 1; } return swPort_onRead_check_length(reactor, port, event); } #ifdef SW_USE_HTTP2 if (conn->http2_stream) { _parse_frame: return swPort_onRead_check_length(reactor, port, event); } #endif int n = 0; char *buf; int buf_len; swHttpRequest *request = NULL; swProtocol *protocol = &port->protocol; //new http request if (conn->object == NULL) { request = sw_malloc(sizeof(swHttpRequest)); bzero(request, sizeof(swHttpRequest)); conn->object = request; } else { request = (swHttpRequest *) conn->object; } if (!request->buffer) { request->buffer = swString_new(SW_HTTP_HEADER_MAX_SIZE); //alloc memory failed. if (!request->buffer) { swReactorThread_onClose(reactor, event); return SW_ERR; } } swString *buffer = request->buffer; recv_data: buf = buffer->str + buffer->length; buf_len = buffer->size - buffer->length; n = swConnection_recv(conn, buf, buf_len, 0); if (n < 0) { switch (swConnection_error(errno)) { case SW_ERROR: swSysError("recv from connection#%d failed.", event->fd); return SW_OK; case SW_CLOSE: conn->close_errno = errno; goto close_fd; default: return SW_OK; } } else if (n == 0) { close_fd: swHttpRequest_free(conn); swReactorThread_onClose(reactor, event); return SW_OK; } else { buffer->length += n; if (request->method == 0 && swHttpRequest_get_protocol(request) < 0) { if (request->excepted == 0 && request->buffer->length < SW_HTTP_HEADER_MAX_SIZE) { return SW_OK; } swoole_error_log(SW_LOG_TRACE, SW_ERROR_HTTP_INVALID_PROTOCOL, "get protocol failed."); #ifdef SW_HTTP_BAD_REQUEST_TIP if (swConnection_send(conn, SW_STRL(SW_HTTP_BAD_REQUEST_TIP), 0) < 0) { swSysError("send() failed."); } #endif goto close_fd; } if (request->method > HTTP_PRI) { swWarn("method no support"); goto close_fd; } #ifdef SW_USE_HTTP2 else if (request->method == HTTP_PRI) { conn->http2_stream = 1; swHttp2_send_setting_frame(protocol, conn); if (n == sizeof(SW_HTTP2_PRI_STRING) - 1) { swHttpRequest_free(conn); return SW_OK; } swString *buffer = swServer_get_buffer(serv, event->fd); if (!buffer) { goto close_fd; } swString_append_ptr(buffer, buf + (sizeof(SW_HTTP2_PRI_STRING) - 1), n - (sizeof(SW_HTTP2_PRI_STRING) - 1)); swHttpRequest_free(conn); conn->skip_recv = 1; goto _parse_frame; } #endif //http header is not the end if (request->header_length == 0) { if (swHttpRequest_get_header_length(request) < 0) { if (buffer->size == buffer->length) { swWarn("[2]http header is too long."); goto close_fd; } else { goto recv_data; } } } //http body if (request->content_length == 0) { swTraceLog(SW_TRACE_SERVER, "content-length=%u, keep-alive=%d", request->content_length, request->keep_alive); // content length field not found if (swHttpRequest_get_header_info(request) < 0) { /* the request is really no body */ if (buffer->length == request->header_length) { /** * send static file content directly in the reactor thread */ if (!(serv->enable_static_handler && swPort_http_static_handler(request, conn))) { /** * dynamic request, dispatch to worker */ swReactorThread_dispatch(conn, buffer->str, buffer->length); } swHttpRequest_free(conn); return SW_OK; } else if (buffer->size == buffer->length) { swWarn("[0]http header is too long."); goto close_fd; } /* wait more data */ else { goto recv_data; } } else if (request->content_length > (protocol->package_max_length - request->header_length)) { swWarn("Content-Length is too big, MaxSize=[%d].", protocol->package_max_length - request->header_length); goto close_fd; } } //total length uint32_t request_size = request->header_length + request->content_length; if (request_size > buffer->size && swString_extend(buffer, request_size) < 0) { goto close_fd; } //discard the redundant data if (buffer->length > request_size) { buffer->length = request_size; } if (buffer->length == request_size) { swReactorThread_dispatch(conn, buffer->str, buffer->length); swHttpRequest_free(conn); } else { #ifdef SW_HTTP_100_CONTINUE //Expect: 100-continue if (swHttpRequest_has_expect_header(request)) { swSendData _send; _send.data = "HTTP/1.1 100 Continue\r\n\r\n"; _send.length = strlen(_send.data); int send_times = 0; direct_send: n = swConnection_send(conn, _send.data, _send.length, 0); if (n < _send.length) { _send.data += n; _send.length -= n; send_times++; if (send_times < 10) { goto direct_send; } else { swWarn("send http header failed"); } } } else { swTrace("PostWait: request->content_length=%d, buffer->length=%zd, request->header_length=%d\n", request->content_length, buffer->length, request->header_length); } #endif goto recv_data; } } return SW_OK; }
/** * @return SW_ERR: close the connection * @return SW_OK: continue */ int swProtocol_recv_check_length(swProtocol *protocol, swConnection *conn, swString *buffer) { char *recvbuf; int ret; uint32_t recvbuf_size; do_recv: recvbuf = buffer->str + buffer->length; recvbuf_size = buffer->offset > 0 ? buffer->offset - buffer->length : protocol->package_length_offset + protocol->package_length_size; int n = swConnection_recv(conn, recvbuf, recvbuf_size, 0); if (n < 0) { switch (swConnection_error(errno)) { case SW_ERROR: swSysError("recv(%d, %p, %d) failed.", conn->fd, recvbuf, recvbuf_size); return SW_OK; case SW_CLOSE: 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_package: ret = protocol->onPackage(conn, buffer->str, buffer->length); conn->recv_wait = 0; swString_clear(buffer); return ret; } else { return SW_OK; } } else { int 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_package; } else { goto do_recv; } } } } return SW_OK; }