int swPort_listen(swListenPort *ls) { if (swSocket_is_dgram(ls->type)) { int sock = swSocket_listen(ls->type, ls->host, ls->port, ls->backlog); if (sock < 0) { return SW_ERR; } int bufsize = SwooleG.socket_buffer_size; setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &bufsize, sizeof(bufsize)); setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &bufsize, sizeof(bufsize)); ls->sock = sock; return sock; } #ifdef SW_USE_OPENSSL if (ls->open_ssl_encrypt) { if (ls->ssl_cert_file == NULL || ls->ssl_key_file == NULL) { swWarn("SSL error, require ssl_cert_file and ssl_key_file."); return SW_ERR; } ls->ssl_context = swSSL_get_context(ls->ssl_method, ls->ssl_cert_file, ls->ssl_key_file); if (ls->ssl_context == NULL) { return SW_ERR; } if (ls->ssl_client_cert_file && swSSL_set_client_certificate(ls->ssl_context, ls->ssl_client_cert_file, ls->ssl_verify_depth) == SW_ERR) { return SW_ERR; } } if (ls->ssl) { if (!ls->ssl_cert_file) { swWarn("need to configure [server->ssl_cert_file]."); return SW_ERR; } if (!ls->ssl_key_file) { swWarn("need to configure [server->ssl_key_file]."); return SW_ERR; } } #endif //TCP int sock = swSocket_listen(ls->type, ls->host, ls->port, ls->backlog); if (sock < 0) { return SW_ERR; } #ifdef TCP_DEFER_ACCEPT if (ls->tcp_defer_accept) { if (setsockopt(sock, IPPROTO_TCP, TCP_DEFER_ACCEPT, (const void*) &ls->tcp_defer_accept, sizeof(int)) < 0) { swSysError("setsockopt(TCP_DEFER_ACCEPT) failed."); } } #endif #ifdef TCP_FASTOPEN if (ls->tcp_fastopen) { if (setsockopt(sock, IPPROTO_TCP, TCP_FASTOPEN, (const void*) &ls->tcp_fastopen, sizeof(int)) < 0) { swSysError("setsockopt(TCP_FASTOPEN) failed."); } } #endif #ifdef SO_KEEPALIVE int sockopt; if (ls->open_tcp_keepalive == 1) { sockopt = 1; if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void *) &sockopt, sizeof(int)) < 0) { swSysError("setsockopt(SO_KEEPALIVE) failed."); } #ifdef TCP_KEEPIDLE setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, (void*) &ls->tcp_keepidle, sizeof(int)); setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, (void *) &ls->tcp_keepinterval, sizeof(int)); setsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT, (void *) &ls->tcp_keepcount, sizeof(int)); #endif } #endif return sock; }
static int swAioBase_thread_onTask(swThreadPool *pool, void *task, int task_len) { swAio_event *event = task; struct in_addr addr; char *ip_addr; int ret = -1; start_switch: switch(event->type) { case SW_AIO_WRITE: if (flock(event->fd, LOCK_EX) < 0) { swSysError("flock(%d, LOCK_EX) failed.", event->fd); break; } if (event->offset == 0) { ret = write(event->fd, event->buf, event->nbytes); } else { ret = pwrite(event->fd, event->buf, event->nbytes, event->offset); } #if 0 if (fsync(event->fd) < 0) { swSysError("fsync(%d) failed.", event->fd); } #endif if (flock(event->fd, LOCK_UN) < 0) { swSysError("flock(%d, LOCK_UN) failed.", event->fd); } break; case SW_AIO_READ: if (flock(event->fd, LOCK_SH) < 0) { swSysError("flock(%d, LOCK_SH) failed.", event->fd); break; } ret = pread(event->fd, event->buf, event->nbytes, event->offset); if (flock(event->fd, LOCK_UN) < 0) { swSysError("flock(%d, LOCK_UN) failed.", event->fd); } break; case SW_AIO_DNS_LOOKUP: ret = swoole_gethostbyname(event->flags == AF_INET6 ? AF_INET6 : AF_INET, event->buf, (char *) &addr); if (ret < 0) { event->error = h_errno; switch (h_errno) { case HOST_NOT_FOUND: bzero(event->buf, event->nbytes); ret = 0; break; default: ret = -1; break; } } else { ip_addr = inet_ntoa(addr); bzero(event->buf, event->nbytes); memcpy(event->buf, ip_addr, strnlen(ip_addr, SW_IP_MAX_LENGTH) + 1); ret = 0; } break; default: swWarn("unknow aio task."); break; } event->ret = ret; if (ret < 0) { if (errno == EINTR || errno == EAGAIN) { goto start_switch; } else { event->error = errno; } } swTrace("aio_thread ok. ret=%d", ret); do { SwooleAIO.lock.lock(&SwooleAIO.lock); ret = write(swAioBase_pipe_write, &task, sizeof(task)); SwooleAIO.lock.unlock(&SwooleAIO.lock); if (ret < 0) { if (errno == EAGAIN) { swYield(); continue; } else if(errno == EINTR) { continue; } else { swWarn("sendto swoole_aio_pipe_write failed. Error: %s[%d]", strerror(errno), errno); } } break; } while(1); return SW_OK; }
void swWorker_onStart(swServer *serv) { /** * Release other worker process */ swWorker *worker; if (SwooleWG.id >= serv->worker_num) { SwooleG.process_type = SW_PROCESS_TASKWORKER; } else { SwooleG.process_type = SW_PROCESS_WORKER; } int is_root = !geteuid(); struct passwd *passwd = NULL; struct group *group = NULL; if (is_root) { //get group info if (SwooleG.group) { group = getgrnam(SwooleG.group); if (!group) { swWarn("get group [%s] info failed.", SwooleG.group); } } //get user info if (SwooleG.user) { passwd = getpwnam(SwooleG.user); if (!passwd) { swWarn("get user [%s] info failed.", SwooleG.user); } } //chroot if (SwooleG.chroot) { if (0 > chroot(SwooleG.chroot)) { swSysError("chroot to [%s] failed.", SwooleG.chroot); } } //set process group if (SwooleG.group && group) { if (setgid(group->gr_gid) < 0) { swSysError("setgid to [%s] failed.", SwooleG.group); } } //set process user if (SwooleG.user && passwd) { if (setuid(passwd->pw_uid) < 0) { swSysError("setuid to [%s] failed.", SwooleG.user); } } } SwooleWG.worker = swServer_get_worker(serv, SwooleWG.id); int i; for (i = 0; i < serv->worker_num + SwooleG.task_worker_num; i++) { worker = swServer_get_worker(serv, i); if (SwooleWG.id == i) { continue; } else { swWorker_free(worker); } if (swIsWorker()) { swSetNonBlock(worker->pipe_master); } } if (serv->onWorkerStart) { serv->onWorkerStart(serv, SwooleWG.id); } }
/** * 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); 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) { 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: 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) { 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; }
static int swClient_onStreamRead(swReactor *reactor, swEvent *event) { int n; swClient *cli = event->socket->object; char *buf = cli->buffer->str + cli->buffer->length; long buf_size = cli->buffer->size - cli->buffer->length; if (cli->http_proxy && cli->http_proxy->state != SW_HTTP_PROXY_STATE_READY) { #ifdef SW_USE_OPENSSL if (cli->open_ssl) { int n = swConnection_recv(event->socket, buf, buf_size, 0); if (n <= 0) { goto __close; } cli->buffer->length += n; if (cli->buffer->length < sizeof(SW_HTTPS_PROXY_HANDSHAKE_RESPONSE) - 1) { return SW_OK; } if (swClient_https_proxy_handshake(cli) < 0) { swoole_error_log(SW_LOG_NOTICE, SW_ERROR_HTTP_PROXY_HANDSHAKE_ERROR, "failed to handshake with http proxy."); goto connect_fail; } else { cli->http_proxy->state = SW_HTTP_PROXY_STATE_READY; swString_clear(cli->buffer); } if (swClient_enable_ssl_encrypt(cli) < 0) { goto connect_fail; } else { if (swClient_ssl_handshake(cli) < 0) { goto connect_fail; } else { cli->socket->ssl_state = SW_SSL_STATE_WAIT_STREAM; } return SwooleG.main_reactor->set(SwooleG.main_reactor, event->fd, SW_FD_STREAM_CLIENT | SW_EVENT_WRITE); } if (cli->onConnect) { execute_onConnect(cli); } return SW_OK; } #endif } if (cli->socks5_proxy && cli->socks5_proxy->state != SW_SOCKS5_STATE_READY) { int n = swConnection_recv(event->socket, buf, buf_size, 0); if (n <= 0) { goto __close; } if (swSocks5_connect(cli, buf, buf_size) < 0) { goto __close; } if (cli->socks5_proxy->state != SW_SOCKS5_STATE_READY) { return SW_OK; } #ifdef SW_USE_OPENSSL if (cli->open_ssl) { if (swClient_enable_ssl_encrypt(cli) < 0) { connect_fail: cli->socket->active = 0; cli->close(cli); if (cli->onError) { cli->onError(cli); } } else { if (swClient_ssl_handshake(cli) < 0) { goto connect_fail; } else { cli->socket->ssl_state = SW_SSL_STATE_WAIT_STREAM; } return SwooleG.main_reactor->set(SwooleG.main_reactor, event->fd, SW_FD_STREAM_CLIENT | SW_EVENT_WRITE); } } else #endif { if (cli->onConnect) { execute_onConnect(cli); } } return SW_OK; } #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) { execute_onConnect(cli); } } #endif /** * redirect stream data to other socket */ if (cli->redirect) { int ret = 0; n = swConnection_recv(event->socket, buf, buf_size, 0); if (n < 0) { goto __error; } else if (n == 0) { goto __close; } if (cli->_redirect_to_socket) { ret = SwooleG.main_reactor->write(SwooleG.main_reactor, cli->_redirect_to_socket, buf, n); } else if (cli->_redirect_to_session) { if (SwooleG.serv->send(SwooleG.serv, cli->_redirect_to_session, buf, n) < 0) { if (SwooleG.error >= SW_ERROR_SESSION_CLOSED_BY_SERVER || SwooleG.error >= SW_ERROR_SESSION_INVALID_ID) { goto __close; } } else { return SW_OK; } } else { ret = swSocket_write_blocking(cli->_redirect_to_file, buf, n); } if (ret < 0) { goto __error; } return SW_OK; } 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; } } #ifdef SW_CLIENT_RECV_AGAIN recv_again: #endif n = swConnection_recv(event->socket, buf, buf_size, 0); if (n < 0) { __error: switch (swConnection_error(errno)) { case SW_ERROR: swSysError("Read from socket[%d] failed.", event->fd); return SW_OK; case SW_CLOSE: goto __close; case SW_WAIT: return SW_OK; default: return SW_OK; } } else if (n == 0) { __close: 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; }
int swSocket_listen(int type, char *host, int port, int backlog) { int sock; int option; int ret; struct sockaddr_in addr_in4; struct sockaddr_in6 addr_in6; struct sockaddr_un addr_un; sock = swSocket_create(type); if (sock < 0) { swSysError("create socket failed."); return SW_ERR; } //reuse address option = 1; if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(int)) < 0) { swSysError("setsockopt(SO_REUSEPORT) failed."); } //reuse port #ifdef HAVE_REUSEPORT if (SwooleG.reuse_port) { if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &option, sizeof(int)) < 0) { swSysError("setsockopt(SO_REUSEPORT) failed."); SwooleG.reuse_port = 0; } } #endif //unix socket if (type == SW_SOCK_UNIX_DGRAM || type == SW_SOCK_UNIX_STREAM) { bzero(&addr_un, sizeof(addr_un)); unlink(host); addr_un.sun_family = AF_UNIX; strcpy(addr_un.sun_path, host); ret = bind(sock, (struct sockaddr*) &addr_un, sizeof(addr_un)); } //IPv6 else if (type > SW_SOCK_UDP) { bzero(&addr_in6, sizeof(addr_in6)); inet_pton(AF_INET6, host, &(addr_in6.sin6_addr)); addr_in6.sin6_port = htons(port); addr_in6.sin6_family = AF_INET6; ret = bind(sock, (struct sockaddr *) &addr_in6, sizeof(addr_in6)); } //IPv4 else { bzero(&addr_in4, sizeof(addr_in4)); inet_pton(AF_INET, host, &(addr_in4.sin_addr)); addr_in4.sin_port = htons(port); addr_in4.sin_family = AF_INET; ret = bind(sock, (struct sockaddr *) &addr_in4, sizeof(addr_in4)); } //bind failed if (ret < 0) { swWarn("bind(%s:%d) failed. Error: %s [%d]", host, port, strerror(errno), errno); return SW_ERR; } if (type == SW_SOCK_UDP || type == SW_SOCK_UDP6 || type == SW_SOCK_UNIX_DGRAM) { return sock; } //listen stream socket ret = listen(sock, backlog); if (ret < 0) { swWarn("listen(%s:%d, %d) failed. Error: %s[%d]", host, port, backlog, strerror(errno), errno); return SW_ERR; } swSetNonBlock(sock); return sock; }
int swPort_set_option(swListenPort *ls) { int sock = ls->sock; //reuse address int option = 1; //reuse port #ifdef HAVE_REUSEPORT if (SwooleG.reuse_port) { if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &option, sizeof(int)) < 0) { swSysError("setsockopt(SO_REUSEPORT) failed."); SwooleG.reuse_port = 0; } } #endif if (swSocket_is_dgram(ls->type)) { int bufsize = SwooleG.socket_buffer_size; setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &bufsize, sizeof(bufsize)); setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &bufsize, sizeof(bufsize)); return SW_OK; } #ifdef SW_USE_OPENSSL if (ls->open_ssl_encrypt) { if (ls->ssl_cert_file == NULL || ls->ssl_key_file == NULL) { swWarn("SSL error, require ssl_cert_file and ssl_key_file."); return SW_ERR; } ls->ssl_context = swSSL_get_context(ls->ssl_method, ls->ssl_cert_file, ls->ssl_key_file); if (ls->ssl_context == NULL) { swWarn("swSSL_get_context() error."); return SW_ERR; } if (ls->ssl_client_cert_file && swSSL_set_client_certificate(ls->ssl_context, ls->ssl_client_cert_file, ls->ssl_verify_depth) == SW_ERR) { swWarn("swSSL_set_client_certificate() error."); return SW_ERR; } if (ls->open_http_protocol) { ls->ssl_config.http = 1; } if (ls->open_http2_protocol) { ls->ssl_config.http_v2 = 1; swSSL_server_http_advise(ls->ssl_context, &ls->ssl_config); } if (swSSL_server_set_cipher(ls->ssl_context, &ls->ssl_config) < 0) { swWarn("swSSL_server_set_cipher() error."); return SW_ERR; } } if (ls->ssl) { if (!ls->ssl_cert_file) { swWarn("need to set [ssl_cert_file] option."); return SW_ERR; } if (!ls->ssl_key_file) { swWarn("need to set [ssl_key_file] option."); return SW_ERR; } } #endif //listen stream socket if (listen(sock, ls->backlog) < 0) { swWarn("listen(%s:%d, %d) failed. Error: %s[%d]", ls->host, ls->port, ls->backlog, strerror(errno), errno); return SW_ERR; } #ifdef TCP_DEFER_ACCEPT if (ls->tcp_defer_accept) { if (setsockopt(sock, IPPROTO_TCP, TCP_DEFER_ACCEPT, (const void*) &ls->tcp_defer_accept, sizeof(int)) < 0) { swSysError("setsockopt(TCP_DEFER_ACCEPT) failed."); } } #endif #ifdef TCP_FASTOPEN if (ls->tcp_fastopen) { if (setsockopt(sock, IPPROTO_TCP, TCP_FASTOPEN, (const void*) &ls->tcp_fastopen, sizeof(int)) < 0) { swSysError("setsockopt(TCP_FASTOPEN) failed."); } } #endif #ifdef SO_KEEPALIVE if (ls->open_tcp_keepalive == 1) { option = 1; if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void *) &option, sizeof(option)) < 0) { swSysError("setsockopt(SO_KEEPALIVE) failed."); } #ifdef TCP_KEEPIDLE setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, (void*) &ls->tcp_keepidle, sizeof(int)); setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, (void *) &ls->tcp_keepinterval, sizeof(int)); setsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT, (void *) &ls->tcp_keepcount, sizeof(int)); #endif } #endif 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; }
static int swReactorKqueue_wait(swReactor *reactor, struct timeval *timeo) { swEvent event; swFd fd_; swReactorKqueue *object = reactor->object; swReactor_handle handle; int i, n, ret; struct timespec t; struct timespec *t_ptr; bzero(&t, sizeof(t)); if (reactor->timeout_msec == 0) { if (timeo == NULL) { reactor->timeout_msec = -1; } else { reactor->timeout_msec = timeo->tv_sec * 1000 + timeo->tv_usec / 1000; } } reactor->start = 1; while (reactor->running > 0) { if (reactor->onBegin != NULL) { reactor->onBegin(reactor); } if (reactor->timeout_msec > 0) { t.tv_sec = reactor->timeout_msec / 1000; t.tv_nsec = (reactor->timeout_msec - t.tv_sec * 1000) * 1000; t_ptr = &t; } else { t_ptr = NULL; } n = kevent(object->epfd, NULL, 0, object->events, object->event_max, t_ptr); if (n < 0) { swTrace("kqueue error.EP=%d | Errno=%d\n", object->epfd, errno); if (swReactor_error(reactor) < 0) { swWarn("Kqueue[#%d] Error: %s[%d]", reactor->id, strerror(errno), errno); return SW_ERR; } else { continue; } } else if (n == 0) { if (reactor->onTimeout != NULL) { reactor->onTimeout(reactor); } continue; } for (i = 0; i < n; i++) { swTraceLog(SW_TRACE_EVENT, "n %d events.", n); if (object->events[i].udata) { memcpy(&fd_, &(object->events[i].udata), sizeof(fd_)); event.fd = fd_.fd; event.from_id = reactor->id; event.type = fd_.fdtype; event.socket = swReactor_get(reactor, event.fd); //read if (object->events[i].filter == EVFILT_READ) { if (event.socket->removed) { continue; } handle = swReactor_getHandle(reactor, SW_EVENT_READ, event.type); ret = handle(reactor, &event); if (ret < 0) { swSysError("kqueue event read socket#%d handler failed.", event.fd); } } //write else if (object->events[i].filter == EVFILT_WRITE) { if (event.socket->removed) { continue; } handle = swReactor_getHandle(reactor, SW_EVENT_WRITE, event.type); ret = handle(reactor, &event); if (ret < 0) { swSysError("kqueue event write socket#%d handler failed.", event.fd); } } else { swWarn("unknown event filter[%d].", object->events[i].filter); } } } if (reactor->onFinish != NULL) { reactor->onFinish(reactor); } if (reactor->once) { break; } } return 0; }
static int swReactorKqueue_set(swReactor *reactor, int fd, int fdtype) { swReactorKqueue *this = reactor->object; struct kevent e; swFd fd_; int ret; bzero(&e, sizeof(e)); int fflags = 0; fd_.fd = fd; fd_.fdtype = swReactor_fdtype(fdtype); if (swReactor_event_read(fdtype)) { #ifdef NOTE_EOF fflags = NOTE_EOF; #endif EV_SET(&e, fd, EVFILT_READ, EV_ADD, fflags, 0, NULL); memcpy(&e.udata, &fd_, sizeof(swFd)); ret = kevent(this->epfd, &e, 1, NULL, 0, NULL); if (ret < 0) { swSysError("kqueue->set(%d, SW_EVENT_READ) failed.", fd); return SW_ERR; } } else { EV_SET(&e, fd, EVFILT_READ, EV_DELETE, 0, 0, NULL); memcpy(&e.udata, &fd_, sizeof(swFd)); ret = kevent(this->epfd, &e, 1, NULL, 0, NULL); if (ret < 0) { swSysError("kqueue->del(%d, SW_EVENT_READ) failed.", fd); return SW_ERR; } } if (swReactor_event_write(fdtype)) { EV_SET(&e, fd, EVFILT_WRITE, EV_ADD, 0, 0, NULL); memcpy(&e.udata, &fd_, sizeof(swFd)); ret = kevent(this->epfd, &e, 1, NULL, 0, NULL); if (ret < 0) { swSysError("kqueue->set(%d, SW_EVENT_WRITE) failed.", fd); return SW_ERR; } } else { EV_SET(&e, fd, EVFILT_WRITE, EV_DELETE, 0, 0, NULL); memcpy(&e.udata, &fd_, sizeof(swFd)); ret = kevent(this->epfd, &e, 1, NULL, 0, NULL); if (ret < 0) { swSysError("kqueue->del(%d, SW_EVENT_WRITE) failed.", fd); return SW_ERR; } } swTraceLog(SW_TRACE_EVENT, "[THREAD #%d]EP=%d|FD=%d, events=%d", SwooleTG.id, this->epfd, fd, fdtype); //execute parent method swReactor_set(reactor, fd, fdtype); return SW_OK; }
/** * Use message queue ipc */ int swFactoryProcess_writer_loop_queue(swThreadParam *param) { swEventData *resp; swServer *serv = SwooleG.serv; int pti = param->pti; swQueue_data sdata; //必须加1,msg_type必须不能为0 sdata.mtype = pti + 1; swSignal_none(); while (SwooleG.running > 0) { swTrace("[Writer]wt_queue[%ld]->out wait", sdata.mtype); if (serv->write_queue.out(&serv->write_queue, &sdata, sizeof(sdata.mdata)) < 0) { if (errno == EINTR) { continue; } swSysError("[writer#%d]wt_queue->out() failed.", pti); } else { int ret; resp = (swEventData *) sdata.mdata; //close connection //TODO: thread safe, should close in reactor thread. if (resp->info.type == SW_EVENT_CLOSE) { close_fd: swServer_connection_close(SwooleG.serv, resp->info.fd); continue; } //sendfile else if (resp->info.type == SW_EVENT_SENDFILE) { ret = swSocket_sendfile_sync(resp->info.fd, resp->data, SW_WRITER_TIMEOUT); } //send data else { ret = swConnection_send_blocking(resp->info.fd, resp->data, resp->info.len, 1000 * SW_WRITER_TIMEOUT); } if (ret < 0) { switch (swConnection_error(errno)) { case SW_ERROR: swSysError("send to client[%d] failed.", resp->info.fd); break; case SW_CLOSE: goto close_fd; default: break; } } } } pthread_exit((void *) param); return SW_OK; }
static int swFactoryProcess_manager_loop(swFactory *factory) { int pid, new_pid; int i; int reload_worker_i = 0; int reload_worker_num; int ret; int worker_exit_code; SwooleG.use_signalfd = 0; SwooleG.use_timerfd = 0; memset(&ManagerProcess, 0, sizeof(ManagerProcess)); swServer *serv = factory->ptr; swWorker *reload_workers; if (serv->onManagerStart) { serv->onManagerStart(serv); } reload_worker_num = serv->worker_num + SwooleG.task_worker_num; reload_workers = sw_calloc(reload_worker_num, sizeof(swWorker)); if (reload_workers == NULL) { swError("malloc[reload_workers] failed"); return SW_ERR; } //for reload swSignal_add(SIGTERM, swManager_signal_handle); swSignal_add(SIGUSR1, swManager_signal_handle); swSignal_add(SIGUSR2, swManager_signal_handle); //swSignal_add(SIGINT, swManager_signal_handle); while (SwooleG.running > 0) { pid = wait(&worker_exit_code); if (pid < 0) { if (ManagerProcess.reloading == 0) { swTrace("wait() failed. Error: %s [%d]", strerror(errno), errno); } else if (ManagerProcess.reload_event_worker == 1) { memcpy(reload_workers, serv->workers, sizeof(swWorker) * serv->worker_num); reload_worker_num = serv->worker_num; if (SwooleG.task_worker_num > 0) { memcpy(reload_workers + serv->worker_num, SwooleG.task_workers.workers, sizeof(swWorker) * SwooleG.task_worker_num); reload_worker_num += SwooleG.task_worker_num; } reload_worker_i = 0; ManagerProcess.reload_event_worker = 0; goto kill_worker; } else if (ManagerProcess.reload_task_worker == 1) { if (SwooleG.task_worker_num == 0) { swWarn("Cannot reload workers, because server no have task workers."); continue; } memcpy(reload_workers, SwooleG.task_workers.workers, sizeof(swWorker) * SwooleG.task_worker_num); reload_worker_num = SwooleG.task_worker_num; reload_worker_i = 0; ManagerProcess.reload_task_worker = 0; goto kill_worker; } } if (SwooleG.running == 1) { for (i = 0; i < serv->worker_num; i++) { //compare PID if (pid != serv->workers[i].pid) { continue; } else { if (serv->onWorkerError != NULL && WEXITSTATUS(worker_exit_code) > 0) { serv->onWorkerError(serv, i, pid, WEXITSTATUS(worker_exit_code)); } pid = 0; while (1) { new_pid = swFactoryProcess_worker_spawn(factory, i); if (new_pid < 0) { usleep(100000); continue; } else { serv->workers[i].pid = new_pid; break; } } } } //task worker if (pid > 0) { swWorker *exit_worker = swHashMap_find_int(SwooleG.task_workers.map, pid); if (exit_worker != NULL) { swProcessPool_spawn(exit_worker); } } } //reload worker kill_worker: if (ManagerProcess.reloading == 1) { //reload finish if (reload_worker_i >= reload_worker_num) { ManagerProcess.reloading = 0; reload_worker_i = 0; continue; } ret = kill(reload_workers[reload_worker_i].pid, SIGTERM); if (ret < 0) { swSysError("[Manager]kill(%d) failed.", reload_workers[reload_worker_i].pid); continue; } reload_worker_i++; } } sw_free(reload_workers); //kill all child process for (i = 0; i < serv->worker_num; i++) { swTrace("[Manager]kill worker processor"); kill(serv->workers[i].pid, SIGTERM); } if (SwooleG.task_worker_num > 0) { swProcessPool_shutdown(&SwooleG.task_workers); } if (serv->onManagerStop) { serv->onManagerStop(serv); } return SW_OK; }
void swWorker_signal_handler(int signo) { switch (signo) { case SIGTERM: if (SwooleG.main_reactor) { SwooleG.main_reactor->running = 0; } else { SwooleG.running = 0; } break; case SIGALRM: swSystemTimer_signal_handler(SIGALRM); break; /** * for test */ case SIGVTALRM: swWarn("SIGVTALRM coming"); break; case SIGUSR1: if (SwooleG.main_reactor) { swWorker *worker = SwooleWG.worker; swWarn(" the worker %d get the signo", worker->pid); SwooleWG.reload = 1; SwooleWG.reload_count = 0; //删掉read管道 swConnection *socket = swReactor_get(SwooleG.main_reactor, worker->pipe_worker); if (socket->events & SW_EVENT_WRITE) { socket->events &= (~SW_EVENT_READ); if (SwooleG.main_reactor->set(SwooleG.main_reactor, worker->pipe_worker, socket->fdtype | socket->events) < 0) { swSysError("reactor->set(%d, SW_EVENT_READ) failed.", worker->pipe_worker); } } else { if (SwooleG.main_reactor->del(SwooleG.main_reactor, worker->pipe_worker) < 0) { swSysError("reactor->del(%d) failed.", worker->pipe_worker); } } } else { SwooleG.running = 0; } break; case SIGUSR2: break; default: #ifdef SIGRTMIN if (signo == SIGRTMIN) { swServer_reopen_log_file(SwooleG.serv); } #endif break; } }