Init Repo

This commit is contained in:
root
2019-09-06 23:53:10 +08:00
commit f0ef89dfbb
7905 changed files with 914138 additions and 0 deletions

1548
vendor/swoole/src/network/Client.c vendored Executable file

File diff suppressed because it is too large Load Diff

374
vendor/swoole/src/network/Connection.c vendored Executable file
View File

@ -0,0 +1,374 @@
/*
+----------------------------------------------------------------------+
| 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 "Server.h"
#include <sys/stat.h>
#ifndef MSG_NOSIGNAL
#define MSG_NOSIGNAL 0
#endif
int swConnection_onSendfile(swConnection *conn, swBuffer_trunk *chunk)
{
int ret;
swTask_sendfile *task = chunk->store.ptr;
#ifdef HAVE_TCP_NOPUSH
if (task->offset == 0 && conn->tcp_nopush == 0)
{
/**
* disable tcp_nodelay
*/
if (conn->tcp_nodelay)
{
int tcp_nodelay = 0;
if (setsockopt(conn->fd, IPPROTO_TCP, TCP_NODELAY, (const void *) &tcp_nodelay, sizeof(int)) == -1)
{
swWarn("setsockopt(TCP_NODELAY) failed. Error: %s[%d]", strerror(errno), errno);
}
}
/**
* enable tcp_nopush
*/
if (swSocket_tcp_nopush(conn->fd, 1) == -1)
{
swWarn("swSocket_tcp_nopush() failed. Error: %s[%d]", strerror(errno), errno);
}
conn->tcp_nopush = 1;
}
#endif
int sendn = (task->length - task->offset > SW_SENDFILE_CHUNK_SIZE) ? SW_SENDFILE_CHUNK_SIZE : task->length - task->offset;
#ifdef SW_USE_OPENSSL
if (conn->ssl)
{
ret = swSSL_sendfile(conn, task->fd, &task->offset, sendn);
}
else
#endif
{
ret = swoole_sendfile(conn->fd, task->fd, &task->offset, sendn);
}
swTrace("ret=%d|task->offset=%ld|sendn=%d|filesize=%ld", ret, (long)task->offset, sendn, task->length);
if (ret <= 0)
{
switch (swConnection_error(errno))
{
case SW_ERROR:
swSysError("sendfile(%s, %ld, %d) failed.", task->filename, (long)task->offset, sendn);
swBuffer_pop_trunk(conn->out_buffer, chunk);
return SW_OK;
case SW_CLOSE:
conn->close_wait = 1;
return SW_ERR;
case SW_WAIT:
conn->send_wait = 1;
return SW_ERR;
default:
break;
}
}
//sendfile finish
if (task->offset >= task->length)
{
swBuffer_pop_trunk(conn->out_buffer, chunk);
#ifdef HAVE_TCP_NOPUSH
/**
* disable tcp_nopush
*/
if (swSocket_tcp_nopush(conn->fd, 0) == -1)
{
swWarn("swSocket_tcp_nopush() failed. Error: %s[%d]", strerror(errno), errno);
}
conn->tcp_nopush = 0;
/**
* enable tcp_nodelay
*/
if (conn->tcp_nodelay)
{
int value = 1;
if (setsockopt(conn->fd, IPPROTO_TCP, TCP_NODELAY, (const void *) &value, sizeof(int)) == -1)
{
swWarn("setsockopt(TCP_NODELAY) failed. Error: %s[%d]", strerror(errno), errno);
}
}
#endif
}
return SW_OK;
}
/**
* send buffer to client
*/
int swConnection_buffer_send(swConnection *conn)
{
int ret, sendn;
swBuffer *buffer = conn->out_buffer;
swBuffer_trunk *trunk = swBuffer_get_trunk(buffer);
sendn = trunk->length - trunk->offset;
if (sendn == 0)
{
swBuffer_pop_trunk(buffer, trunk);
return SW_OK;
}
ret = swConnection_send(conn, trunk->store.ptr + trunk->offset, sendn, 0);
if (ret < 0)
{
switch (swConnection_error(errno))
{
case SW_ERROR:
swWarn("send to fd[%d] failed. Error: %s[%d]", conn->fd, strerror(errno), errno);
break;
case SW_CLOSE:
conn->close_errno = errno;
conn->close_wait = 1;
return SW_ERR;
case SW_WAIT:
conn->send_wait = 1;
return SW_ERR;
default:
break;
}
return SW_OK;
}
//trunk full send
else if (ret == sendn || sendn == 0)
{
swBuffer_pop_trunk(buffer, trunk);
}
else
{
trunk->offset += ret;
}
return SW_OK;
}
swString* swConnection_get_string_buffer(swConnection *conn)
{
swString *buffer = conn->object;
if (buffer == NULL)
{
return swString_new(SW_BUFFER_SIZE);
}
else
{
return buffer;
}
}
static char tmp_address[INET6_ADDRSTRLEN];
char* swConnection_get_ip(swConnection *conn)
{
if (conn->socket_type == SW_SOCK_TCP)
{
return inet_ntoa(conn->info.addr.inet_v4.sin_addr);
}
else if (conn->socket_type == SW_SOCK_TCP6)
{
if (inet_ntop(AF_INET6, &conn->info.addr.inet_v6.sin6_addr, tmp_address, sizeof(tmp_address)) == NULL)
{
return "unknown";
}
else
{
return tmp_address;
}
}
else if (conn->socket_type == SW_SOCK_UNIX_STREAM)
{
return conn->info.addr.un.sun_path;
}
else
{
return "unknown";
}
}
int swConnection_get_port(swConnection *conn)
{
if (conn->socket_type == SW_SOCK_TCP)
{
return ntohs(conn->info.addr.inet_v4.sin_port);
}
else
{
return ntohs(conn->info.addr.inet_v6.sin6_port);
}
}
void swConnection_sendfile_destructor(swBuffer_trunk *chunk)
{
swTask_sendfile *task = chunk->store.ptr;
close(task->fd);
sw_free(task->filename);
sw_free(task);
}
int swConnection_sendfile(swConnection *conn, char *filename, off_t offset, size_t length)
{
if (conn->out_buffer == NULL)
{
conn->out_buffer = swBuffer_new(SW_BUFFER_SIZE);
if (conn->out_buffer == NULL)
{
return SW_ERR;
}
}
swBuffer_trunk error_chunk;
swTask_sendfile *task = sw_malloc(sizeof(swTask_sendfile));
if (task == NULL)
{
swWarn("malloc for swTask_sendfile failed.");
return SW_ERR;
}
bzero(task, sizeof(swTask_sendfile));
task->filename = sw_strdup(filename);
int file_fd = open(filename, O_RDONLY);
if (file_fd < 0)
{
sw_free(task->filename);
sw_free(task);
swSysError("open(%s) failed.", filename);
return SW_OK;
}
task->fd = file_fd;
task->offset = offset;
struct stat file_stat;
if (fstat(file_fd, &file_stat) < 0)
{
swSysError("fstat(%s) failed.", filename);
error_chunk.store.ptr = task;
swConnection_sendfile_destructor(&error_chunk);
return SW_ERR;
}
if (offset < 0 || (length + offset > file_stat.st_size))
{
swoole_error_log(SW_LOG_WARNING, SW_ERROR_INVALID_PARAMS, "length or offset is invalid.");
error_chunk.store.ptr = task;
swConnection_sendfile_destructor(&error_chunk);
return SW_OK;
}
if (length == 0)
{
task->length = file_stat.st_size;
}
else
{
task->length = length + offset;
}
swBuffer_trunk *chunk = swBuffer_new_trunk(conn->out_buffer, SW_CHUNK_SENDFILE, 0);
if (chunk == NULL)
{
swWarn("get out_buffer trunk failed.");
error_chunk.store.ptr = task;
swConnection_sendfile_destructor(&error_chunk);
return SW_ERR;
}
chunk->store.ptr = (void *) task;
chunk->destroy = swConnection_sendfile_destructor;
return SW_OK;
}
void swConnection_clear_string_buffer(swConnection *conn)
{
swString *buffer = conn->object;
if (buffer != NULL)
{
swString_free(buffer);
conn->object = NULL;
}
}
swBuffer_trunk* swConnection_get_in_buffer(swConnection *conn)
{
swBuffer_trunk *trunk = NULL;
swBuffer *buffer;
if (conn->in_buffer == NULL)
{
buffer = swBuffer_new(SW_BUFFER_SIZE);
//buffer create failed
if (buffer == NULL)
{
return NULL;
}
//new trunk
trunk = swBuffer_new_trunk(buffer, SW_CHUNK_DATA, buffer->trunk_size);
if (trunk == NULL)
{
sw_free(buffer);
return NULL;
}
conn->in_buffer = buffer;
}
else
{
buffer = conn->in_buffer;
trunk = buffer->tail;
if (trunk == NULL || trunk->length == buffer->trunk_size)
{
trunk = swBuffer_new_trunk(buffer, SW_CHUNK_DATA, buffer->trunk_size);
}
}
return trunk;
}
swBuffer_trunk* swConnection_get_out_buffer(swConnection *conn, uint32_t type)
{
swBuffer_trunk *trunk;
if (conn->out_buffer == NULL)
{
conn->out_buffer = swBuffer_new(SW_BUFFER_SIZE);
if (conn->out_buffer == NULL)
{
return NULL;
}
}
if (type == SW_CHUNK_SENDFILE)
{
trunk = swBuffer_new_trunk(conn->out_buffer, SW_CHUNK_SENDFILE, 0);
}
else
{
trunk = swBuffer_get_trunk(conn->out_buffer);
if (trunk == NULL)
{
trunk = swBuffer_new_trunk(conn->out_buffer, SW_CHUNK_DATA, conn->out_buffer->trunk_size);
}
}
return trunk;
}

485
vendor/swoole/src/network/DNS.c vendored Executable file
View File

@ -0,0 +1,485 @@
/*
+----------------------------------------------------------------------+
| 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 "Client.h"
#define SW_DNS_SERVER_CONF "/etc/resolv.conf"
#define SW_DNS_SERVER_NUM 2
enum swDNS_type
{
SW_DNS_A_RECORD = 0x01, //Lookup IPv4 address
SW_DNS_AAAA_RECORD = 0x1c, //Lookup IPv6 address
SW_DNS_MX_RECORD = 0x0f //Lookup mail server for domain
};
enum swDNS_error
{
SW_DNS_NOT_EXIST, //Error: adress does not exist
SW_DNS_TIMEOUT, //Lookup time expired
SW_DNS_ERROR //No memory or other error
};
typedef struct
{
void (*callback)(char *domain, swDNSResolver_result *result, void *data);
char *domain;
void *data;
} swDNS_lookup_request;
typedef struct
{
uint8_t num;
} swDNS_result;
/* Struct for the DNS Header */
typedef struct
{
uint16_t id;
uchar rd :1;
uchar tc :1;
uchar aa :1;
uchar opcode :4;
uchar qr :1;
uchar rcode :4;
uchar z :3;
uchar ra :1;
uint16_t qdcount;
uint16_t ancount;
uint16_t nscount;
uint16_t arcount;
} swDNSResolver_header;
/* Struct for the flags for the DNS Question */
typedef struct q_flags
{
uint16_t qtype;
uint16_t qclass;
} Q_FLAGS;
/* Struct for the flags for the DNS RRs */
typedef struct rr_flags
{
uint16_t type;
uint16_t class;
uint32_t ttl;
uint16_t rdlength;
} RR_FLAGS;
static uint16_t swoole_dns_request_id = 1;
static swClient *resolver_socket = NULL;
static swHashMap *request_map = NULL;
static int domain_encode(char *src, int n, char *dest);
static void domain_decode(char *str);
static int swDNSResolver_get_server();
static int swDNSResolver_onReceive(swReactor *reactor, swEvent *event);
static int swDNSResolver_get_server()
{
FILE *fp;
char line[100];
char buf[16] = {0};
if ((fp = fopen(SW_DNS_SERVER_CONF, "rt")) == NULL)
{
swWarn("fopen("SW_DNS_SERVER_CONF") failed. Error: %s[%d]", strerror(errno), errno);
return SW_ERR;
}
while (fgets(line, 100, fp))
{
if (strncmp(line, "nameserver", 10) == 0)
{
strcpy(buf, strtok(line, " "));
strcpy(buf, strtok(NULL, "\n"));
break;
}
}
fclose(fp);
if (strlen(buf) == 0)
{
SwooleG.dns_server_v4 = sw_strdup(SW_DNS_DEFAULT_SERVER);
}
else
{
SwooleG.dns_server_v4 = sw_strdup(buf);
}
return SW_OK;
}
static int swDNSResolver_onReceive(swReactor *reactor, swEvent *event)
{
swDNSResolver_header *header = NULL;
Q_FLAGS *qflags = NULL;
RR_FLAGS *rrflags = NULL;
char packet[SW_CLIENT_BUFFER_SIZE];
uchar rdata[10][254];
uint32_t type[10];
char *temp;
uint16_t steps;
char *_domain_name;
char name[10][254];
int i, j;
int ret = recv(event->fd, packet, sizeof(packet) - 1, 0);
if (ret <= 0)
{
return SW_ERR;
}
packet[ret] = 0;
header = (swDNSResolver_header *) packet;
steps = sizeof(swDNSResolver_header);
_domain_name = &packet[steps];
domain_decode(_domain_name);
steps = steps + (strlen(_domain_name) + 2);
qflags = (Q_FLAGS *) &packet[steps];
(void) qflags;
steps = steps + sizeof(Q_FLAGS);
int ancount = ntohs(header->ancount);
if (ancount > 10)
{
ancount = 10;
}
/* Parsing the RRs from the reply packet */
for (i = 0; i < ancount; ++i)
{
type[i] = 0;
/* Parsing the NAME portion of the RR */
temp = &packet[steps];
j = 0;
while (*temp != 0)
{
if ((uchar) (*temp) == 0xc0)
{
++temp;
temp = &packet[(uint8_t) *temp];
}
else
{
name[i][j] = *temp;
++j;
++temp;
}
}
name[i][j] = '\0';
domain_decode(name[i]);
steps = steps + 2;
/* Parsing the RR flags of the RR */
rrflags = (RR_FLAGS *) &packet[steps];
steps = steps + sizeof(RR_FLAGS) - 2;
/* Parsing the IPv4 address in the RR */
if (ntohs(rrflags->type) == 1)
{
for (j = 0; j < ntohs(rrflags->rdlength); ++j)
{
rdata[i][j] = (uchar) packet[steps + j];
}
type[i] = ntohs(rrflags->type);
}
/* Parsing the canonical name in the RR */
if (ntohs(rrflags->type) == 5)
{
temp = &packet[steps];
j = 0;
while (*temp != 0)
{
if ((uchar)(*temp) == 0xc0)
{
++temp;
temp = &packet[(uint8_t) *temp];
}
else
{
rdata[i][j] = *temp;
++j;
++temp;
}
}
rdata[i][j] = '\0';
domain_decode((char *) rdata[i]);
type[i] = ntohs(rrflags->type);
}
steps = steps + ntohs(rrflags->rdlength);
}
char key[1024];
int request_id = ntohs(header->id);
int key_len = snprintf(key, sizeof(key), "%s-%d", _domain_name, request_id);
swDNS_lookup_request *request = swHashMap_find(request_map, key, key_len);
if (request == NULL)
{
swWarn("bad response, request_id=%d.", request_id);
return SW_OK;
}
swDNSResolver_result result;
bzero(&result, sizeof(result));
for (i = 0; i < ancount; ++i)
{
if (type[i] != SW_DNS_A_RECORD)
{
continue;
}
j = result.num;
result.num++;
result.hosts[j].length = sprintf(result.hosts[j].address, "%d.%d.%d.%d", rdata[i][0], rdata[i][1], rdata[i][2], rdata[i][3]);
if (result.num == SW_DNS_HOST_BUFFER_SIZE)
{
break;
}
}
request->callback(request->domain, &result, request->data);
swHashMap_del(request_map, key, key_len);
sw_free(request->domain);
sw_free(request);
return SW_OK;
}
int swDNSResolver_request(char *domain, void (*callback)(char *, swDNSResolver_result *, void *), void *data)
{
char *_domain_name;
Q_FLAGS *qflags = NULL;
char packet[SW_BUFFER_SIZE_STD];
char key[1024];
swDNSResolver_header *header = NULL;
int steps = 0;
if (SwooleG.dns_server_v4 == NULL)
{
if (swDNSResolver_get_server() < 0)
{
return SW_ERR;
}
}
header = (swDNSResolver_header *) packet;
header->id = htons(swoole_dns_request_id);
header->qr = 0;
header->opcode = 0;
header->aa = 0;
header->tc = 0;
header->rd = 1;
header->ra = 0;
header->z = 0;
header->rcode = 0;
header->qdcount = htons(1);
header->ancount = 0x0000;
header->nscount = 0x0000;
header->arcount = 0x0000;
steps = sizeof(swDNSResolver_header);
_domain_name = &packet[steps];
int len = strlen(domain);
if (len >= sizeof(key))
{
swWarn("domain name is too long.");
return SW_ERR;
}
int key_len = snprintf(key, sizeof(key), "%s-%d", domain, swoole_dns_request_id);
if (!request_map)
{
request_map = swHashMap_new(128, NULL);
}
else if (swHashMap_find(request_map, key, key_len))
{
swoole_error_log(SW_LOG_WARNING, SW_ERROR_DNSLOOKUP_DUPLICATE_REQUEST, "duplicate request.");
return SW_ERR;
}
swDNS_lookup_request *request = sw_malloc(sizeof(swDNS_lookup_request));
if (request == NULL)
{
swWarn("malloc(%d) failed.", (int ) sizeof(swDNS_lookup_request));
return SW_ERR;
}
request->domain = sw_strndup(domain, len + 1);
if (request->domain == NULL)
{
swWarn("strdup(%d) failed.", len + 1);
sw_free(request);
return SW_ERR;
}
request->data = data;
request->callback = callback;
if (domain_encode(request->domain, len, _domain_name) < 0)
{
swWarn("invalid domain[%s].", domain);
sw_free(request->domain);
sw_free(request);
return SW_ERR;
}
steps += (strlen((const char *) _domain_name) + 1);
qflags = (Q_FLAGS *) &packet[steps];
qflags->qtype = htons(SW_DNS_A_RECORD);
qflags->qclass = htons(0x0001);
steps += sizeof(Q_FLAGS);
if (resolver_socket == NULL)
{
resolver_socket = sw_malloc(sizeof(swClient));
if (resolver_socket == NULL)
{
sw_free(request->domain);
sw_free(request);
swWarn("malloc failed.");
return SW_ERR;
}
if (swClient_create(resolver_socket, SW_SOCK_UDP, 0) < 0)
{
sw_free(resolver_socket);
sw_free(request->domain);
sw_free(request);
return SW_ERR;
}
char *_port;
int dns_server_port = SW_DNS_SERVER_PORT;
char dns_server_host[32];
strcpy(dns_server_host, SwooleG.dns_server_v4);
if ((_port = strchr(SwooleG.dns_server_v4, ':')))
{
dns_server_port = atoi(_port + 1);
dns_server_host[_port - SwooleG.dns_server_v4] = '\0';
}
if (resolver_socket->connect(resolver_socket, dns_server_host, dns_server_port, 1, 0) < 0)
{
do_close: resolver_socket->close(resolver_socket);
swClient_free(resolver_socket);
sw_free(resolver_socket);
sw_free(request->domain);
sw_free(request);
resolver_socket = NULL;
return SW_ERR;
}
SwooleG.main_reactor->setHandle(SwooleG.main_reactor, SW_FD_DNS_RESOLVER, swDNSResolver_onReceive);
if (SwooleG.main_reactor->add(SwooleG.main_reactor, resolver_socket->socket->fd, SW_FD_DNS_RESOLVER))
{
goto do_close;
}
}
if (resolver_socket->send(resolver_socket, (char *) packet, steps, 0) < 0)
{
goto do_close;
}
swHashMap_add(request_map, key, key_len, request);
swoole_dns_request_id++;
return SW_OK;
}
int swDNSResolver_free()
{
if (resolver_socket == NULL)
{
return SW_ERR;
}
if (SwooleG.main_reactor == NULL)
{
return SW_ERR;
}
if (swHashMap_count(request_map) > 0)
{
return SW_ERR;
}
SwooleG.main_reactor->del(SwooleG.main_reactor, resolver_socket->socket->fd);
resolver_socket->close(resolver_socket);
swClient_free(resolver_socket);
sw_free(resolver_socket);
resolver_socket = NULL;
swHashMap_free(request_map);
request_map = NULL;
return SW_OK;
}
/**
* The function converts the dot-based hostname into the DNS format
* (i.e. www.apple.com into 3www5apple3com0)
*/
static int domain_encode(char *src, int n, char *dest)
{
if (src[n] == '.')
{
return SW_ERR;
}
int pos = 0;
int i;
int len = 0;
memcpy(dest + 1, src, n + 1);
dest[n + 1] = '.';
dest[n + 2] = 0;
src = dest + 1;
n++;
for (i = 0; i < n; i++)
{
if (src[i] == '.')
{
len = i - pos;
dest[pos] = len;
pos += len + 1;
}
}
dest[pos] = 0;
return SW_OK;
}
/**
* This function converts a DNS-based hostname into dot-based format
* (i.e. 3www5apple3com0 into www.apple.com)
*/
static void domain_decode(char *str)
{
int i, j;
for (i = 0; i < strlen((const char*) str); i++)
{
unsigned int len = str[i];
for (j = 0; j < len; j++)
{
str[i] = str[i + 1];
i++;
}
str[i] = '.';
}
str[i - 1] = '\0';
}

642
vendor/swoole/src/network/Manager.c vendored Executable file
View File

@ -0,0 +1,642 @@
/*
+----------------------------------------------------------------------+
| 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 <sys/wait.h>
typedef struct
{
uint8_t reloading;
uint8_t reload_all_worker;
uint8_t reload_task_worker;
uint8_t read_message;
uint8_t alarm;
} swManagerProcess;
static int swManager_loop(swFactory *factory);
static void swManager_signal_handle(int sig);
static pid_t swManager_spawn_worker(swFactory *factory, int worker_id);
static void swManager_check_exit_status(swServer *serv, int worker_id, pid_t pid, int status);
static swManagerProcess ManagerProcess;
//create worker child proccess
int swManager_start(swFactory *factory)
{
swFactoryProcess *object = factory->object;
int i;
pid_t pid;
swServer *serv = factory->ptr;
object->pipes = sw_calloc(serv->worker_num, sizeof(swPipe));
if (object->pipes == NULL)
{
swError("malloc[worker_pipes] failed. Error: %s [%d]", strerror(errno), errno);
return SW_ERR;
}
//worker进程的pipes
for (i = 0; i < serv->worker_num; i++)
{
if (swPipeUnsock_create(&object->pipes[i], 1, SOCK_DGRAM) < 0)
{
return SW_ERR;
}
serv->workers[i].pipe_master = object->pipes[i].getFd(&object->pipes[i], SW_PIPE_MASTER);
serv->workers[i].pipe_worker = object->pipes[i].getFd(&object->pipes[i], SW_PIPE_WORKER);
serv->workers[i].pipe_object = &object->pipes[i];
swServer_store_pipe_fd(serv, serv->workers[i].pipe_object);
}
if (serv->task_worker_num > 0)
{
if (swServer_create_task_worker(serv) < 0)
{
return SW_ERR;
}
swProcessPool *pool = &serv->gs->task_workers;
swTaskWorker_init(pool);
swWorker *worker;
for (i = 0; i < serv->task_worker_num; i++)
{
worker = &pool->workers[i];
if (swWorker_create(worker) < 0)
{
return SW_ERR;
}
if (serv->task_ipc_mode == SW_TASK_IPC_UNIXSOCK)
{
swServer_store_pipe_fd(SwooleG.serv, worker->pipe_object);
}
}
}
//User Worker Process
if (serv->user_worker_num > 0)
{
serv->user_workers = SwooleG.memory_pool->alloc(SwooleG.memory_pool, serv->user_worker_num * sizeof(swWorker));
if (serv->user_workers == NULL)
{
swoole_error_log(SW_LOG_ERROR, SW_ERROR_SYSTEM_CALL_FAIL, "gmalloc[server->user_workers] failed.");
return SW_ERR;
}
swUserWorker_node *user_worker;
i = 0;
LL_FOREACH(serv->user_worker_list, user_worker)
{
memcpy(&serv->user_workers[i], user_worker->worker, sizeof(swWorker));
if (swWorker_create(&serv->user_workers[i]) < 0)
{
return SW_ERR;
}
i++;
}
}
serv->message_box = swChannel_new(65536, sizeof(swWorkerStopMessage), SW_CHAN_LOCK | SW_CHAN_SHM);
if (serv->message_box == NULL)
{
return SW_ERR;
}
pid = fork();
switch (pid)
{
//fork manager process
case 0:
//wait master process
SW_START_SLEEP;
if (serv->gs->start == 0)
{
return SW_OK;
}
swServer_close_listen_port(serv);
/**
* create task worker process
*/
if (serv->task_worker_num > 0)
{
swProcessPool_start(&serv->gs->task_workers);
}
/**
* create worker process
*/
for (i = 0; i < serv->worker_num; i++)
{
//close(worker_pipes[i].pipes[0]);
pid = swManager_spawn_worker(factory, i);
if (pid < 0)
{
swError("fork() failed.");
return SW_ERR;
}
else
{
serv->workers[i].pid = pid;
}
}
/**
* create user worker process
*/
if (serv->user_worker_list)
{
swUserWorker_node *user_worker;
LL_FOREACH(serv->user_worker_list, user_worker)
{
/**
* store the pipe object
*/
if (user_worker->worker->pipe_object)
{
swServer_store_pipe_fd(serv, user_worker->worker->pipe_object);
}
swManager_spawn_user_worker(serv, user_worker->worker);
}
}
SwooleG.process_type = SW_PROCESS_MANAGER;
SwooleG.pid = getpid();
exit(swManager_loop(factory));
break;
//master process
default:
serv->gs->manager_pid = pid;
break;
case -1:
swError("fork() failed.");
return SW_ERR;
}
return SW_OK;
}
static void swManager_check_exit_status(swServer *serv, int worker_id, pid_t pid, int status)
{
if (status != 0)
{
swWarn("worker#%d abnormal exit, status=%d, signal=%d", worker_id, WEXITSTATUS(status), WTERMSIG(status));
if (serv->onWorkerError != NULL)
{
serv->onWorkerError(serv, worker_id, pid, WEXITSTATUS(status), WTERMSIG(status));
}
}
}
static int swManager_loop(swFactory *factory)
{
int pid, new_pid;
int i;
int reload_worker_i = 0;
int reload_worker_num;
int reload_init = 0;
pid_t reload_worker_pid = 0;
int status;
SwooleG.use_signalfd = 0;
SwooleG.use_timerfd = 0;
memset(&ManagerProcess, 0, sizeof(ManagerProcess));
swServer *serv = factory->ptr;
swWorker *reload_workers;
if (serv->hooks[SW_SERVER_HOOK_MANAGER_START])
{
swServer_call_hook(serv, SW_SERVER_HOOK_MANAGER_START, serv);
}
if (serv->onManagerStart)
{
serv->onManagerStart(serv);
}
reload_worker_num = serv->worker_num + serv->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(SIGHUP, NULL);
swSignal_add(SIGTERM, swManager_signal_handle);
swSignal_add(SIGUSR1, swManager_signal_handle);
swSignal_add(SIGUSR2, swManager_signal_handle);
swSignal_add(SIGIO, swManager_signal_handle);
#ifdef SIGRTMIN
swSignal_add(SIGRTMIN, swManager_signal_handle);
#endif
//swSignal_add(SIGINT, swManager_signal_handle);
if (serv->manager_alarm > 0)
{
alarm(serv->manager_alarm);
swSignal_add(SIGALRM, swManager_signal_handle);
}
SwooleG.main_reactor = NULL;
while (SwooleG.running > 0)
{
_wait: pid = wait(&status);
if (ManagerProcess.read_message)
{
swWorkerStopMessage msg;
while (swChannel_pop(serv->message_box, &msg, sizeof(msg)) > 0)
{
if (SwooleG.running == 0)
{
continue;
}
pid_t new_pid = swManager_spawn_worker(factory, msg.worker_id);
if (new_pid > 0)
{
serv->workers[msg.worker_id].pid = new_pid;
}
}
ManagerProcess.read_message = 0;
}
if (pid < 0)
{
if (ManagerProcess.alarm == 1)
{
ManagerProcess.alarm = 0;
alarm(serv->manager_alarm);
if (serv->hooks[SW_SERVER_HOOK_MANAGER_TIMER])
{
swServer_call_hook(serv, SW_SERVER_HOOK_MANAGER_TIMER, serv);
}
}
if (ManagerProcess.reloading == 0)
{
error: if (errno != EINTR)
{
swSysError("wait() failed.");
}
continue;
}
//reload task & event workers
else if (ManagerProcess.reload_all_worker == 1)
{
swNotice("Server is reloading now.");
if (reload_init == 0)
{
reload_init = 1;
memcpy(reload_workers, serv->workers, sizeof(swWorker) * serv->worker_num);
reload_worker_num = serv->worker_num;
if (serv->task_worker_num > 0)
{
memcpy(reload_workers + serv->worker_num, serv->gs->task_workers.workers,
sizeof(swWorker) * serv->task_worker_num);
reload_worker_num += serv->task_worker_num;
}
ManagerProcess.reload_all_worker = 0;
if (serv->reload_async)
{
for (i = 0; i < serv->worker_num; i++)
{
if (kill(reload_workers[i].pid, SIGTERM) < 0)
{
swSysError("kill(%d, SIGTERM) [%d] failed.", reload_workers[i].pid, i);
}
}
reload_worker_i = serv->worker_num;
}
else
{
reload_worker_i = 0;
}
}
goto kill_worker;
}
//only reload task workers
else if (ManagerProcess.reload_task_worker == 1)
{
if (serv->task_worker_num == 0)
{
swWarn("cannot reload task workers, task workers is not started.");
continue;
}
swNotice("Server is reloading now.");
if (reload_init == 0)
{
memcpy(reload_workers, serv->gs->task_workers.workers, sizeof(swWorker) * serv->task_worker_num);
reload_worker_num = serv->task_worker_num;
reload_worker_i = 0;
reload_init = 1;
ManagerProcess.reload_task_worker = 0;
}
goto kill_worker;
}
else
{
goto error;
}
}
if (SwooleG.running == 1)
{
//event workers
for (i = 0; i < serv->worker_num; i++)
{
//compare PID
if (pid != serv->workers[i].pid)
{
continue;
}
if (WIFSTOPPED(status) && serv->workers[i].tracer)
{
serv->workers[i].tracer(&serv->workers[i]);
serv->workers[i].tracer = NULL;
goto _wait;
}
//Check the process return code and signal
swManager_check_exit_status(serv, i, pid, status);
while (1)
{
new_pid = swManager_spawn_worker(factory, i);
if (new_pid < 0)
{
usleep(100000);
continue;
}
else
{
serv->workers[i].pid = new_pid;
break;
}
}
}
swWorker *exit_worker;
//task worker
if (serv->gs->task_workers.map)
{
exit_worker = swHashMap_find_int(serv->gs->task_workers.map, pid);
if (exit_worker != NULL)
{
if (WIFSTOPPED(status) && exit_worker->tracer)
{
exit_worker->tracer(exit_worker);
exit_worker->tracer = NULL;
goto _wait;
}
swManager_check_exit_status(serv, exit_worker->id, pid, status);
swProcessPool_spawn(&serv->gs->task_workers, exit_worker);
}
}
//user process
if (serv->user_worker_map != NULL)
{
swManager_wait_user_worker(&serv->gs->event_workers, pid, status);
}
if (pid == reload_worker_pid)
{
reload_worker_i++;
}
}
//reload worker
kill_worker: if (ManagerProcess.reloading == 1)
{
//reload finish
if (reload_worker_i >= reload_worker_num)
{
reload_worker_pid = reload_worker_i = reload_init = ManagerProcess.reloading = 0;
continue;
}
reload_worker_pid = reload_workers[reload_worker_i].pid;
if (kill(reload_worker_pid, SIGTERM) < 0)
{
if (errno == ECHILD)
{
reload_worker_i++;
goto kill_worker;
}
swSysError("kill(%d, SIGTERM) [%d] failed.", reload_workers[reload_worker_i].pid, reload_worker_i);
}
}
}
sw_free(reload_workers);
swSignal_none();
//kill all child process
for (i = 0; i < serv->worker_num; i++)
{
swTrace("[Manager]kill worker processor");
kill(serv->workers[i].pid, SIGTERM);
}
//kill and wait task process
if (serv->task_worker_num > 0)
{
swProcessPool_shutdown(&serv->gs->task_workers);
}
//wait child process
for (i = 0; i < serv->worker_num; i++)
{
if (swWaitpid(serv->workers[i].pid, &status, 0) < 0)
{
swSysError("waitpid(%d) failed.", serv->workers[i].pid);
}
}
//kill all user process
if (serv->user_worker_map)
{
swManager_kill_user_worker(serv);
}
if (serv->onManagerStop)
{
serv->onManagerStop(serv);
}
return SW_OK;
}
static pid_t swManager_spawn_worker(swFactory *factory, int worker_id)
{
pid_t pid;
int ret;
pid = fork();
//fork() failed
if (pid < 0)
{
swWarn("Fork Worker failed. Error: %s [%d]", strerror(errno), errno);
return SW_ERR;
}
//worker child processor
else if (pid == 0)
{
ret = swWorker_loop(factory, worker_id);
exit(ret);
}
//parent,add to writer
else
{
return pid;
}
}
static void swManager_signal_handle(int sig)
{
switch (sig)
{
case SIGTERM:
SwooleG.running = 0;
break;
/**
* reload all workers
*/
case SIGUSR1:
if (ManagerProcess.reloading == 0)
{
ManagerProcess.reloading = 1;
ManagerProcess.reload_all_worker = 1;
}
break;
/**
* only reload task workers
*/
case SIGUSR2:
if (ManagerProcess.reloading == 0)
{
ManagerProcess.reloading = 1;
ManagerProcess.reload_task_worker = 1;
}
break;
case SIGIO:
ManagerProcess.read_message = 1;
break;
case SIGALRM:
ManagerProcess.alarm = 1;
break;
default:
#ifdef SIGRTMIN
if (sig == SIGRTMIN)
{
swServer_reopen_log_file(SwooleG.serv);
}
#endif
break;
}
}
int swManager_wait_user_worker(swProcessPool *pool, pid_t pid, int status)
{
swServer *serv = SwooleG.serv;
swWorker *exit_worker = swHashMap_find_int(serv->user_worker_map, pid);
if (exit_worker != NULL)
{
swManager_check_exit_status(serv, exit_worker->id, pid, status);
return swManager_spawn_user_worker(serv, exit_worker);
}
else
{
return SW_ERR;
}
}
void swManager_kill_user_worker(swServer *serv)
{
if (!serv->user_worker_map)
{
return;
}
swWorker* user_worker;
uint64_t key;
int __stat_loc;
//kill user process
while (1)
{
user_worker = swHashMap_each_int(serv->user_worker_map, &key);
//hashmap empty
if (user_worker == NULL)
{
break;
}
kill(user_worker->pid, SIGTERM);
}
//wait user process
while (1)
{
user_worker = swHashMap_each_int(serv->user_worker_map, &key);
//hashmap empty
if (user_worker == NULL)
{
break;
}
if (swWaitpid(user_worker->pid, &__stat_loc, 0) < 0)
{
swSysError("waitpid(%d) failed.", user_worker->pid);
}
}
}
pid_t swManager_spawn_user_worker(swServer *serv, swWorker* worker)
{
pid_t pid = fork();
if (pid < 0)
{
swWarn("Fork Worker failed. Error: %s [%d]", strerror(errno), errno);
return SW_ERR;
}
//child
else if (pid == 0)
{
SwooleG.process_type = SW_PROCESS_USERWORKER;
SwooleWG.worker = worker;
SwooleWG.id = worker->id;
worker->pid = getpid();
//close tcp listen socket
if (serv->factory_mode == SW_MODE_SINGLE)
{
swServer_close_port(serv, SW_TRUE);
}
serv->onUserWorkerStart(serv, worker);
exit(0);
}
//parent
else
{
if (worker->pid)
{
swHashMap_del_int(serv->user_worker_map, worker->pid);
}
worker->pid = pid;
swHashMap_add_int(serv->user_worker_map, pid, worker);
return pid;
}
}

757
vendor/swoole/src/network/Port.c vendored Executable file
View File

@ -0,0 +1,757 @@
/*
+----------------------------------------------------------------------+
| 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 "Server.h"
#include "http.h"
#include "http2.h"
#include "websocket.h"
#include "mqtt.h"
#include "redis.h"
#include <sys/stat.h>
static int swPort_onRead_raw(swReactor *reactor, swListenPort *lp, swEvent *event);
static int swPort_onRead_check_length(swReactor *reactor, swListenPort *lp, swEvent *event);
static int swPort_onRead_check_eof(swReactor *reactor, swListenPort *lp, swEvent *event);
static int swPort_onRead_http(swReactor *reactor, swListenPort *lp, swEvent *event);
static int swPort_onRead_redis(swReactor *reactor, swListenPort *lp, swEvent *event);
static int swPort_http_static_handler(swHttpRequest *request, swConnection *conn);
void swPort_init(swListenPort *port)
{
port->sock = 0;
port->ssl = 0;
//listen backlog
port->backlog = SW_BACKLOG;
//tcp keepalive
port->tcp_keepcount = SW_TCP_KEEPCOUNT;
port->tcp_keepinterval = SW_TCP_KEEPINTERVAL;
port->tcp_keepidle = SW_TCP_KEEPIDLE;
port->open_tcp_nopush = 1;
port->protocol.package_length_type = 'N';
port->protocol.package_length_size = 4;
port->protocol.package_body_offset = 4;
port->protocol.package_max_length = SW_BUFFER_INPUT_SIZE;
port->socket_buffer_size = SwooleG.socket_buffer_size;
char eof[] = SW_DATA_EOF;
port->protocol.package_eof_len = sizeof(SW_DATA_EOF) - 1;
memcpy(port->protocol.package_eof, eof, port->protocol.package_eof_len);
}
#ifdef SW_USE_OPENSSL
int swPort_enable_ssl_encrypt(swListenPort *ls)
{
if (ls->ssl_option.cert_file == NULL || ls->ssl_option.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_option);
if (ls->ssl_context == NULL)
{
swWarn("swSSL_get_context() error.");
return SW_ERR;
}
/**
* OpenSSL thread-safe
*/
swSSL_init_thread_safety();
if (ls->ssl_option.client_cert_file
&& swSSL_set_client_certificate(ls->ssl_context, ls->ssl_option.client_cert_file,
ls->ssl_option.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;
}
return SW_OK;
}
#endif
int swPort_listen(swListenPort *ls)
{
int sock = ls->sock;
int option = 1;
//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)
{
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
ls->buffer_high_watermark = ls->socket_buffer_size * 0.8;
ls->buffer_low_watermark = 0;
return SW_OK;
}
void swPort_set_protocol(swListenPort *ls)
{
//Thread mode must copy the data.
//will free after onFinish
if (ls->open_eof_check)
{
if (ls->protocol.package_eof_len > sizeof(ls->protocol.package_eof))
{
ls->protocol.package_eof_len = sizeof(ls->protocol.package_eof);
}
ls->protocol.onPackage = swReactorThread_dispatch;
ls->onRead = swPort_onRead_check_eof;
}
else if (ls->open_length_check)
{
if (ls->protocol.package_length_type != '\0')
{
ls->protocol.get_package_length = swProtocol_get_package_length;
}
ls->protocol.onPackage = swReactorThread_dispatch;
ls->onRead = swPort_onRead_check_length;
}
else if (ls->open_http_protocol)
{
if (ls->open_websocket_protocol)
{
ls->protocol.get_package_length = swWebSocket_get_package_length;
ls->protocol.onPackage = swWebSocket_dispatch_frame;
ls->protocol.package_length_size = SW_WEBSOCKET_HEADER_LEN + SW_WEBSOCKET_MASK_LEN + sizeof(uint64_t);
}
#ifdef SW_USE_HTTP2
else if (ls->open_http2_protocol)
{
ls->protocol.get_package_length = swHttp2_get_frame_length;
ls->protocol.package_length_size = SW_HTTP2_FRAME_HEADER_SIZE;
ls->protocol.onPackage = swReactorThread_dispatch;
}
#endif
ls->onRead = swPort_onRead_http;
}
else if (ls->open_mqtt_protocol)
{
ls->protocol.get_package_length = swMqtt_get_package_length;
ls->protocol.onPackage = swReactorThread_dispatch;
ls->onRead = swPort_onRead_check_length;
}
else if (ls->open_redis_protocol)
{
ls->protocol.onPackage = swReactorThread_dispatch;
ls->onRead = swPort_onRead_redis;
}
else
{
ls->onRead = swPort_onRead_raw;
}
}
void swPort_clear_protocol(swListenPort *ls)
{
ls->open_eof_check = 0;
ls->open_length_check = 0;
ls->open_http_protocol = 0;
ls->open_websocket_protocol = 0;
#ifdef SW_USE_HTTP2
ls->open_http2_protocol = 0;
#endif
ls->open_mqtt_protocol = 0;
ls->open_redis_protocol = 0;
}
static int swPort_onRead_raw(swReactor *reactor, swListenPort *port, swEvent *event)
{
int n;
swDispatchData task;
swConnection *conn = event->socket;
n = swConnection_recv(conn, task.data.data, SW_BUFFER_SIZE, 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: swReactorThread_onClose(reactor, event);
return SW_OK;
}
else
{
task.data.info.fd = event->fd;
task.data.info.from_id = event->from_id;
task.data.info.len = n;
task.data.info.type = SW_EVENT_TCP;
task.target_worker_id = -1;
return swReactorThread_dispatch(conn, task.data.data, task.data.info.len);
}
return SW_OK;
}
static int swPort_onRead_check_length(swReactor *reactor, swListenPort *port, swEvent *event)
{
swServer *serv = reactor->ptr;
swConnection *conn = event->socket;
swProtocol *protocol = &port->protocol;
swString *buffer = swServer_get_buffer(serv, event->fd);
if (!buffer)
{
return SW_ERR;
}
if (swProtocol_recv_check_length(protocol, conn, buffer) < 0)
{
swTrace("Close Event.FD=%d|From=%d", event->fd, event->from_id);
swReactorThread_onClose(reactor, event);
}
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)
{
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
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
//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)
{
if (swHttpRequest_get_content_length(request) < 0)
{
if (memcmp(buffer->str + buffer->length - 4, "\r\n\r\n", 4) == 0)
{
/**
* 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 - 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;
}
}
//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;
}
static int swPort_onRead_redis(swReactor *reactor, swListenPort *port, swEvent *event)
{
swConnection *conn = event->socket;
swProtocol *protocol = &port->protocol;
swServer *serv = reactor->ptr;
swString *buffer = swServer_get_buffer(serv, event->fd);
if (!buffer)
{
return SW_ERR;
}
if (swRedis_recv(protocol, conn, buffer) < 0)
{
swReactorThread_onClose(reactor, event);
}
return SW_OK;
}
static int swPort_onRead_check_eof(swReactor *reactor, swListenPort *port, swEvent *event)
{
swConnection *conn = event->socket;
swProtocol *protocol = &port->protocol;
swServer *serv = reactor->ptr;
swString *buffer = swServer_get_buffer(serv, event->fd);
if (!buffer)
{
return SW_ERR;
}
if (swProtocol_recv_check_eof(protocol, conn, buffer) < 0)
{
swReactorThread_onClose(reactor, event);
}
return SW_OK;
}
void swPort_free(swListenPort *port)
{
#ifdef SW_USE_OPENSSL
if (port->ssl)
{
swSSL_free_context(port->ssl_context);
sw_free(port->ssl_option.cert_file);
sw_free(port->ssl_option.key_file);
if (port->ssl_option.client_cert_file)
{
sw_free(port->ssl_option.client_cert_file);
}
}
#endif
close(port->sock);
//remove unix socket file
if (port->type == SW_SOCK_UNIX_STREAM || port->type == SW_SOCK_UNIX_DGRAM)
{
unlink(port->host);
}
}
#ifndef PATH_MAX
#define PATH_MAX 4096
#endif
int swPort_http_static_handler(swHttpRequest *request, swConnection *conn)
{
swServer *serv = SwooleG.serv;
char *url = request->buffer->str + request->url_offset;
char *params = memchr(url, '?', request->url_length);
struct
{
off_t offset;
size_t length;
char filename[PATH_MAX];
} buffer;
char *p = buffer.filename;
memcpy(p, serv->document_root, serv->document_root_len);
p += serv->document_root_len;
uint32_t n = params ? params - url : request->url_length;
memcpy(p, url, n);
p += n;
*p = 0;
struct stat file_stat;
if (lstat(buffer.filename, &file_stat) < 0)
{
return SW_FALSE;
}
if ((file_stat.st_mode & S_IFMT) != S_IFREG)
{
return SW_FALSE;
}
char header_buffer[1024];
swSendData response;
response.info.fd = conn->session_id;
response.info.type = SW_EVENT_TCP;
p = request->buffer->str + request->url_offset + request->url_length + 10;
char *pe = request->buffer->str + request->header_length;
char *date_if_modified_since = NULL;
int length_if_modified_since = 0;
int state = 0;
for (; p < pe; p++)
{
switch(state)
{
case 0:
if (strncasecmp(p, SW_STRL("If-Modified-Since") - 1) == 0)
{
p += sizeof("If-Modified-Since");
state = 1;
}
break;
case 1:
if (!isspace(*p))
{
date_if_modified_since = p;
state = 2;
}
break;
case 2:
if (strncasecmp(p, SW_STRL("\r\n") - 1) == 0)
{
length_if_modified_since = p - date_if_modified_since;
goto check_modify_date;
}
break;
default:
break;
}
}
char date_[64];
struct tm *tm1;
check_modify_date: tm1 = gmtime(&serv->gs->now);
strftime(date_, sizeof(date_), "%a, %d %b %Y %H:%M:%S %Z", tm1);
char date_last_modified[64];
#ifdef __MACH__
time_t file_mtime = file_stat.st_mtimespec.tv_sec;
#else
time_t file_mtime = file_stat.st_mtim.tv_sec;
#endif
struct tm *tm2 = gmtime(&file_mtime);
strftime(date_last_modified, sizeof(date_last_modified), "%a, %d %b %Y %H:%M:%S %Z", tm2);
if (state == 2)
{
struct tm tm3;
char date_tmp[64];
memcpy(date_tmp, date_if_modified_since, length_if_modified_since);
date_tmp[length_if_modified_since] = 0;
char *date_format = NULL;
if (strptime(date_tmp, SW_HTTP_RFC1123_DATE_GMT, &tm3) != NULL)
{
date_format = SW_HTTP_RFC1123_DATE_GMT;
}
else if (strptime(date_tmp, SW_HTTP_RFC1123_DATE_UTC, &tm3) != NULL)
{
date_format = SW_HTTP_RFC1123_DATE_UTC;
}
else if (strptime(date_tmp, SW_HTTP_RFC850_DATE, &tm3) != NULL)
{
date_format = SW_HTTP_RFC850_DATE;
}
else if (strptime(date_tmp, SW_HTTP_ASCTIME_DATE, &tm3) != NULL)
{
date_format = SW_HTTP_ASCTIME_DATE;
}
if (date_format && mktime(&tm3) - (int) timezone >= file_mtime)
{
response.length = response.info.len = snprintf(header_buffer, sizeof(header_buffer),
"HTTP/1.1 304 Not Modified\r\n"
"Connection: Keep-Alive\r\n"
"Date: %s\r\n"
"Last-Modified: %s\r\n"
"Server: %s\r\n\r\n", date_, date_last_modified,
SW_HTTP_SERVER_SOFTWARE);
response.data = header_buffer;
swReactorThread_send(&response);
return SW_TRUE;
}
}
response.length = response.info.len = snprintf(header_buffer, sizeof(header_buffer),
"HTTP/1.1 200 OK\r\n"
"Connection: Keep-Alive\r\n"
"Content-Length: %ld\r\n"
"Content-Type: %s\r\n"
"Date: %s\r\n"
"Last-Modified: %s\r\n"
"Server: %s\r\n\r\n", (long) file_stat.st_size, swoole_get_mimetype(buffer.filename),
date_,
date_last_modified,
SW_HTTP_SERVER_SOFTWARE);
response.data = header_buffer;
#ifdef HAVE_TCP_NOPUSH
if (conn->tcp_nopush == 0)
{
if (swSocket_tcp_nopush(conn->fd, 1) == -1)
{
swWarn("swSocket_tcp_nopush() failed. Error: %s[%d]", strerror(errno), errno);
}
conn->tcp_nopush = 1;
}
#endif
swReactorThread_send(&response);
buffer.offset = 0;
buffer.length = file_stat.st_size;
response.info.type = SW_EVENT_SENDFILE;
response.length = response.info.len = sizeof(swSendFile_request) + buffer.length + 1;
response.data = (void*) &buffer;
swReactorThread_send(&response);
return SW_TRUE;
}

828
vendor/swoole/src/network/ProcessPool.c vendored Executable file
View File

@ -0,0 +1,828 @@
/*
+----------------------------------------------------------------------+
| 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 "Client.h"
/**
* call onTask
*/
static int swProcessPool_worker_loop(swProcessPool *pool, swWorker *worker);
/**
* call onMessage
*/
static int swProcessPool_worker_loop_ex(swProcessPool *pool, swWorker *worker);
static void swProcessPool_free(swProcessPool *pool);
/**
* Process manager
*/
int swProcessPool_create(swProcessPool *pool, int worker_num, int max_request, key_t msgqueue_key, int ipc_mode)
{
bzero(pool, sizeof(swProcessPool));
pool->worker_num = worker_num;
pool->max_request = max_request;
pool->workers = SwooleG.memory_pool->alloc(SwooleG.memory_pool, worker_num * sizeof(swWorker));
if (pool->workers == NULL)
{
swSysError("malloc[1] failed.");
return SW_ERR;
}
if (ipc_mode == SW_IPC_MSGQUEUE)
{
pool->use_msgqueue = 1;
pool->msgqueue_key = msgqueue_key;
pool->queue = sw_malloc(sizeof(swMsgQueue));
if (pool->queue == NULL)
{
swSysError("malloc[2] failed.");
return SW_ERR;
}
if (swMsgQueue_create(pool->queue, 1, pool->msgqueue_key, 0) < 0)
{
return SW_ERR;
}
}
else if (ipc_mode == SW_IPC_SOCKET)
{
pool->use_socket = 1;
pool->stream = sw_malloc(sizeof(swStreamInfo));
if (pool->stream == NULL)
{
swWarn("malloc[2] failed.");
return SW_ERR;
}
bzero(pool->stream, sizeof(swStreamInfo));
}
else if (ipc_mode == SW_IPC_UNIXSOCK)
{
pool->pipes = sw_calloc(worker_num, sizeof(swPipe));
if (pool->pipes == NULL)
{
swWarn("malloc[2] failed.");
return SW_ERR;
}
swPipe *pipe;
int i;
for (i = 0; i < worker_num; i++)
{
pipe = &pool->pipes[i];
if (swPipeUnsock_create(pipe, 1, SOCK_DGRAM) < 0)
{
return SW_ERR;
}
pool->workers[i].pipe_master = pipe->getFd(pipe, SW_PIPE_MASTER);
pool->workers[i].pipe_worker = pipe->getFd(pipe, SW_PIPE_WORKER);
pool->workers[i].pipe_object = pipe;
}
}
else
{
ipc_mode = SW_IPC_NONE;
}
pool->map = swHashMap_new(SW_HASHMAP_INIT_BUCKET_N, NULL);
if (pool->map == NULL)
{
swProcessPool_free(pool);
return SW_ERR;
}
pool->ipc_mode = ipc_mode;
if (ipc_mode > SW_IPC_NONE)
{
pool->main_loop = swProcessPool_worker_loop;
}
return SW_OK;
}
int swProcessPool_create_unix_socket(swProcessPool *pool, char *socket_file, int blacklog)
{
if (pool->ipc_mode != SW_IPC_SOCKET)
{
swWarn("ipc_mode is not SW_IPC_SOCKET.");
return SW_ERR;
}
pool->stream->socket_file = sw_strdup(socket_file);
if (pool->stream->socket_file == NULL)
{
return SW_ERR;
}
pool->stream->socket = swSocket_create_server(SW_SOCK_UNIX_STREAM, pool->stream->socket_file, 0, blacklog);
if (pool->stream->socket < 0)
{
return SW_ERR;
}
return SW_OK;
}
int swProcessPool_create_tcp_socket(swProcessPool *pool, char *host, int port, int blacklog)
{
if (pool->ipc_mode != SW_IPC_SOCKET)
{
swWarn("ipc_mode is not SW_IPC_SOCKET.");
return SW_ERR;
}
pool->stream->socket_file = sw_strdup(host);
if (pool->stream->socket_file == NULL)
{
return SW_ERR;
}
pool->stream->socket = swSocket_create_server(SW_SOCK_TCP, host, port, blacklog);
if (pool->stream->socket < 0)
{
return SW_ERR;
}
return SW_OK;
}
/**
* start workers
*/
int swProcessPool_start(swProcessPool *pool)
{
if (pool->ipc_mode == SW_IPC_SOCKET && (pool->stream == NULL || pool->stream->socket == 0))
{
swWarn("must first listen to an tcp port.");
return SW_ERR;
}
int i;
pool->started = 1;
pool->run_worker_num = pool->worker_num;
for (i = 0; i < pool->worker_num; i++)
{
pool->workers[i].pool = pool;
pool->workers[i].id = pool->start_id + i;
pool->workers[i].type = pool->type;
if (swProcessPool_spawn(pool, &(pool->workers[i])) < 0)
{
return SW_ERR;
}
}
return SW_OK;
}
static sw_inline int swProcessPool_schedule(swProcessPool *pool)
{
if (pool->dispatch_mode == SW_DISPATCH_QUEUE)
{
return 0;
}
int i, target_worker_id = 0;
int run_worker_num = pool->run_worker_num;
for (i = 0; i < run_worker_num + 1; i++)
{
target_worker_id = sw_atomic_fetch_add(&pool->round_id, 1) % run_worker_num;
if (pool->workers[target_worker_id].status == SW_WORKER_IDLE)
{
break;
}
}
return target_worker_id;
}
int swProcessPool_response(swProcessPool *pool, char *data, int length)
{
if (pool->stream == NULL || pool->stream->last_connection == 0 || pool->stream->response_buffer == NULL)
{
SwooleG.error = SW_ERROR_INVALID_PARAMS;
return SW_ERR;
}
return swString_append_ptr(pool->stream->response_buffer, data, length);
}
/**
* dispatch data to worker
*/
int swProcessPool_dispatch(swProcessPool *pool, swEventData *data, int *dst_worker_id)
{
int ret = 0;
swWorker *worker;
if (pool->use_socket)
{
swStream *stream = swStream_new(pool->stream->socket_file, 0, SW_SOCK_UNIX_STREAM);
if (stream == NULL)
{
return SW_ERR;
}
stream->response = NULL;
stream->session_id = 0;
if (swStream_send(stream, (char*) data, sizeof(data->info) + data->info.len) < 0)
{
stream->cancel = 1;
return SW_ERR;
}
return SW_OK;
}
if (*dst_worker_id < 0)
{
*dst_worker_id = swProcessPool_schedule(pool);
}
*dst_worker_id += pool->start_id;
worker = swProcessPool_get_worker(pool, *dst_worker_id);
int sendn = sizeof(data->info) + data->info.len;
ret = swWorker_send2worker(worker, data, sendn, SW_PIPE_MASTER | SW_PIPE_NONBLOCK);
if (ret >= 0)
{
sw_atomic_fetch_add(&worker->tasking_num, 1);
}
else
{
swWarn("send %d bytes to worker#%d failed.", sendn, *dst_worker_id);
}
return ret;
}
/**
* dispatch data to worker
*/
int swProcessPool_dispatch_blocking(swProcessPool *pool, swEventData *data, int *dst_worker_id)
{
int ret = 0;
int sendn = sizeof(data->info) + data->info.len;
if (pool->use_socket)
{
swClient _socket;
if (swClient_create(&_socket, SW_SOCK_UNIX_STREAM, SW_SOCK_SYNC) < 0)
{
return SW_ERR;
}
if (_socket.connect(&_socket, pool->stream->socket_file, 0, -1, 0) < 0)
{
return SW_ERR;
}
if (_socket.send(&_socket, (void*) data, sendn, 0) < 0)
{
return SW_ERR;
}
_socket.close(&_socket);
return SW_OK;
}
if (*dst_worker_id < 0)
{
*dst_worker_id = swProcessPool_schedule(pool);
}
*dst_worker_id += pool->start_id;
swWorker *worker = swProcessPool_get_worker(pool, *dst_worker_id);
ret = swWorker_send2worker(worker, data, sendn, SW_PIPE_MASTER);
if (ret < 0)
{
swWarn("send %d bytes to worker#%d failed.", sendn, *dst_worker_id);
}
else
{
sw_atomic_fetch_add(&worker->tasking_num, 1);
}
return ret;
}
void swProcessPool_shutdown(swProcessPool *pool)
{
int i, status;
swWorker *worker;
SwooleG.running = 0;
swSignal_none();
//concurrent kill
for (i = 0; i < pool->run_worker_num; i++)
{
worker = &pool->workers[i];
if (swKill(worker->pid, SIGTERM) < 0)
{
swSysError("kill(%d) failed.", worker->pid);
continue;
}
}
for (i = 0; i < pool->run_worker_num; i++)
{
worker = &pool->workers[i];
if (swWaitpid(worker->pid, &status, 0) < 0)
{
swSysError("waitpid(%d) failed.", worker->pid);
}
}
swProcessPool_free(pool);
pool->started = 0;
}
pid_t swProcessPool_spawn(swProcessPool *pool, swWorker *worker)
{
pid_t pid = fork();
int ret_code = 0;
switch (pid)
{
//child
case 0:
/**
* Process start
*/
if (pool->onWorkerStart != NULL)
{
pool->onWorkerStart(pool, worker->id);
}
/**
* Process main loop
*/
if (pool->main_loop)
{
ret_code = pool->main_loop(pool, worker);
}
/**
* Process stop
*/
if (pool->onWorkerStop != NULL)
{
pool->onWorkerStop(pool, worker->id);
}
exit(ret_code);
break;
case -1:
swWarn("fork() failed. Error: %s [%d]", strerror(errno), errno);
break;
//parent
default:
//remove old process
if (worker->pid)
{
swHashMap_del_int(pool->map, worker->pid);
}
worker->pid = pid;
//insert new process
swHashMap_add_int(pool->map, pid, worker);
break;
}
return pid;
}
static int swProcessPool_worker_loop(swProcessPool *pool, swWorker *worker)
{
struct
{
long mtype;
swEventData buf;
} out;
int n = 0, ret;
int task_n, worker_task_always = 0;
if (pool->max_request < 1)
{
task_n = 1;
worker_task_always = 1;
}
else
{
task_n = pool->max_request;
if (pool->max_request > 10)
{
n = swoole_system_random(1, pool->max_request / 2);
if (n > 0)
{
task_n += n;
}
}
}
/**
* Use from_fd save the task_worker->id
*/
out.buf.info.from_fd = worker->id;
if (pool->dispatch_mode == SW_DISPATCH_QUEUE)
{
out.mtype = 0;
}
else
{
out.mtype = worker->id + 1;
}
while (SwooleG.running > 0 && task_n > 0)
{
/**
* fetch task
*/
if (pool->use_msgqueue)
{
n = swMsgQueue_pop(pool->queue, (swQueue_data *) &out, sizeof(out.buf));
if (n < 0 && errno != EINTR)
{
swSysError("[Worker#%d] msgrcv() failed.", worker->id);
break;
}
}
else if (pool->use_socket)
{
int fd = accept(pool->stream->socket, NULL, NULL);
if (fd < 0)
{
if (errno == EAGAIN || errno == EINTR)
{
continue;
}
else
{
swSysError("accept(%d) failed.", pool->stream->socket);
break;
}
}
n = swStream_recv_blocking(fd, (void*) &out.buf, sizeof(out.buf));
if (n == SW_CLOSE)
{
close(fd);
continue;
}
pool->stream->last_connection = fd;
}
else
{
n = read(worker->pipe_worker, &out.buf, sizeof(out.buf));
if (n < 0 && errno != EINTR)
{
swSysError("[Worker#%d] read(%d) failed.", worker->id, worker->pipe_worker);
}
}
/**
* timer
*/
if (n < 0)
{
if (errno == EINTR && SwooleG.signal_alarm)
{
alarm_handler: SwooleG.signal_alarm = 0;
swTimer_select(&SwooleG.timer);
}
continue;
}
/**
* do task
*/
worker->status = SW_WORKER_BUSY;
worker->request_time = time(NULL);
ret = pool->onTask(pool, &out.buf);
worker->status = SW_WORKER_IDLE;
worker->request_time = 0;
worker->traced = 0;
if (pool->use_socket && pool->stream->last_connection > 0)
{
int _end = 0;
swSocket_write_blocking(pool->stream->last_connection, (void *) &_end, sizeof(_end));
close(pool->stream->last_connection);
pool->stream->last_connection = 0;
}
/**
* timer
*/
if (SwooleG.signal_alarm)
{
goto alarm_handler;
}
if (ret >= 0 && !worker_task_always)
{
task_n--;
}
}
return SW_OK;
}
int swProcessPool_set_protocol(swProcessPool *pool, int task_protocol, uint32_t max_packet_size)
{
if (task_protocol)
{
pool->main_loop = swProcessPool_worker_loop;
}
else
{
pool->packet_buffer = sw_malloc(max_packet_size);
if (pool->packet_buffer == NULL)
{
swSysError("malloc(%d) failed.", max_packet_size);
return SW_ERR;
}
if (pool->stream)
{
pool->stream->response_buffer = swString_new(SW_BUFFER_SIZE_STD);
if (pool->stream->response_buffer == NULL)
{
sw_free(pool->packet_buffer);
return SW_ERR;
}
}
pool->max_packet_size = max_packet_size;
pool->main_loop = swProcessPool_worker_loop_ex;
}
return SW_OK;
}
static int swProcessPool_worker_loop_ex(swProcessPool *pool, swWorker *worker)
{
int n;
char *data;
swQueue_data *outbuf = (swQueue_data *) pool->packet_buffer;
outbuf->mtype = 0;
while (SwooleG.running > 0)
{
/**
* fetch task
*/
if (pool->use_msgqueue)
{
n = swMsgQueue_pop(pool->queue, outbuf, sizeof(outbuf->mdata));
if (n < 0 && errno != EINTR)
{
swSysError("[Worker#%d] msgrcv() failed.", worker->id);
break;
}
data = outbuf->mdata;
}
else if (pool->use_socket)
{
int fd = accept(pool->stream->socket, NULL, NULL);
if (fd < 0)
{
if (errno == EAGAIN || errno == EINTR)
{
continue;
}
else
{
swSysError("accept(%d) failed.", pool->stream->socket);
break;
}
}
int tmp = 0;
if (swSocket_recv_blocking(fd, &tmp, sizeof(tmp), MSG_WAITALL) <= 0)
{
goto _close;
}
n = ntohl(tmp);
if (n <= 0)
{
goto _close;
}
else if (n > pool->max_packet_size)
{
goto _close;
}
if (swSocket_recv_blocking(fd, pool->packet_buffer, n, MSG_WAITALL) <= 0)
{
_close: close(fd);
continue;
}
data = pool->packet_buffer;
pool->stream->last_connection = fd;
}
else
{
n = read(worker->pipe_worker, pool->packet_buffer, pool->max_packet_size);
if (n < 0 && errno != EINTR)
{
swSysError("[Worker#%d] read(%d) failed.", worker->id, worker->pipe_worker);
}
data = pool->packet_buffer;
}
/**
* timer
*/
if (n < 0)
{
if (errno == EINTR && SwooleG.signal_alarm)
{
alarm_handler: SwooleG.signal_alarm = 0;
swTimer_select(&SwooleG.timer);
}
continue;
}
pool->onMessage(pool, data, n);
if (pool->use_socket && pool->stream->last_connection > 0)
{
swString *resp_buf = pool->stream->response_buffer;
if (resp_buf && resp_buf->length > 0)
{
int _l = htonl(resp_buf->length);
swSocket_write_blocking(pool->stream->last_connection, &_l, sizeof(_l));
swSocket_write_blocking(pool->stream->last_connection, resp_buf->str, resp_buf->length);
swString_clear(resp_buf);
}
close(pool->stream->last_connection);
pool->stream->last_connection = 0;
}
/**
* timer
*/
if (SwooleG.signal_alarm)
{
goto alarm_handler;
}
}
return SW_OK;
}
/**
* add a worker to pool
*/
int swProcessPool_add_worker(swProcessPool *pool, swWorker *worker)
{
swHashMap_add_int(pool->map, worker->pid, worker);
return SW_OK;
}
int swProcessPool_wait(swProcessPool *pool)
{
int pid, new_pid;
int reload_worker_i = 0;
pid_t reload_worker_pid = 0;
int ret;
int status;
swWorker *reload_workers = sw_calloc(pool->worker_num, sizeof(swWorker));
if (reload_workers == NULL)
{
swError("malloc[reload_workers] failed");
return SW_ERR;
}
while (SwooleG.running)
{
pid = wait(&status);
if (pid < 0)
{
if (SwooleG.running == 0)
{
break;
}
if (pool->reloading == 0)
{
if (errno != EINTR)
{
swWarn("[Manager] wait failed. Error: %s [%d]", strerror(errno), errno);
}
continue;
}
swNotice("reload workers.");
if (pool->reload_init == 0)
{
pool->reload_init = 1;
memcpy(reload_workers, pool->workers, sizeof(swWorker) * pool->worker_num);
}
goto kill_worker;
}
if (SwooleG.running == 1)
{
swWorker *exit_worker = swHashMap_find_int(pool->map, pid);
if (exit_worker == NULL)
{
if (pool->onWorkerNotFound)
{
pool->onWorkerNotFound(pool, pid, status);
}
else
{
swWarn("[Manager]unknow worker[pid=%d]", pid);
}
continue;
}
if (!WIFEXITED(status))
{
swWarn("worker#%d abnormal exit, status=%d, signal=%d", exit_worker->id, WEXITSTATUS(status), WTERMSIG(status));
}
new_pid = swProcessPool_spawn(pool, exit_worker);
if (new_pid < 0)
{
swWarn("Fork worker process failed. Error: %s [%d]", strerror(errno), errno);
sw_free(reload_workers);
return SW_ERR;
}
swHashMap_del_int(pool->map, pid);
if (pid == reload_worker_pid)
{
reload_worker_i++;
}
}
//reload worker
kill_worker: if (pool->reloading == 1)
{
//reload finish
if (reload_worker_i >= pool->worker_num)
{
pool->reloading = pool->reload_init = reload_worker_pid = reload_worker_i = 0;
continue;
}
reload_worker_pid = reload_workers[reload_worker_i].pid;
ret = kill(reload_worker_pid, SIGTERM);
if (ret < 0)
{
if (errno == ECHILD)
{
reload_worker_i++;
goto kill_worker;
}
swSysError("[Manager]kill(%d) failed.", reload_workers[reload_worker_i].pid);
continue;
}
}
}
sw_free(reload_workers);
return SW_OK;
}
static void swProcessPool_free(swProcessPool *pool)
{
int i;
swPipe *_pipe;
if (pool->pipes)
{
for (i = 0; i < pool->worker_num; i++)
{
_pipe = &pool->pipes[i];
_pipe->close(_pipe);
}
sw_free(pool->pipes);
}
if (pool->use_msgqueue == 1 && pool->msgqueue_key == 0)
{
swMsgQueue_free(pool->queue);
}
if (pool->stream)
{
if (pool->stream->socket)
{
unlink(pool->stream->socket_file);
sw_free((void*) pool->stream->socket_file);
}
if (pool->stream->socket)
{
close(pool->stream->socket);
}
if (pool->stream->response_buffer)
{
swString_free(pool->stream->response_buffer);
}
sw_free(pool->stream);
}
if (pool->map)
{
swHashMap_free(pool->map);
}
}

582
vendor/swoole/src/network/ReactorProcess.c vendored Executable file
View File

@ -0,0 +1,582 @@
/*
+----------------------------------------------------------------------+
| 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 "Server.h"
static int swReactorProcess_loop(swProcessPool *pool, swWorker *worker);
static int swReactorProcess_onPipeRead(swReactor *reactor, swEvent *event);
static int swReactorProcess_send2client(swFactory *, swSendData *);
static int swReactorProcess_send2worker(int, void *, int);
static void swReactorProcess_onTimeout(swTimer *timer, swTimer_node *tnode);
#ifdef HAVE_REUSEPORT
static int swReactorProcess_reuse_port(swListenPort *ls);
#endif
static uint32_t heartbeat_check_lasttime = 0;
int swReactorProcess_create(swServer *serv)
{
serv->reactor_num = serv->worker_num;
serv->reactor_threads = sw_calloc(1, sizeof(swReactorThread));
if (serv->reactor_threads == NULL)
{
swSysError("calloc[1](%d) failed.", (int )(serv->reactor_num * sizeof(swReactorThread)));
return SW_ERR;
}
serv->connection_list = sw_calloc(serv->max_connection, sizeof(swConnection));
if (serv->connection_list == NULL)
{
swSysError("calloc[2](%d) failed.", (int )(serv->max_connection * sizeof(swConnection)));
return SW_ERR;
}
//create factry object
if (swFactory_create(&(serv->factory)) < 0)
{
swError("create factory failed.");
return SW_ERR;
}
serv->factory.finish = swReactorProcess_send2client;
return SW_OK;
}
/**
* base模式
* 在worker进程中直接accept连接
*/
int swReactorProcess_start(swServer *serv)
{
swListenPort *ls;
if (serv->onStart != NULL)
{
serv->onStart(serv);
}
//listen TCP
if (serv->have_tcp_sock == 1)
{
LL_FOREACH(serv->listen_list, ls)
{
if (swSocket_is_dgram(ls->type))
{
continue;
}
if (SwooleG.reuse_port)
{
if (close(ls->sock) < 0)
{
swSysError("close(%d) failed.", ls->sock);
}
continue;
}
else
{
//listen server socket
if (swPort_listen(ls) < 0)
{
return SW_ERR;
}
}
}
}
if (swProcessPool_create(&serv->gs->event_workers, serv->worker_num, serv->max_request, 0, SW_IPC_UNIXSOCK) < 0)
{
return SW_ERR;
}
serv->gs->event_workers.ptr = serv;
serv->gs->event_workers.main_loop = swReactorProcess_loop;
serv->gs->event_workers.type = SW_PROCESS_WORKER;
serv->gs->event_workers.run_worker_num = serv->worker_num;
//no worker
if (serv->worker_num == 1 && serv->task_worker_num == 0 && serv->max_request == 0 && serv->user_worker_list == NULL)
{
swWorker single_worker;
bzero(&single_worker, sizeof(single_worker));
return swReactorProcess_loop(&serv->gs->event_workers, &single_worker);
}
swWorker *worker;
int i;
for (i = 0; i < serv->worker_num; i++)
{
worker = &serv->gs->event_workers.workers[i];
if (swWorker_create(worker) < 0)
{
return SW_ERR;
}
}
//task workers
if (serv->task_worker_num > 0)
{
if (swServer_create_task_worker(serv) < 0)
{
return SW_ERR;
}
swTaskWorker_init(&serv->gs->task_workers);
swProcessPool_start(&serv->gs->task_workers);
int i;
for (i = 0; i < serv->gs->task_workers.worker_num; i++)
{
swProcessPool_add_worker(&serv->gs->event_workers, &serv->gs->task_workers.workers[i]);
}
}
/**
* create user worker process
*/
if (serv->user_worker_list)
{
swUserWorker_node *user_worker;
LL_FOREACH(serv->user_worker_list, user_worker)
{
/**
* store the pipe object
*/
if (user_worker->worker->pipe_object)
{
swServer_store_pipe_fd(serv, user_worker->worker->pipe_object);
}
swManager_spawn_user_worker(serv, user_worker->worker);
}
serv->gs->event_workers.onWorkerNotFound = swManager_wait_user_worker;
}
/**
* manager process is the same as the master process
*/
SwooleG.pid = serv->gs->manager_pid = getpid();
SwooleG.process_type = SW_PROCESS_MASTER;
/**
* manager process can not use signalfd
*/
SwooleG.use_timerfd = 0;
SwooleG.use_signalfd = 0;
SwooleG.use_timer_pipe = 0;
swServer_signal_init(serv);
swProcessPool_start(&serv->gs->event_workers);
swProcessPool_wait(&serv->gs->event_workers);
swProcessPool_shutdown(&serv->gs->event_workers);
swManager_kill_user_worker(serv);
return SW_OK;
}
static int swReactorProcess_onPipeRead(swReactor *reactor, swEvent *event)
{
swEventData task;
swSendData _send;
swServer *serv = reactor->ptr;
swFactory *factory = &serv->factory;
swString *buffer_output;
if (read(event->fd, &task, sizeof(task)) <= 0)
{
return SW_ERR;
}
switch (task.info.type)
{
case SW_EVENT_PIPE_MESSAGE:
serv->onPipeMessage(serv, &task);
break;
case SW_EVENT_FINISH:
serv->onFinish(serv, &task);
break;
case SW_EVENT_SENDFILE:
memcpy(&_send.info, &task.info, sizeof(_send.info));
_send.data = task.data;
factory->finish(factory, &_send);
break;
case SW_EVENT_PROXY_START:
case SW_EVENT_PROXY_END:
buffer_output = SwooleWG.buffer_output[task.info.from_id];
swString_append_ptr(buffer_output, task.data, task.info.len);
if (task.info.type == SW_EVENT_PROXY_END)
{
memcpy(&_send.info, &task.info, sizeof(_send.info));
_send.info.type = SW_EVENT_TCP;
_send.data = buffer_output->str;
_send.length = buffer_output->length;
factory->finish(factory, &_send);
swString_clear(buffer_output);
}
break;
default:
break;
}
return SW_OK;
}
static int swReactorProcess_loop(swProcessPool *pool, swWorker *worker)
{
swServer *serv = pool->ptr;
swReactor *reactor = &(serv->reactor_threads[0].reactor);
SwooleG.process_type = SW_PROCESS_WORKER;
SwooleG.pid = getpid();
SwooleWG.id = worker->id;
if (serv->max_request > 0)
{
SwooleWG.run_always = 0;
}
SwooleWG.max_request = serv->max_request;
SwooleWG.worker = worker;
SwooleTG.id = 0;
if (worker->id == 0)
{
SwooleTG.update_time = 1;
}
swServer_worker_init(serv, worker);
int n_buffer = serv->worker_num + serv->task_worker_num;
SwooleWG.buffer_output = sw_malloc(sizeof(swString*) * n_buffer);
if (SwooleWG.buffer_output == NULL)
{
swError("malloc for SwooleWG.buffer_output failed.");
return SW_ERR;
}
int i;
for (i = 0; i < n_buffer; i++)
{
SwooleWG.buffer_output[i] = swString_new(SW_BUFFER_SIZE_BIG);
if (SwooleWG.buffer_output[i] == NULL)
{
swError("buffer_output init failed.");
return SW_ERR;
}
}
//create reactor
if (swReactor_create(reactor, SW_REACTOR_MAXEVENTS) < 0)
{
return SW_ERR;
}
swListenPort *ls;
int fdtype;
LL_FOREACH(serv->listen_list, ls)
{
fdtype = swSocket_is_dgram(ls->type) ? SW_FD_UDP : SW_FD_LISTEN;
#ifdef HAVE_REUSEPORT
if (fdtype == SW_FD_LISTEN && SwooleG.reuse_port)
{
if (swReactorProcess_reuse_port(ls) < 0)
{
return SW_ERR;
}
}
#endif
reactor->add(reactor, ls->sock, fdtype);
}
SwooleG.main_reactor = reactor;
reactor->id = worker->id;
reactor->ptr = serv;
#ifdef SW_USE_RINGBUFFER
serv->reactor_threads[0].buffer_input = swMalloc_new();
if (serv->reactor_threads[0].buffer_input == NULL)
{
return SW_ERR;
}
#endif
#ifdef HAVE_SIGNALFD
if (SwooleG.use_signalfd)
{
swSignalfd_setup(SwooleG.main_reactor);
}
#endif
reactor->thread = 1;
reactor->socket_list = serv->connection_list;
reactor->max_socket = serv->max_connection;
reactor->disable_accept = 0;
reactor->enable_accept = swServer_enable_accept;
reactor->close = swReactorThread_close;
//set event handler
//connect
reactor->setHandle(reactor, SW_FD_LISTEN, swServer_master_onAccept);
//close
reactor->setHandle(reactor, SW_FD_CLOSE, swReactorProcess_onClose);
//pipe
reactor->setHandle(reactor, SW_FD_WRITE, swReactor_onWrite);
reactor->setHandle(reactor, SW_FD_PIPE | SW_EVENT_READ, swReactorProcess_onPipeRead);
swServer_store_listen_socket(serv);
if (worker->pipe_worker)
{
swSetNonBlock(worker->pipe_worker);
swSetNonBlock(worker->pipe_master);
reactor->add(reactor, worker->pipe_worker, SW_FD_PIPE);
reactor->add(reactor, worker->pipe_master, SW_FD_PIPE);
}
//task workers
if (serv->task_worker_num > 0)
{
swPipe *p;
swConnection *psock;
int pfd;
if (serv->task_ipc_mode == SW_TASK_IPC_UNIXSOCK)
{
for (i = 0; i < serv->gs->task_workers.worker_num; i++)
{
p = serv->gs->task_workers.workers[i].pipe_object;
pfd = p->getFd(p, 1);
psock = swReactor_get(reactor, pfd);
psock->fdtype = SW_FD_PIPE;
swSetNonBlock(pfd);
}
}
}
//set protocol function point
swReactorThread_set_protocol(serv, reactor);
/**
* init timer
*/
if (swTimer_init(1000) < 0)
{
return SW_ERR;
}
/**
* 1 second timer, update serv->gs->now
*/
if (SwooleG.timer.add(&SwooleG.timer, 1000, 1, serv, swServer_master_onTimer) == NULL)
{
return SW_ERR;
}
if (serv->onWorkerStart)
{
serv->onWorkerStart(serv, worker->id);
}
/**
* for heartbeat check
*/
if (serv->heartbeat_check_interval > 0)
{
if (SwooleG.timer.add(&SwooleG.timer, serv->heartbeat_check_interval * 1000, 1, reactor, swReactorProcess_onTimeout) == NULL)
{
return SW_ERR;
}
}
reactor->wait(reactor, NULL);
if (serv->onWorkerStop)
{
serv->onWorkerStop(serv, worker->id);
}
return SW_OK;
}
int swReactorProcess_onClose(swReactor *reactor, swEvent *event)
{
int fd = event->fd;
swServer *serv = reactor->ptr;
swConnection *conn = swServer_connection_get(SwooleG.serv, fd);
if (conn == NULL || conn->active == 0)
{
return SW_ERR;
}
if (reactor->del(reactor, fd) == 0)
{
return swServer_tcp_notify(serv, conn, SW_EVENT_CLOSE);
}
else
{
return SW_ERR;
}
}
static int swReactorProcess_send2worker(int pipe_fd, void *data, int length)
{
if (swIsTaskWorker())
{
return swSocket_write_blocking(pipe_fd, data, length);
}
else
{
return SwooleG.main_reactor->write(SwooleG.main_reactor, pipe_fd, data, length);
}
}
static int swReactorProcess_send2client(swFactory *factory, swSendData *_send)
{
swServer *serv = SwooleG.serv;
int session_id = _send->info.fd;
if (_send->length == 0)
{
_send->length = _send->info.len;
}
swSession *session = swServer_get_session(serv, session_id);
if (session->fd == 0)
{
swoole_error_log(SW_LOG_NOTICE, SW_ERROR_SESSION_NOT_EXIST, "send %d byte failed, session#%d does not exist.", _send->length, session_id);
return SW_ERR;
}
//proxy
if (session->reactor_id != SwooleWG.id)
{
swTrace("session->reactor_id=%d, SwooleWG.id=%d", session->reactor_id, SwooleWG.id);
swWorker *worker = swProcessPool_get_worker(&serv->gs->event_workers, session->reactor_id);
swEventData proxy_msg;
if (_send->info.type == SW_EVENT_TCP)
{
proxy_msg.info.fd = session_id;
proxy_msg.info.from_id = SwooleWG.id;
proxy_msg.info.type = SW_EVENT_PROXY_START;
size_t send_n = _send->length;
size_t offset = 0;
while (send_n > 0)
{
if (send_n > SW_BUFFER_SIZE)
{
proxy_msg.info.len = SW_BUFFER_SIZE;
}
else
{
proxy_msg.info.type = SW_EVENT_PROXY_END;
proxy_msg.info.len = send_n;
}
memcpy(proxy_msg.data, _send->data + offset, proxy_msg.info.len);
send_n -= proxy_msg.info.len;
offset += proxy_msg.info.len;
swReactorProcess_send2worker(worker->pipe_master, &proxy_msg, sizeof(proxy_msg.info) + proxy_msg.info.len);
}
swTrace("proxy message, fd=%d, len=%ld",worker->pipe_master, sizeof(proxy_msg.info) + proxy_msg.info.len);
}
else if (_send->info.type == SW_EVENT_SENDFILE)
{
memcpy(&proxy_msg.info, &_send->info, sizeof(proxy_msg.info));
memcpy(proxy_msg.data, _send->data, _send->length);
return swReactorProcess_send2worker(worker->pipe_master, &proxy_msg, sizeof(proxy_msg.info) + proxy_msg.info.len);
}
else
{
swWarn("unkown event type[%d].", _send->info.type);
return SW_ERR;
}
return SW_OK;
}
else
{
return swFactory_finish(factory, _send);
}
}
static void swReactorProcess_onTimeout(swTimer *timer, swTimer_node *tnode)
{
swReactor *reactor = tnode->data;
swServer *serv = reactor->ptr;
swEvent notify_ev;
swConnection *conn;
if (serv->gs->now < heartbeat_check_lasttime + 10)
{
return;
}
int fd;
int serv_max_fd;
int serv_min_fd;
int checktime;
bzero(&notify_ev, sizeof(notify_ev));
notify_ev.type = SW_EVENT_CLOSE;
serv_max_fd = swServer_get_maxfd(serv);
serv_min_fd = swServer_get_minfd(serv);
checktime = serv->gs->now - serv->heartbeat_idle_time;
for (fd = serv_min_fd; fd <= serv_max_fd; fd++)
{
conn = swServer_connection_get(serv, fd);
if (conn != NULL && conn->active == 1 && conn->fdtype == SW_FD_TCP)
{
if (conn->protect || conn->last_time > checktime)
{
continue;
}
#ifdef SW_USE_OPENSSL
if (conn->ssl && conn->ssl_state != SW_SSL_STATE_READY)
{
swReactorThread_close(reactor, fd);
continue;
}
#endif
notify_ev.fd = fd;
notify_ev.from_id = conn->from_id;
swReactorProcess_onClose(reactor, &notify_ev);
}
}
}
#ifdef HAVE_REUSEPORT
static int swReactorProcess_reuse_port(swListenPort *ls)
{
//create new socket
int sock = swSocket_create(ls->type);
if (sock < 0)
{
swSysError("create socket failed.");
return SW_ERR;
}
//bind address and port
if (swSocket_bind(sock, ls->type, ls->host, &ls->port) < 0)
{
close(sock);
return SW_ERR;
}
//stream socket, set nonblock
if (swSocket_is_stream(ls->type))
{
swSetNonBlock(sock);
}
ls->sock = sock;
return swPort_listen(ls);
}
#endif

1619
vendor/swoole/src/network/ReactorThread.c vendored Executable file

File diff suppressed because it is too large Load Diff

1894
vendor/swoole/src/network/Server.c vendored Executable file

File diff suppressed because it is too large Load Diff

169
vendor/swoole/src/network/Stream.c vendored Executable file
View File

@ -0,0 +1,169 @@
/*
+----------------------------------------------------------------------+
| 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 "Client.h"
static void swStream_free(swStream *stream);
static void swStream_onConnect(swClient *cli)
{
swStream *stream = (swStream*) cli->object;
if (stream->cancel)
{
cli->close(cli);
}
*((uint32_t *) stream->buffer->str) = ntohl(stream->buffer->length - 4);
if (cli->send(cli, stream->buffer->str, stream->buffer->length, 0) < 0)
{
cli->close(cli);
}
else
{
swString_free(stream->buffer);
stream->buffer = NULL;
}
}
static void swStream_onError(swClient *cli)
{
swStream_free(cli->object);
}
static void swStream_onReceive(swClient *cli, char *data, uint32_t length)
{
swStream *stream = (swStream*) cli->object;
if (length == 4)
{
cli->socket->close_wait = 1;
}
else
{
stream->response(stream, data + 4, length - 4);
}
}
static void swStream_onClose(swClient *cli)
{
swStream_free(cli->object);
}
static void swStream_free(swStream *stream)
{
if (stream->buffer)
{
swString_free(stream->buffer);
}
sw_free(stream);
}
swStream* swStream_new(char *dst_host, int dst_port, int type)
{
swStream *stream = (swStream*) sw_malloc(sizeof(swStream));
bzero(stream, sizeof(swStream));
swClient *cli = &stream->client;
if (swClient_create(cli, type, 1) < 0)
{
swStream_free(stream);
return NULL;
}
cli->onConnect = swStream_onConnect;
cli->onReceive = swStream_onReceive;
cli->onError = swStream_onError;
cli->onClose = swStream_onClose;
cli->object = stream;
cli->open_length_check = 1;
swStream_set_protocol(&cli->protocol);
if (cli->connect(cli, dst_host, dst_port, -1, 0) < 0)
{
swSysError("failed to connect to [%s:%d].", dst_host, dst_port);
swStream_free(stream);
return NULL;
}
else
{
return stream;
}
}
/**
* Stream Protocol: Length(32bit/Network Byte Order) + Body
*/
void swStream_set_protocol(swProtocol *protocol)
{
protocol->get_package_length = swProtocol_get_package_length;
protocol->package_length_size = 4;
protocol->package_length_type = 'N';
protocol->package_body_offset = 4;
protocol->package_length_offset = 0;
}
void swStream_set_max_length(swStream *stream, uint32_t max_length)
{
stream->client.protocol.package_max_length = max_length;
}
int swStream_send(swStream *stream, char *data, size_t length)
{
if (stream->buffer == NULL)
{
stream->buffer = swString_new(swoole_size_align(length + 4, SwooleG.pagesize));
if (stream->buffer == NULL)
{
return SW_ERR;
}
stream->buffer->length = 4;
}
if (swString_append_ptr(stream->buffer, data, length) < 0)
{
return SW_ERR;
}
return SW_OK;
}
int swStream_recv_blocking(int fd, void *__buf, size_t __len)
{
int tmp = 0;
int ret = swSocket_recv_blocking(fd, &tmp, sizeof(tmp), MSG_WAITALL);
if (ret <= 0)
{
return SW_CLOSE;
}
int length = ntohl(tmp);
if (length <= 0)
{
return SW_CLOSE;
}
else if (length > __len)
{
return SW_CLOSE;
}
ret = swSocket_recv_blocking(fd, __buf, length, MSG_WAITALL);
if (ret <= 0)
{
return SW_CLOSE;
}
else
{
return SW_READY;
}
}

320
vendor/swoole/src/network/TaskWorker.c vendored Executable file
View File

@ -0,0 +1,320 @@
/*
+----------------------------------------------------------------------+
| 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"
static swEventData *current_task = NULL;
static void swTaskWorker_signal_init(void);
void swTaskWorker_init(swProcessPool *pool)
{
swServer *serv = SwooleG.serv;
pool->ptr = serv;
pool->onTask = swTaskWorker_onTask;
pool->onWorkerStart = swTaskWorker_onStart;
pool->onWorkerStop = swTaskWorker_onStop;
pool->type = SW_PROCESS_TASKWORKER;
pool->start_id = serv->worker_num;
pool->run_worker_num = serv->task_worker_num;
if (serv->task_ipc_mode == SW_TASK_IPC_PREEMPTIVE)
{
pool->dispatch_mode = SW_DISPATCH_QUEUE;
}
}
/**
* in worker process
*/
int swTaskWorker_onFinish(swReactor *reactor, swEvent *event)
{
swServer *serv = reactor->ptr;
swEventData task;
int n;
do
{
n = read(event->fd, &task, sizeof(task));
} while (n < 0 && errno == EINTR);
return serv->onFinish(serv, &task);
}
int swTaskWorker_onTask(swProcessPool *pool, swEventData *task)
{
int ret = SW_OK;
swServer *serv = pool->ptr;
current_task = task;
if (task->info.type == SW_EVENT_PIPE_MESSAGE)
{
serv->onPipeMessage(serv, task);
}
else
{
ret = serv->onTask(serv, task);
}
return ret;
}
int swTaskWorker_large_pack(swEventData *task, void *data, int data_len)
{
swPackage_task pkg;
bzero(&pkg, sizeof(pkg));
memcpy(pkg.tmpfile, SwooleG.task_tmpdir, SwooleG.task_tmpdir_len);
//create temp file
int tmp_fd = swoole_tmpfile(pkg.tmpfile);
if (tmp_fd < 0)
{
return SW_ERR;
}
//write to file
if (swoole_sync_writefile(tmp_fd, data, data_len) <= 0)
{
swWarn("write to tmpfile failed.");
return SW_ERR;
}
task->info.len = sizeof(swPackage_task);
//use tmp file
swTask_type(task) |= SW_TASK_TMPFILE;
pkg.length = data_len;
memcpy(task->data, &pkg, sizeof(swPackage_task));
close(tmp_fd);
return SW_OK;
}
static void swTaskWorker_signal_init(void)
{
swSignal_set(SIGHUP, NULL, 1, 0);
swSignal_set(SIGPIPE, NULL, 1, 0);
swSignal_set(SIGUSR1, swWorker_signal_handler, 1, 0);
swSignal_set(SIGUSR2, NULL, 1, 0);
swSignal_set(SIGTERM, swWorker_signal_handler, 1, 0);
swSignal_set(SIGALRM, swSystemTimer_signal_handler, 1, 0);
#ifdef SIGRTMIN
swSignal_set(SIGRTMIN, swWorker_signal_handler, 1, 0);
#endif
}
void swTaskWorker_onStart(swProcessPool *pool, int worker_id)
{
swServer *serv = pool->ptr;
SwooleWG.id = worker_id;
SwooleG.pid = getpid();
SwooleG.use_timer_pipe = 0;
SwooleG.use_timerfd = 0;
swServer_close_port(serv, SW_TRUE);
swTaskWorker_signal_init();
swWorker_onStart(serv);
SwooleG.main_reactor = NULL;
swWorker *worker = swProcessPool_get_worker(pool, worker_id);
worker->start_time = serv->gs->now;
worker->request_count = 0;
worker->traced = 0;
SwooleWG.worker = worker;
SwooleWG.worker->status = SW_WORKER_IDLE;
}
void swTaskWorker_onStop(swProcessPool *pool, int worker_id)
{
swServer *serv = pool->ptr;
swWorker_onStop(serv);
}
/**
* Send the task result to worker
*/
int swTaskWorker_finish(swServer *serv, char *data, int data_len, int flags)
{
swEventData buf;
if (!current_task)
{
swWarn("cannot use finish in worker");
return SW_ERR;
}
if (serv->task_worker_num < 1)
{
swWarn("cannot use task/finish, because no set serv->task_worker_num.");
return SW_ERR;
}
if (current_task->info.type == SW_EVENT_PIPE_MESSAGE)
{
swWarn("task/finish is not supported in onPipeMessage callback.");
return SW_ERR;
}
uint16_t source_worker_id = current_task->info.from_id;
swWorker *worker = swServer_get_worker(serv, source_worker_id);
if (worker == NULL)
{
swWarn("invalid worker_id[%d].", source_worker_id);
return SW_ERR;
}
int ret;
//for swoole_server_task
if (swTask_type(current_task) & SW_TASK_NONBLOCK)
{
buf.info.type = SW_EVENT_FINISH;
buf.info.fd = current_task->info.fd;
//callback function
if (swTask_type(current_task) & SW_TASK_CALLBACK)
{
flags |= SW_TASK_CALLBACK;
}
else if (swTask_type(current_task) & SW_TASK_COROUTINE)
{
flags |= SW_TASK_COROUTINE;
}
swTask_type(&buf) = flags;
//write to file
if (data_len >= SW_IPC_MAX_SIZE - sizeof(buf.info))
{
if (swTaskWorker_large_pack(&buf, data, data_len) < 0 )
{
swWarn("large task pack failed()");
return SW_ERR;
}
}
else
{
memcpy(buf.data, data, data_len);
buf.info.len = data_len;
}
if (worker->pool->use_socket && worker->pool->stream->last_connection > 0)
{
int32_t _len = htonl(data_len);
ret = swSocket_write_blocking(worker->pool->stream->last_connection, (void *) &_len, sizeof(_len));
if (ret > 0)
{
ret = swSocket_write_blocking(worker->pool->stream->last_connection, data, data_len);
}
}
else
{
ret = swWorker_send2worker(worker, &buf, sizeof(buf.info) + buf.info.len, SW_PIPE_MASTER);
}
}
else
{
uint64_t flag = 1;
/**
* Use worker shm store the result
*/
swEventData *result = &(serv->task_result[source_worker_id]);
swPipe *task_notify_pipe = &(serv->task_notify[source_worker_id]);
//lock worker
worker->lock.lock(&worker->lock);
if (swTask_type(current_task) & SW_TASK_WAITALL)
{
sw_atomic_t *finish_count = (sw_atomic_t*) result->data;
char *_tmpfile = result->data + 4;
int fd = open(_tmpfile, O_APPEND | O_WRONLY);
if (fd >= 0)
{
buf.info.type = SW_EVENT_FINISH;
buf.info.fd = current_task->info.fd;
swTask_type(&buf) = flags;
//result pack
if (data_len >= SW_IPC_MAX_SIZE - sizeof(buf.info))
{
if (swTaskWorker_large_pack(&buf, data, data_len) < 0)
{
swWarn("large task pack failed()");
buf.info.len = 0;
}
}
else
{
buf.info.len = data_len;
memcpy(buf.data, data, data_len);
}
//write to tmpfile
if (swoole_sync_writefile(fd, &buf, sizeof(buf.info) + buf.info.len) < 0)
{
swSysError("write(%s, %ld) failed.", result->data, sizeof(buf.info) + buf.info.len);
}
sw_atomic_fetch_add(finish_count, 1);
close(fd);
}
}
else
{
result->info.type = SW_EVENT_FINISH;
result->info.fd = current_task->info.fd;
swTask_type(result) = flags;
if (data_len >= SW_IPC_MAX_SIZE - sizeof(buf.info))
{
if (swTaskWorker_large_pack(result, data, data_len) < 0)
{
//unlock worker
worker->lock.unlock(&worker->lock);
swWarn("large task pack failed()");
return SW_ERR;
}
}
else
{
memcpy(result->data, data, data_len);
result->info.len = data_len;
}
}
//unlock worker
worker->lock.unlock(&worker->lock);
while (1)
{
ret = task_notify_pipe->write(task_notify_pipe, &flag, sizeof(flag));
#ifdef HAVE_KQUEUE
if (ret < 0 && (errno == EAGAIN || errno == ENOBUFS))
#else
if (ret < 0 && errno == EAGAIN)
#endif
{
if (swSocket_wait(task_notify_pipe->getFd(task_notify_pipe, 1), -1, SW_EVENT_WRITE) == 0)
{
continue;
}
}
break;
}
}
if (ret < 0)
{
swWarn("TaskWorker: send result to worker failed. Error: %s[%d]", strerror(errno), errno);
}
return ret;
}

186
vendor/swoole/src/network/ThreadPool.c vendored Executable file
View File

@ -0,0 +1,186 @@
/*
+----------------------------------------------------------------------+
| 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"
#define swThreadPool_thread(p,id) (&p->threads[id])
static void* swThreadPool_loop(void *arg);
int swThreadPool_create(swThreadPool *pool, int thread_num)
{
bzero(pool, sizeof(swThreadPool));
pool->threads = (swThread *) sw_calloc(thread_num, sizeof(swThread));
pool->params = (swThreadParam *) sw_calloc(thread_num, sizeof(swThreadParam));
if (pool->threads == NULL || pool->params == NULL)
{
swWarn("swThreadPool_create malloc fail");
return SW_ERR;
}
swTrace("threads=%p|params=%p", pool->threads, pool->params);
#ifdef SW_THREADPOOL_USE_CHANNEL
pool->chan = swChannel_create(1024 * 256, 512, 0);
if (pool->chan == NULL)
{
swWarn("swThreadPool_create create channel failed");
return SW_ERR;
}
#else
int size = SwooleG.max_sockets >= SW_THREADPOOL_QUEUE_LEN ? SwooleG.max_sockets + 1 : SW_THREADPOOL_QUEUE_LEN;
if (swRingQueue_init(&pool->queue, size) < 0)
{
return SW_ERR;
}
#endif
if (swCond_create(&pool->cond) < 0)
{
return SW_ERR;
}
pool->thread_num = thread_num;
return SW_OK;
}
int swThreadPool_dispatch(swThreadPool *pool, void *task, int task_len)
{
int ret;
pool->cond.lock(&pool->cond);
#ifdef SW_THREADPOOL_USE_CHANNEL
ret = swChannel_in(pool->chan, task, task_len);
#else
ret = swRingQueue_push(&pool->queue, task);
#endif
pool->cond.unlock(&pool->cond);
if (ret < 0)
{
swoole_error_log(SW_LOG_ERROR, SW_ERROR_QUEUE_FULL, "the queue of thread pool is full.");
return SW_ERR;
}
sw_atomic_t *task_num = &pool->task_num;
sw_atomic_fetch_add(task_num, 1);
return pool->cond.notify(&pool->cond);
}
int swThreadPool_run(swThreadPool *pool)
{
int i;
for (i = 0; i < pool->thread_num; i++)
{
pool->params[i].pti = i;
pool->params[i].object = pool;
if (pthread_create(&(swThreadPool_thread(pool,i)->tid), NULL, swThreadPool_loop, &pool->params[i]) < 0)
{
swWarn("pthread_create failed. Error: %s[%d]", strerror(errno), errno);
return SW_ERR;
}
}
return SW_OK;
}
int swThreadPool_free(swThreadPool *pool)
{
int i;
if (pool->shutdown)
{
return -1;
}
pool->shutdown = 1;
//broadcast all thread
pool->cond.broadcast(&(pool->cond));
for (i = 0; i < pool->thread_num; i++)
{
pthread_join((swThreadPool_thread(pool,i)->tid), NULL);
}
#ifdef SW_THREADPOOL_USE_CHANNEL
swChannel_free(pool->chan);
#else
swRingQueue_free(&pool->queue);
#endif
pool->cond.free(&pool->cond);
return SW_OK;
}
static void* swThreadPool_loop(void *arg)
{
swThreadParam *param = arg;
swThreadPool *pool = param->object;
int id = param->pti;
int ret;
void *task;
SwooleTG.buffer_stack = swString_new(8192);
if (SwooleTG.buffer_stack == NULL)
{
return NULL;
}
if (pool->onStart)
{
pool->onStart(pool, id);
}
while (SwooleG.running)
{
pool->cond.lock(&pool->cond);
if (pool->shutdown)
{
pool->cond.unlock(&pool->cond);
swTrace("thread [%d] will exit\n", id);
pthread_exit(NULL);
}
if (pool->task_num == 0)
{
pool->cond.wait(&pool->cond);
}
swTrace("thread [%d] is starting to work\n", id);
ret = swRingQueue_pop(&pool->queue, &task);
pool->cond.unlock(&pool->cond);
if (ret >= 0)
{
sw_atomic_t *task_num = &pool->task_num;
sw_atomic_fetch_sub(task_num, 1);
pool->onTask(pool, (void *) task, ret);
}
}
if (pool->onStop)
{
pool->onStop(pool, id);
}
swString_free(SwooleTG.buffer_stack);
pthread_exit(NULL);
return NULL;
}

135
vendor/swoole/src/network/TimeWheel.c vendored Executable file
View File

@ -0,0 +1,135 @@
/*
+----------------------------------------------------------------------+
| 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"
#ifdef SW_USE_TIMEWHEEL
swTimeWheel* swTimeWheel_new(uint16_t size)
{
swTimeWheel *tw = sw_malloc(sizeof(swTimeWheel));
if (!tw)
{
swWarn("malloc(%ld) failed.", sizeof(swTimeWheel));
return NULL;
}
tw->size = size;
tw->current = 0;
tw->wheel = sw_calloc(size, sizeof(void*));
if (tw->wheel == NULL)
{
swWarn("malloc(%ld) failed.", sizeof(void*) * size);
sw_free(tw);
return NULL;
}
int i;
for (i = 0; i < size; i++)
{
tw->wheel[i] = swHashMap_new(16, NULL);
if (tw->wheel[i] == NULL)
{
swTimeWheel_free(tw);
return NULL;
}
}
return tw;
}
void swTimeWheel_free(swTimeWheel *tw)
{
int i;
for (i = 0; i < tw->size; i++)
{
if (tw->wheel[i] != NULL)
{
swHashMap_free(tw->wheel[i]);
tw->wheel[i] = NULL;
}
}
sw_free(tw->wheel);
sw_free(tw);
}
void swTimeWheel_forward(swTimeWheel *tw, swReactor *reactor)
{
swHashMap *set = tw->wheel[tw->current];
tw->current = tw->current == tw->size - 1 ? 0 : tw->current + 1;
swTraceLog(SW_TRACE_REACTOR, "current=%d.", tw->current);
swConnection *conn;
uint64_t fd;
while (1)
{
conn = swHashMap_each_int(set, &fd);
if (conn == NULL)
{
break;
}
conn->close_force = 1;
conn->close_notify = 1;
conn->close_wait = 1;
conn->close_actively = 1;
//notify to reactor thread
if (conn->removed)
{
reactor->close(reactor, (int) fd);
}
else
{
reactor->set(reactor, fd, SW_FD_TCP | SW_EVENT_WRITE);
}
}
}
void swTimeWheel_add(swTimeWheel *tw, swConnection *conn)
{
uint16_t index = tw->current == 0 ? tw->size - 1 : tw->current - 1;
swHashMap *new_set = tw->wheel[index];
swHashMap_add_int(new_set, conn->fd, conn);
conn->timewheel_index = index;
swTraceLog(SW_TRACE_REACTOR, "current=%d, fd=%d, index=%d.", tw->current, conn->fd, index);
}
void swTimeWheel_update(swTimeWheel *tw, swConnection *conn)
{
uint16_t new_index = swTimeWheel_new_index(tw);
swHashMap *new_set = tw->wheel[new_index];
swHashMap_add_int(new_set, conn->fd, conn);
swHashMap *old_set = tw->wheel[conn->timewheel_index];
swHashMap_del_int(old_set, conn->fd);
swTraceLog(SW_TRACE_REACTOR, "current=%d, fd=%d, old_index=%d, new_index=%d.", tw->current, conn->fd, new_index, conn->timewheel_index);
conn->timewheel_index = new_index;
}
void swTimeWheel_remove(swTimeWheel *tw, swConnection *conn)
{
swHashMap *set = tw->wheel[conn->timewheel_index];
swHashMap_del_int(set, conn->fd);
swTraceLog(SW_TRACE_REACTOR, "current=%d, fd=%d.", tw->current, conn->fd);
}
#endif

245
vendor/swoole/src/network/Timer.c vendored Executable file
View File

@ -0,0 +1,245 @@
/*
+----------------------------------------------------------------------+
| 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"
static int swReactorTimer_init(long msec);
static int swReactorTimer_set(swTimer *timer, long exec_msec);
static swTimer_node* swTimer_add(swTimer *timer, int _msec, int interval, void *data, swTimerCallback callback);
int swTimer_now(struct timeval *time)
{
#if defined(SW_USE_MONOTONIC_TIME) && defined(CLOCK_MONOTONIC)
struct timespec _now;
if (clock_gettime(CLOCK_MONOTONIC, &_now) < 0)
{
swSysError("clock_gettime(CLOCK_MONOTONIC) failed.");
return SW_ERR;
}
time->tv_sec = _now.tv_sec;
time->tv_usec = _now.tv_nsec / 1000;
#else
if (gettimeofday(time, NULL) < 0)
{
swSysError("gettimeofday() failed.");
return SW_ERR;
}
#endif
return SW_OK;
}
static sw_inline int64_t swTimer_get_relative_msec()
{
struct timeval now;
if (swTimer_now(&now) < 0)
{
return SW_ERR;
}
int64_t msec1 = (now.tv_sec - SwooleG.timer.basetime.tv_sec) * 1000;
int64_t msec2 = (now.tv_usec - SwooleG.timer.basetime.tv_usec) / 1000;
return msec1 + msec2;
}
int swTimer_init(long msec)
{
if (swTimer_now(&SwooleG.timer.basetime) < 0)
{
return SW_ERR;
}
SwooleG.timer.heap = swHeap_new(1024, SW_MIN_HEAP);
if (!SwooleG.timer.heap)
{
return SW_ERR;
}
SwooleG.timer.map = swHashMap_new(SW_HASHMAP_INIT_BUCKET_N, NULL);
if (!SwooleG.timer.map)
{
swHeap_free(SwooleG.timer.heap);
SwooleG.timer.heap = NULL;
return SW_ERR;
}
SwooleG.timer._current_id = -1;
SwooleG.timer._next_msec = msec;
SwooleG.timer._next_id = 1;
SwooleG.timer.add = swTimer_add;
if (swIsTaskWorker())
{
swSystemTimer_init(msec, SwooleG.use_timer_pipe);
}
else
{
swReactorTimer_init(msec);
}
return SW_OK;
}
void swTimer_free(swTimer *timer)
{
if (timer->heap)
{
swHeap_free(timer->heap);
}
}
static int swReactorTimer_init(long exec_msec)
{
SwooleG.main_reactor->check_timer = SW_TRUE;
SwooleG.main_reactor->timeout_msec = exec_msec;
SwooleG.timer.set = swReactorTimer_set;
SwooleG.timer.fd = -1;
return SW_OK;
}
static int swReactorTimer_set(swTimer *timer, long exec_msec)
{
SwooleG.main_reactor->timeout_msec = exec_msec;
return SW_OK;
}
static swTimer_node* swTimer_add(swTimer *timer, int _msec, int interval, void *data, swTimerCallback callback)
{
swTimer_node *tnode = sw_malloc(sizeof(swTimer_node));
if (!tnode)
{
swSysError("malloc(%ld) failed.", sizeof(swTimer_node));
return NULL;
}
int64_t now_msec = swTimer_get_relative_msec();
if (now_msec < 0)
{
sw_free(tnode);
return NULL;
}
tnode->data = data;
tnode->type = SW_TIMER_TYPE_KERNEL;
tnode->exec_msec = now_msec + _msec;
tnode->interval = interval ? _msec : 0;
tnode->remove = 0;
tnode->callback = callback;
if (timer->_next_msec < 0 || timer->_next_msec > _msec)
{
timer->set(timer, _msec);
timer->_next_msec = _msec;
}
tnode->id = timer->_next_id++;
if (unlikely(tnode->id < 0))
{
tnode->id = 1;
timer->_next_id = 2;
}
timer->num++;
tnode->heap_node = swHeap_push(timer->heap, tnode->exec_msec, tnode);
if (tnode->heap_node == NULL)
{
sw_free(tnode);
return NULL;
}
swHashMap_add_int(timer->map, tnode->id, tnode);
return tnode;
}
int swTimer_del(swTimer *timer, swTimer_node *tnode)
{
if (tnode->remove)
{
return SW_FALSE;
}
if (SwooleG.timer._current_id > 0 && tnode->id == SwooleG.timer._current_id)
{
tnode->remove = 1;
return SW_TRUE;
}
if (swHashMap_del_int(timer->map, tnode->id) < 0)
{
return SW_ERR;
}
if (tnode->heap_node)
{
//remove from min-heap
swHeap_remove(timer->heap, tnode->heap_node);
sw_free(tnode->heap_node);
}
sw_free(tnode);
timer->num --;
return SW_TRUE;
}
int swTimer_select(swTimer *timer)
{
int64_t now_msec = swTimer_get_relative_msec();
if (now_msec < 0)
{
return SW_ERR;
}
swTimer_node *tnode = NULL;
swHeap_node *tmp;
long timer_id;
while ((tmp = swHeap_top(timer->heap)))
{
tnode = tmp->data;
if (tnode->exec_msec > now_msec)
{
break;
}
timer_id = timer->_current_id = tnode->id;
if (!tnode->remove)
{
tnode->callback(timer, tnode);
}
timer->_current_id = -1;
//persistent timer
if (tnode->interval > 0 && !tnode->remove)
{
while (tnode->exec_msec <= now_msec)
{
tnode->exec_msec += tnode->interval;
}
swHeap_change_priority(timer->heap, tnode->exec_msec, tmp);
continue;
}
timer->num--;
swHeap_pop(timer->heap);
swHashMap_del_int(timer->map, timer_id);
sw_free(tnode);
}
if (!tnode || !tmp)
{
timer->_next_msec = -1;
timer->set(timer, -1);
}
else
{
timer->set(timer, tnode->exec_msec - now_msec);
}
return SW_OK;
}

897
vendor/swoole/src/network/Worker.c vendored Executable file
View File

@ -0,0 +1,897 @@
/*
+----------------------------------------------------------------------+
| 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 "Client.h"
#include "async.h"
#include <pwd.h>
#include <grp.h>
static int swWorker_onPipeReceive(swReactor *reactor, swEvent *event);
static void swWorker_onTimeout(swTimer *timer, swTimer_node *tnode);
static int swWorker_onStreamAccept(swReactor *reactor, swEvent *event);
static int swWorker_onStreamRead(swReactor *reactor, swEvent *event);
static int swWorker_onStreamPackage(swConnection *conn, char *data, uint32_t length);
static int swWorker_onStreamClose(swReactor *reactor, swEvent *event);
static void swWorker_stop();
int swWorker_create(swWorker *worker)
{
/**
* Create shared memory storage
*/
worker->send_shm = sw_shm_malloc(SwooleG.serv->buffer_output_size);
if (worker->send_shm == NULL)
{
swWarn("malloc for worker->store failed.");
return SW_ERR;
}
swMutex_create(&worker->lock, 1);
return SW_OK;
}
void swWorker_free(swWorker *worker)
{
if (worker->send_shm)
{
sw_shm_free(worker->send_shm);
}
}
void swWorker_signal_init(void)
{
swSignal_clear();
/**
* use user settings
*/
SwooleG.use_signalfd = SwooleG.enable_signalfd;
swSignal_add(SIGHUP, NULL);
swSignal_add(SIGPIPE, NULL);
swSignal_add(SIGUSR1, NULL);
swSignal_add(SIGUSR2, NULL);
//swSignal_add(SIGINT, swWorker_signal_handler);
swSignal_add(SIGTERM, swWorker_signal_handler);
swSignal_add(SIGALRM, swSystemTimer_signal_handler);
//for test
swSignal_add(SIGVTALRM, swWorker_signal_handler);
#ifdef SIGRTMIN
swSignal_add(SIGRTMIN, swWorker_signal_handler);
#endif
}
void swWorker_signal_handler(int signo)
{
switch (signo)
{
case SIGTERM:
/**
* Event worker
*/
if (SwooleG.main_reactor)
{
swWorker_stop();
}
/**
* Task worker
*/
else
{
SwooleG.running = 0;
}
break;
case SIGALRM:
swSystemTimer_signal_handler(SIGALRM);
break;
/**
* for test
*/
case SIGVTALRM:
swWarn("SIGVTALRM coming");
break;
case SIGUSR1:
break;
case SIGUSR2:
break;
default:
#ifdef SIGRTMIN
if (signo == SIGRTMIN)
{
swServer_reopen_log_file(SwooleG.serv);
}
#endif
break;
}
}
static sw_inline int swWorker_discard_data(swServer *serv, swEventData *task)
{
int fd = task->info.fd;
//check connection
swConnection *conn = swServer_connection_verify(serv, task->info.fd);
if (conn == NULL)
{
if (serv->disable_notify && !serv->discard_timeout_request)
{
return SW_FALSE;
}
goto discard_data;
}
else
{
if (conn->closed)
{
goto discard_data;
}
else
{
return SW_FALSE;
}
}
discard_data:
#ifdef SW_USE_RINGBUFFER
if (task->info.type == SW_EVENT_PACKAGE)
{
swPackage package;
memcpy(&package, task->data, sizeof(package));
swReactorThread *thread = swServer_get_thread(SwooleG.serv, task->info.from_id);
thread->buffer_input->free(thread->buffer_input, package.data);
swoole_error_log(SW_LOG_WARNING, SW_ERROR_SESSION_DISCARD_TIMEOUT_DATA, "[1]received the wrong data[%d bytes] from socket#%d", package.length, fd);
}
else
#endif
{
swoole_error_log(SW_LOG_WARNING, SW_ERROR_SESSION_DISCARD_TIMEOUT_DATA, "[1]received the wrong data[%d bytes] from socket#%d", task->info.len, fd);
}
return SW_TRUE;
}
static int swWorker_onStreamAccept(swReactor *reactor, swEvent *event)
{
int fd = 0;
swSocketAddress client_addr;
socklen_t client_addrlen = sizeof(client_addr);
#ifdef HAVE_ACCEPT4
fd = accept4(event->fd, (struct sockaddr *) &client_addr, &client_addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC);
#else
fd = accept(event->fd, (struct sockaddr *) &client_addr, &client_addrlen);
#endif
if (fd < 0)
{
switch (errno)
{
case EINTR:
case EAGAIN:
return SW_OK;
default:
swoole_error_log(SW_LOG_ERROR, SW_ERROR_SYSTEM_CALL_FAIL, "accept() failed. Error: %s[%d]", strerror(errno),
errno);
return SW_OK;
}
}
#ifndef HAVE_ACCEPT4
else
{
swoole_fcntl_set_option(fd, 1, 1);
}
#endif
swConnection *conn = swReactor_get(reactor, fd);
bzero(conn, sizeof(swConnection));
conn->fd = fd;
conn->active = 1;
conn->socket_type = SW_SOCK_UNIX_STREAM;
memcpy(&conn->info.addr, &client_addr, sizeof(client_addr));
if (reactor->add(reactor, fd, SW_FD_STREAM | SW_EVENT_READ) < 0)
{
return SW_ERR;
}
return SW_OK;
}
static int swWorker_onStreamRead(swReactor *reactor, swEvent *event)
{
swConnection *conn = event->socket;
swServer *serv = SwooleG.serv;
swProtocol *protocol = &serv->stream_protocol;
swString *buffer;
if (!event->socket->recv_buffer)
{
buffer = swLinkedList_shift(serv->buffer_pool);
if (buffer == NULL)
{
buffer = swString_new(8192);
if (!buffer)
{
return SW_ERR;
}
}
event->socket->recv_buffer = buffer;
}
else
{
buffer = event->socket->recv_buffer;
}
if (swProtocol_recv_check_length(protocol, conn, buffer) < 0)
{
swWorker_onStreamClose(reactor, event);
}
return SW_OK;
}
static int swWorker_onStreamClose(swReactor *reactor, swEvent *event)
{
swConnection *conn = event->socket;
swServer *serv = SwooleG.serv;
swString_clear(conn->recv_buffer);
swLinkedList_append(serv->buffer_pool, conn->recv_buffer);
conn->recv_buffer = NULL;
reactor->del(reactor, conn->fd);
reactor->close(reactor, conn->fd);
return SW_OK;
}
static int swWorker_onStreamPackage(swConnection *conn, char *data, uint32_t length)
{
swServer *serv = SwooleG.serv;
swEventData *task = (swEventData *) (data + 4);
serv->last_stream_fd = conn->fd;
swString *package = swWorker_get_buffer(serv, task->info.from_id);
uint32_t data_length = length - sizeof(task->info) - 4;
//merge data to package buffer
swString_append_ptr(package, data + sizeof(task->info) + 4, data_length);
swWorker_onTask(&serv->factory, task);
int _end = htonl(0);
SwooleG.main_reactor->write(SwooleG.main_reactor, conn->fd, (void *) &_end, sizeof(_end));
return SW_OK;
}
int swWorker_onTask(swFactory *factory, swEventData *task)
{
swServer *serv = factory->ptr;
swString *package = NULL;
swDgramPacket *header;
#ifdef SW_USE_OPENSSL
swConnection *conn;
#endif
factory->last_from_id = task->info.from_id;
serv->last_session_id = task->info.fd;
swWorker *worker = SwooleWG.worker;
//worker busy
worker->status = SW_WORKER_BUSY;
switch (task->info.type)
{
//no buffer
case SW_EVENT_TCP:
//ringbuffer shm package
case SW_EVENT_PACKAGE:
//discard data
if (swWorker_discard_data(serv, task) == SW_TRUE)
{
break;
}
do_task:
{
worker->request_time = serv->gs->now;
#ifdef SW_BUFFER_RECV_TIME
serv->last_receive_usec = task->info.time;
#endif
serv->onReceive(serv, task);
worker->request_time = 0;
#ifdef SW_BUFFER_RECV_TIME
serv->last_receive_usec = 0;
#endif
worker->traced = 0;
worker->request_count++;
sw_atomic_fetch_add(&serv->stats->request_count, 1);
}
if (task->info.type == SW_EVENT_PACKAGE_END)
{
package->length = 0;
}
break;
//chunk package
case SW_EVENT_PACKAGE_START:
case SW_EVENT_PACKAGE_END:
//discard data
if (swWorker_discard_data(serv, task) == SW_TRUE)
{
break;
}
package = swWorker_get_buffer(serv, task->info.from_id);
if (task->info.len > 0)
{
//merge data to package buffer
swString_append_ptr(package, task->data, task->info.len);
}
//package end
if (task->info.type == SW_EVENT_PACKAGE_END)
{
goto do_task;
}
break;
case SW_EVENT_UDP:
case SW_EVENT_UDP6:
case SW_EVENT_UNIX_DGRAM:
package = swWorker_get_buffer(serv, task->info.from_id);
swString_append_ptr(package, task->data, task->info.len);
if (package->offset == 0)
{
header = (swDgramPacket *) package->str;
package->offset = header->length;
}
//one packet
if (package->offset == package->length - sizeof(swDgramPacket))
{
worker->request_count++;
worker->request_time = serv->gs->now;
#ifdef SW_BUFFER_RECV_TIME
serv->last_receive_usec = task->info.time;
#endif
sw_atomic_fetch_add(&serv->stats->request_count, 1);
serv->onPacket(serv, task);
worker->request_time = 0;
#ifdef SW_BUFFER_RECV_TIME
serv->last_receive_usec = 0;
#endif
worker->traced = 0;
worker->request_count++;
swString_clear(package);
}
break;
case SW_EVENT_CLOSE:
#ifdef SW_USE_OPENSSL
conn = swServer_connection_verify_no_ssl(serv, task->info.fd);
if (conn && conn->ssl_client_cert.length > 0)
{
sw_free(conn->ssl_client_cert.str);
bzero(&conn->ssl_client_cert, sizeof(conn->ssl_client_cert.str));
}
#endif
factory->end(factory, task->info.fd);
break;
case SW_EVENT_CONNECT:
#ifdef SW_USE_OPENSSL
//SSL client certificate
if (task->info.len > 0)
{
conn = swServer_connection_verify_no_ssl(serv, task->info.fd);
conn->ssl_client_cert.str = sw_strndup(task->data, task->info.len);
conn->ssl_client_cert.size = conn->ssl_client_cert.length = task->info.len;
}
#endif
if (serv->onConnect)
{
serv->onConnect(serv, &task->info);
}
break;
case SW_EVENT_BUFFER_FULL:
if (serv->onBufferFull)
{
serv->onBufferFull(serv, &task->info);
}
break;
case SW_EVENT_BUFFER_EMPTY:
if (serv->onBufferEmpty)
{
serv->onBufferEmpty(serv, &task->info);
}
break;
case SW_EVENT_FINISH:
serv->onFinish(serv, task);
break;
case SW_EVENT_PIPE_MESSAGE:
serv->onPipeMessage(serv, task);
break;
default:
swWarn("[Worker] error event[type=%d]", (int )task->info.type);
break;
}
//worker idle
worker->status = SW_WORKER_IDLE;
//maximum number of requests, process will exit.
if (!SwooleWG.run_always && worker->request_count >= SwooleWG.max_request)
{
swWorker_stop();
}
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 + serv->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);
}
}
SwooleWG.worker->status = SW_WORKER_IDLE;
sw_shm_protect(serv->session_list, PROT_READ);
if (serv->onWorkerStart)
{
serv->onWorkerStart(serv, SwooleWG.id);
}
}
void swWorker_onStop(swServer *serv)
{
if (serv->onWorkerStop)
{
serv->onWorkerStop(serv, SwooleWG.id);
}
}
static void swWorker_stop()
{
swWorker *worker = SwooleWG.worker;
swServer *serv = SwooleG.serv;
worker->status = SW_WORKER_BUSY;
/**
* force to end
*/
if (serv->reload_async == 0)
{
SwooleG.running = 0;
SwooleG.main_reactor->running = 0;
return;
}
//The worker process is shutting down now.
if (SwooleWG.wait_exit)
{
return;
}
//remove read event
if (worker->pipe_worker)
{
swReactor_remove_read_event(SwooleG.main_reactor, worker->pipe_worker);
}
if (serv->stream_fd > 0)
{
SwooleG.main_reactor->del(SwooleG.main_reactor, serv->stream_fd);
close(serv->stream_fd);
serv->stream_fd = 0;
}
if (serv->onWorkerStop)
{
serv->onWorkerStop(serv, SwooleWG.id);
serv->onWorkerStop = NULL;
}
if (serv->factory_mode == SW_MODE_SINGLE)
{
swListenPort *port;
LL_FOREACH(serv->listen_list, port)
{
SwooleG.main_reactor->del(SwooleG.main_reactor, port->sock);
swPort_free(port);
}
if (worker->pipe_worker)
{
SwooleG.main_reactor->del(SwooleG.main_reactor, worker->pipe_worker);
SwooleG.main_reactor->del(SwooleG.main_reactor, worker->pipe_master);
}
goto try_to_exit;
}
swWorkerStopMessage msg;
msg.pid = SwooleG.pid;
msg.worker_id = SwooleWG.id;
//send message to manager
if (swChannel_push(SwooleG.serv->message_box, &msg, sizeof(msg)) < 0)
{
SwooleG.running = 0;
}
else
{
kill(serv->gs->manager_pid, SIGIO);
}
try_to_exit: SwooleWG.wait_exit = 1;
if (SwooleG.timer.fd == 0)
{
swTimer_init(serv->max_wait_time * 1000);
}
SwooleG.timer.add(&SwooleG.timer, serv->max_wait_time * 1000, 0, NULL, swWorker_onTimeout);
swWorker_try_to_exit();
}
static void swWorker_onTimeout(swTimer *timer, swTimer_node *tnode)
{
SwooleG.running = 0;
SwooleG.main_reactor->running = 0;
swoole_error_log(SW_LOG_WARNING, SW_ERROR_SERVER_WORKER_EXIT_TIMEOUT, "worker exit timeout, forced to terminate.");
}
void swWorker_try_to_exit()
{
swServer *serv = SwooleG.serv;
int expect_event_num = SwooleG.use_signalfd ? 1 : 0;
if (SwooleAIO.init && SwooleAIO.task_num == 0)
{
swAio_free();
}
swDNSResolver_free();
//close all client connections
if (serv->factory_mode == SW_MODE_SINGLE)
{
int find_fd = swServer_get_minfd(serv);
int max_fd = swServer_get_maxfd(serv);
swConnection *conn;
for (; find_fd <= max_fd; find_fd++)
{
conn = &serv->connection_list[find_fd];
if (conn->active == 1 && swSocket_is_stream(conn->socket_type) && !(conn->events & SW_EVENT_WRITE))
{
serv->close(serv, conn->session_id, 0);
}
}
}
uint8_t call_worker_exit_func = 0;
while (1)
{
if (SwooleG.main_reactor->event_num == expect_event_num)
{
SwooleG.main_reactor->running = 0;
SwooleG.running = 0;
}
else
{
if (serv->onWorkerExit && call_worker_exit_func == 0)
{
serv->onWorkerExit(serv, SwooleWG.id);
call_worker_exit_func = 1;
continue;
}
}
break;
}
}
void swWorker_clean(void)
{
int i;
swServer *serv = SwooleG.serv;
swWorker *worker;
for (i = 0; i < serv->worker_num + serv->task_worker_num; i++)
{
worker = swServer_get_worker(serv, i);
if (SwooleG.main_reactor)
{
if (worker->pipe_worker)
{
swReactor_wait_write_buffer(SwooleG.main_reactor, worker->pipe_worker);
}
if (worker->pipe_master)
{
swReactor_wait_write_buffer(SwooleG.main_reactor, worker->pipe_master);
}
}
}
}
/**
* worker main loop
*/
int swWorker_loop(swFactory *factory, int worker_id)
{
swServer *serv = factory->ptr;
#ifndef SW_WORKER_USE_SIGNALFD
SwooleG.use_signalfd = 0;
#elif defined(HAVE_SIGNALFD)
SwooleG.use_signalfd = 1;
#endif
//timerfd
#ifdef HAVE_TIMERFD
SwooleG.use_timerfd = 1;
#endif
//worker_id
SwooleWG.id = worker_id;
SwooleG.pid = getpid();
swWorker *worker = swServer_get_worker(serv, worker_id);
swServer_worker_init(serv, worker);
SwooleG.main_reactor = sw_malloc(sizeof(swReactor));
if (SwooleG.main_reactor == NULL)
{
swError("[Worker] malloc for reactor failed.");
return SW_ERR;
}
if (swReactor_create(SwooleG.main_reactor, SW_REACTOR_MAXEVENTS) < 0)
{
swError("[Worker] create worker_reactor failed.");
return SW_ERR;
}
worker->status = SW_WORKER_IDLE;
int pipe_worker = worker->pipe_worker;
swSetNonBlock(pipe_worker);
SwooleG.main_reactor->ptr = serv;
SwooleG.main_reactor->add(SwooleG.main_reactor, pipe_worker, SW_FD_PIPE | SW_EVENT_READ);
SwooleG.main_reactor->setHandle(SwooleG.main_reactor, SW_FD_PIPE, swWorker_onPipeReceive);
SwooleG.main_reactor->setHandle(SwooleG.main_reactor, SW_FD_WRITE, swReactor_onWrite);
/**
* set pipe buffer size
*/
int i;
swConnection *pipe_socket;
for (i = 0; i < serv->worker_num + serv->task_worker_num; i++)
{
worker = swServer_get_worker(serv, i);
pipe_socket = swReactor_get(SwooleG.main_reactor, worker->pipe_master);
pipe_socket->buffer_size = SW_MAX_INT;
pipe_socket = swReactor_get(SwooleG.main_reactor, worker->pipe_worker);
pipe_socket->buffer_size = SW_MAX_INT;
}
if (serv->dispatch_mode == SW_DISPATCH_STREAM)
{
SwooleG.main_reactor->add(SwooleG.main_reactor, serv->stream_fd, SW_FD_LISTEN | SW_EVENT_READ);
SwooleG.main_reactor->setHandle(SwooleG.main_reactor, SW_FD_LISTEN, swWorker_onStreamAccept);
SwooleG.main_reactor->setHandle(SwooleG.main_reactor, SW_FD_STREAM, swWorker_onStreamRead);
swStream_set_protocol(&serv->stream_protocol);
serv->stream_protocol.package_max_length = SW_MAX_INT;
serv->stream_protocol.onPackage = swWorker_onStreamPackage;
serv->buffer_pool = swLinkedList_new(0, NULL);
}
swWorker_onStart(serv);
#ifdef HAVE_SIGNALFD
if (SwooleG.use_signalfd)
{
swSignalfd_setup(SwooleG.main_reactor);
}
#endif
//main loop
SwooleG.main_reactor->wait(SwooleG.main_reactor, NULL);
//clear pipe buffer
swWorker_clean();
//worker shutdown
swWorker_onStop(serv);
return SW_OK;
}
/**
* Send data to ReactorThread
*/
int swWorker_send2reactor(swEventData *ev_data, size_t sendn, int session_id)
{
int ret;
swServer *serv = SwooleG.serv;
int _pipe_fd = swWorker_get_send_pipe(serv, session_id, ev_data->info.from_id);
if (SwooleG.main_reactor)
{
ret = SwooleG.main_reactor->write(SwooleG.main_reactor, _pipe_fd, ev_data, sendn);
}
else
{
ret = swSocket_write_blocking(_pipe_fd, ev_data, sendn);
}
return ret;
}
/**
* receive data from reactor
*/
static int swWorker_onPipeReceive(swReactor *reactor, swEvent *event)
{
swEventData task;
swServer *serv = reactor->ptr;
swFactory *factory = &serv->factory;
int ret;
read_from_pipe:
if (read(event->fd, &task, sizeof(task)) > 0)
{
ret = swWorker_onTask(factory, &task);
#ifndef SW_WORKER_RECV_AGAIN
/**
* Big package
*/
if (task.info.type == SW_EVENT_PACKAGE_START)
#endif
{
//no data
if (ret < 0 && errno == EAGAIN)
{
return SW_OK;
}
else if (ret > 0)
{
goto read_from_pipe;
}
}
return ret;
}
return SW_ERR;
}
int swWorker_send2worker(swWorker *dst_worker, void *buf, int n, int flag)
{
int pipefd, ret;
if (flag & SW_PIPE_MASTER)
{
pipefd = dst_worker->pipe_master;
}
else
{
pipefd = dst_worker->pipe_worker;
}
//message-queue
if (dst_worker->pool->use_msgqueue)
{
struct
{
long mtype;
swEventData buf;
} msg;
msg.mtype = dst_worker->id + 1;
memcpy(&msg.buf, buf, n);
return swMsgQueue_push(dst_worker->pool->queue, (swQueue_data *) &msg, n);
}
if ((flag & SW_PIPE_NONBLOCK) && SwooleG.main_reactor)
{
return SwooleG.main_reactor->write(SwooleG.main_reactor, pipefd, buf, n);
}
else
{
ret = swSocket_write_blocking(pipefd, buf, n);
}
return ret;
}