Mini Shell
/*
+----------------------------------------------------------------------+
| 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@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Author: Tianfeng Han <mikan.tenny@gmail.com> |
+----------------------------------------------------------------------+
*/
#ifndef SW_SERVER_H_
#define SW_SERVER_H_
#include "swoole.h"
#include "buffer.h"
#include "connection.h"
#if defined(__sun) && !defined(s6_addr32)
#define s6_addr32 _S6_un._S6_u32
#endif
#ifdef __cplusplus
extern "C" {
#endif
#define SW_REACTOR_NUM SW_CPU_NUM
#define SW_WORKER_NUM (SW_CPU_NUM*2)
enum swServer_event_type
{
//networking socket
SW_EVENT_TCP,
SW_EVENT_UDP,
SW_EVENT_TCP6,
SW_EVENT_UDP6,
//tcp event
SW_EVENT_CLOSE,
SW_EVENT_CONNECT,
//timer
SW_EVENT_TIMER,
//task
SW_EVENT_TASK,
SW_EVENT_FINISH,
//sendfile
SW_EVENT_SENDFILE,
//dgram
SW_EVENT_UNIX_DGRAM,
SW_EVENT_UNIX_STREAM,
//pipe
SW_EVENT_PIPE_MESSAGE,
//proxy
SW_EVENT_PROXY_START,
SW_EVENT_PROXY_END,
SW_EVENT_CONFIRM,
//event operate
SW_EVENT_PAUSE_RECV,
SW_EVENT_RESUME_RECV,
//buffer event
SW_EVENT_BUFFER_FULL,
SW_EVENT_BUFFER_EMPTY,
};
enum swIPCType
{
SW_IPC_NONE = 0,
SW_IPC_UNIXSOCK = 1,
SW_IPC_MSGQUEUE = 2,
SW_IPC_SOCKET = 3,
};
enum swTaskIPCMode
{
SW_TASK_IPC_UNIXSOCK = 1,
SW_TASK_IPC_MSGQUEUE = 2,
SW_TASK_IPC_PREEMPTIVE = 3,
SW_TASK_IPC_STREAM = 4,
};
enum swResponseType
{
SW_RESPONSE_SMALL = 0,
SW_RESPONSE_SHM = 1,
SW_RESPONSE_TMPFILE,
SW_RESPONSE_EXIT,
};
enum swWorkerPipeType
{
SW_PIPE_WORKER = 0,
SW_PIPE_MASTER = 1,
SW_PIPE_NONBLOCK = 2,
};
/**
* use swDataHead->from_fd, 1 byte 8 bit
*/
enum swTaskType
{
SW_TASK_TMPFILE = 1, //tmp file
SW_TASK_SERIALIZE = 2, //php serialize
SW_TASK_NONBLOCK = 4, //task
SW_TASK_CALLBACK = 8, //callback
SW_TASK_WAITALL = 16, //for taskWaitAll
SW_TASK_COROUTINE = 32, //coroutine
SW_TASK_PEEK = 64, //peek
SW_TASK_NOREPLY = 128, //don't reply
};
typedef struct _swReactorThread
{
pthread_t thread_id;
swReactor reactor;
int notify_pipe;
} swReactorThread;
typedef struct _swListenPort
{
struct _swListenPort *next, *prev;
/**
* tcp socket listen backlog
*/
uint16_t backlog;
/**
* open tcp_defer_accept option
*/
int tcp_defer_accept;
/**
* TCP_FASTOPEN
*/
int tcp_fastopen;
/**
* TCP KeepAlive
*/
int tcp_keepidle;
int tcp_keepinterval;
int tcp_keepcount;
int socket_buffer_size;
uint32_t buffer_high_watermark;
uint32_t buffer_low_watermark;
uint8_t type;
uint8_t ssl;
int port;
int sock;
pthread_t thread_id;
char host[SW_HOST_MAXSIZE];
/**
* check data eof
*/
uint32_t open_eof_check :1;
/**
* built-in http protocol
*/
uint32_t open_http_protocol :1;
/**
* built-in http2.0 protocol
*/
uint32_t open_http2_protocol :1;
/**
* built-in websocket protocol
*/
uint32_t open_websocket_protocol :1;
/**
* open websocket close frame
*/
uint32_t open_websocket_close_frame :1;
/**
* one package: length check
*/
uint32_t open_length_check :1;
/**
* for mqtt protocol
*/
uint32_t open_mqtt_protocol :1;
/**
* redis protocol
*/
uint32_t open_redis_protocol :1;
/**
* open tcp nodelay option
*/
uint32_t open_tcp_nodelay :1;
/**
* open tcp nopush option(for sendfile)
*/
uint32_t open_tcp_nopush :1;
/**
* open tcp keepalive
*/
uint32_t open_tcp_keepalive :1;
/**
* open tcp keepalive
*/
uint32_t open_ssl_encrypt :1;
/**
* Sec-WebSocket-Protocol
*/
char *websocket_subprotocol;
uint16_t websocket_subprotocol_length;
/**
* set socket option
*/
int kernel_socket_recv_buffer_size;
int kernel_socket_send_buffer_size;
#ifdef SW_USE_OPENSSL
SSL_CTX *ssl_context;
swSSL_config ssl_config;
swSSL_option ssl_option;
#endif
sw_atomic_t connection_num;
swProtocol protocol;
void *ptr;
int (*onRead)(swReactor *reactor, struct _swListenPort *port, swEvent *event);
} swListenPort;
typedef struct _swUserWorker_node
{
struct _swUserWorker_node *next, *prev;
swWorker *worker;
} swUserWorker_node;
typedef struct {
char *filename;
uint16_t name_len;
int fd;
size_t length;
off_t offset;
} swTask_sendfile;
typedef struct
{
uint16_t num;
} swUserWorker;
typedef struct
{
pid_t pid;
uint16_t worker_id;
} swWorkerStopMessage;
//-----------------------------------Factory--------------------------------------------
typedef struct
{
swDataHead info;
swString data;
} swPackagePtr;
struct _swFactory
{
void *object;
void *ptr; //server object
int last_from_id;
swReactor *reactor; //reserve for reactor
int (*start)(struct _swFactory *);
int (*shutdown)(struct _swFactory *);
int (*dispatch)(struct _swFactory *, swSendData *);
int (*finish)(struct _swFactory *, swSendData *);
int (*notify)(struct _swFactory *, swDataHead *); //send a event notify
int (*end)(struct _swFactory *, int fd);
void (*free)(struct _swFactory *);
};
typedef int (*swServer_dispatch_function)(swServer *, swConnection *, swSendData *);
int swFactory_create(swFactory *factory);
int swFactory_finish(swFactory *factory, swSendData *_send);
int swFactory_check_callback(swFactory *factory);
int swFactoryProcess_create(swFactory *factory, int worker_num);
//------------------------------------Server-------------------------------------------
enum swServer_callback_type
{
SW_SERVER_CALLBACK_onConnect = 1,
SW_SERVER_CALLBACK_onReceive,
SW_SERVER_CALLBACK_onClose,
};
enum swServer_hook_type
{
SW_SERVER_HOOK_MASTER_START,
SW_SERVER_HOOK_MASTER_TIMER,
SW_SERVER_HOOK_REACTOR_START,
SW_SERVER_HOOK_WORKER_START,
SW_SERVER_HOOK_TASK_WORKER_START,
SW_SERVER_HOOK_MASTER_CONNECT,
SW_SERVER_HOOK_REACTOR_CONNECT,
SW_SERVER_HOOK_WORKER_CONNECT,
SW_SERVER_HOOK_REACTOR_RECEIVE,
SW_SERVER_HOOK_WORKER_RECEIVE,
SW_SERVER_HOOK_REACTOR_CLOSE,
SW_SERVER_HOOK_WORKER_CLOSE,
SW_SERVER_HOOK_MANAGER_START,
SW_SERVER_HOOK_MANAGER_TIMER,
SW_SERVER_HOOK_PROCESS_TIMER,
};
typedef struct
{
time_t start_time;
sw_atomic_t connection_num;
sw_atomic_t tasking_num;
sw_atomic_long_t accept_count;
sw_atomic_long_t close_count;
sw_atomic_long_t request_count;
} swServerStats;
typedef struct
{
pid_t master_pid;
pid_t manager_pid;
uint32_t session_round :24;
sw_atomic_t start; //after swServer_start will set start=1
time_t now;
sw_atomic_t spinlock;
swProcessPool task_workers;
swProcessPool event_workers;
} swServerGS;
struct _swServer
{
/**
* reactor thread/process num
*/
uint16_t reactor_num;
/**
* worker process num
*/
uint16_t worker_num;
/**
* The number of pipe per reactor maintenance
*/
uint16_t reactor_pipe_num;
uint8_t factory_mode;
uint8_t dgram_port_num;
/**
* package dispatch mode
*/
uint8_t dispatch_mode;
/**
* No idle work process is available.
*/
uint8_t scheduler_warning;
int worker_uid;
int worker_groupid;
/**
* max connection num
*/
uint32_t max_connection;
/**
* worker process max request
*/
uint32_t max_request;
int udp_socket_ipv4;
int udp_socket_ipv6;
uint32_t max_wait_time;
/*----------------------------Reactor schedule--------------------------------*/
uint16_t reactor_round_i;
uint16_t reactor_next_i;
uint16_t reactor_schedule_count;
sw_atomic_t worker_round_id;
/**
* run as a daemon process
*/
uint32_t daemonize :1;
/**
* have dgram socket
*/
uint32_t have_dgram_sock :1;
/**
* have stream socket
*/
uint32_t have_stream_sock :1;
/**
* open cpu affinity setting
*/
uint32_t open_cpu_affinity :1;
/**
* disable notice when use SW_DISPATCH_ROUND and SW_DISPATCH_QUEUE
*/
uint32_t disable_notify :1;
/**
* discard the timeout request
*/
uint32_t discard_timeout_request :1;
/**
* parse cookie header
*/
uint32_t http_parse_cookie :1;
/**
* parse x-www-form-urlencoded data
*/
uint32_t http_parse_post :1;
/**
* http content compression
*/
uint32_t http_compression :1;
/**
* handle static files
*/
uint32_t enable_static_handler :1;
/**
* enable onConnect/onClose event when use dispatch_mode=1/3
*/
uint32_t enable_unsafe_event :1;
/**
* waiting for worker onConnect callback function to return
*/
uint32_t enable_delay_receive :1;
/**
* asynchronous reloading
*/
uint32_t reload_async :1;
/**
* enable coroutine in task worker
*/
uint32_t task_enable_coroutine :1;
/**
* slowlog
*/
uint32_t trace_event_worker :1;
/**
* yield coroutine when the output buffer is full
*/
uint32_t send_yield :1;
/**
* enable coroutine
*/
uint32_t enable_coroutine :1;
/**
* disable multi-threads
*/
uint32_t single_thread :1;
/**
* heartbeat check time
*/
uint16_t heartbeat_idle_time;
uint16_t heartbeat_check_interval;
int *cpu_affinity_available;
int cpu_affinity_available_num;
swPipeBuffer **pipe_buffers;
double send_timeout;
uint16_t listen_port_num;
time_t reload_time;
time_t warning_time;
/* buffer output/input setting*/
uint32_t buffer_output_size;
uint32_t buffer_input_size;
uint32_t ipc_max_size;
void *ptr2;
void *private_data_3;
swFactory factory;
swListenPort *listen_list;
pthread_t heartbeat_pidt;
/**
* task process
*/
uint16_t task_worker_num;
uint8_t task_ipc_mode;
uint16_t task_max_request;
swPipe *task_notify;
swEventData *task_result;
/**
* user process
*/
uint16_t user_worker_num;
swUserWorker_node *user_worker_list;
swHashMap *user_worker_map;
swWorker *user_workers;
swReactorThread *reactor_threads;
swWorker *workers;
swChannel *message_box;
swServerStats *stats;
swServerGS *gs;
#ifdef HAVE_PTHREAD_BARRIER
pthread_barrier_t barrier;
#endif
swConnection *connection_list;
swSession *session_list;
/**
* temporary directory for HTTP uploaded file.
*/
char *upload_tmp_dir;
/**
* http compression level for gzip/br
*/
uint8_t http_compression_level;
/**
* http static file directory
*/
char *document_root;
uint16_t document_root_len;
/**
* master process pid
*/
char *pid_file;
/**
* stream
*/
char *stream_socket;
int stream_fd;
swProtocol stream_protocol;
int last_stream_fd;
swLinkedList *buffer_pool;
#ifdef SW_BUFFER_RECV_TIME
double last_receive_usec;
#endif
int manager_alarm;
/**
* message queue key
*/
uint64_t message_queue_key;
/**
* slow request log
*/
uint8_t request_slowlog_timeout;
FILE *request_slowlog_file;
swReactor *reactor_ptr; //Main Reactor
swFactory *factory_ptr; //Factory
swLinkedList *hooks[SW_MAX_HOOK_TYPE];
void (*onStart)(swServer *serv);
void (*onManagerStart)(swServer *serv);
void (*onManagerStop)(swServer *serv);
void (*onShutdown)(swServer *serv);
void (*onPipeMessage)(swServer *, swEventData *);
void (*onWorkerStart)(swServer *serv, int worker_id);
void (*onWorkerStop)(swServer *serv, int worker_id);
void (*onWorkerExit)(swServer *serv, int worker_id);
void (*onWorkerError)(swServer *serv, int worker_id, pid_t worker_pid, int exit_code, int signo);
void (*onUserWorkerStart)(swServer *serv, swWorker *worker);
/**
* Client
*/
int (*onReceive)(swServer *, swEventData *);
int (*onPacket)(swServer *, swEventData *);
void (*onClose)(swServer *serv, swDataHead *);
void (*onConnect)(swServer *serv, swDataHead *);
void (*onBufferFull)(swServer *serv, swDataHead *);
void (*onBufferEmpty)(swServer *serv, swDataHead *);
/**
* Task Worker
*/
int (*onTask)(swServer *serv, swEventData *data);
int (*onFinish)(swServer *serv, swEventData *data);
/**
* Server method
*/
int (*send)(swServer *serv, int session_id, void *data, uint32_t length);
int (*sendfile)(swServer *serv, int session_id, char *file, uint32_t l_file, off_t offset, size_t length);
int (*sendwait)(swServer *serv, int session_id, void *data, uint32_t length);
int (*close)(swServer *serv, int session_id, int reset);
int (*notify)(swServer *serv, swConnection *conn, int event);
int (*feedback)(swServer *serv, int session_id, int event);
int (*dispatch_func)(swServer *, swConnection *, swSendData *);
};
typedef struct
{
size_t length;
char tmpfile[SW_TASK_TMPDIR_SIZE + sizeof(SW_TASK_TMP_FILE)];
} swPackage_task;
typedef struct
{
int length;
int worker_id;
} swPackage_response;
int swServer_master_onAccept(swReactor *reactor, swEvent *event);
void swServer_master_onTimer(swTimer *timer, swTimer_node *tnode);
int swServer_master_send(swServer *serv, swSendData *_send);
int swServer_onFinish(swFactory *factory, swSendData *resp);
int swServer_onFinish2(swFactory *factory, swSendData *resp);
void swServer_init(swServer *serv);
void swServer_signal_init(swServer *serv);
int swServer_start(swServer *serv);
swListenPort* swServer_add_port(swServer *serv, int type, const char *host, int port);
void swServer_close_port(swServer *serv, enum swBool_type only_stream_port);
int swServer_add_worker(swServer *serv, swWorker *worker);
int swServer_add_systemd_socket(swServer *serv);
int swServer_add_hook(swServer *serv, enum swServer_hook_type type, swCallback func, int push_back);
void swServer_call_hook(swServer *serv, enum swServer_hook_type type, void *arg);
int swServer_create(swServer *serv);
int swServer_free(swServer *serv);
int swServer_shutdown(swServer *serv);
static sw_inline swString *swServer_get_buffer(swServer *serv, int fd)
{
swString *buffer = serv->connection_list[fd].recv_buffer;
if (buffer == NULL)
{
buffer = swString_new(SW_BUFFER_SIZE_STD);
//alloc memory failed.
if (!buffer)
{
return NULL;
}
serv->connection_list[fd].recv_buffer = buffer;
}
return buffer;
}
static sw_inline void swServer_free_buffer(swServer *serv, int fd)
{
swString *buffer = serv->connection_list[fd].recv_buffer;
if (buffer)
{
swString_free(buffer);
serv->connection_list[fd].recv_buffer = NULL;
}
}
static sw_inline swListenPort* swServer_get_port(swServer *serv, int fd)
{
sw_atomic_t server_fd = serv->connection_list[fd].from_fd;
return (swListenPort*) serv->connection_list[server_fd].object;
}
int swServer_udp_send(swServer *serv, swSendData *resp);
#define SW_MAX_SESSION_ID 0x1000000
static sw_inline int swEventData_is_dgram(uint8_t type)
{
switch (type)
{
case SW_EVENT_UDP:
case SW_EVENT_UDP6:
case SW_EVENT_UNIX_DGRAM:
return SW_TRUE;
default:
return SW_FALSE;
}
}
static sw_inline int swEventData_is_stream(uint8_t type)
{
switch (type)
{
case SW_EVENT_TCP:
case SW_EVENT_TCP6:
case SW_EVENT_UNIX_STREAM:
case SW_EVENT_CONNECT:
case SW_EVENT_CLOSE:
case SW_EVENT_PAUSE_RECV:
case SW_EVENT_RESUME_RECV:
case SW_EVENT_BUFFER_FULL:
case SW_EVENT_BUFFER_EMPTY:
return SW_TRUE;
default:
return SW_FALSE;
}
}
swPipe * swServer_get_pipe_object(swServer *serv, int pipe_fd);
void swServer_store_pipe_fd(swServer *serv, swPipe *p);
void swServer_store_listen_socket(swServer *serv);
int swServer_get_socket(swServer *serv, int port);
int swServer_worker_create(swServer *serv, swWorker *worker);
int swServer_worker_init(swServer *serv, swWorker *worker);
void swServer_worker_start(swServer *serv, swWorker *worker);
swString** swServer_create_worker_buffer(swServer *serv);
int swServer_create_task_worker(swServer *serv);
void swServer_enable_accept(swReactor *reactor);
void swServer_reopen_log_file(swServer *serv);
void swTaskWorker_init(swServer *serv);
int swTaskWorker_onTask(swProcessPool *pool, swEventData *task);
int swTaskWorker_onFinish(swReactor *reactor, swEvent *event);
void swTaskWorker_onStart(swProcessPool *pool, int worker_id);
void swTaskWorker_onStop(swProcessPool *pool, int worker_id);
int swTaskWorker_large_pack(swEventData *task, void *data, int data_len);
int swTaskWorker_finish(swServer *serv, char *data, int data_len, int flags, swEventData *current_task);
#define swTask_type(task) ((task)->info.from_fd)
static sw_inline swString* swTaskWorker_large_unpack(swEventData *task_result)
{
swPackage_task _pkg;
memcpy(&_pkg, task_result->data, sizeof(_pkg));
int tmp_file_fd = open(_pkg.tmpfile, O_RDONLY);
if (tmp_file_fd < 0)
{
swSysWarn("open(%s) failed", _pkg.tmpfile);
return NULL;
}
if (SwooleTG.buffer_stack->size < _pkg.length && swString_extend_align(SwooleTG.buffer_stack, _pkg.length) < 0)
{
close(tmp_file_fd);
return NULL;
}
if (swoole_sync_readfile(tmp_file_fd, SwooleTG.buffer_stack->str, _pkg.length) != _pkg.length)
{
close(tmp_file_fd);
return NULL;
}
close(tmp_file_fd);
if (!(swTask_type(task_result) & SW_TASK_PEEK))
{
unlink(_pkg.tmpfile);
}
SwooleTG.buffer_stack->length = _pkg.length;
return SwooleTG.buffer_stack;
}
#define swPackage_data(task) ((task->info.type==SW_EVENT_PACKAGE_END)?SwooleWG.buffer_input[task->info.from_id]->str:task->data)
#define swPackage_length(task) ((task->info.type==SW_EVENT_PACKAGE_END)?SwooleWG.buffer_input[task->info.from_id]->length:task->info.len)
#define SW_SERVER_MAX_FD_INDEX 0 //max connection socket
#define SW_SERVER_MIN_FD_INDEX 1 //min listen socket
#define SW_SERVER_TIMER_FD_INDEX 2 //for timerfd
// connection_list[0] => the largest fd
#define swServer_set_maxfd(serv,maxfd) (serv->connection_list[SW_SERVER_MAX_FD_INDEX].fd=maxfd)
#define swServer_get_maxfd(serv) (serv->connection_list[SW_SERVER_MAX_FD_INDEX].fd)
// connection_list[1] => the smallest fd
#define swServer_set_minfd(serv,maxfd) (serv->connection_list[SW_SERVER_MIN_FD_INDEX].fd=maxfd)
#define swServer_get_minfd(serv) (serv->connection_list[SW_SERVER_MIN_FD_INDEX].fd)
#define swServer_get_thread(serv, reactor_id) (&(serv->reactor_threads[reactor_id]))
static sw_inline swConnection* swServer_connection_get(swServer *serv, int fd)
{
if (fd <= 2 || (uint32_t) fd > serv->max_connection)
{
return NULL;
}
else
{
return &serv->connection_list[fd];
}
}
static sw_inline swSession* swServer_get_session(swServer *serv, uint32_t session_id)
{
return &serv->session_list[session_id % SW_SESSION_LIST_SIZE];
}
static sw_inline int swServer_get_fd(swServer *serv, uint32_t session_id)
{
return serv->session_list[session_id % SW_SESSION_LIST_SIZE].fd;
}
static sw_inline swWorker* swServer_get_worker(swServer *serv, uint16_t worker_id)
{
//Event Worker
if (worker_id < serv->worker_num)
{
return &(serv->gs->event_workers.workers[worker_id]);
}
//Task Worker
uint16_t task_worker_max = serv->task_worker_num + serv->worker_num;
if (worker_id < task_worker_max)
{
return &(serv->gs->task_workers.workers[worker_id - serv->worker_num]);
}
//User Worker
uint16_t user_worker_max = task_worker_max + serv->user_worker_num;
if (worker_id < user_worker_max)
{
return &(serv->user_workers[worker_id - task_worker_max]);
}
return NULL;
}
static sw_inline int swServer_worker_schedule(swServer *serv, int fd, swSendData *data)
{
uint32_t key;
if (serv->dispatch_func)
{
int id = serv->dispatch_func(serv, swServer_connection_get(serv, fd), data);
if (id != SW_DISPATCH_RESULT_USERFUNC_FALLBACK)
{
return id;
}
}
//polling mode
if (serv->dispatch_mode == SW_DISPATCH_ROUND)
{
key = sw_atomic_fetch_add(&serv->worker_round_id, 1);
}
//Using the FD touch access to hash
else if (serv->dispatch_mode == SW_DISPATCH_FDMOD)
{
key = fd;
}
//Using the IP touch access to hash
else if (serv->dispatch_mode == SW_DISPATCH_IPMOD)
{
swConnection *conn = swServer_connection_get(serv, fd);
//UDP
if (conn == NULL)
{
key = fd;
}
//IPv4
else if (conn->socket_type == SW_SOCK_TCP)
{
key = conn->info.addr.inet_v4.sin_addr.s_addr;
}
//IPv6
else
{
#ifdef HAVE_KQUEUE
key = *(((uint32_t *) &conn->info.addr.inet_v6.sin6_addr) + 3);
#elif defined(_WIN32)
key = conn->info.addr.inet_v6.sin6_addr.u.Word[3];
#else
key = conn->info.addr.inet_v6.sin6_addr.s6_addr32[3];
#endif
}
}
else if (serv->dispatch_mode == SW_DISPATCH_UIDMOD)
{
swConnection *conn = swServer_connection_get(serv, fd);
if (conn == NULL || conn->uid == 0)
{
key = fd;
}
else
{
key = conn->uid;
}
}
//Preemptive distribution
else
{
int i;
int found = 0;
for (i = 0; i < serv->worker_num + 1; i++)
{
key = sw_atomic_fetch_add(&serv->worker_round_id, 1) % serv->worker_num;
if (serv->workers[key].status == SW_WORKER_IDLE)
{
found = 1;
break;
}
}
if (unlikely(found == 0))
{
serv->scheduler_warning = 1;
}
swTraceLog(SW_TRACE_SERVER, "schedule=%d, round=%d", key, serv->worker_round_id);
return key;
}
return key % serv->worker_num;
}
void swServer_worker_onStart(swServer *serv);
void swServer_worker_onStop(swServer *serv);
int swWorker_onTask(swFactory *factory, swEventData *task);
void swWorker_stop(swWorker *worker);
static sw_inline swConnection *swWorker_get_connection(swServer *serv, int session_id)
{
int real_fd = swServer_get_fd(serv, session_id);
swConnection *conn = swServer_connection_get(serv, real_fd);
return conn;
}
static sw_inline swString *swWorker_get_buffer(swServer *serv, int reactor_id)
{
if (serv->factory_mode == SW_MODE_BASE)
{
return SwooleWG.buffer_input[0];
}
else
{
return SwooleWG.buffer_input[reactor_id];
}
}
static sw_inline size_t swWorker_get_data(swEventData *req, char **data_ptr)
{
size_t length;
if (req->info.flags & SW_EVENT_DATA_PTR)
{
swPackagePtr *task = (swPackagePtr *) req;
*data_ptr = task->data.str;
length = task->data.length;
}
else if (req->info.flags & SW_EVENT_DATA_END)
{
swString *worker_buffer = swWorker_get_buffer(SwooleG.serv, req->info.from_id);
*data_ptr = worker_buffer->str;
length = worker_buffer->length;
}
else
{
*data_ptr = req->data;
length = req->info.len;
}
return length;
}
static sw_inline swConnection *swServer_connection_verify_no_ssl(swServer *serv, uint32_t session_id)
{
swSession *session = swServer_get_session(serv, session_id);
int fd = session->fd;
swConnection *conn = swServer_connection_get(serv, fd);
if (!conn || conn->active == 0)
{
return NULL;
}
if (session->id != session_id || conn->session_id != session_id)
{
return NULL;
}
return conn;
}
static sw_inline swConnection *swServer_connection_verify(swServer *serv, int session_id)
{
swConnection *conn = swServer_connection_verify_no_ssl(serv, session_id);
#ifdef SW_USE_OPENSSL
if (!conn)
{
return NULL;
}
if (conn->ssl && conn->ssl_state != SW_SSL_STATE_READY)
{
swoole_error_log(SW_LOG_NOTICE, SW_ERROR_SSL_NOT_READY, "SSL not ready");
return NULL;
}
#endif
return conn;
}
void swPort_init(swListenPort *port);
void swPort_free(swListenPort *port);
void swPort_set_protocol(swListenPort *ls);
int swPort_listen(swListenPort *ls);
#ifdef SW_USE_OPENSSL
int swPort_enable_ssl_encrypt(swListenPort *ls);
#endif
void swPort_clear_protocol(swListenPort *ls);
void swWorker_free(swWorker *worker);
void swWorker_onStart(swServer *serv);
void swWorker_onStop(swServer *serv);
void swWorker_try_to_exit();
int swWorker_loop(swServer *serv, int worker_pti);
int swWorker_send2reactor(swServer *serv, swEventData *ev_data, size_t sendn, int fd);
int swWorker_send2worker(swWorker *dst_worker, void *buf, int n, int flag);
void swWorker_signal_handler(int signo);
void swWorker_signal_init(void);
void swWorker_clean(void);
/**
* reactor_id: The fd in which the reactor.
*/
static sw_inline int swWorker_get_send_pipe(swServer *serv, int session_id, int reactor_id)
{
int pipe_index = session_id % serv->reactor_pipe_num;
/**
* pipe_worker_id: The pipe in which worker.
*/
int pipe_worker_id = reactor_id + (pipe_index * serv->reactor_num);
swWorker *worker = swServer_get_worker(serv, pipe_worker_id);
return worker->pipe_worker;
}
int swReactorThread_create(swServer *serv);
int swReactorThread_start(swServer *serv);
void swReactorThread_set_protocol(swServer *serv, swReactor *reactor);
void swReactorThread_free(swServer *serv);
int swReactorThread_close(swReactor *reactor, int fd);
int swReactorThread_dispatch(swConnection *conn, char *data, uint32_t length);
int swReactorThread_send2worker(swServer *serv, swWorker *worker, void *data, int len);
int swReactorProcess_create(swServer *serv);
int swReactorProcess_start(swServer *serv);
int swManager_start(swServer *serv);
pid_t swManager_spawn_user_worker(swServer *serv, swWorker* worker);
pid_t swManager_spawn_task_worker(swServer *serv, swWorker* worker);
int swManager_wait_other_worker(swProcessPool *pool, pid_t pid, int status);
void swManager_kill_user_worker(swServer *serv);
#ifdef __cplusplus
}
#endif
#endif /* SW_SERVER_H_ */
Zerion Mini Shell 1.0