You've already forked qlg.tsgz.moe
Init Repo
This commit is contained in:
249
vendor/swoole/src/core/Channel.c
vendored
Executable file
249
vendor/swoole/src/core/Channel.c
vendored
Executable file
@ -0,0 +1,249 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| 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 SW_CHANNEL_MIN_MEM (1024*64)
|
||||
|
||||
typedef struct _swChannel_item
|
||||
{
|
||||
int length;
|
||||
char data[0];
|
||||
} swChannel_item;
|
||||
|
||||
swChannel* swChannel_new(size_t size, int maxlen, int flags)
|
||||
{
|
||||
assert(size >= maxlen);
|
||||
int ret;
|
||||
void *mem;
|
||||
|
||||
//use shared memory
|
||||
if (flags & SW_CHAN_SHM)
|
||||
{
|
||||
mem = sw_shm_malloc(size + sizeof(swChannel));
|
||||
}
|
||||
else
|
||||
{
|
||||
mem = sw_malloc(size + sizeof(swChannel));
|
||||
}
|
||||
|
||||
if (mem == NULL)
|
||||
{
|
||||
swWarn("swChannel_create: malloc(%ld) failed.", size);
|
||||
return NULL;
|
||||
}
|
||||
swChannel *object = mem;
|
||||
mem += sizeof(swChannel);
|
||||
|
||||
bzero(object, sizeof(swChannel));
|
||||
|
||||
//overflow space
|
||||
object->size = size;
|
||||
object->mem = mem;
|
||||
object->maxlen = maxlen;
|
||||
object->flag = flags;
|
||||
|
||||
//use lock
|
||||
if (flags & SW_CHAN_LOCK)
|
||||
{
|
||||
//init lock
|
||||
if (swMutex_create(&object->lock, 1) < 0)
|
||||
{
|
||||
swWarn("mutex init failed.");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
//use notify
|
||||
if (flags & SW_CHAN_NOTIFY)
|
||||
{
|
||||
ret = swPipeNotify_auto(&object->notify_fd, 1, 1);
|
||||
if (ret < 0)
|
||||
{
|
||||
swWarn("notify_fd init failed.");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return object;
|
||||
}
|
||||
|
||||
/**
|
||||
* push data(no lock)
|
||||
*/
|
||||
int swChannel_in(swChannel *object, void *in, int data_length)
|
||||
{
|
||||
assert(data_length <= object->maxlen);
|
||||
if (swChannel_full(object))
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
swChannel_item *item;
|
||||
int msize = sizeof(item->length) + data_length;
|
||||
|
||||
if (object->tail < object->head)
|
||||
{
|
||||
//no enough memory space
|
||||
if ((object->head - object->tail) < msize)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
item = object->mem + object->tail;
|
||||
object->tail += msize;
|
||||
}
|
||||
else
|
||||
{
|
||||
item = object->mem + object->tail;
|
||||
object->tail += msize;
|
||||
if (object->tail >= object->size)
|
||||
{
|
||||
object->tail = 0;
|
||||
object->tail_tag = 1 - object->tail_tag;
|
||||
}
|
||||
}
|
||||
object->num++;
|
||||
object->bytes += data_length;
|
||||
item->length = data_length;
|
||||
memcpy(item->data, in, data_length);
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* pop data(no lock)
|
||||
*/
|
||||
int swChannel_out(swChannel *object, void *out, int buffer_length)
|
||||
{
|
||||
if (swChannel_empty(object))
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
|
||||
swChannel_item *item = object->mem + object->head;
|
||||
assert(buffer_length >= item->length);
|
||||
memcpy(out, item->data, item->length);
|
||||
object->head += (item->length + sizeof(item->length));
|
||||
if (object->head >= object->size)
|
||||
{
|
||||
object->head = 0;
|
||||
object->head_tag = 1 - object->head_tag;
|
||||
}
|
||||
object->num--;
|
||||
object->bytes -= item->length;
|
||||
return item->length;
|
||||
}
|
||||
|
||||
/**
|
||||
* peek data
|
||||
*/
|
||||
int swChannel_peek(swChannel *object, void *out, int buffer_length)
|
||||
{
|
||||
if (swChannel_empty(object))
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
|
||||
int length;
|
||||
object->lock.lock(&object->lock);
|
||||
swChannel_item *item = object->mem + object->head;
|
||||
assert(buffer_length >= item->length);
|
||||
memcpy(out, item->data, item->length);
|
||||
length = item->length;
|
||||
object->lock.unlock(&object->lock);
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
/**
|
||||
* wait notify
|
||||
*/
|
||||
int swChannel_wait(swChannel *object)
|
||||
{
|
||||
assert(object->flag & SW_CHAN_NOTIFY);
|
||||
uint64_t flag;
|
||||
return object->notify_fd.read(&object->notify_fd, &flag, sizeof(flag));
|
||||
}
|
||||
|
||||
/**
|
||||
* new data coming, notify to customer
|
||||
*/
|
||||
int swChannel_notify(swChannel *object)
|
||||
{
|
||||
assert(object->flag & SW_CHAN_NOTIFY);
|
||||
uint64_t flag = 1;
|
||||
return object->notify_fd.write(&object->notify_fd, &flag, sizeof(flag));
|
||||
}
|
||||
|
||||
/**
|
||||
* push data (lock)
|
||||
*/
|
||||
int swChannel_push(swChannel *object, void *in, int data_length)
|
||||
{
|
||||
assert(object->flag & SW_CHAN_LOCK);
|
||||
object->lock.lock(&object->lock);
|
||||
int ret = swChannel_in(object, in, data_length);
|
||||
object->lock.unlock(&object->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* free channel
|
||||
*/
|
||||
void swChannel_free(swChannel *object)
|
||||
{
|
||||
if (object->flag & SW_CHAN_LOCK)
|
||||
{
|
||||
object->lock.free(&object->lock);
|
||||
}
|
||||
if (object->flag & SW_CHAN_NOTIFY)
|
||||
{
|
||||
object->notify_fd.close(&object->notify_fd);
|
||||
}
|
||||
if (object->flag & SW_CHAN_SHM)
|
||||
{
|
||||
sw_shm_free(object);
|
||||
}
|
||||
else
|
||||
{
|
||||
sw_free(object);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* pop data (lock)
|
||||
*/
|
||||
int swChannel_pop(swChannel *object, void *out, int buffer_length)
|
||||
{
|
||||
assert(object->flag & SW_CHAN_LOCK);
|
||||
object->lock.lock(&object->lock);
|
||||
int n = swChannel_out(object, out, buffer_length);
|
||||
object->lock.unlock(&object->lock);
|
||||
return n;
|
||||
}
|
||||
|
||||
void swChannel_print(swChannel *chan)
|
||||
{
|
||||
printf("swChannel\n{\n"
|
||||
" off_t head = %ld;\n"
|
||||
" off_t tail = %ld;\n"
|
||||
" size_t size = %ld;\n"
|
||||
" char head_tag = %d;\n"
|
||||
" char tail_tag = %d;\n"
|
||||
" int num = %d;\n"
|
||||
" size_t bytes = %ld;\n"
|
||||
" int flag = %d;\n"
|
||||
" int maxlen = %d;\n"
|
||||
"\n}\n", (long)chan->head, (long)chan->tail, chan->size, chan->tail_tag, chan->head_tag, chan->num, chan->bytes,
|
||||
chan->flag, chan->maxlen);
|
||||
}
|
||||
|
151
vendor/swoole/src/core/RingQueue.c
vendored
Executable file
151
vendor/swoole/src/core/RingQueue.c
vendored
Executable file
@ -0,0 +1,151 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| 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 <stdio.h>
|
||||
#include "swoole.h"
|
||||
#include "RingQueue.h"
|
||||
|
||||
#ifdef SW_USE_RINGQUEUE_TS
|
||||
|
||||
int swRingQueue_init(swRingQueue *queue, int buffer_size)
|
||||
{
|
||||
queue->size = buffer_size;
|
||||
queue->flags = (char *)sw_malloc(queue->size);
|
||||
if (queue->flags == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
queue->data = (void **)sw_calloc(queue->size, sizeof(void*));
|
||||
if (queue->data == NULL)
|
||||
{
|
||||
sw_free(queue->flags);
|
||||
return -1;
|
||||
}
|
||||
queue->head = 0;
|
||||
queue->tail = 0;
|
||||
memset(queue->flags, 0, queue->size);
|
||||
memset(queue->data, 0, queue->size * sizeof(void*));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int swRingQueue_push(swRingQueue *queue, void * ele)
|
||||
{
|
||||
if (!(queue->num < queue->size))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
int cur_tail_index = queue->tail;
|
||||
char * cur_tail_flag_index = queue->flags + cur_tail_index;
|
||||
//TODO Scheld
|
||||
while (!sw_atomic_cmp_set(cur_tail_flag_index, 0, 1))
|
||||
{
|
||||
cur_tail_index = queue->tail;
|
||||
cur_tail_flag_index = queue->flags + cur_tail_index;
|
||||
}
|
||||
|
||||
// 两个入队线程之间的同步
|
||||
//TODO 取模操作可以优化
|
||||
int update_tail_index = (cur_tail_index + 1) % queue->size;
|
||||
|
||||
// 如果已经被其他的线程更新过,则不需要更新;
|
||||
// 否则,更新为 (cur_tail_index+1) % size;
|
||||
sw_atomic_cmp_set(&queue->tail, cur_tail_index, update_tail_index);
|
||||
|
||||
// 申请到可用的存储空间
|
||||
*(queue->data + cur_tail_index) = ele;
|
||||
|
||||
sw_atomic_fetch_add(cur_tail_flag_index, 1);
|
||||
sw_atomic_fetch_add(&queue->num, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int swRingQueue_pop(swRingQueue *queue, void **ele)
|
||||
{
|
||||
if (!(queue->num > 0))
|
||||
return -1;
|
||||
int cur_head_index = queue->head;
|
||||
char * cur_head_flag_index = queue->flags + cur_head_index;
|
||||
|
||||
while (!sw_atomic_cmp_set(cur_head_flag_index, 2, 3))
|
||||
{
|
||||
cur_head_index = queue->head;
|
||||
cur_head_flag_index = queue->flags + cur_head_index;
|
||||
}
|
||||
//TODO 取模操作可以优化
|
||||
int update_head_index = (cur_head_index + 1) % queue->size;
|
||||
sw_atomic_cmp_set(&queue->head, cur_head_index, update_head_index);
|
||||
*ele = *(queue->data + cur_head_index);
|
||||
|
||||
sw_atomic_fetch_sub(cur_head_flag_index, 3);
|
||||
sw_atomic_fetch_sub(&queue->num, 1);
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
|
||||
int swRingQueue_init(swRingQueue *queue, int buffer_size)
|
||||
{
|
||||
queue->data = sw_calloc(buffer_size, sizeof(void*));
|
||||
if (queue->data == NULL)
|
||||
{
|
||||
swWarn("malloc failed.");
|
||||
return -1;
|
||||
}
|
||||
queue->size = buffer_size;
|
||||
queue->head = 0;
|
||||
queue->tail = 0;
|
||||
queue->tag = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void swRingQueue_free(swRingQueue *queue)
|
||||
{
|
||||
sw_free(queue->data);
|
||||
}
|
||||
|
||||
int swRingQueue_push(swRingQueue *queue, void *push_data)
|
||||
{
|
||||
if (swRingQueue_full(queue))
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
|
||||
queue->data[queue->tail] = push_data;
|
||||
queue->tail = (queue->tail + 1) % queue->size;
|
||||
|
||||
if (queue->tail == queue->head)
|
||||
{
|
||||
queue->tag = 1;
|
||||
}
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
int swRingQueue_pop(swRingQueue *queue, void **pop_data)
|
||||
{
|
||||
if (swRingQueue_empty(queue))
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
|
||||
*pop_data = queue->data[queue->head];
|
||||
queue->head = (queue->head + 1) % queue->size;
|
||||
|
||||
if (queue->tail == queue->head)
|
||||
{
|
||||
queue->tag = 0;
|
||||
}
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
#endif
|
92
vendor/swoole/src/core/UnitTest.c
vendored
Executable file
92
vendor/swoole/src/core/UnitTest.c
vendored
Executable file
@ -0,0 +1,92 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| 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 "tests.h"
|
||||
#include "uthash.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
swUnitTest_Func func;
|
||||
char *comment;
|
||||
int run_times;
|
||||
char *key;
|
||||
} swHashTable_unitTest;
|
||||
|
||||
static swHashMap *utmap = NULL;
|
||||
|
||||
void _swUnitTest_setup(swUnitTest_Func func, char *func_name, int run_times, char *comment)
|
||||
{
|
||||
if (!utmap)
|
||||
{
|
||||
utmap = swHashMap_new(32, free);
|
||||
}
|
||||
swHashTable_unitTest *u;
|
||||
u = (swHashTable_unitTest *) malloc(sizeof(swHashTable_unitTest));
|
||||
u->key = func_name;
|
||||
u->func = func;
|
||||
u->run_times = run_times;
|
||||
u->comment = comment;
|
||||
swHashMap_add(utmap, func_name, strlen(func_name), u);
|
||||
}
|
||||
|
||||
int swUnitTest_run(swUnitTest *object)
|
||||
{
|
||||
int max_len = 128;
|
||||
int argc = object->argc;
|
||||
char **argv = object->argv;
|
||||
int ret;
|
||||
char *key;
|
||||
|
||||
swUnitTest_Func func;
|
||||
swHashTable_unitTest *tmp;
|
||||
|
||||
int i = 0;
|
||||
|
||||
if (argc < 2)
|
||||
{
|
||||
printf("Please enter %s unitTest_name\n", argv[0]);
|
||||
|
||||
while (1)
|
||||
{
|
||||
tmp = swHashMap_each(utmap, &key);
|
||||
if (!tmp)
|
||||
break;
|
||||
printf("#%d.\t%s: %s\n", ++i, tmp->key, tmp->comment);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
tmp = swHashMap_each(utmap, &key);
|
||||
if (strncmp(argv[1], key, max_len) == 0)
|
||||
{
|
||||
func = tmp->func;
|
||||
printf("running\n");
|
||||
ret = func(object);
|
||||
break;
|
||||
}
|
||||
} while (tmp);
|
||||
|
||||
printf("finish\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
void p_str(void *str)
|
||||
{
|
||||
printf("Str: %s|len=%ld\n", (char *) str, strlen((char *) str));
|
||||
}
|
149
vendor/swoole/src/core/array.c
vendored
Executable file
149
vendor/swoole/src/core/array.c
vendored
Executable file
@ -0,0 +1,149 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| 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 "array.h"
|
||||
|
||||
/**
|
||||
* Create new array
|
||||
*/
|
||||
swArray *swArray_new(int page_size, size_t item_size)
|
||||
{
|
||||
swArray *array = sw_malloc(sizeof(swArray));
|
||||
if (array == NULL)
|
||||
{
|
||||
swoole_error_log(SW_LOG_ERROR, SW_ERROR_MALLOC_FAIL, "malloc[0] failed.");
|
||||
return NULL;
|
||||
}
|
||||
bzero(array, sizeof(swArray));
|
||||
|
||||
array->pages = sw_malloc(sizeof(void*) * SW_ARRAY_PAGE_MAX);
|
||||
if (array->pages == NULL)
|
||||
{
|
||||
sw_free(array);
|
||||
swoole_error_log(SW_LOG_ERROR, SW_ERROR_MALLOC_FAIL, "malloc[1] failed.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
array->item_size = item_size;
|
||||
array->page_size = page_size;
|
||||
|
||||
swArray_extend(array);
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destory the array
|
||||
*/
|
||||
void swArray_free(swArray *array)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < array->page_num; i++)
|
||||
{
|
||||
sw_free(array->pages[i]);
|
||||
}
|
||||
sw_free(array->pages);
|
||||
sw_free(array);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extend the memory pages of the array
|
||||
*/
|
||||
int swArray_extend(swArray *array)
|
||||
{
|
||||
if (array->page_num == SW_ARRAY_PAGE_MAX)
|
||||
{
|
||||
swWarn("max page_num is %d", array->page_num);
|
||||
return SW_ERR;
|
||||
}
|
||||
array->pages[array->page_num] = sw_calloc(array->page_size, array->item_size);
|
||||
if (array->pages[array->page_num] == NULL)
|
||||
{
|
||||
swWarn("malloc[1] failed.");
|
||||
return SW_ERR;
|
||||
}
|
||||
array->page_num++;
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch data by index of the array
|
||||
*/
|
||||
void *swArray_fetch(swArray *array, uint32_t n)
|
||||
{
|
||||
int page = swArray_page(array, n);
|
||||
if (page >= array->page_num)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
return array->pages[page] + (swArray_offset(array, n) * array->item_size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Append to the array
|
||||
*/
|
||||
int swArray_append(swArray *array, void *data)
|
||||
{
|
||||
int n = array->offset++;
|
||||
int page = swArray_page(array, n);
|
||||
|
||||
if (page >= array->page_num && swArray_extend(array) < 0)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
array->item_num++;
|
||||
memcpy(array->pages[page] + (swArray_offset(array, n) * array->item_size), data, array->item_size);
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
int swArray_store(swArray *array, uint32_t n, void *data)
|
||||
{
|
||||
int page = swArray_page(array, n);
|
||||
if (page >= array->page_num)
|
||||
{
|
||||
swWarn("fetch index[%d] out of array", n);
|
||||
return SW_ERR;
|
||||
}
|
||||
memcpy(array->pages[page] + (swArray_offset(array, n) * array->item_size), data, array->item_size);
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
void *swArray_alloc(swArray *array, uint32_t n)
|
||||
{
|
||||
while (n >= array->page_num * array->page_size)
|
||||
{
|
||||
if (swArray_extend(array) < 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int page = swArray_page(array, n);
|
||||
if (page >= array->page_num)
|
||||
{
|
||||
swWarn("fetch index[%d] out of array", n);
|
||||
return NULL;
|
||||
}
|
||||
return array->pages[page] + (swArray_offset(array, n) * array->item_size);
|
||||
}
|
||||
|
||||
void swArray_clear(swArray *array)
|
||||
{
|
||||
array->offset = 0;
|
||||
array->item_num = 0;
|
||||
}
|
1255
vendor/swoole/src/core/base.c
vendored
Executable file
1255
vendor/swoole/src/core/base.c
vendored
Executable file
File diff suppressed because it is too large
Load Diff
40
vendor/swoole/src/core/error.cc
vendored
Executable file
40
vendor/swoole/src/core/error.cc
vendored
Executable file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| 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 <string>
|
||||
|
||||
namespace swoole
|
||||
{
|
||||
|
||||
class Exception
|
||||
{
|
||||
public:
|
||||
int code;
|
||||
|
||||
Exception(enum swErrorCode _code)
|
||||
{
|
||||
code = _code;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
;
|
||||
|
||||
void swoole_throw_error(enum swErrorCode code)
|
||||
{
|
||||
throw swoole::Exception(code);
|
||||
}
|
515
vendor/swoole/src/core/hashmap.c
vendored
Executable file
515
vendor/swoole/src/core/hashmap.c
vendored
Executable file
@ -0,0 +1,515 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| 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 "uthash.h"
|
||||
#include "hash.h"
|
||||
|
||||
typedef struct swHashMap_node
|
||||
{
|
||||
uint64_t key_int;
|
||||
char *key_str;
|
||||
void *data;
|
||||
UT_hash_handle hh;
|
||||
} swHashMap_node;
|
||||
|
||||
static int swHashMap_node_delete(swHashMap_node *root, swHashMap_node *del_node);
|
||||
|
||||
static sw_inline void swHashMap_node_dtor(swHashMap *hmap, swHashMap_node *node)
|
||||
{
|
||||
if (hmap->dtor)
|
||||
{
|
||||
hmap->dtor(node->data);
|
||||
}
|
||||
}
|
||||
|
||||
static sw_inline void swHashMap_node_free(swHashMap *hmap, swHashMap_node *node)
|
||||
{
|
||||
swHashMap_node_dtor(hmap, node);
|
||||
sw_free(node->key_str);
|
||||
sw_free(node);
|
||||
}
|
||||
|
||||
static sw_inline int swHashMap_node_add(swHashMap_node *root, swHashMap_node *add)
|
||||
{
|
||||
unsigned _ha_bkt;
|
||||
add->hh.next = NULL;
|
||||
add->hh.key = add->key_str;
|
||||
add->hh.keylen = add->key_int;
|
||||
|
||||
root->hh.tbl->tail->next = add;
|
||||
add->hh.prev = ELMT_FROM_HH(root->hh.tbl, root->hh.tbl->tail);
|
||||
root->hh.tbl->tail = &(add->hh);
|
||||
|
||||
root->hh.tbl->num_items++;
|
||||
add->hh.tbl = root->hh.tbl;
|
||||
add->hh.hashv = swoole_hash_jenkins(add->key_str, add->key_int);
|
||||
_ha_bkt = add->hh.hashv & (root->hh.tbl->num_buckets - 1);
|
||||
|
||||
HASH_ADD_TO_BKT(root->hh.tbl->buckets[_ha_bkt], &add->hh);
|
||||
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
static sw_inline swHashMap_node* swHashMap_node_each(swHashMap* hmap)
|
||||
{
|
||||
swHashMap_node *iterator = hmap->iterator;
|
||||
swHashMap_node *tmp;
|
||||
|
||||
if (hmap->root->hh.tbl->num_items == 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
if (iterator == NULL)
|
||||
{
|
||||
iterator = hmap->root;
|
||||
}
|
||||
tmp = iterator->hh.next;
|
||||
if (tmp)
|
||||
{
|
||||
hmap->iterator = tmp;
|
||||
return tmp;
|
||||
}
|
||||
else
|
||||
{
|
||||
hmap->iterator = NULL;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
swHashMap* swHashMap_new(uint32_t bucket_num, swHashMap_dtor dtor)
|
||||
{
|
||||
swHashMap *hmap = sw_malloc(sizeof(swHashMap));
|
||||
if (!hmap)
|
||||
{
|
||||
swWarn("malloc[1] failed.");
|
||||
return NULL;
|
||||
}
|
||||
swHashMap_node *root = sw_malloc(sizeof(swHashMap_node));
|
||||
if (!root)
|
||||
{
|
||||
swWarn("malloc[2] failed.");
|
||||
sw_free(hmap);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bzero(hmap, sizeof(swHashMap));
|
||||
hmap->root = root;
|
||||
|
||||
bzero(root, sizeof(swHashMap_node));
|
||||
|
||||
root->hh.tbl = (UT_hash_table*) sw_malloc(sizeof(UT_hash_table));
|
||||
if (!(root->hh.tbl))
|
||||
{
|
||||
swWarn("malloc for table failed.");
|
||||
sw_free(hmap);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(root->hh.tbl, 0, sizeof(UT_hash_table));
|
||||
root->hh.tbl->tail = &(root->hh);
|
||||
root->hh.tbl->num_buckets = SW_HASHMAP_INIT_BUCKET_N;
|
||||
root->hh.tbl->log2_num_buckets = HASH_INITIAL_NUM_BUCKETS_LOG2;
|
||||
root->hh.tbl->hho = (char*) (&root->hh) - (char*) root;
|
||||
root->hh.tbl->buckets = (UT_hash_bucket*) sw_malloc(SW_HASHMAP_INIT_BUCKET_N * sizeof(struct UT_hash_bucket));
|
||||
if (!root->hh.tbl->buckets)
|
||||
{
|
||||
swWarn("malloc for buckets failed.");
|
||||
sw_free(hmap);
|
||||
return NULL;
|
||||
}
|
||||
memset(root->hh.tbl->buckets, 0, SW_HASHMAP_INIT_BUCKET_N * sizeof(struct UT_hash_bucket));
|
||||
root->hh.tbl->signature = HASH_SIGNATURE;
|
||||
|
||||
hmap->dtor = dtor;
|
||||
|
||||
return hmap;
|
||||
}
|
||||
|
||||
int swHashMap_add(swHashMap* hmap, char *key, uint16_t key_len, void *data)
|
||||
{
|
||||
swHashMap_node *node = (swHashMap_node*) sw_malloc(sizeof(swHashMap_node));
|
||||
if (node == NULL)
|
||||
{
|
||||
swWarn("malloc failed.");
|
||||
return SW_ERR;
|
||||
}
|
||||
bzero(node, sizeof(swHashMap_node));
|
||||
swHashMap_node *root = hmap->root;
|
||||
node->key_str = sw_strndup(key, key_len);
|
||||
node->key_int = key_len;
|
||||
node->data = data;
|
||||
return swHashMap_node_add(root, node);
|
||||
}
|
||||
|
||||
int swHashMap_add_int(swHashMap *hmap, uint64_t key, void *data)
|
||||
{
|
||||
swHashMap_node *node = (swHashMap_node*) sw_malloc(sizeof(swHashMap_node));
|
||||
swHashMap_node *root = hmap->root;
|
||||
if (node == NULL)
|
||||
{
|
||||
swWarn("malloc failed");
|
||||
return SW_ERR;
|
||||
}
|
||||
node->key_int = key;
|
||||
node->data = data;
|
||||
node->key_str = NULL;
|
||||
HASH_ADD_INT(root, key_int, node);
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
static sw_inline swHashMap_node *swHashMap_node_find(swHashMap_node *root, char *key_str, uint16_t key_len)
|
||||
{
|
||||
swHashMap_node *out;
|
||||
unsigned bucket, hash;
|
||||
out = NULL;
|
||||
if (root)
|
||||
{
|
||||
hash = swoole_hash_jenkins(key_str, key_len);
|
||||
bucket = hash & (root->hh.tbl->num_buckets - 1);
|
||||
HASH_FIND_IN_BKT(root->hh.tbl, hh, (root)->hh.tbl->buckets[bucket], key_str, key_len, out);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
static int swHashMap_node_delete(swHashMap_node *root, swHashMap_node *del_node)
|
||||
{
|
||||
unsigned bucket;
|
||||
struct UT_hash_handle *_hd_hh_del;
|
||||
|
||||
if ((del_node->hh.prev == NULL) && (del_node->hh.next == NULL))
|
||||
{
|
||||
sw_free(root->hh.tbl->buckets);
|
||||
sw_free(root->hh.tbl);
|
||||
}
|
||||
else
|
||||
{
|
||||
_hd_hh_del = &(del_node->hh);
|
||||
if (del_node == ELMT_FROM_HH(root->hh.tbl, root->hh.tbl->tail))
|
||||
{
|
||||
root->hh.tbl->tail = (UT_hash_handle*) ((ptrdiff_t) (del_node->hh.prev) + root->hh.tbl->hho);
|
||||
}
|
||||
if (del_node->hh.prev)
|
||||
{
|
||||
((UT_hash_handle*) ((ptrdiff_t) (del_node->hh.prev) + root->hh.tbl->hho))->next = del_node->hh.next;
|
||||
}
|
||||
else
|
||||
{
|
||||
DECLTYPE_ASSIGN(root, del_node->hh.next);
|
||||
}
|
||||
if (_hd_hh_del->next)
|
||||
{
|
||||
((UT_hash_handle*) ((ptrdiff_t) _hd_hh_del->next + root->hh.tbl->hho))->prev = _hd_hh_del->prev;
|
||||
}
|
||||
HASH_TO_BKT(_hd_hh_del->hashv, root->hh.tbl->num_buckets, bucket);
|
||||
HASH_DEL_IN_BKT(hh, root->hh.tbl->buckets[bucket], _hd_hh_del);
|
||||
root->hh.tbl->num_items--;
|
||||
}
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
void* swHashMap_find(swHashMap* hmap, char *key, uint16_t key_len)
|
||||
{
|
||||
swHashMap_node *root = hmap->root;
|
||||
swHashMap_node *ret = swHashMap_node_find(root, key, key_len);
|
||||
if (ret == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
return ret->data;
|
||||
}
|
||||
|
||||
void* swHashMap_find_int(swHashMap* hmap, uint64_t key)
|
||||
{
|
||||
swHashMap_node *ret = NULL;
|
||||
swHashMap_node *root = hmap->root;
|
||||
HASH_FIND_INT(root, &key, ret);
|
||||
if (ret == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
return ret->data;
|
||||
}
|
||||
|
||||
int swHashMap_update(swHashMap* hmap, char *key, uint16_t key_len, void *data)
|
||||
{
|
||||
swHashMap_node *root = hmap->root;
|
||||
swHashMap_node *node = swHashMap_node_find(root, key, key_len);
|
||||
if (node == NULL)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
swHashMap_node_dtor(hmap, node);
|
||||
node->data = data;
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
void swHashMap_update_int(swHashMap* hmap, uint64_t key, void *data)
|
||||
{
|
||||
swHashMap_node *ret = NULL;
|
||||
swHashMap_node *root = hmap->root;
|
||||
HASH_FIND_INT(root, &key, ret);
|
||||
if (ret == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
swHashMap_node_dtor(hmap, ret);
|
||||
ret->data = data;
|
||||
}
|
||||
|
||||
int swHashMap_del(swHashMap* hmap, char *key, uint16_t key_len)
|
||||
{
|
||||
swHashMap_node *root = hmap->root;
|
||||
swHashMap_node *node = swHashMap_node_find(root, key, key_len);
|
||||
if (node == NULL)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
swHashMap_node_delete(root, node);
|
||||
swHashMap_node_free(hmap, node);
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
int swHashMap_del_int(swHashMap *hmap, uint64_t key)
|
||||
{
|
||||
swHashMap_node *ret = NULL;
|
||||
swHashMap_node *root = hmap->root;
|
||||
|
||||
HASH_FIND_INT(root, &key, ret);
|
||||
if (ret == NULL)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
HASH_DEL(root, ret);
|
||||
swHashMap_node_free(hmap, ret);
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
int swHashMap_move(swHashMap *hmap, char *old_key, uint16_t old_key_len, char *new_key, uint16_t new_key_len)
|
||||
{
|
||||
swHashMap_node *root = hmap->root;
|
||||
swHashMap_node *node = swHashMap_node_find(root, old_key, old_key_len);
|
||||
if (node == NULL)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
swHashMap_node_delete(root, node);
|
||||
sw_free(node->key_str);
|
||||
node->key_str = sw_strndup(new_key, new_key_len);
|
||||
node->key_int = new_key_len;
|
||||
return swHashMap_node_add(root, node);
|
||||
}
|
||||
|
||||
int swHashMap_move_int(swHashMap *hmap, uint64_t old_key, uint64_t new_key)
|
||||
{
|
||||
swHashMap_node *ret = NULL;
|
||||
swHashMap_node *root = hmap->root;
|
||||
|
||||
HASH_FIND_INT(root, &old_key, ret);
|
||||
if (ret == NULL)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
HASH_DEL(root, ret);
|
||||
|
||||
ret->key_int = new_key;
|
||||
HASH_ADD_INT(root, key_int, ret);
|
||||
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
void* swHashMap_each(swHashMap* hmap, char **key)
|
||||
{
|
||||
swHashMap_node *node = swHashMap_node_each(hmap);
|
||||
if (node)
|
||||
{
|
||||
*key = node->key_str;
|
||||
return node->data;
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void* swHashMap_each_int(swHashMap* hmap, uint64_t *key)
|
||||
{
|
||||
swHashMap_node *node = swHashMap_node_each(hmap);
|
||||
if (node)
|
||||
{
|
||||
*key = node->key_int;
|
||||
return node->data;
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t swHashMap_count(swHashMap* hmap)
|
||||
{
|
||||
if (hmap == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return HASH_COUNT(hmap->root);
|
||||
}
|
||||
|
||||
void swHashMap_free(swHashMap* hmap)
|
||||
{
|
||||
swHashMap_node *find, *tmp = NULL;
|
||||
swHashMap_node *root = hmap->root;
|
||||
HASH_ITER(hh, root, find, tmp)
|
||||
{
|
||||
if (find == root) continue;
|
||||
swHashMap_node_delete(root, find);
|
||||
swHashMap_node_free(hmap, find);
|
||||
}
|
||||
|
||||
sw_free(hmap->root->hh.tbl->buckets);
|
||||
sw_free(hmap->root->hh.tbl);
|
||||
sw_free(hmap->root);
|
||||
|
||||
sw_free(hmap);
|
||||
}
|
||||
|
||||
/* {{{ COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or
|
||||
* code or tables extracted from it, as desired without restriction.
|
||||
*
|
||||
* First, the polynomial itself and its table of feedback terms. The
|
||||
* polynomial is
|
||||
* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0
|
||||
*
|
||||
* Note that we take it "backwards" and put the highest-order term in
|
||||
* the lowest-order bit. The X^32 term is "implied"; the LSB is the
|
||||
* X^31 term, etc. The X^0 term (usually shown as "+1") results in
|
||||
* the MSB being 1
|
||||
*
|
||||
* Note that the usual hardware shift register implementation, which
|
||||
* is what we're using (we're merely optimizing it by doing eight-bit
|
||||
* chunks at a time) shifts bits into the lowest-order term. In our
|
||||
* implementation, that means shifting towards the right. Why do we
|
||||
* do it this way? Because the calculated CRC must be transmitted in
|
||||
* order from highest-order term to lowest-order term. UARTs transmit
|
||||
* characters in order from LSB to MSB. By storing the CRC this way
|
||||
* we hand it to the UART in the order low-byte to high-byte; the UART
|
||||
* sends each low-bit to hight-bit; and the result is transmission bit
|
||||
* by bit from highest- to lowest-order term without requiring any bit
|
||||
* shuffling on our part. Reception works similarly
|
||||
*
|
||||
* The feedback terms table consists of 256, 32-bit entries. Notes
|
||||
*
|
||||
* The table can be generated at runtime if desired; code to do so
|
||||
* is shown later. It might not be obvious, but the feedback
|
||||
* terms simply represent the results of eight shift/xor opera
|
||||
* tions for all combinations of data and CRC register values
|
||||
*
|
||||
* The values must be right-shifted by eight bits by the "updcrc
|
||||
* logic; the shift must be unsigned (bring in zeroes). On some
|
||||
* hardware you could probably optimize the shift in assembler by
|
||||
* using byte-swap instructions
|
||||
* polynomial $edb88320
|
||||
*
|
||||
*
|
||||
* CRC32 code derived from work by Gary S. Brown.
|
||||
*/
|
||||
|
||||
static unsigned int crc32_tab[] = {
|
||||
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
|
||||
0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
|
||||
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
|
||||
0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
|
||||
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
|
||||
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
|
||||
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
|
||||
0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
|
||||
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
|
||||
0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
|
||||
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
|
||||
0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
|
||||
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
|
||||
0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
|
||||
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
|
||||
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
|
||||
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
|
||||
0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
|
||||
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
|
||||
0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
|
||||
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
|
||||
0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
|
||||
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
|
||||
0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
|
||||
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
|
||||
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
|
||||
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
|
||||
0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
|
||||
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
|
||||
0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
|
||||
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
|
||||
0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
|
||||
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
|
||||
0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
|
||||
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
|
||||
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
|
||||
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
|
||||
0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
|
||||
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
|
||||
0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
|
||||
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
|
||||
0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
|
||||
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
|
||||
};
|
||||
|
||||
static inline uint32_t crc32(char *buf, unsigned int size)
|
||||
{
|
||||
const char *p;
|
||||
register int crc = 0;
|
||||
|
||||
p = buf;
|
||||
while (size--)
|
||||
{
|
||||
crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
|
||||
}
|
||||
|
||||
return crc ^ ~0U;
|
||||
}
|
||||
|
||||
uint32_t swoole_crc32(char *data, uint32_t size)
|
||||
{
|
||||
if (size < CRC_STRING_MAXLEN)
|
||||
{
|
||||
return crc32(data, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
int i = 0;
|
||||
char crc_contents[CRC_STRING_MAXLEN];
|
||||
int head = CRC_STRING_MAXLEN >> 2;
|
||||
int tail = CRC_STRING_MAXLEN >> 4;
|
||||
int body = CRC_STRING_MAXLEN - head - tail;
|
||||
char *p = data + head;
|
||||
char *q = crc_contents + head;
|
||||
int step = (size - tail - head) / body;
|
||||
|
||||
memcpy(crc_contents, data, head);
|
||||
for (; i < body; i++, q++, p += step)
|
||||
{
|
||||
*q = *p;
|
||||
}
|
||||
memcpy(q, p, tail);
|
||||
return crc32(crc_contents, CRC_STRING_MAXLEN);
|
||||
}
|
||||
}
|
219
vendor/swoole/src/core/heap.c
vendored
Executable file
219
vendor/swoole/src/core/heap.c
vendored
Executable file
@ -0,0 +1,219 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| 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 "heap.h"
|
||||
|
||||
#define left(i) ((i) << 1)
|
||||
#define right(i) (((i) << 1) + 1)
|
||||
#define parent(i) ((i) >> 1)
|
||||
|
||||
static void swHeap_bubble_up(swHeap *heap, uint32_t i);
|
||||
static uint32_t swHeap_maxchild(swHeap *heap, uint32_t i);
|
||||
static void swHeap_percolate_down(swHeap *heap, uint32_t i);
|
||||
|
||||
swHeap *swHeap_new(size_t n, uint8_t type)
|
||||
{
|
||||
swHeap *heap = sw_malloc(sizeof(swHeap));
|
||||
if (!heap)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
if (!(heap->nodes = sw_malloc((n + 1) * sizeof(void *))))
|
||||
{
|
||||
sw_free(heap);
|
||||
return NULL;
|
||||
}
|
||||
heap->num = 1;
|
||||
heap->size = (n + 1);
|
||||
heap->type = type;
|
||||
return heap;
|
||||
}
|
||||
|
||||
void swHeap_free(swHeap *heap)
|
||||
{
|
||||
sw_free(heap->nodes);
|
||||
sw_free(heap);
|
||||
}
|
||||
|
||||
static sw_inline int swHeap_compare(uint8_t type, uint64_t a, uint64_t b)
|
||||
{
|
||||
if (type == SW_MIN_HEAP)
|
||||
{
|
||||
return a > b;
|
||||
}
|
||||
else
|
||||
{
|
||||
return a < b;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t swHeap_size(swHeap *q)
|
||||
{
|
||||
return (q->num - 1);
|
||||
}
|
||||
|
||||
static uint32_t swHeap_maxchild(swHeap *heap, uint32_t i)
|
||||
{
|
||||
uint32_t child_i = left(i);
|
||||
if (child_i >= heap->num)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
swHeap_node * child_node = heap->nodes[child_i];
|
||||
if ((child_i + 1) < heap->num && swHeap_compare(heap->type, child_node->priority, heap->nodes[child_i + 1]->priority))
|
||||
{
|
||||
child_i++;
|
||||
}
|
||||
return child_i;
|
||||
}
|
||||
|
||||
static void swHeap_bubble_up(swHeap *heap, uint32_t i)
|
||||
{
|
||||
swHeap_node *moving_node = heap->nodes[i];
|
||||
uint32_t parent_i;
|
||||
|
||||
for (parent_i = parent(i);
|
||||
(i > 1) && swHeap_compare(heap->type, heap->nodes[parent_i]->priority, moving_node->priority);
|
||||
i = parent_i, parent_i = parent(i))
|
||||
{
|
||||
heap->nodes[i] = heap->nodes[parent_i];
|
||||
heap->nodes[i]->position = i;
|
||||
}
|
||||
|
||||
heap->nodes[i] = moving_node;
|
||||
moving_node->position = i;
|
||||
}
|
||||
|
||||
static void swHeap_percolate_down(swHeap *heap, uint32_t i)
|
||||
{
|
||||
uint32_t child_i;
|
||||
swHeap_node *moving_node = heap->nodes[i];
|
||||
|
||||
while ((child_i = swHeap_maxchild(heap, i))
|
||||
&& swHeap_compare(heap->type, moving_node->priority, heap->nodes[child_i]->priority))
|
||||
{
|
||||
heap->nodes[i] = heap->nodes[child_i];
|
||||
heap->nodes[i]->position = i;
|
||||
i = child_i;
|
||||
}
|
||||
|
||||
heap->nodes[i] = moving_node;
|
||||
moving_node->position = i;
|
||||
}
|
||||
|
||||
swHeap_node* swHeap_push(swHeap *heap, uint64_t priority, void *data)
|
||||
{
|
||||
void *tmp;
|
||||
uint32_t i;
|
||||
uint32_t newsize;
|
||||
|
||||
if (heap->num >= heap->size)
|
||||
{
|
||||
newsize = heap->size * 2;
|
||||
if (!(tmp = sw_realloc(heap->nodes, sizeof(void *) * newsize)))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
heap->nodes = tmp;
|
||||
heap->size = newsize;
|
||||
}
|
||||
|
||||
swHeap_node *node = sw_malloc(sizeof(swHeap_node));
|
||||
if (!node)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
node->priority = priority;
|
||||
node->data = data;
|
||||
i = heap->num++;
|
||||
heap->nodes[i] = node;
|
||||
swHeap_bubble_up(heap, i);
|
||||
return node;
|
||||
}
|
||||
|
||||
void swHeap_change_priority(swHeap *heap, uint64_t new_priority, void* ptr)
|
||||
{
|
||||
swHeap_node *node = ptr;
|
||||
uint32_t pos = node->position;
|
||||
uint64_t old_pri = node->priority;
|
||||
|
||||
node->priority = new_priority;
|
||||
if (swHeap_compare(heap->type, old_pri, new_priority))
|
||||
{
|
||||
swHeap_bubble_up(heap, pos);
|
||||
}
|
||||
else
|
||||
{
|
||||
swHeap_percolate_down(heap, pos);
|
||||
}
|
||||
}
|
||||
|
||||
int swHeap_remove(swHeap *heap, swHeap_node *node)
|
||||
{
|
||||
uint32_t pos = node->position;
|
||||
heap->nodes[pos] = heap->nodes[--heap->num];
|
||||
|
||||
if (swHeap_compare(heap->type, node->priority, heap->nodes[pos]->priority))
|
||||
{
|
||||
swHeap_bubble_up(heap, pos);
|
||||
}
|
||||
else
|
||||
{
|
||||
swHeap_percolate_down(heap, pos);
|
||||
}
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
void *swHeap_pop(swHeap *heap)
|
||||
{
|
||||
swHeap_node *head;
|
||||
if (!heap || heap->num == 1)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
head = heap->nodes[1];
|
||||
heap->nodes[1] = heap->nodes[--heap->num];
|
||||
swHeap_percolate_down(heap, 1);
|
||||
|
||||
void *data = head->data;
|
||||
sw_free(head);
|
||||
return data;
|
||||
}
|
||||
|
||||
void *swHeap_peek(swHeap *heap)
|
||||
{
|
||||
if (heap->num == 1)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
swHeap_node *node = heap->nodes[1];
|
||||
if (!node)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
return node->data;
|
||||
}
|
||||
|
||||
void swHeap_print(swHeap *heap)
|
||||
{
|
||||
int i;
|
||||
for(i = 1; i < heap->num; i++)
|
||||
{
|
||||
printf("#%d\tpriority=%ld, data=%p\n", i, (long)heap->nodes[i]->priority, heap->nodes[i]->data);
|
||||
}
|
||||
}
|
225
vendor/swoole/src/core/list.c
vendored
Executable file
225
vendor/swoole/src/core/list.c
vendored
Executable file
@ -0,0 +1,225 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| 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"
|
||||
|
||||
swLinkedList* swLinkedList_new(uint8_t type, swDestructor dtor)
|
||||
{
|
||||
swLinkedList *q = sw_malloc(sizeof(swLinkedList));
|
||||
if (q == NULL)
|
||||
{
|
||||
swWarn("malloc(%ld) failed.", sizeof(swLinkedList));
|
||||
return NULL;
|
||||
}
|
||||
bzero(q, sizeof(swLinkedList));
|
||||
q->type = type;
|
||||
q->dtor = dtor;
|
||||
return q;
|
||||
}
|
||||
|
||||
int swLinkedList_append(swLinkedList *ll, void *data)
|
||||
{
|
||||
swLinkedList_node *node = sw_malloc(sizeof(swLinkedList_node));
|
||||
if (node == NULL)
|
||||
{
|
||||
swWarn("malloc(%ld) failed.", sizeof(swLinkedList_node));
|
||||
return SW_ERR;
|
||||
}
|
||||
node->data = data;
|
||||
node->next = NULL;
|
||||
ll->num++;
|
||||
if (ll->tail)
|
||||
{
|
||||
ll->tail->next = node;
|
||||
node->prev = ll->tail;
|
||||
ll->tail = node;
|
||||
}
|
||||
else
|
||||
{
|
||||
node->next = NULL;
|
||||
node->prev = NULL;
|
||||
ll->head = node;
|
||||
ll->tail = node;
|
||||
}
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
int swLinkedList_prepend(swLinkedList *ll, void *data)
|
||||
{
|
||||
swLinkedList_node *node = sw_malloc(sizeof(swLinkedList_node));
|
||||
if (node == NULL)
|
||||
{
|
||||
swWarn("malloc(%ld) failed.", sizeof(swLinkedList_node));
|
||||
return SW_ERR;
|
||||
}
|
||||
node->data = data;
|
||||
node->prev = NULL;
|
||||
ll->num ++;
|
||||
if (ll->head)
|
||||
{
|
||||
ll->head->prev = node;
|
||||
node->next = ll->head;
|
||||
ll->head = node;
|
||||
}
|
||||
else
|
||||
{
|
||||
node->next = NULL;
|
||||
node->prev = NULL;
|
||||
ll->head = node;
|
||||
ll->tail = node;
|
||||
}
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pop the element off the end of queue
|
||||
*/
|
||||
void* swLinkedList_pop(swLinkedList *ll)
|
||||
{
|
||||
if (ll->tail == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
swLinkedList_node *node = ll->tail;
|
||||
if (node == ll->head)
|
||||
{
|
||||
ll->head = NULL;
|
||||
ll->tail = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
swLinkedList_node *prev = ll->tail->prev;
|
||||
prev->next = NULL;
|
||||
ll->tail = prev;
|
||||
}
|
||||
ll->num--;
|
||||
void *data = node->data;
|
||||
sw_free(node);
|
||||
return data;
|
||||
}
|
||||
|
||||
void swLinkedList_remove_node(swLinkedList *ll, swLinkedList_node *remove_node)
|
||||
{
|
||||
if (ll->num == 0 || remove_node == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
swLinkedList_node *prev = remove_node->prev;
|
||||
swLinkedList_node *next = remove_node->next;
|
||||
|
||||
if (remove_node == ll->head)
|
||||
{
|
||||
ll->head = next;
|
||||
if (next == NULL)
|
||||
{
|
||||
ll->tail = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
next->prev = NULL;
|
||||
}
|
||||
}
|
||||
else if (remove_node == ll->tail)
|
||||
{
|
||||
ll->tail = prev;
|
||||
if (prev == NULL)
|
||||
{
|
||||
ll->head = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
prev->next = NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
next->prev = prev;
|
||||
prev->next = next;
|
||||
}
|
||||
ll->num--;
|
||||
sw_free(remove_node);
|
||||
}
|
||||
|
||||
swLinkedList_node* swLinkedList_find(swLinkedList *ll, void *data)
|
||||
{
|
||||
if (ll->num == 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
swLinkedList_node *node = ll->head;
|
||||
swLinkedList_node *tmp;
|
||||
|
||||
while (node)
|
||||
{
|
||||
tmp = node->next;
|
||||
if (node->data == data)
|
||||
{
|
||||
return node;
|
||||
}
|
||||
node = tmp;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shift an element off the beginning of queue
|
||||
*/
|
||||
void* swLinkedList_shift(swLinkedList *ll)
|
||||
{
|
||||
if (ll->head == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
swLinkedList_node *node = ll->head;
|
||||
if (node == ll->tail)
|
||||
{
|
||||
ll->head = NULL;
|
||||
ll->tail = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
swLinkedList_node *next = ll->head->next;
|
||||
next->prev = NULL;
|
||||
ll->head = next;
|
||||
}
|
||||
ll->num--;
|
||||
void *data = node->data;
|
||||
sw_free(node);
|
||||
return data;
|
||||
}
|
||||
|
||||
void swLinkedList_free(swLinkedList *ll)
|
||||
{
|
||||
swLinkedList_node *node = ll->head;
|
||||
swLinkedList_node *tmp;
|
||||
|
||||
while (node)
|
||||
{
|
||||
tmp = node->next;
|
||||
if (ll->dtor)
|
||||
{
|
||||
ll->dtor(node->data);
|
||||
}
|
||||
sw_free(node);
|
||||
node = tmp;
|
||||
}
|
||||
|
||||
sw_free(ll);
|
||||
}
|
106
vendor/swoole/src/core/log.c
vendored
Executable file
106
vendor/swoole/src/core/log.c
vendored
Executable file
@ -0,0 +1,106 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| 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 SW_LOG_BUFFER_SIZE 1024
|
||||
#define SW_LOG_DATE_STRLEN 64
|
||||
|
||||
int swLog_init(char *logfile)
|
||||
{
|
||||
SwooleG.log_fd = open(logfile, O_APPEND| O_RDWR | O_CREAT, 0666);
|
||||
if (SwooleG.log_fd < 0)
|
||||
{
|
||||
printf("open(%s) failed. Error: %s[%d]\n", logfile, strerror(errno), errno);
|
||||
SwooleG.log_fd = 0;
|
||||
return SW_ERR;
|
||||
}
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
void swLog_free(void)
|
||||
{
|
||||
if (SwooleG.log_fd > STDOUT_FILENO)
|
||||
{
|
||||
close(SwooleG.log_fd);
|
||||
}
|
||||
}
|
||||
|
||||
void swLog_put(int level, char *cnt)
|
||||
{
|
||||
const char *level_str;
|
||||
char date_str[SW_LOG_DATE_STRLEN];
|
||||
char log_str[SW_LOG_BUFFER_SIZE];
|
||||
int n;
|
||||
|
||||
switch (level)
|
||||
{
|
||||
case SW_LOG_DEBUG:
|
||||
level_str = "DEBUG";
|
||||
break;
|
||||
case SW_LOG_NOTICE:
|
||||
level_str = "NOTICE";
|
||||
break;
|
||||
case SW_LOG_ERROR:
|
||||
level_str = "ERROR";
|
||||
break;
|
||||
case SW_LOG_WARNING:
|
||||
level_str = "WARNING";
|
||||
break;
|
||||
case SW_LOG_TRACE:
|
||||
level_str = "TRACE";
|
||||
break;
|
||||
default:
|
||||
level_str = "INFO";
|
||||
break;
|
||||
}
|
||||
|
||||
time_t t;
|
||||
struct tm *p;
|
||||
t = time(NULL);
|
||||
p = localtime(&t);
|
||||
snprintf(date_str, SW_LOG_DATE_STRLEN, "%d-%02d-%02d %02d:%02d:%02d", p->tm_year + 1900, p->tm_mon + 1, p->tm_mday, p->tm_hour, p->tm_min, p->tm_sec);
|
||||
|
||||
char process_flag = '@';
|
||||
int process_id = 0;
|
||||
|
||||
switch(SwooleG.process_type)
|
||||
{
|
||||
case SW_PROCESS_MASTER:
|
||||
process_flag = '#';
|
||||
process_id = SwooleTG.id;
|
||||
break;
|
||||
case SW_PROCESS_MANAGER:
|
||||
process_flag = '$';
|
||||
break;
|
||||
case SW_PROCESS_WORKER:
|
||||
process_flag = '*';
|
||||
process_id = SwooleWG.id;
|
||||
break;
|
||||
case SW_PROCESS_TASKWORKER:
|
||||
process_flag = '^';
|
||||
process_id = SwooleWG.id;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
n = snprintf(log_str, SW_LOG_BUFFER_SIZE, "[%s %c%d.%d]\t%s\t%s\n", date_str, process_flag, SwooleG.pid, process_id, level_str, cnt);
|
||||
if (write(SwooleG.log_fd, log_str, n) < 0)
|
||||
{
|
||||
printf("write(log_fd, size=%d) failed. Error: %s[%d].\n", n, strerror(errno), errno);
|
||||
}
|
||||
}
|
405
vendor/swoole/src/core/rbtree.c
vendored
Executable file
405
vendor/swoole/src/core/rbtree.c
vendored
Executable file
@ -0,0 +1,405 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| 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 "rbtree.h"
|
||||
|
||||
static inline void swRbtree_left_rotate(swRbtree_node **root, swRbtree_node *sentinel, swRbtree_node *node);
|
||||
static inline void swRbtree_right_rotate(swRbtree_node **root, swRbtree_node *sentinel, swRbtree_node *node);
|
||||
static inline void swRbtree_insert_value(swRbtree_node *temp, swRbtree_node *node, swRbtree_node *sentinel);
|
||||
|
||||
void swRbtree_insert_value(swRbtree_node *temp, swRbtree_node *node, swRbtree_node *sentinel)
|
||||
{
|
||||
swRbtree_node **p;
|
||||
while (1)
|
||||
{
|
||||
p = (node->key < temp->key) ? &temp->left : &temp->right;
|
||||
if (*p == sentinel)
|
||||
{
|
||||
break;
|
||||
}
|
||||
temp = *p;
|
||||
}
|
||||
|
||||
*p = node;
|
||||
node->parent = temp;
|
||||
node->left = sentinel;
|
||||
node->right = sentinel;
|
||||
swRbtree_red(node);
|
||||
}
|
||||
|
||||
void swRbtree_insert(swRbtree *tree, uint32_t key, void *value)
|
||||
{
|
||||
swRbtree_node **root, *temp, *sentinel;
|
||||
|
||||
root = (swRbtree_node **) &tree->root;
|
||||
sentinel = tree->sentinel;
|
||||
|
||||
swRbtree_node *node = (swRbtree_node *) malloc(sizeof(swRbtree_node));
|
||||
|
||||
node->value = value;
|
||||
node->key = key;
|
||||
if (*root == sentinel)
|
||||
{
|
||||
node->parent = NULL;
|
||||
node->left = sentinel;
|
||||
node->right = sentinel;
|
||||
swRbtree_black(node);
|
||||
*root = node;
|
||||
return;
|
||||
}
|
||||
|
||||
swRbtree_insert_value(*root, node, sentinel);
|
||||
|
||||
/* re-balance tree */
|
||||
|
||||
while (node != *root && swRbtree_is_red(node->parent))
|
||||
{
|
||||
if (node->parent == node->parent->parent->left)
|
||||
{
|
||||
temp = node->parent->parent->right;
|
||||
if (swRbtree_is_red(temp))
|
||||
{
|
||||
swRbtree_black(node->parent);
|
||||
swRbtree_black(temp);
|
||||
swRbtree_red(node->parent->parent);
|
||||
node = node->parent->parent;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (node == node->parent->right)
|
||||
{
|
||||
node = node->parent;
|
||||
swRbtree_left_rotate(root, sentinel, node);
|
||||
}
|
||||
|
||||
swRbtree_black(node->parent);
|
||||
swRbtree_red(node->parent->parent);
|
||||
swRbtree_right_rotate(root, sentinel, node->parent->parent);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
temp = node->parent->parent->left;
|
||||
|
||||
if (swRbtree_is_red(temp))
|
||||
{
|
||||
swRbtree_black(node->parent);
|
||||
swRbtree_black(temp);
|
||||
swRbtree_red(node->parent->parent);
|
||||
node = node->parent->parent;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (node == node->parent->left)
|
||||
{
|
||||
node = node->parent;
|
||||
swRbtree_right_rotate(root, sentinel, node);
|
||||
}
|
||||
|
||||
swRbtree_black(node->parent);
|
||||
swRbtree_red(node->parent->parent);
|
||||
swRbtree_left_rotate(root, sentinel, node->parent->parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
swRbtree_black(*root);
|
||||
}
|
||||
|
||||
void swRbtree_delete(swRbtree *tree, uint32_t key)
|
||||
{
|
||||
uint32_t red;
|
||||
swRbtree_node find_node;
|
||||
swRbtree_node **root, *sentinel, *subst, *temp, *w;
|
||||
swRbtree_node *node = &find_node;
|
||||
node->key = key;
|
||||
|
||||
root = (swRbtree_node **) &tree->root;
|
||||
sentinel = tree->sentinel;
|
||||
|
||||
if (node->left == sentinel)
|
||||
{
|
||||
temp = node->right;
|
||||
subst = node;
|
||||
}
|
||||
else if (node->right == sentinel)
|
||||
{
|
||||
temp = node->left;
|
||||
subst = node;
|
||||
}
|
||||
else
|
||||
{
|
||||
subst = swRbtree_min(node->right, sentinel);
|
||||
|
||||
if (subst->left != sentinel)
|
||||
{
|
||||
temp = subst->left;
|
||||
}
|
||||
else
|
||||
{
|
||||
temp = subst->right;
|
||||
}
|
||||
}
|
||||
|
||||
if (subst == *root)
|
||||
{
|
||||
*root = temp;
|
||||
swRbtree_black(temp);
|
||||
|
||||
/* DEBUG stuff */
|
||||
node->left = NULL;
|
||||
node->right = NULL;
|
||||
node->parent = NULL;
|
||||
node->key = 0;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
red = swRbtree_is_red(subst);
|
||||
|
||||
if (subst == subst->parent->left)
|
||||
{
|
||||
subst->parent->left = temp;
|
||||
}
|
||||
else
|
||||
{
|
||||
subst->parent->right = temp;
|
||||
}
|
||||
|
||||
if (subst == node)
|
||||
{
|
||||
temp->parent = subst->parent;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (subst->parent == node)
|
||||
{
|
||||
temp->parent = subst;
|
||||
}
|
||||
else
|
||||
{
|
||||
temp->parent = subst->parent;
|
||||
}
|
||||
|
||||
subst->left = node->left;
|
||||
subst->right = node->right;
|
||||
subst->parent = node->parent;
|
||||
swRbtree_copy_color(subst, node);
|
||||
|
||||
if (node == *root)
|
||||
{
|
||||
*root = subst;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (node == node->parent->left)
|
||||
{
|
||||
node->parent->left = subst;
|
||||
}
|
||||
else
|
||||
{
|
||||
node->parent->right = subst;
|
||||
}
|
||||
}
|
||||
|
||||
if (subst->left != sentinel)
|
||||
{
|
||||
subst->left->parent = subst;
|
||||
}
|
||||
|
||||
if (subst->right != sentinel)
|
||||
{
|
||||
subst->right->parent = subst;
|
||||
}
|
||||
}
|
||||
|
||||
if (red)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* a delete fixup */
|
||||
|
||||
while (temp != *root && swRbtree_is_black(temp))
|
||||
{
|
||||
if (temp == temp->parent->left)
|
||||
{
|
||||
w = temp->parent->right;
|
||||
|
||||
if (swRbtree_is_red(w))
|
||||
{
|
||||
swRbtree_black(w);
|
||||
swRbtree_red(temp->parent);
|
||||
swRbtree_left_rotate(root, sentinel, temp->parent);
|
||||
w = temp->parent->right;
|
||||
}
|
||||
|
||||
if (swRbtree_is_black(w->left) && swRbtree_is_black(w->right))
|
||||
{
|
||||
swRbtree_red(w);
|
||||
temp = temp->parent;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (swRbtree_is_black(w->right))
|
||||
{
|
||||
swRbtree_black(w->left);
|
||||
swRbtree_red(w);
|
||||
swRbtree_right_rotate(root, sentinel, w);
|
||||
w = temp->parent->right;
|
||||
}
|
||||
|
||||
swRbtree_copy_color(w, temp->parent);
|
||||
swRbtree_black(temp->parent);
|
||||
swRbtree_black(w->right);
|
||||
swRbtree_left_rotate(root, sentinel, temp->parent);
|
||||
temp = *root;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
w = temp->parent->left;
|
||||
|
||||
if (swRbtree_is_red(w))
|
||||
{
|
||||
swRbtree_black(w);
|
||||
swRbtree_red(temp->parent);
|
||||
swRbtree_right_rotate(root, sentinel, temp->parent);
|
||||
w = temp->parent->left;
|
||||
}
|
||||
|
||||
if (swRbtree_is_black(w->left) && swRbtree_is_black(w->right))
|
||||
{
|
||||
swRbtree_red(w);
|
||||
temp = temp->parent;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (swRbtree_is_black(w->left))
|
||||
{
|
||||
swRbtree_black(w->right);
|
||||
swRbtree_red(w);
|
||||
swRbtree_left_rotate(root, sentinel, w);
|
||||
w = temp->parent->left;
|
||||
}
|
||||
|
||||
swRbtree_copy_color(w, temp->parent);
|
||||
swRbtree_black(temp->parent);
|
||||
swRbtree_black(w->left);
|
||||
swRbtree_right_rotate(root, sentinel, temp->parent);
|
||||
temp = *root;
|
||||
}
|
||||
}
|
||||
}
|
||||
swRbtree_black(temp);
|
||||
}
|
||||
|
||||
static inline void swRbtree_left_rotate(swRbtree_node **root, swRbtree_node *sentinel, swRbtree_node *node)
|
||||
{
|
||||
swRbtree_node *temp;
|
||||
|
||||
temp = node->right;
|
||||
node->right = temp->left;
|
||||
|
||||
if (temp->left != sentinel)
|
||||
{
|
||||
temp->left->parent = node;
|
||||
}
|
||||
|
||||
temp->parent = node->parent;
|
||||
|
||||
if (node == *root)
|
||||
{
|
||||
*root = temp;
|
||||
|
||||
}
|
||||
else if (node == node->parent->left)
|
||||
{
|
||||
node->parent->left = temp;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
node->parent->right = temp;
|
||||
}
|
||||
|
||||
temp->left = node;
|
||||
node->parent = temp;
|
||||
}
|
||||
|
||||
static inline void swRbtree_right_rotate(swRbtree_node **root, swRbtree_node *sentinel, swRbtree_node *node)
|
||||
{
|
||||
swRbtree_node *temp;
|
||||
|
||||
temp = node->left;
|
||||
node->left = temp->right;
|
||||
|
||||
if (temp->right != sentinel)
|
||||
{
|
||||
temp->right->parent = node;
|
||||
}
|
||||
|
||||
temp->parent = node->parent;
|
||||
|
||||
if (node == *root)
|
||||
{
|
||||
*root = temp;
|
||||
}
|
||||
else if (node == node->parent->right)
|
||||
{
|
||||
node->parent->right = temp;
|
||||
}
|
||||
else
|
||||
{
|
||||
node->parent->left = temp;
|
||||
}
|
||||
|
||||
temp->right = node;
|
||||
node->parent = temp;
|
||||
}
|
||||
|
||||
void *swRbtree_find(swRbtree *tree, uint32_t key)
|
||||
{
|
||||
swRbtree_node *tmp = tree->root;
|
||||
swRbtree_node *sentinel = tree->sentinel;
|
||||
while (tmp != sentinel)
|
||||
{
|
||||
if (key != tmp->key)
|
||||
{
|
||||
tmp = (key < tmp->key) ? tmp->left : tmp->right;
|
||||
continue;
|
||||
}
|
||||
return tmp->value;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
swRbtree* swRbtree_new()
|
||||
{
|
||||
swRbtree *rbtree = sw_malloc(sizeof(swRbtree));
|
||||
swRbtree_node *sentinel = sw_malloc(sizeof(swRbtree_node));
|
||||
|
||||
sentinel->color = 0;
|
||||
rbtree->root = sentinel;
|
||||
rbtree->sentinel = sentinel;
|
||||
return rbtree;
|
||||
}
|
||||
|
||||
void swRbtree_free(swRbtree* rbtree)
|
||||
{
|
||||
sw_free(rbtree->root);
|
||||
sw_free(rbtree);
|
||||
}
|
499
vendor/swoole/src/core/socket.c
vendored
Executable file
499
vendor/swoole/src/core/socket.c
vendored
Executable file
@ -0,0 +1,499 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| 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 <sys/stat.h>
|
||||
#include <poll.h>
|
||||
|
||||
int swSocket_sendfile_sync(int sock, char *filename, off_t offset, size_t length, double timeout)
|
||||
{
|
||||
int timeout_ms = timeout < 0 ? -1 : timeout * 1000;
|
||||
int file_fd = open(filename, O_RDONLY);
|
||||
if (file_fd < 0)
|
||||
{
|
||||
swWarn("open(%s) failed. Error: %s[%d]", filename, strerror(errno), errno);
|
||||
return SW_ERR;
|
||||
}
|
||||
|
||||
if (length == 0)
|
||||
{
|
||||
struct stat file_stat;
|
||||
if (fstat(file_fd, &file_stat) < 0)
|
||||
{
|
||||
swWarn("fstat() failed. Error: %s[%d]", strerror(errno), errno);
|
||||
close(file_fd);
|
||||
return SW_ERR;
|
||||
}
|
||||
length = file_stat.st_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
length = offset + length;
|
||||
}
|
||||
|
||||
int n, sendn;
|
||||
while (offset < length)
|
||||
{
|
||||
if (swSocket_wait(sock, timeout_ms, SW_EVENT_WRITE) < 0)
|
||||
{
|
||||
close(file_fd);
|
||||
return SW_ERR;
|
||||
}
|
||||
else
|
||||
{
|
||||
sendn = (length - offset > SW_SENDFILE_CHUNK_SIZE) ? SW_SENDFILE_CHUNK_SIZE : length - offset;
|
||||
n = swoole_sendfile(sock, file_fd, &offset, sendn);
|
||||
if (n <= 0)
|
||||
{
|
||||
close(file_fd);
|
||||
swSysError("sendfile(%d, %s) failed.", sock, filename);
|
||||
return SW_ERR;
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
close(file_fd);
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* clear socket buffer.
|
||||
*/
|
||||
void swSocket_clean(int fd)
|
||||
{
|
||||
char buf[2048];
|
||||
while (recv(fd, buf, sizeof(buf), MSG_DONTWAIT) > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait socket can read or write.
|
||||
*/
|
||||
int swSocket_wait(int fd, int timeout_ms, int events)
|
||||
{
|
||||
struct pollfd event;
|
||||
event.fd = fd;
|
||||
event.events = 0;
|
||||
|
||||
if (events & SW_EVENT_READ)
|
||||
{
|
||||
event.events |= POLLIN;
|
||||
}
|
||||
if (events & SW_EVENT_WRITE)
|
||||
{
|
||||
event.events |= POLLOUT;
|
||||
}
|
||||
while (1)
|
||||
{
|
||||
int ret = poll(&event, 1, timeout_ms);
|
||||
if (ret == 0)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
else if (ret < 0 && errno != EINTR)
|
||||
{
|
||||
swWarn("poll() failed. Error: %s[%d]", strerror(errno), errno);
|
||||
return SW_ERR;
|
||||
}
|
||||
else
|
||||
{
|
||||
return SW_OK;
|
||||
}
|
||||
}
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait some sockets can read or write.
|
||||
*/
|
||||
int swSocket_wait_multi(int *list_of_fd, int n_fd, int timeout_ms, int events)
|
||||
{
|
||||
assert(n_fd < 65535);
|
||||
|
||||
struct pollfd *event_list = sw_calloc(n_fd, sizeof(struct pollfd));
|
||||
int i;
|
||||
|
||||
int _events = 0;
|
||||
if (events & SW_EVENT_READ)
|
||||
{
|
||||
_events |= POLLIN;
|
||||
}
|
||||
if (events & SW_EVENT_WRITE)
|
||||
{
|
||||
_events |= POLLOUT;
|
||||
}
|
||||
|
||||
for (i = 0; i < n_fd; i++)
|
||||
{
|
||||
event_list[i].fd = list_of_fd[i];
|
||||
event_list[i].events = _events;
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
int ret = poll(event_list, n_fd, timeout_ms);
|
||||
if (ret == 0)
|
||||
{
|
||||
sw_free(event_list);
|
||||
return SW_ERR;
|
||||
}
|
||||
else if (ret < 0 && errno != EINTR)
|
||||
{
|
||||
swWarn("poll() failed. Error: %s[%d]", strerror(errno), errno);
|
||||
sw_free(event_list);
|
||||
return SW_ERR;
|
||||
}
|
||||
else
|
||||
{
|
||||
sw_free(event_list);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
sw_free(event_list);
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
int swSocket_write_blocking(int __fd, void *__data, int __len)
|
||||
{
|
||||
int n = 0;
|
||||
int written = 0;
|
||||
|
||||
while (written < __len)
|
||||
{
|
||||
n = write(__fd, __data + written, __len - written);
|
||||
if (n < 0)
|
||||
{
|
||||
if (errno == EINTR)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
#ifdef HAVE_KQUEUE
|
||||
else if (errno == EAGAIN || errno == ENOBUFS)
|
||||
#else
|
||||
else if (errno == EAGAIN)
|
||||
#endif
|
||||
{
|
||||
swSocket_wait(__fd, SW_WORKER_WAIT_TIMEOUT, SW_EVENT_WRITE);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
swSysError("write %d bytes failed.", __len);
|
||||
return SW_ERR;
|
||||
}
|
||||
}
|
||||
written += n;
|
||||
}
|
||||
|
||||
return written;
|
||||
}
|
||||
|
||||
int swSocket_recv_blocking(int fd, void *__data, size_t __len, int flags)
|
||||
{
|
||||
int ret;
|
||||
size_t read_bytes = 0;
|
||||
|
||||
while (read_bytes != __len)
|
||||
{
|
||||
errno = 0;
|
||||
ret = recv(fd, __data + read_bytes, __len - read_bytes, flags);
|
||||
if (ret > 0)
|
||||
{
|
||||
read_bytes += ret;
|
||||
}
|
||||
else if (ret == 0 && errno == 0)
|
||||
{
|
||||
return read_bytes;
|
||||
}
|
||||
else if (ret <= 0 && errno != 0 && errno != EINTR)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return read_bytes;
|
||||
}
|
||||
|
||||
int swSocket_udp_sendto(int server_sock, char *dst_ip, int dst_port, char *data, uint32_t len)
|
||||
{
|
||||
struct sockaddr_in addr;
|
||||
if (inet_aton(dst_ip, &addr.sin_addr) == 0)
|
||||
{
|
||||
swWarn("ip[%s] is invalid.", dst_ip);
|
||||
return SW_ERR;
|
||||
}
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(dst_port);
|
||||
return swSocket_sendto_blocking(server_sock, data, len, 0, (struct sockaddr *) &addr, sizeof(addr));
|
||||
}
|
||||
|
||||
int swSocket_udp_sendto6(int server_sock, char *dst_ip, int dst_port, char *data, uint32_t len)
|
||||
{
|
||||
struct sockaddr_in6 addr;
|
||||
bzero(&addr, sizeof(addr));
|
||||
if (inet_pton(AF_INET6, dst_ip, &addr.sin6_addr) < 0)
|
||||
{
|
||||
swWarn("ip[%s] is invalid.", dst_ip);
|
||||
return SW_ERR;
|
||||
}
|
||||
addr.sin6_port = (uint16_t) htons(dst_port);
|
||||
addr.sin6_family = AF_INET6;
|
||||
return swSocket_sendto_blocking(server_sock, data, len, 0, (struct sockaddr *) &addr, sizeof(addr));
|
||||
}
|
||||
|
||||
int swSocket_unix_sendto(int server_sock, char *dst_path, char *data, uint32_t len)
|
||||
{
|
||||
struct sockaddr_un addr;
|
||||
bzero(&addr, sizeof(addr));
|
||||
strncpy(addr.sun_path, dst_path, sizeof(addr.sun_path));
|
||||
return swSocket_sendto_blocking(server_sock, data, len, 0, (struct sockaddr *) &addr, sizeof(addr));
|
||||
}
|
||||
|
||||
int swSocket_sendto_blocking(int fd, void *__buf, size_t __n, int flag, struct sockaddr *__addr, socklen_t __addr_len)
|
||||
{
|
||||
int n = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
n = sendto(fd, __buf, __n, flag, __addr, __addr_len);
|
||||
if (n >= 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (errno == EINTR)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else if (errno == EAGAIN)
|
||||
{
|
||||
swSocket_wait(fd, 1000, SW_EVENT_WRITE);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
int swSocket_create(int type)
|
||||
{
|
||||
int _domain;
|
||||
int _type;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case SW_SOCK_TCP:
|
||||
_domain = PF_INET;
|
||||
_type = SOCK_STREAM;
|
||||
break;
|
||||
case SW_SOCK_TCP6:
|
||||
_domain = PF_INET6;
|
||||
_type = SOCK_STREAM;
|
||||
break;
|
||||
case SW_SOCK_UDP:
|
||||
_domain = PF_INET;
|
||||
_type = SOCK_DGRAM;
|
||||
break;
|
||||
case SW_SOCK_UDP6:
|
||||
_domain = PF_INET6;
|
||||
_type = SOCK_DGRAM;
|
||||
break;
|
||||
case SW_SOCK_UNIX_DGRAM:
|
||||
_domain = PF_UNIX;
|
||||
_type = SOCK_DGRAM;
|
||||
break;
|
||||
case SW_SOCK_UNIX_STREAM:
|
||||
_domain = PF_UNIX;
|
||||
_type = SOCK_STREAM;
|
||||
break;
|
||||
default:
|
||||
swWarn("unknown socket type [%d]", type);
|
||||
return SW_ERR;
|
||||
}
|
||||
return socket(_domain, _type, 0);
|
||||
}
|
||||
|
||||
int swSocket_bind(int sock, int type, char *host, int *port)
|
||||
{
|
||||
int ret;
|
||||
|
||||
struct sockaddr_in addr_in4;
|
||||
struct sockaddr_in6 addr_in6;
|
||||
struct sockaddr_un addr_un;
|
||||
socklen_t len;
|
||||
|
||||
//SO_REUSEADDR option
|
||||
int option = 1;
|
||||
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(int)) < 0)
|
||||
{
|
||||
swoole_error_log(SW_LOG_WARNING, SW_ERROR_SYSTEM_CALL_FAIL, "setsockopt(%d, SO_REUSEADDR) failed.", sock);
|
||||
}
|
||||
//reuse port
|
||||
#ifdef HAVE_REUSEPORT
|
||||
if (SwooleG.reuse_port)
|
||||
{
|
||||
if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &option, sizeof(int)) < 0)
|
||||
{
|
||||
swSysError("setsockopt(SO_REUSEPORT) failed.");
|
||||
SwooleG.reuse_port = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
//unix socket
|
||||
if (type == SW_SOCK_UNIX_DGRAM || type == SW_SOCK_UNIX_STREAM)
|
||||
{
|
||||
bzero(&addr_un, sizeof(addr_un));
|
||||
unlink(host);
|
||||
addr_un.sun_family = AF_UNIX;
|
||||
strncpy(addr_un.sun_path, host, sizeof(addr_un.sun_path) - 1);
|
||||
ret = bind(sock, (struct sockaddr*) &addr_un, sizeof(addr_un));
|
||||
}
|
||||
//IPv6
|
||||
else if (type > SW_SOCK_UDP)
|
||||
{
|
||||
bzero(&addr_in6, sizeof(addr_in6));
|
||||
inet_pton(AF_INET6, host, &(addr_in6.sin6_addr));
|
||||
addr_in6.sin6_port = htons(*port);
|
||||
addr_in6.sin6_family = AF_INET6;
|
||||
ret = bind(sock, (struct sockaddr *) &addr_in6, sizeof(addr_in6));
|
||||
if (ret == 0 && *port == 0)
|
||||
{
|
||||
len = sizeof(addr_in6);
|
||||
if (getsockname(sock, (struct sockaddr *) &addr_in6, &len) != -1)
|
||||
{
|
||||
*port = ntohs(addr_in6.sin6_port);
|
||||
}
|
||||
}
|
||||
}
|
||||
//IPv4
|
||||
else
|
||||
{
|
||||
bzero(&addr_in4, sizeof(addr_in4));
|
||||
inet_pton(AF_INET, host, &(addr_in4.sin_addr));
|
||||
addr_in4.sin_port = htons(*port);
|
||||
addr_in4.sin_family = AF_INET;
|
||||
ret = bind(sock, (struct sockaddr *) &addr_in4, sizeof(addr_in4));
|
||||
if (ret == 0 && *port == 0)
|
||||
{
|
||||
len = sizeof(addr_in4);
|
||||
if (getsockname(sock, (struct sockaddr *) &addr_in4, &len) != -1)
|
||||
{
|
||||
*port = ntohs(addr_in4.sin_port);
|
||||
}
|
||||
}
|
||||
}
|
||||
//bind failed
|
||||
if (ret < 0)
|
||||
{
|
||||
swoole_error_log(SW_LOG_WARNING, SW_ERROR_SYSTEM_CALL_FAIL, "bind(%s:%d) failed. Error: %s [%d]", host, *port, strerror(errno), errno);
|
||||
return SW_ERR;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int swSocket_set_buffer_size(int fd, int buffer_size)
|
||||
{
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &buffer_size, sizeof(buffer_size)) < 0)
|
||||
{
|
||||
swSysError("setsockopt(%d, SOL_SOCKET, SO_SNDBUF, %d) failed.", fd, buffer_size);
|
||||
return SW_ERR;
|
||||
}
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &buffer_size, sizeof(buffer_size)) < 0)
|
||||
{
|
||||
swSysError("setsockopt(%d, SOL_SOCKET, SO_RCVBUF, %d) failed.", fd, buffer_size);
|
||||
return SW_ERR;
|
||||
}
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
int swSocket_set_timeout(int sock, double timeout)
|
||||
{
|
||||
int ret;
|
||||
struct timeval timeo;
|
||||
timeo.tv_sec = (int) timeout;
|
||||
timeo.tv_usec = (int) ((timeout - timeo.tv_sec) * 1000 * 1000);
|
||||
ret = setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (void *) &timeo, sizeof(timeo));
|
||||
if (ret < 0)
|
||||
{
|
||||
swWarn("setsockopt(SO_SNDTIMEO) failed. Error: %s[%d]", strerror(errno), errno);
|
||||
return SW_ERR;
|
||||
}
|
||||
ret = setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (void *) &timeo, sizeof(timeo));
|
||||
if (ret < 0)
|
||||
{
|
||||
swWarn("setsockopt(SO_RCVTIMEO) failed. Error: %s[%d]", strerror(errno), errno);
|
||||
return SW_ERR;
|
||||
}
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
int swSocket_create_server(int type, char *address, int port, int backlog)
|
||||
{
|
||||
#if 0
|
||||
int type;
|
||||
char host[32];
|
||||
int port = 0;
|
||||
|
||||
if (strncasecmp(address, "unix:/", 6) == 0)
|
||||
{
|
||||
address += 5;
|
||||
type = SW_SOCK_UNIX_STREAM;
|
||||
}
|
||||
else
|
||||
{
|
||||
char *port_str = strchr(address, ':');
|
||||
if (!port_str)
|
||||
{
|
||||
swoole_error_log(SW_LOG_ERROR, SW_ERROR_INVALID_PARAMS, "invalid address[%s]", address);
|
||||
return SW_ERR;
|
||||
}
|
||||
type = SW_SOCK_TCP6;
|
||||
memcpy(host, address, port_str - address);
|
||||
host[port_str - address] = 0;
|
||||
port = atoi(port_str + 1);
|
||||
address = host;
|
||||
}
|
||||
#endif
|
||||
|
||||
int fd = swSocket_create(type);
|
||||
if (fd < 0)
|
||||
{
|
||||
swoole_error_log(SW_LOG_ERROR, SW_ERROR_SYSTEM_CALL_FAIL, "socket() failed. Error: %s[%d]", strerror(errno), errno);
|
||||
return SW_ERR;
|
||||
}
|
||||
|
||||
if (swSocket_bind(fd, type, address, &port) < 0)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
|
||||
if (listen(fd, backlog) < 0)
|
||||
{
|
||||
swoole_error_log(SW_LOG_ERROR, SW_ERROR_SYSTEM_CALL_FAIL, "listen(%s:%d, %d) failed. Error: %s[%d]", address, port, backlog, strerror(errno), errno);
|
||||
return SW_ERR;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
294
vendor/swoole/src/core/string.c
vendored
Executable file
294
vendor/swoole/src/core/string.c
vendored
Executable file
@ -0,0 +1,294 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| 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"
|
||||
|
||||
swString *swString_new(size_t size)
|
||||
{
|
||||
swString *str = sw_malloc(sizeof(swString));
|
||||
if (str == NULL)
|
||||
{
|
||||
swWarn("malloc[1] failed.");
|
||||
return NULL;
|
||||
}
|
||||
bzero(str, sizeof(swString));
|
||||
str->size = size;
|
||||
str->str = sw_malloc(size);
|
||||
if (str->str == NULL)
|
||||
{
|
||||
swSysError("malloc[2](%ld) failed.", size);
|
||||
sw_free(str);
|
||||
return NULL;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
void swString_print(swString *str)
|
||||
{
|
||||
printf("String[length=%d,size=%d,offset=%d]=%s\n", (int) str->length, (int) str->size, (int) str->offset,
|
||||
str->str);
|
||||
}
|
||||
|
||||
swString *swString_dup2(swString *src)
|
||||
{
|
||||
swString *dst = swString_new(src->size);
|
||||
if (dst)
|
||||
{
|
||||
swTrace("string dup2. new=%p, old=%p\n", dst, src);
|
||||
dst->length = src->length;
|
||||
dst->offset = src->offset;
|
||||
memcpy(dst->str, src->str, src->length);
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
swString *swString_dup(const char *src_str, int length)
|
||||
{
|
||||
swString *str = sw_malloc(sizeof(swString));
|
||||
if (str == NULL)
|
||||
{
|
||||
swWarn("malloc[1] failed.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bzero(str, sizeof(swString));
|
||||
str->length = length;
|
||||
str->size = length + 1;
|
||||
str->str = sw_malloc(str->size);
|
||||
if (str->str == NULL)
|
||||
{
|
||||
swWarn("malloc[2] failed.");
|
||||
sw_free(str);
|
||||
return NULL;
|
||||
}
|
||||
memcpy(str->str, src_str, length + 1);
|
||||
return str;
|
||||
}
|
||||
|
||||
int swString_append(swString *str, swString *append_str)
|
||||
{
|
||||
int new_size = str->length + append_str->length;
|
||||
if (new_size > str->size)
|
||||
{
|
||||
if (swString_extend(str, swoole_size_align(new_size * 2, sysconf(_SC_PAGESIZE))) < 0)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
}
|
||||
memcpy(str->str + str->length, append_str->str, append_str->length);
|
||||
str->length += append_str->length;
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
int swString_append_int(swString *str, int value)
|
||||
{
|
||||
char buf[16];
|
||||
int s_len = swoole_itoa(buf, value);
|
||||
|
||||
int new_size = str->length + s_len;
|
||||
if (new_size > str->size)
|
||||
{
|
||||
if (swString_extend(str, swoole_size_align(new_size * 2, sysconf(_SC_PAGESIZE))) < 0)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(str->str + str->length, buf, s_len);
|
||||
str->length += s_len;
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
int swString_append_ptr(swString *str, char *append_str, int length)
|
||||
{
|
||||
int new_size = str->length + length;
|
||||
if (new_size > str->size)
|
||||
{
|
||||
if (swString_extend(str, swoole_size_align(new_size * 2, sysconf(_SC_PAGESIZE))) < 0)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
}
|
||||
memcpy(str->str + str->length, append_str, length);
|
||||
str->length += length;
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
int swString_write(swString *str, off_t offset, swString *write_str)
|
||||
{
|
||||
int new_length = offset + write_str->length;
|
||||
if (new_length > str->size)
|
||||
{
|
||||
if (swString_extend(str, swoole_size_align(new_length * 2, sysconf(_SC_PAGESIZE))) < 0)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(str->str + offset, write_str->str, write_str->length);
|
||||
|
||||
if (new_length > str->length)
|
||||
{
|
||||
str->length = new_length;
|
||||
}
|
||||
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
int swString_write_ptr(swString *str, off_t offset, char *write_str, int length)
|
||||
{
|
||||
int new_length = offset + length;
|
||||
if (new_length > str->size)
|
||||
{
|
||||
if (swString_extend(str, swoole_size_align(new_length * 2, sysconf(_SC_PAGESIZE))) < 0)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(str->str + offset, write_str, length);
|
||||
|
||||
if (new_length > str->length)
|
||||
{
|
||||
str->length = new_length;
|
||||
}
|
||||
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
int swString_extend(swString *str, size_t new_size)
|
||||
{
|
||||
assert(new_size > str->size);
|
||||
char *new_str = sw_realloc(str->str, new_size);
|
||||
if (new_str == NULL)
|
||||
{
|
||||
swSysError("realloc(%ld) failed.", new_size);
|
||||
return SW_ERR;
|
||||
}
|
||||
str->str = new_str;
|
||||
str->size = new_size;
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
char* swString_alloc(swString *str, size_t __size)
|
||||
{
|
||||
if (str->length + __size < str->size)
|
||||
{
|
||||
if (swString_extend_align(str, str->length + __size) < 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
char *tmp = str->str + str->length;
|
||||
str->length += __size;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
uint32_t swoole_utf8_decode(u_char **p, size_t n)
|
||||
{
|
||||
size_t len;
|
||||
uint32_t u, i, valid;
|
||||
|
||||
u = **p;
|
||||
|
||||
if (u >= 0xf0)
|
||||
{
|
||||
u &= 0x07;
|
||||
valid = 0xffff;
|
||||
len = 3;
|
||||
}
|
||||
else if (u >= 0xe0)
|
||||
{
|
||||
u &= 0x0f;
|
||||
valid = 0x7ff;
|
||||
len = 2;
|
||||
}
|
||||
else if (u >= 0xc2)
|
||||
{
|
||||
u &= 0x1f;
|
||||
valid = 0x7f;
|
||||
len = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
(*p)++;
|
||||
return 0xffffffff;
|
||||
}
|
||||
|
||||
if (n - 1 < len)
|
||||
{
|
||||
return 0xfffffffe;
|
||||
}
|
||||
|
||||
(*p)++;
|
||||
|
||||
while (len)
|
||||
{
|
||||
i = *(*p)++;
|
||||
if (i < 0x80)
|
||||
{
|
||||
return 0xffffffff;
|
||||
}
|
||||
u = (u << 6) | (i & 0x3f);
|
||||
len--;
|
||||
}
|
||||
|
||||
if (u > valid)
|
||||
{
|
||||
return u;
|
||||
}
|
||||
|
||||
return 0xffffffff;
|
||||
}
|
||||
|
||||
size_t swoole_utf8_length(u_char *p, size_t n)
|
||||
{
|
||||
u_char c, *last;
|
||||
size_t len;
|
||||
|
||||
last = p + n;
|
||||
|
||||
for (len = 0; p < last; len++)
|
||||
{
|
||||
c = *p;
|
||||
if (c < 0x80)
|
||||
{
|
||||
p++;
|
||||
continue;
|
||||
}
|
||||
if (swoole_utf8_decode(&p, n) > 0x10ffff)
|
||||
{
|
||||
/* invalid UTF-8 */
|
||||
return n;
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
static char characters[] =
|
||||
{ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
|
||||
'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
|
||||
't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', };
|
||||
|
||||
void swoole_random_string(char *buf, size_t size)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < size; i++)
|
||||
{
|
||||
buf[i] = characters[swoole_rand(0, sizeof(characters) - 1)];
|
||||
}
|
||||
buf[i] = '\0';
|
||||
}
|
182
vendor/swoole/src/coroutine/base.cc
vendored
Executable file
182
vendor/swoole/src/coroutine/base.cc
vendored
Executable file
@ -0,0 +1,182 @@
|
||||
#include "coroutine.h"
|
||||
#include "context.h"
|
||||
#include <string>
|
||||
|
||||
/* allocate cid for coroutine */
|
||||
typedef struct cidmap
|
||||
{
|
||||
uint32_t nr_free;
|
||||
char page[65536];
|
||||
} cidmap_t;
|
||||
|
||||
using namespace swoole;
|
||||
|
||||
struct coroutine_s
|
||||
{
|
||||
public:
|
||||
Context ctx;
|
||||
int cid;
|
||||
coroutine_s(int _cid, size_t stack_size, coroutine_func_t fn, void* private_data) :
|
||||
ctx(stack_size, fn, private_data)
|
||||
{
|
||||
cid = _cid;
|
||||
}
|
||||
};
|
||||
|
||||
static struct
|
||||
{
|
||||
int stack_size;
|
||||
int current_cid;
|
||||
int previous_cid;
|
||||
struct coroutine_s *coroutines[MAX_CORO_NUM_LIMIT + 1];
|
||||
coroutine_close_t onClose;
|
||||
} swCoroG =
|
||||
{ SW_DEFAULT_C_STACK_SIZE, -1, -1,
|
||||
{ NULL, }, NULL };
|
||||
|
||||
/* 1 <= cid <= 524288 */
|
||||
static cidmap_t cidmap =
|
||||
{ MAX_CORO_NUM_LIMIT,
|
||||
{ 0 } };
|
||||
|
||||
static int last_cid = -1;
|
||||
|
||||
static inline int test_and_set_bit(int cid, void *addr)
|
||||
{
|
||||
uint32_t mask = 1U << (cid & 0x1f);
|
||||
uint32_t *p = ((uint32_t*) addr) + (cid >> 5);
|
||||
uint32_t old = *p;
|
||||
|
||||
*p = old | mask;
|
||||
|
||||
return (old & mask) == 0;
|
||||
}
|
||||
|
||||
static inline void clear_bit(int cid, void *addr)
|
||||
{
|
||||
uint32_t mask = 1U << (cid & 0x1f);
|
||||
uint32_t *p = ((uint32_t*) addr) + (cid >> 5);
|
||||
uint32_t old = *p;
|
||||
|
||||
*p = old & ~mask;
|
||||
}
|
||||
|
||||
/* find next free cid */
|
||||
static inline int find_next_zero_bit(void *addr, int cid)
|
||||
{
|
||||
uint32_t *p;
|
||||
uint32_t mask;
|
||||
int mark = cid;
|
||||
|
||||
cid++;
|
||||
cid &= 0x7ffff;
|
||||
while (cid != mark)
|
||||
{
|
||||
mask = 1U << (cid & 0x1f);
|
||||
p = ((uint32_t*) addr) + (cid >> 5);
|
||||
|
||||
if ((~(*p) & mask))
|
||||
{
|
||||
break;
|
||||
}
|
||||
++cid;
|
||||
cid &= 0x7fff;
|
||||
}
|
||||
|
||||
return cid;
|
||||
}
|
||||
|
||||
static inline int alloc_cidmap()
|
||||
{
|
||||
int cid;
|
||||
|
||||
if (cidmap.nr_free == 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
cid = find_next_zero_bit(&cidmap.page, last_cid);
|
||||
if (test_and_set_bit(cid, &cidmap.page))
|
||||
{
|
||||
--cidmap.nr_free;
|
||||
last_cid = cid;
|
||||
return cid + 1;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline void free_cidmap(int cid)
|
||||
{
|
||||
cid--;
|
||||
cidmap.nr_free++;
|
||||
clear_bit(cid, &cidmap.page);
|
||||
}
|
||||
|
||||
int coroutine_create(coroutine_func_t fn, void* args)
|
||||
{
|
||||
int cid = alloc_cidmap();
|
||||
if (unlikely(cid == -1))
|
||||
{
|
||||
swWarn("alloc_cidmap failed");
|
||||
return CORO_LIMIT;
|
||||
}
|
||||
|
||||
coroutine_t *co = new coroutine_t(cid, swCoroG.stack_size, fn, args);
|
||||
swCoroG.coroutines[cid] = co;
|
||||
swCoroG.previous_cid = swCoroG.current_cid;
|
||||
swCoroG.current_cid = cid;
|
||||
co->ctx.SwapIn();
|
||||
if (co->ctx.end)
|
||||
{
|
||||
if (swCoroG.onClose)
|
||||
{
|
||||
swCoroG.onClose();
|
||||
}
|
||||
coroutine_release(co);
|
||||
}
|
||||
return cid;
|
||||
}
|
||||
|
||||
void coroutine_yield(coroutine_t *co)
|
||||
{
|
||||
swCoroG.current_cid = swCoroG.previous_cid;
|
||||
co->ctx.SwapOut();
|
||||
}
|
||||
|
||||
void coroutine_resume(coroutine_t *co)
|
||||
{
|
||||
swCoroG.previous_cid = swCoroG.current_cid;
|
||||
swCoroG.current_cid = co->cid;
|
||||
co->ctx.SwapIn();
|
||||
if (co->ctx.end)
|
||||
{
|
||||
if (swCoroG.onClose)
|
||||
{
|
||||
swCoroG.onClose();
|
||||
}
|
||||
coroutine_release(co);
|
||||
}
|
||||
}
|
||||
|
||||
void coroutine_release(coroutine_t *co)
|
||||
{
|
||||
free_cidmap(co->cid);
|
||||
swCoroG.coroutines[co->cid] = NULL;
|
||||
delete co;
|
||||
}
|
||||
|
||||
void coroutine_set_close(coroutine_close_t func)
|
||||
{
|
||||
swCoroG.onClose = func;
|
||||
}
|
||||
|
||||
coroutine_t* coroutine_get_by_id(int cid)
|
||||
{
|
||||
return swCoroG.coroutines[cid];
|
||||
}
|
||||
|
||||
int coroutine_get_cid()
|
||||
{
|
||||
return swCoroG.current_cid;
|
||||
}
|
76
vendor/swoole/src/coroutine/boost.cc
vendored
Executable file
76
vendor/swoole/src/coroutine/boost.cc
vendored
Executable file
@ -0,0 +1,76 @@
|
||||
#include "swoole.h"
|
||||
#include "context.h"
|
||||
|
||||
#if USE_BOOST_CONTEXT
|
||||
|
||||
using namespace swoole;
|
||||
|
||||
Context::Context(size_t stack_size, coroutine_func_t fn, void* private_data) :
|
||||
fn_(fn), stack_size_(stack_size), private_data_(private_data)
|
||||
{
|
||||
BOOST_ASSERT(boost::context::stack_traits::minimum_size() <= stack_size_);
|
||||
BOOST_ASSERT(
|
||||
boost::context::stack_traits::is_unbounded()
|
||||
|| (boost::context::stack_traits::maximum_size() >= stack_size_));
|
||||
|
||||
protect_page_ = 0;
|
||||
end = false;
|
||||
swap_ctx_ = NULL;
|
||||
|
||||
stack_ = (char*) sw_malloc(stack_size_);
|
||||
swDebug("alloc stack: size=%u, ptr=%p.", stack_size_, stack_);
|
||||
|
||||
void* sp = (void*) ((char*) stack_ + stack_size_);
|
||||
#ifdef USE_VALGRIND
|
||||
valgrind_stack_id = VALGRIND_STACK_REGISTER(sp, stack_);
|
||||
#endif
|
||||
ctx_ = boost::context::make_fcontext(sp, stack_size_, (void (*)(intptr_t))&context_func);
|
||||
|
||||
uint32_t protect_page = get_protect_stack_page();
|
||||
if (protect_page)
|
||||
{
|
||||
if (protect_stack(stack_, stack_size_, protect_page))
|
||||
{
|
||||
protect_page_ = protect_page;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Context::~Context()
|
||||
{
|
||||
if (stack_)
|
||||
{
|
||||
swDebug("free stack: ptr=%p", stack_);
|
||||
if (protect_page_)
|
||||
{
|
||||
unprotect_stack(stack_, protect_page_);
|
||||
}
|
||||
#if defined(USE_VALGRIND)
|
||||
VALGRIND_STACK_DEREGISTER(valgrind_stack_id);
|
||||
#endif
|
||||
sw_free(stack_);
|
||||
stack_ = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool Context::SwapIn()
|
||||
{
|
||||
boost::context::jump_fcontext(&swap_ctx_, ctx_, (intptr_t) this, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Context::SwapOut()
|
||||
{
|
||||
boost::context::jump_fcontext(&ctx_, swap_ctx_, (intptr_t) this, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Context::context_func(void *arg)
|
||||
{
|
||||
Context* _this = (Context*) arg;
|
||||
_this->fn_(_this->private_data_);
|
||||
_this->end = true;
|
||||
_this->SwapOut();
|
||||
}
|
||||
|
||||
#endif
|
71
vendor/swoole/src/coroutine/context.cc
vendored
Executable file
71
vendor/swoole/src/coroutine/context.cc
vendored
Executable file
@ -0,0 +1,71 @@
|
||||
#include "swoole.h"
|
||||
#include "context.h"
|
||||
|
||||
#ifndef SW_NO_USE_ASM_CONTEXT
|
||||
|
||||
using namespace swoole;
|
||||
|
||||
Context::Context(size_t stack_size, coroutine_func_t fn, void* private_data) :
|
||||
fn_(fn), stack_size_(stack_size), private_data_(private_data)
|
||||
{
|
||||
protect_page_ = 0;
|
||||
end = false;
|
||||
swap_ctx_ = NULL;
|
||||
|
||||
stack_ = (char*) sw_malloc(stack_size_);
|
||||
swDebug("alloc stack: size=%u, ptr=%p.", stack_size_, stack_);
|
||||
|
||||
void* sp = (void*) ((char*) stack_ + stack_size_);
|
||||
#ifdef USE_VALGRIND
|
||||
valgrind_stack_id = VALGRIND_STACK_REGISTER(sp, stack_);
|
||||
#endif
|
||||
ctx_ = make_fcontext(sp, stack_size_, (void (*)(intptr_t))&context_func);
|
||||
|
||||
uint32_t protect_page = get_protect_stack_page();
|
||||
if (protect_page)
|
||||
{
|
||||
if (protect_stack(stack_, stack_size_, protect_page))
|
||||
{
|
||||
protect_page_ = protect_page;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Context::~Context()
|
||||
{
|
||||
if (stack_)
|
||||
{
|
||||
swDebug("free stack: ptr=%p", stack_);
|
||||
if (protect_page_)
|
||||
{
|
||||
unprotect_stack(stack_, protect_page_);
|
||||
}
|
||||
#if defined(USE_VALGRIND)
|
||||
VALGRIND_STACK_DEREGISTER(valgrind_stack_id);
|
||||
#endif
|
||||
sw_free(stack_);
|
||||
stack_ = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool Context::SwapIn()
|
||||
{
|
||||
jump_fcontext(&swap_ctx_, ctx_, (intptr_t) this, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Context::SwapOut()
|
||||
{
|
||||
jump_fcontext(&ctx_, swap_ctx_, (intptr_t) this, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Context::context_func(void *arg)
|
||||
{
|
||||
Context *_this = (Context *) arg;
|
||||
_this->fn_(_this->private_data_);
|
||||
_this->end = true;
|
||||
_this->SwapOut();
|
||||
}
|
||||
|
||||
#endif
|
79
vendor/swoole/src/coroutine/ucontext.cc
vendored
Executable file
79
vendor/swoole/src/coroutine/ucontext.cc
vendored
Executable file
@ -0,0 +1,79 @@
|
||||
#include "swoole.h"
|
||||
#include "context.h"
|
||||
|
||||
#if USE_UCONTEXT
|
||||
|
||||
using namespace swoole;
|
||||
|
||||
Context::Context(size_t stack_size, coroutine_func_t fn, void* private_data) :
|
||||
fn_(fn), stack_size_(stack_size), private_data_(private_data)
|
||||
{
|
||||
if (-1 == getcontext(&ctx_))
|
||||
{
|
||||
swoole_throw_error(SW_ERROR_CO_GETCONTEXT_FAILED);
|
||||
return;
|
||||
}
|
||||
|
||||
protect_page_ = 0;
|
||||
end = false;
|
||||
|
||||
stack_ = (char*) sw_malloc(stack_size);
|
||||
swDebug("alloc stack: size=%lu, ptr=%p", stack_size, stack_);
|
||||
|
||||
ctx_.uc_stack.ss_sp = stack_;
|
||||
ctx_.uc_stack.ss_size = stack_size;
|
||||
ctx_.uc_link = NULL;
|
||||
|
||||
#if defined(USE_VALGRIND)
|
||||
valgrind_stack_id = VALGRIND_STACK_REGISTER(static_cast<char *>(stack_) + stack_size, stack_);
|
||||
#endif
|
||||
|
||||
makecontext(&ctx_, (void (*)(void))&context_func, 1, this);
|
||||
|
||||
uint32_t protect_page = get_protect_stack_page();
|
||||
if (protect_page)
|
||||
{
|
||||
if (protect_stack(stack_, stack_size, protect_page))
|
||||
{
|
||||
protect_page_ = protect_page;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Context::~Context()
|
||||
{
|
||||
if (stack_)
|
||||
{
|
||||
swDebug("free stack: ptr=%p", stack_);
|
||||
if (protect_page_)
|
||||
{
|
||||
unprotect_stack(stack_, protect_page_);
|
||||
}
|
||||
|
||||
#if defined(USE_VALGRIND)
|
||||
VALGRIND_STACK_DEREGISTER(valgrind_stack_id);
|
||||
#endif
|
||||
sw_free(stack_);
|
||||
stack_ = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool Context::SwapIn()
|
||||
{
|
||||
return 0 == swapcontext(&swap_ctx_, &ctx_);
|
||||
}
|
||||
|
||||
bool Context::SwapOut()
|
||||
{
|
||||
return 0 == swapcontext(&ctx_, &swap_ctx_);
|
||||
}
|
||||
|
||||
void Context::context_func(void *arg)
|
||||
{
|
||||
Context *_this = (Context *) arg;
|
||||
_this->fn_(_this->private_data_);
|
||||
_this->end = true;
|
||||
_this->SwapOut();
|
||||
}
|
||||
|
||||
#endif
|
170
vendor/swoole/src/factory/Factory.c
vendored
Executable file
170
vendor/swoole/src/factory/Factory.c
vendored
Executable file
@ -0,0 +1,170 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| 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"
|
||||
|
||||
int swFactory_create(swFactory *factory)
|
||||
{
|
||||
factory->dispatch = swFactory_dispatch;
|
||||
factory->finish = swFactory_finish;
|
||||
factory->start = swFactory_start;
|
||||
factory->shutdown = swFactory_shutdown;
|
||||
factory->end = swFactory_end;
|
||||
factory->notify = swFactory_notify;
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
int swFactory_start(swFactory *factory)
|
||||
{
|
||||
SwooleWG.run_always = 1;
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
int swFactory_shutdown(swFactory *factory)
|
||||
{
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
int swFactory_dispatch(swFactory *factory, swDispatchData *task)
|
||||
{
|
||||
swServer *serv = factory->ptr;
|
||||
factory->last_from_id = task->data.info.from_id;
|
||||
|
||||
if (swEventData_is_stream(task->data.info.type))
|
||||
{
|
||||
swConnection *conn = swServer_connection_get(serv, task->data.info.fd);
|
||||
if (conn == NULL || conn->active == 0)
|
||||
{
|
||||
swWarn("dispatch[type=%d] failed, connection#%d is not active.", task->data.info.type, task->data.info.fd);
|
||||
return SW_ERR;
|
||||
}
|
||||
//server active close, discard data.
|
||||
if (conn->closed)
|
||||
{
|
||||
swWarn("dispatch[type=%d] failed, connection#%d is closed by server.", task->data.info.type,
|
||||
task->data.info.fd);
|
||||
return SW_OK;
|
||||
}
|
||||
//converted fd to session_id
|
||||
task->data.info.fd = conn->session_id;
|
||||
task->data.info.from_fd = conn->from_fd;
|
||||
}
|
||||
return swWorker_onTask(factory, &task->data);
|
||||
}
|
||||
|
||||
int swFactory_notify(swFactory *factory, swDataHead *info)
|
||||
{
|
||||
swServer *serv = factory->ptr;
|
||||
swConnection *conn = swServer_connection_get(serv, info->fd);
|
||||
if (conn == NULL || conn->active == 0)
|
||||
{
|
||||
swWarn("dispatch[type=%d] failed, connection#%d is not active.", info->type, info->fd);
|
||||
return SW_ERR;
|
||||
}
|
||||
//server active close, discard data.
|
||||
if (conn->closed)
|
||||
{
|
||||
swWarn("dispatch[type=%d] failed, connection#%d is closed by server.", info->type, info->fd);
|
||||
return SW_OK;
|
||||
}
|
||||
//converted fd to session_id
|
||||
info->fd = conn->session_id;
|
||||
info->from_fd = conn->from_fd;
|
||||
return swWorker_onTask(factory, (swEventData *) info);
|
||||
}
|
||||
|
||||
int swFactory_end(swFactory *factory, int fd)
|
||||
{
|
||||
swServer *serv = factory->ptr;
|
||||
swSendData _send;
|
||||
swDataHead info;
|
||||
|
||||
bzero(&_send, sizeof(_send));
|
||||
_send.info.fd = fd;
|
||||
_send.info.len = 0;
|
||||
_send.info.type = SW_EVENT_CLOSE;
|
||||
|
||||
swConnection *conn = swWorker_get_connection(serv, fd);
|
||||
if (conn == NULL || conn->active == 0)
|
||||
{
|
||||
//swWarn("can not close. Connection[%d] not found.", _send.info.fd);
|
||||
return SW_ERR;
|
||||
}
|
||||
else if (conn->close_force)
|
||||
{
|
||||
goto do_close;
|
||||
}
|
||||
else if (conn->closing)
|
||||
{
|
||||
swWarn("The connection[%d] is closing.", fd);
|
||||
return SW_ERR;
|
||||
}
|
||||
else if (conn->closed)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
else
|
||||
{
|
||||
do_close:
|
||||
conn->closing = 1;
|
||||
if (serv->onClose != NULL)
|
||||
{
|
||||
info.fd = fd;
|
||||
if (conn->close_actively)
|
||||
{
|
||||
info.from_id = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
info.from_id = conn->from_id;
|
||||
}
|
||||
info.from_fd = conn->from_fd;
|
||||
serv->onClose(serv, &info);
|
||||
}
|
||||
conn->closing = 0;
|
||||
conn->closed = 1;
|
||||
conn->close_errno = 0;
|
||||
|
||||
if (swBuffer_empty(conn->out_buffer) || conn->removed)
|
||||
{
|
||||
swReactor *reactor = &serv->reactor_threads[SwooleTG.id].reactor;
|
||||
return swReactorThread_close(reactor, conn->fd);
|
||||
}
|
||||
else
|
||||
{
|
||||
swBuffer_trunk *trunk = swBuffer_new_trunk(conn->out_buffer, SW_CHUNK_CLOSE, 0);
|
||||
trunk->store.data.val1 = _send.info.type;
|
||||
return SW_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int swFactory_finish(swFactory *factory, swSendData *resp)
|
||||
{
|
||||
if (resp->length == 0)
|
||||
{
|
||||
resp->length = resp->info.len;
|
||||
}
|
||||
if (swReactorThread_send(resp) < 0)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
else
|
||||
{
|
||||
return SW_OK;
|
||||
}
|
||||
}
|
335
vendor/swoole/src/factory/FactoryProcess.c
vendored
Executable file
335
vendor/swoole/src/factory/FactoryProcess.c
vendored
Executable file
@ -0,0 +1,335 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| 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 <signal.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
static int swFactoryProcess_start(swFactory *factory);
|
||||
static int swFactoryProcess_notify(swFactory *factory, swDataHead *event);
|
||||
static int swFactoryProcess_dispatch(swFactory *factory, swDispatchData *buf);
|
||||
static int swFactoryProcess_finish(swFactory *factory, swSendData *data);
|
||||
static int swFactoryProcess_shutdown(swFactory *factory);
|
||||
static int swFactoryProcess_end(swFactory *factory, int fd);
|
||||
|
||||
int swFactoryProcess_create(swFactory *factory, int worker_num)
|
||||
{
|
||||
swFactoryProcess *object;
|
||||
object = SwooleG.memory_pool->alloc(SwooleG.memory_pool, sizeof(swFactoryProcess));
|
||||
if (object == NULL)
|
||||
{
|
||||
swWarn("[Master] malloc[object] failed");
|
||||
return SW_ERR;
|
||||
}
|
||||
|
||||
factory->object = object;
|
||||
factory->dispatch = swFactoryProcess_dispatch;
|
||||
factory->finish = swFactoryProcess_finish;
|
||||
factory->start = swFactoryProcess_start;
|
||||
factory->notify = swFactoryProcess_notify;
|
||||
factory->shutdown = swFactoryProcess_shutdown;
|
||||
factory->end = swFactoryProcess_end;
|
||||
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
static int swFactoryProcess_shutdown(swFactory *factory)
|
||||
{
|
||||
int status;
|
||||
swServer *serv = factory->ptr;
|
||||
|
||||
if (swKill(serv->gs->manager_pid, SIGTERM) < 0)
|
||||
{
|
||||
swSysError("kill(%d) failed.", serv->gs->manager_pid);
|
||||
}
|
||||
|
||||
if (swWaitpid(serv->gs->manager_pid, &status, 0) < 0)
|
||||
{
|
||||
swSysError("waitpid(%d) failed.", serv->gs->manager_pid);
|
||||
}
|
||||
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
static int swFactoryProcess_start(swFactory *factory)
|
||||
{
|
||||
int i;
|
||||
swServer *serv = factory->ptr;
|
||||
swWorker *worker;
|
||||
|
||||
for (i = 0; i < serv->worker_num; i++)
|
||||
{
|
||||
worker = swServer_get_worker(serv, i);
|
||||
if (swWorker_create(worker) < 0)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
serv->reactor_pipe_num = serv->worker_num / serv->reactor_num;
|
||||
|
||||
//必须先启动manager进程组,否则会带线程fork
|
||||
if (swManager_start(factory) < 0)
|
||||
{
|
||||
swWarn("swFactoryProcess_manager_start failed.");
|
||||
return SW_ERR;
|
||||
}
|
||||
//主进程需要设置为直写模式
|
||||
factory->finish = swFactory_finish;
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
static __thread struct
|
||||
{
|
||||
long target_worker_id;
|
||||
swDataHead _send;
|
||||
} sw_notify_data;
|
||||
|
||||
/**
|
||||
* [ReactorThread] notify info to worker process
|
||||
*/
|
||||
static int swFactoryProcess_notify(swFactory *factory, swDataHead *ev)
|
||||
{
|
||||
memcpy(&sw_notify_data._send, ev, sizeof(swDataHead));
|
||||
sw_notify_data._send.len = 0;
|
||||
sw_notify_data.target_worker_id = -1;
|
||||
return factory->dispatch(factory, (swDispatchData *) &sw_notify_data);
|
||||
}
|
||||
|
||||
/**
|
||||
* [ReactorThread] dispatch request to worker
|
||||
*/
|
||||
static int swFactoryProcess_dispatch(swFactory *factory, swDispatchData *task)
|
||||
{
|
||||
uint32_t send_len = sizeof(task->data.info) + task->data.info.len;
|
||||
int target_worker_id;
|
||||
swServer *serv = SwooleG.serv;
|
||||
int fd = task->data.info.fd;
|
||||
|
||||
if (task->target_worker_id < 0)
|
||||
{
|
||||
#ifndef SW_USE_RINGBUFFER
|
||||
if (SwooleTG.factory_lock_target)
|
||||
{
|
||||
if (SwooleTG.factory_target_worker < 0)
|
||||
{
|
||||
target_worker_id = swServer_worker_schedule(serv, fd, &task->data);
|
||||
SwooleTG.factory_target_worker = target_worker_id;
|
||||
}
|
||||
else
|
||||
{
|
||||
target_worker_id = SwooleTG.factory_target_worker;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
target_worker_id = swServer_worker_schedule(serv, fd, &task->data);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
target_worker_id = task->target_worker_id;
|
||||
}
|
||||
//discard the data packet.
|
||||
if (target_worker_id < 0)
|
||||
{
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
if (swEventData_is_stream(task->data.info.type))
|
||||
{
|
||||
swConnection *conn = swServer_connection_get(serv, fd);
|
||||
if (conn == NULL || conn->active == 0)
|
||||
{
|
||||
swWarn("dispatch[type=%d] failed, connection#%d is not active.", task->data.info.type, fd);
|
||||
return SW_ERR;
|
||||
}
|
||||
//server active close, discard data.
|
||||
if (conn->closed)
|
||||
{
|
||||
//Connection has been clsoed by server
|
||||
if (!(task->data.info.type == SW_EVENT_CLOSE && conn->close_force))
|
||||
{
|
||||
return SW_OK;
|
||||
}
|
||||
}
|
||||
//converted fd to session_id
|
||||
task->data.info.fd = conn->session_id;
|
||||
task->data.info.from_fd = conn->from_fd;
|
||||
}
|
||||
|
||||
return swReactorThread_send2worker((void *) &(task->data), send_len, target_worker_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* worker: send to client
|
||||
*/
|
||||
static int swFactoryProcess_finish(swFactory *factory, swSendData *resp)
|
||||
{
|
||||
int ret, sendn;
|
||||
swServer *serv = factory->ptr;
|
||||
int session_id = resp->info.fd;
|
||||
|
||||
swConnection *conn;
|
||||
if (resp->info.type != SW_EVENT_CLOSE)
|
||||
{
|
||||
conn = swServer_connection_verify(serv, session_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
conn = swServer_connection_verify_no_ssl(serv, session_id);
|
||||
}
|
||||
if (!conn)
|
||||
{
|
||||
swoole_error_log(SW_LOG_NOTICE, SW_ERROR_SESSION_NOT_EXIST, "connection[fd=%d] does not exists.", session_id);
|
||||
return SW_ERR;
|
||||
}
|
||||
else if ((conn->closed || conn->removed) && resp->info.type != SW_EVENT_CLOSE)
|
||||
{
|
||||
int _len = resp->length > 0 ? resp->length : resp->info.len;
|
||||
swoole_error_log(SW_LOG_NOTICE, SW_ERROR_SESSION_CLOSED, "send %d byte failed, because connection[fd=%d] is closed.", _len, session_id);
|
||||
return SW_ERR;
|
||||
}
|
||||
else if (conn->overflow)
|
||||
{
|
||||
swoole_error_log(SW_LOG_WARNING, SW_ERROR_OUTPUT_BUFFER_OVERFLOW, "send failed, connection[fd=%d] output buffer has been overflowed.", session_id);
|
||||
return SW_ERR;
|
||||
}
|
||||
|
||||
swEventData ev_data;
|
||||
ev_data.info.fd = session_id;
|
||||
ev_data.info.type = resp->info.type;
|
||||
swWorker *worker = swServer_get_worker(serv, SwooleWG.id);
|
||||
|
||||
/**
|
||||
* Big response, use shared memory
|
||||
*/
|
||||
if (resp->length > 0)
|
||||
{
|
||||
if (worker == NULL || worker->send_shm == NULL)
|
||||
{
|
||||
goto pack_data;
|
||||
}
|
||||
|
||||
//worker process
|
||||
if (SwooleG.main_reactor)
|
||||
{
|
||||
int _pipe_fd = swWorker_get_send_pipe(serv, session_id, conn->from_id);
|
||||
swConnection *_pipe_socket = swReactor_get(SwooleG.main_reactor, _pipe_fd);
|
||||
|
||||
//cannot use send_shm
|
||||
if (!swBuffer_empty(_pipe_socket->out_buffer))
|
||||
{
|
||||
pack_data:
|
||||
if (swTaskWorker_large_pack(&ev_data, resp->data, resp->length) < 0)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
ev_data.info.from_fd = SW_RESPONSE_TMPFILE;
|
||||
goto send_to_reactor_thread;
|
||||
}
|
||||
}
|
||||
|
||||
swPackage_response response;
|
||||
response.length = resp->length;
|
||||
response.worker_id = SwooleWG.id;
|
||||
ev_data.info.from_fd = SW_RESPONSE_SHM;
|
||||
ev_data.info.len = sizeof(response);
|
||||
memcpy(ev_data.data, &response, sizeof(response));
|
||||
|
||||
swTrace("[Worker] big response, length=%d|worker_id=%d", response.length, response.worker_id);
|
||||
|
||||
worker->lock.lock(&worker->lock);
|
||||
memcpy(worker->send_shm, resp->data, resp->length);
|
||||
}
|
||||
else
|
||||
{
|
||||
//copy data
|
||||
memcpy(ev_data.data, resp->data, resp->info.len);
|
||||
|
||||
ev_data.info.len = resp->info.len;
|
||||
ev_data.info.from_fd = SW_RESPONSE_SMALL;
|
||||
}
|
||||
|
||||
send_to_reactor_thread: ev_data.info.from_id = conn->from_id;
|
||||
sendn = ev_data.info.len + sizeof(resp->info);
|
||||
|
||||
swTrace("[Worker] send: sendn=%d|type=%d|content=%s", sendn, resp->info.type, resp->data);
|
||||
ret = swWorker_send2reactor(&ev_data, sendn, session_id);
|
||||
if (ret < 0)
|
||||
{
|
||||
swWarn("sendto to reactor failed. Error: %s [%d]", strerror(errno), errno);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int swFactoryProcess_end(swFactory *factory, int fd)
|
||||
{
|
||||
swServer *serv = factory->ptr;
|
||||
swSendData _send;
|
||||
swDataHead info;
|
||||
|
||||
bzero(&_send, sizeof(_send));
|
||||
_send.info.fd = fd;
|
||||
_send.info.len = 0;
|
||||
_send.info.type = SW_EVENT_CLOSE;
|
||||
|
||||
swConnection *conn = swWorker_get_connection(serv, fd);
|
||||
if (conn == NULL || conn->active == 0)
|
||||
{
|
||||
SwooleG.error = SW_ERROR_SESSION_NOT_EXIST;
|
||||
return SW_ERR;
|
||||
}
|
||||
else if (conn->close_force)
|
||||
{
|
||||
goto do_close;
|
||||
}
|
||||
else if (conn->closing)
|
||||
{
|
||||
swoole_error_log(SW_LOG_NOTICE, SW_ERROR_SESSION_CLOSING, "The connection[%d] is closing.", fd);
|
||||
return SW_ERR;
|
||||
}
|
||||
else if (conn->closed)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
else
|
||||
{
|
||||
do_close:
|
||||
conn->closing = 1;
|
||||
if (serv->onClose != NULL)
|
||||
{
|
||||
info.fd = fd;
|
||||
if (conn->close_actively)
|
||||
{
|
||||
info.from_id = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
info.from_id = conn->from_id;
|
||||
}
|
||||
info.from_fd = conn->from_fd;
|
||||
serv->onClose(serv, &info);
|
||||
}
|
||||
conn->closing = 0;
|
||||
conn->closed = 1;
|
||||
conn->close_errno = 0;
|
||||
return factory->finish(factory, &_send);
|
||||
}
|
||||
}
|
245
vendor/swoole/src/factory/FactoryThread.c
vendored
Executable file
245
vendor/swoole/src/factory/FactoryThread.c
vendored
Executable 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"
|
||||
#include "Server.h"
|
||||
|
||||
static int swFactoryThread_dispatch(swFactory *factory, swDispatchData *buf);
|
||||
static int swFactoryThread_finish(swFactory *factory, swSendData *data);
|
||||
static int swFactoryThread_shutdown(swFactory *factory);
|
||||
static int swFactoryThread_start(swFactory *factory);
|
||||
|
||||
typedef struct _swWorkerThread
|
||||
{
|
||||
pthread_t ptid; //线程ID
|
||||
int pipe_num; //writer thread's pipe num
|
||||
int *pipes; //worker pipes
|
||||
int c_pipe; //current pipe
|
||||
swReactor reactor;
|
||||
swShareMemory shm; //共享内存
|
||||
swPipe evfd; //eventfd
|
||||
} swWorkerThread;
|
||||
|
||||
typedef struct _swFactoryThread
|
||||
{
|
||||
int worker_num;
|
||||
swThreadPool workers;
|
||||
} swFactoryThread;
|
||||
|
||||
static int swFactoryThread_onTask(swThreadPool *pool, void *data, int len);
|
||||
static void swFactoryThread_onStart(swThreadPool *pool, int id);
|
||||
static void swFactoryThread_onStop(swThreadPool *pool, int id);
|
||||
|
||||
int swFactoryThread_create(swFactory *factory, int worker_num)
|
||||
{
|
||||
swFactoryThread *object;
|
||||
swServer *serv = factory->ptr;
|
||||
|
||||
object = sw_calloc(worker_num, sizeof(swFactoryThread));
|
||||
if (object == NULL)
|
||||
{
|
||||
swWarn("malloc[0] failed");
|
||||
return SW_ERR;
|
||||
}
|
||||
|
||||
if (swThreadPool_create(&object->workers, worker_num) < 0)
|
||||
{
|
||||
sw_free(object);
|
||||
return SW_ERR;
|
||||
}
|
||||
|
||||
int i;
|
||||
swReactorThread *thread;
|
||||
for (i = 0; i < serv->reactor_num; i++)
|
||||
{
|
||||
thread = swServer_get_thread(serv, i);
|
||||
swMutex_create(&thread->lock, 0);
|
||||
}
|
||||
|
||||
object->worker_num = worker_num;
|
||||
|
||||
factory->object = object;
|
||||
factory->dispatch = swFactoryThread_dispatch;
|
||||
factory->finish = swFactoryThread_finish;
|
||||
factory->end = swFactory_end;
|
||||
factory->start = swFactoryThread_start;
|
||||
factory->shutdown = swFactoryThread_shutdown;
|
||||
factory->notify = swFactory_notify;
|
||||
|
||||
object->workers.onStart = swFactoryThread_onStart;
|
||||
object->workers.onStop = swFactoryThread_onStop;
|
||||
object->workers.onTask = swFactoryThread_onTask;
|
||||
|
||||
object->workers.ptr1 = factory->ptr;
|
||||
object->workers.ptr2 = factory;
|
||||
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
static int swFactoryThread_start(swFactory *factory)
|
||||
{
|
||||
swFactoryThread *object = factory->object;
|
||||
SwooleWG.run_always = 1;
|
||||
swThreadPool_run(&object->workers);
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
static int swFactoryThread_shutdown(swFactory *factory)
|
||||
{
|
||||
SwooleG.running = 0;
|
||||
swFactoryThread *object = factory->object;
|
||||
swThreadPool_free(&object->workers);
|
||||
sw_free(object);
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
static int swFactoryThread_finish(swFactory *factory, swSendData *_send)
|
||||
{
|
||||
swServer *serv = SwooleG.serv;
|
||||
uint32_t session_id = _send->info.fd;
|
||||
|
||||
if (_send->length == 0)
|
||||
{
|
||||
_send->length = _send->info.len;
|
||||
}
|
||||
|
||||
swConnection *conn = swServer_connection_verify(serv, session_id);
|
||||
if (!conn)
|
||||
{
|
||||
if (_send->info.type == SW_EVENT_TCP)
|
||||
{
|
||||
swWarn("send %d byte failed, session#%d is closed.", _send->length, session_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
swWarn("send [%d] failed, session#%d is closed.", _send->info.type, session_id);
|
||||
}
|
||||
return SW_ERR;
|
||||
}
|
||||
|
||||
return swSocket_write_blocking(conn->fd, _send->data, _send->length);
|
||||
}
|
||||
|
||||
/**
|
||||
* 写线程模式
|
||||
*/
|
||||
int swFactoryThread_dispatch(swFactory *factory, swDispatchData *task)
|
||||
{
|
||||
swServer *serv = SwooleG.serv;
|
||||
swFactoryThread *object = factory->object;
|
||||
|
||||
if (swEventData_is_stream(task->data.info.type))
|
||||
{
|
||||
swConnection *conn = swServer_connection_get(serv, task->data.info.fd);
|
||||
if (conn == NULL || conn->active == 0)
|
||||
{
|
||||
swWarn("dispatch[type=%d] failed, connection#%d is not active.", task->data.info.type, task->data.info.fd);
|
||||
return SW_ERR;
|
||||
}
|
||||
//server active close, discard data.
|
||||
if (conn->closed)
|
||||
{
|
||||
swWarn("dispatch[type=%d] failed, connection#%d is closed by server.", task->data.info.type,
|
||||
task->data.info.fd);
|
||||
return SW_OK;
|
||||
}
|
||||
//converted fd to session_id
|
||||
task->data.info.fd = conn->session_id;
|
||||
task->data.info.from_fd = conn->from_fd;
|
||||
}
|
||||
|
||||
int mem_size = sizeof(swDataHead) + task->data.info.len + 1;
|
||||
char *data = sw_malloc(mem_size);
|
||||
if (data == NULL)
|
||||
{
|
||||
swWarn("malloc failed");
|
||||
return SW_ERR;
|
||||
}
|
||||
|
||||
memcpy(data, &(task->data), mem_size);
|
||||
data[sizeof(swDataHead) + task->data.info.len] = 0;
|
||||
|
||||
if (swThreadPool_dispatch(&object->workers, (void *) data, 0) < 0)
|
||||
{
|
||||
swWarn("RingQueue is full");
|
||||
return SW_ERR;
|
||||
}
|
||||
else
|
||||
{
|
||||
return SW_OK;
|
||||
}
|
||||
}
|
||||
|
||||
static void swFactoryThread_onStart(swThreadPool *pool, int id)
|
||||
{
|
||||
swServer *serv = pool->ptr1;
|
||||
|
||||
if (serv->onWorkerStart != NULL)
|
||||
{
|
||||
serv->onWorkerStart(serv, id);
|
||||
}
|
||||
|
||||
swSignal_none();
|
||||
|
||||
SwooleTG.id = serv->reactor_num + id;
|
||||
SwooleTG.type = SW_THREAD_WORKER;
|
||||
|
||||
SwooleTG.buffer_input = swServer_create_worker_buffer(serv);
|
||||
if (!SwooleTG.buffer_input)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//cpu affinity setting
|
||||
#ifdef HAVE_CPU_AFFINITY
|
||||
if (serv->open_cpu_affinity)
|
||||
{
|
||||
cpu_set_t cpu_set;
|
||||
CPU_ZERO(&cpu_set);
|
||||
if (serv->cpu_affinity_available_num)
|
||||
{
|
||||
CPU_SET(serv->cpu_affinity_available[id % serv->cpu_affinity_available_num], &cpu_set);
|
||||
}
|
||||
else
|
||||
{
|
||||
CPU_SET(id % SW_CPU_NUM, &cpu_set);
|
||||
}
|
||||
if (0 != pthread_setaffinity_np(pthread_self(), sizeof(cpu_set), &cpu_set))
|
||||
{
|
||||
swWarn("pthread_setaffinity_np() failed");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
static void swFactoryThread_onStop(swThreadPool *pool, int id)
|
||||
{
|
||||
swServer *serv = SwooleG.serv;
|
||||
|
||||
if (serv->onWorkerStop != NULL)
|
||||
{
|
||||
serv->onWorkerStop(serv, id);
|
||||
}
|
||||
}
|
||||
|
||||
static int swFactoryThread_onTask(swThreadPool *pool, void *data, int len)
|
||||
{
|
||||
swFactory *factory = pool->ptr2;
|
||||
int ret = swWorker_onTask(factory, (swEventData*) data);
|
||||
sw_free(data);
|
||||
return ret;
|
||||
}
|
49
vendor/swoole/src/lock/AtomicLock.c
vendored
Executable file
49
vendor/swoole/src/lock/AtomicLock.c
vendored
Executable file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| 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 swAtomicLock_lock(swLock *lock);
|
||||
static int swAtomicLock_unlock(swLock *lock);
|
||||
static int swAtomicLock_trylock(swLock *lock);
|
||||
|
||||
int swAtomicLock_create(swLock *lock, int spin)
|
||||
{
|
||||
bzero(lock, sizeof(swLock));
|
||||
lock->type = SW_ATOMLOCK;
|
||||
lock->object.atomlock.spin = spin;
|
||||
lock->lock = swAtomicLock_lock;
|
||||
lock->unlock = swAtomicLock_unlock;
|
||||
lock->trylock = swAtomicLock_trylock;
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
static int swAtomicLock_lock(swLock *lock)
|
||||
{
|
||||
sw_spinlock(&lock->object.atomlock.lock_t);
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
static int swAtomicLock_unlock(swLock *lock)
|
||||
{
|
||||
return lock->object.atomlock.lock_t = 0;
|
||||
}
|
||||
|
||||
static int swAtomicLock_trylock(swLock *lock)
|
||||
{
|
||||
sw_atomic_t *atomic = &lock->object.atomlock.lock_t;
|
||||
return (*(atomic) == 0 && sw_atomic_cmp_set(atomic, 0, 1));
|
||||
}
|
89
vendor/swoole/src/lock/Cond.c
vendored
Executable file
89
vendor/swoole/src/lock/Cond.c
vendored
Executable file
@ -0,0 +1,89 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| 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 swCond_notify(swCond *cond);
|
||||
static int swCond_broadcast(swCond *cond);
|
||||
static int swCond_timewait(swCond *cond, long sec, long nsec);
|
||||
static int swCond_wait(swCond *cond);
|
||||
static int swCond_lock(swCond *cond);
|
||||
static int swCond_unlock(swCond *cond);
|
||||
static void swCond_free(swCond *cond);
|
||||
|
||||
int swCond_create(swCond *cond)
|
||||
{
|
||||
if (pthread_cond_init(&cond->_cond, NULL) < 0)
|
||||
{
|
||||
swWarn("pthread_cond_init fail. Error: %s [%d]", strerror(errno), errno);
|
||||
return SW_ERR;
|
||||
}
|
||||
if (swMutex_create(&cond->_lock, 0) < 0)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
|
||||
cond->notify = swCond_notify;
|
||||
cond->broadcast = swCond_broadcast;
|
||||
cond->timewait = swCond_timewait;
|
||||
cond->wait = swCond_wait;
|
||||
cond->lock = swCond_lock;
|
||||
cond->unlock = swCond_unlock;
|
||||
cond->free = swCond_free;
|
||||
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
static int swCond_notify(swCond *cond)
|
||||
{
|
||||
return pthread_cond_signal(&cond->_cond);
|
||||
}
|
||||
|
||||
static int swCond_broadcast(swCond *cond)
|
||||
{
|
||||
return pthread_cond_broadcast(&cond->_cond);
|
||||
}
|
||||
|
||||
static int swCond_timewait(swCond *cond, long sec, long nsec)
|
||||
{
|
||||
struct timespec timeo;
|
||||
|
||||
timeo.tv_sec = sec;
|
||||
timeo.tv_nsec = nsec;
|
||||
|
||||
return pthread_cond_timedwait(&cond->_cond, &cond->_lock.object.mutex._lock, &timeo);
|
||||
}
|
||||
|
||||
static int swCond_wait(swCond *cond)
|
||||
{
|
||||
return pthread_cond_wait(&cond->_cond, &cond->_lock.object.mutex._lock);
|
||||
}
|
||||
|
||||
static int swCond_lock(swCond *cond)
|
||||
{
|
||||
return cond->_lock.lock(&cond->_lock);
|
||||
}
|
||||
|
||||
static int swCond_unlock(swCond *cond)
|
||||
{
|
||||
return cond->_lock.unlock(&cond->_lock);
|
||||
}
|
||||
|
||||
static void swCond_free(swCond *cond)
|
||||
{
|
||||
pthread_cond_destroy(&cond->_cond);
|
||||
cond->_lock.free(&cond->_lock);
|
||||
}
|
73
vendor/swoole/src/lock/FileLock.c
vendored
Executable file
73
vendor/swoole/src/lock/FileLock.c
vendored
Executable file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| 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 swFileLock_lock_rd(swLock *lock);
|
||||
static int swFileLock_lock_rw(swLock *lock);
|
||||
static int swFileLock_unlock(swLock *lock);
|
||||
static int swFileLock_trylock_rw(swLock *lock);
|
||||
static int swFileLock_trylock_rd(swLock *lock);
|
||||
static int swFileLock_free(swLock *lock);
|
||||
|
||||
int swFileLock_create(swLock *lock, int fd)
|
||||
{
|
||||
bzero(lock, sizeof(swLock));
|
||||
lock->type = SW_FILELOCK;
|
||||
lock->object.filelock.fd = fd;
|
||||
lock->lock_rd = swFileLock_lock_rd;
|
||||
lock->lock = swFileLock_lock_rw;
|
||||
lock->trylock_rd = swFileLock_trylock_rd;
|
||||
lock->trylock = swFileLock_trylock_rw;
|
||||
lock->unlock = swFileLock_unlock;
|
||||
lock->free = swFileLock_free;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int swFileLock_lock_rd(swLock *lock)
|
||||
{
|
||||
lock->object.filelock.lock_t.l_type = F_RDLCK;
|
||||
return fcntl(lock->object.filelock.fd, F_SETLKW, &lock->object.filelock);
|
||||
}
|
||||
|
||||
static int swFileLock_lock_rw(swLock *lock)
|
||||
{
|
||||
lock->object.filelock.lock_t.l_type = F_WRLCK;
|
||||
return fcntl(lock->object.filelock.fd, F_SETLKW, &lock->object.filelock);
|
||||
}
|
||||
|
||||
static int swFileLock_unlock(swLock *lock)
|
||||
{
|
||||
lock->object.filelock.lock_t.l_type = F_UNLCK;
|
||||
return fcntl(lock->object.filelock.fd, F_SETLKW, &lock->object.filelock);
|
||||
}
|
||||
|
||||
static int swFileLock_trylock_rw(swLock *lock)
|
||||
{
|
||||
lock->object.filelock.lock_t.l_type = F_WRLCK;
|
||||
return fcntl(lock->object.filelock.fd, F_SETLK, &lock->object.filelock);
|
||||
}
|
||||
|
||||
static int swFileLock_trylock_rd(swLock *lock)
|
||||
{
|
||||
lock->object.filelock.lock_t.l_type = F_RDLCK;
|
||||
return fcntl(lock->object.filelock.fd, F_SETLK, &lock->object.filelock);
|
||||
}
|
||||
|
||||
static int swFileLock_free(swLock *lock)
|
||||
{
|
||||
return close(lock->object.filelock.fd);
|
||||
}
|
100
vendor/swoole/src/lock/Mutex.c
vendored
Executable file
100
vendor/swoole/src/lock/Mutex.c
vendored
Executable file
@ -0,0 +1,100 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| 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 swMutex_lock(swLock *lock);
|
||||
static int swMutex_unlock(swLock *lock);
|
||||
static int swMutex_trylock(swLock *lock);
|
||||
static int swMutex_free(swLock *lock);
|
||||
|
||||
int swMutex_create(swLock *lock, int use_in_process)
|
||||
{
|
||||
int ret;
|
||||
bzero(lock, sizeof(swLock));
|
||||
lock->type = SW_MUTEX;
|
||||
pthread_mutexattr_init(&lock->object.mutex.attr);
|
||||
if (use_in_process == 1)
|
||||
{
|
||||
pthread_mutexattr_setpshared(&lock->object.mutex.attr, PTHREAD_PROCESS_SHARED);
|
||||
}
|
||||
if ((ret = pthread_mutex_init(&lock->object.mutex._lock, &lock->object.mutex.attr)) < 0)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
lock->lock = swMutex_lock;
|
||||
lock->unlock = swMutex_unlock;
|
||||
lock->trylock = swMutex_trylock;
|
||||
lock->free = swMutex_free;
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
static int swMutex_lock(swLock *lock)
|
||||
{
|
||||
return pthread_mutex_lock(&lock->object.mutex._lock);
|
||||
}
|
||||
|
||||
static int swMutex_unlock(swLock *lock)
|
||||
{
|
||||
return pthread_mutex_unlock(&lock->object.mutex._lock);
|
||||
}
|
||||
|
||||
static int swMutex_trylock(swLock *lock)
|
||||
{
|
||||
return pthread_mutex_trylock(&lock->object.mutex._lock);
|
||||
}
|
||||
|
||||
#ifdef HAVE_MUTEX_TIMEDLOCK
|
||||
int swMutex_lockwait(swLock *lock, int timeout_msec)
|
||||
{
|
||||
struct timespec timeo;
|
||||
timeo.tv_sec = timeout_msec / 1000;
|
||||
timeo.tv_nsec = (timeout_msec - timeo.tv_sec * 1000) * 1000 * 1000;
|
||||
return pthread_mutex_timedlock(&lock->object.mutex._lock, &timeo);
|
||||
}
|
||||
#else
|
||||
int swMutex_lockwait(swLock *lock, int timeout_msec)
|
||||
{
|
||||
int sub = 1;
|
||||
int sleep_ms = 1000;
|
||||
|
||||
if (timeout_msec > 100)
|
||||
{
|
||||
sub = 10;
|
||||
sleep_ms = 10000;
|
||||
}
|
||||
|
||||
while( timeout_msec > 0)
|
||||
{
|
||||
if (pthread_mutex_trylock(&lock->object.mutex._lock) == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
usleep(sleep_ms);
|
||||
timeout_msec -= sub;
|
||||
}
|
||||
}
|
||||
return ETIMEDOUT;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int swMutex_free(swLock *lock)
|
||||
{
|
||||
pthread_mutexattr_destroy(&lock->object.mutex.attr);
|
||||
return pthread_mutex_destroy(&lock->object.mutex._lock);
|
||||
}
|
81
vendor/swoole/src/lock/RWLock.c
vendored
Executable file
81
vendor/swoole/src/lock/RWLock.c
vendored
Executable file
@ -0,0 +1,81 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| 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 HAVE_RWLOCK
|
||||
|
||||
static int swRWLock_lock_rd(swLock *lock);
|
||||
static int swRWLock_lock_rw(swLock *lock);
|
||||
static int swRWLock_unlock(swLock *lock);
|
||||
static int swRWLock_trylock_rw(swLock *lock);
|
||||
static int swRWLock_trylock_rd(swLock *lock);
|
||||
static int swRWLock_free(swLock *lock);
|
||||
|
||||
int swRWLock_create(swLock *lock, int use_in_process)
|
||||
{
|
||||
int ret;
|
||||
bzero(lock, sizeof(swLock));
|
||||
lock->type = SW_RWLOCK;
|
||||
pthread_rwlockattr_init(&lock->object.rwlock.attr);
|
||||
if (use_in_process == 1)
|
||||
{
|
||||
pthread_rwlockattr_setpshared(&lock->object.rwlock.attr, PTHREAD_PROCESS_SHARED);
|
||||
}
|
||||
if ((ret = pthread_rwlock_init(&lock->object.rwlock._lock, &lock->object.rwlock.attr)) < 0)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
lock->lock_rd = swRWLock_lock_rd;
|
||||
lock->lock = swRWLock_lock_rw;
|
||||
lock->unlock = swRWLock_unlock;
|
||||
lock->trylock = swRWLock_trylock_rw;
|
||||
lock->trylock_rd = swRWLock_trylock_rd;
|
||||
lock->free = swRWLock_free;
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
static int swRWLock_lock_rd(swLock *lock)
|
||||
{
|
||||
return pthread_rwlock_rdlock(&lock->object.rwlock._lock);
|
||||
}
|
||||
|
||||
static int swRWLock_lock_rw(swLock *lock)
|
||||
{
|
||||
return pthread_rwlock_wrlock(&lock->object.rwlock._lock);
|
||||
}
|
||||
|
||||
static int swRWLock_unlock(swLock *lock)
|
||||
{
|
||||
return pthread_rwlock_unlock(&lock->object.rwlock._lock);
|
||||
}
|
||||
|
||||
static int swRWLock_trylock_rd(swLock *lock)
|
||||
{
|
||||
return pthread_rwlock_tryrdlock(&lock->object.rwlock._lock);
|
||||
}
|
||||
|
||||
static int swRWLock_trylock_rw(swLock *lock)
|
||||
{
|
||||
return pthread_rwlock_trywrlock(&lock->object.rwlock._lock);
|
||||
}
|
||||
|
||||
static int swRWLock_free(swLock *lock)
|
||||
{
|
||||
return pthread_rwlock_destroy(&lock->object.rwlock._lock);
|
||||
}
|
||||
|
||||
#endif
|
68
vendor/swoole/src/lock/Semaphore.c
vendored
Executable file
68
vendor/swoole/src/lock/Semaphore.c
vendored
Executable file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| 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 <sys/sem.h>
|
||||
|
||||
static int swSem_lock(swLock *lock);
|
||||
static int swSem_unlock(swLock *lock);
|
||||
static int swSem_free(swLock *lock);
|
||||
|
||||
int swSem_create(swLock *lock, key_t key)
|
||||
{
|
||||
int ret;
|
||||
lock->type = SW_SEM;
|
||||
if ((ret = semget(key, 1, IPC_CREAT | 0666)) < 0)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
|
||||
if (semctl(ret, 0, SETVAL, 1) == -1)
|
||||
{
|
||||
swWarn("semctl(SETVAL) failed");
|
||||
return SW_ERR;
|
||||
}
|
||||
lock->object.sem.semid = ret;
|
||||
|
||||
lock->lock = swSem_lock;
|
||||
lock->unlock = swSem_unlock;
|
||||
lock->free = swSem_free;
|
||||
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
static int swSem_unlock(swLock *lock)
|
||||
{
|
||||
struct sembuf sem;
|
||||
sem.sem_flg = SEM_UNDO;
|
||||
sem.sem_num = 0;
|
||||
sem.sem_op = 1;
|
||||
return semop(lock->object.sem.semid, &sem, 1);
|
||||
}
|
||||
|
||||
static int swSem_lock(swLock *lock)
|
||||
{
|
||||
struct sembuf sem;
|
||||
sem.sem_flg = SEM_UNDO;
|
||||
sem.sem_num = 0;
|
||||
sem.sem_op = -1;
|
||||
return semop(lock->object.sem.semid, &sem, 1);
|
||||
}
|
||||
|
||||
static int swSem_free(swLock *lock)
|
||||
{
|
||||
return semctl(lock->object.sem.semid, 0, IPC_RMID);
|
||||
}
|
62
vendor/swoole/src/lock/SpinLock.c
vendored
Executable file
62
vendor/swoole/src/lock/SpinLock.c
vendored
Executable file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| 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 HAVE_SPINLOCK
|
||||
|
||||
static int swSpinLock_lock(swLock *lock);
|
||||
static int swSpinLock_unlock(swLock *lock);
|
||||
static int swSpinLock_trylock(swLock *lock);
|
||||
static int swSpinLock_free(swLock *lock);
|
||||
|
||||
int swSpinLock_create(swLock *lock, int use_in_process)
|
||||
{
|
||||
int ret;
|
||||
bzero(lock, sizeof(swLock));
|
||||
lock->type = SW_SPINLOCK;
|
||||
if ((ret = pthread_spin_init(&lock->object.spinlock.lock_t, use_in_process)) < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
lock->lock = swSpinLock_lock;
|
||||
lock->unlock = swSpinLock_unlock;
|
||||
lock->trylock = swSpinLock_trylock;
|
||||
lock->free = swSpinLock_free;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int swSpinLock_lock(swLock *lock)
|
||||
{
|
||||
return pthread_spin_lock(&lock->object.spinlock.lock_t);
|
||||
}
|
||||
|
||||
static int swSpinLock_unlock(swLock *lock)
|
||||
{
|
||||
return pthread_spin_unlock(&lock->object.spinlock.lock_t);
|
||||
}
|
||||
|
||||
static int swSpinLock_trylock(swLock *lock)
|
||||
{
|
||||
return pthread_spin_trylock(&lock->object.spinlock.lock_t);
|
||||
}
|
||||
|
||||
static int swSpinLock_free(swLock *lock)
|
||||
{
|
||||
return pthread_spin_destroy(&lock->object.spinlock.lock_t);
|
||||
}
|
||||
|
||||
#endif
|
174
vendor/swoole/src/memory/Buffer.c
vendored
Executable file
174
vendor/swoole/src/memory/Buffer.c
vendored
Executable file
@ -0,0 +1,174 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| 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 "buffer.h"
|
||||
|
||||
/**
|
||||
* create new buffer
|
||||
*/
|
||||
swBuffer* swBuffer_new(int trunk_size)
|
||||
{
|
||||
swBuffer *buffer = sw_malloc(sizeof(swBuffer));
|
||||
if (buffer == NULL)
|
||||
{
|
||||
swWarn("malloc for buffer failed. Error: %s[%d]", strerror(errno), errno);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bzero(buffer, sizeof(swBuffer));
|
||||
buffer->trunk_size = trunk_size;
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* create new trunk
|
||||
*/
|
||||
swBuffer_trunk *swBuffer_new_trunk(swBuffer *buffer, uint32_t type, uint32_t size)
|
||||
{
|
||||
swBuffer_trunk *chunk = sw_malloc(sizeof(swBuffer_trunk));
|
||||
if (chunk == NULL)
|
||||
{
|
||||
swWarn("malloc for trunk failed. Error: %s[%d]", strerror(errno), errno);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bzero(chunk, sizeof(swBuffer_trunk));
|
||||
|
||||
//require alloc memory
|
||||
if (type == SW_CHUNK_DATA && size > 0)
|
||||
{
|
||||
void *buf = sw_malloc(size);
|
||||
if (buf == NULL)
|
||||
{
|
||||
swWarn("malloc(%d) for data failed. Error: %s[%d]", size, strerror(errno), errno);
|
||||
sw_free(chunk);
|
||||
return NULL;
|
||||
}
|
||||
chunk->size = size;
|
||||
chunk->store.ptr = buf;
|
||||
}
|
||||
|
||||
chunk->type = type;
|
||||
buffer->trunk_num ++;
|
||||
|
||||
if (buffer->head == NULL)
|
||||
{
|
||||
buffer->tail = buffer->head = chunk;
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer->tail->next = chunk;
|
||||
buffer->tail = chunk;
|
||||
}
|
||||
|
||||
return chunk;
|
||||
}
|
||||
|
||||
/**
|
||||
* pop the head chunk
|
||||
*/
|
||||
void swBuffer_pop_trunk(swBuffer *buffer, swBuffer_trunk *chunk)
|
||||
{
|
||||
if (chunk->next == NULL)
|
||||
{
|
||||
buffer->head = NULL;
|
||||
buffer->tail = NULL;
|
||||
buffer->length = 0;
|
||||
buffer->trunk_num = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer->head = chunk->next;
|
||||
buffer->length -= chunk->length;
|
||||
buffer->trunk_num--;
|
||||
}
|
||||
if (chunk->type == SW_CHUNK_DATA)
|
||||
{
|
||||
sw_free(chunk->store.ptr);
|
||||
}
|
||||
if (chunk->destroy)
|
||||
{
|
||||
chunk->destroy(chunk);
|
||||
}
|
||||
sw_free(chunk);
|
||||
}
|
||||
|
||||
/**
|
||||
* free buffer
|
||||
*/
|
||||
int swBuffer_free(swBuffer *buffer)
|
||||
{
|
||||
volatile swBuffer_trunk *chunk = buffer->head;
|
||||
void * *will_free_trunk; //free the point
|
||||
while (chunk != NULL)
|
||||
{
|
||||
if (chunk->type == SW_CHUNK_DATA)
|
||||
{
|
||||
sw_free(chunk->store.ptr);
|
||||
}
|
||||
will_free_trunk = (void *) chunk;
|
||||
chunk = chunk->next;
|
||||
sw_free(will_free_trunk);
|
||||
}
|
||||
sw_free(buffer);
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* append to buffer queue
|
||||
*/
|
||||
int swBuffer_append(swBuffer *buffer, void *data, uint32_t size)
|
||||
{
|
||||
swBuffer_trunk *chunk = swBuffer_new_trunk(buffer, SW_CHUNK_DATA, size);
|
||||
if (chunk == NULL)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
|
||||
buffer->length += size;
|
||||
chunk->length = size;
|
||||
|
||||
memcpy(chunk->store.ptr, data, size);
|
||||
|
||||
swTraceLog(SW_TRACE_BUFFER, "trunk_n=%d|size=%d|trunk_len=%d|trunk=%p", buffer->trunk_num, size,
|
||||
chunk->length, chunk);
|
||||
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* print buffer
|
||||
*/
|
||||
void swBuffer_debug(swBuffer *buffer, int print_data)
|
||||
{
|
||||
int i = 0;
|
||||
volatile swBuffer_trunk *trunk = buffer->head;
|
||||
printf("%s\n%s\n", SW_START_LINE, __func__);
|
||||
while (trunk != NULL)
|
||||
{
|
||||
i++;
|
||||
printf("%d.\tlen=%d", i, trunk->length);
|
||||
if (print_data)
|
||||
{
|
||||
printf("\tdata=%s", (char *) trunk->store.ptr);
|
||||
}
|
||||
printf("\n");
|
||||
trunk = trunk->next;
|
||||
}
|
||||
printf("%s\n%s\n", SW_END_LINE, __func__);
|
||||
}
|
249
vendor/swoole/src/memory/FixedPool.c
vendored
Executable file
249
vendor/swoole/src/memory/FixedPool.c
vendored
Executable file
@ -0,0 +1,249 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| 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 void swFixedPool_init(swFixedPool *object);
|
||||
static void* swFixedPool_alloc(swMemoryPool *pool, uint32_t size);
|
||||
static void swFixedPool_free(swMemoryPool *pool, void *ptr);
|
||||
static void swFixedPool_destroy(swMemoryPool *pool);
|
||||
|
||||
void swFixedPool_debug_slice(swFixedPool_slice *slice);
|
||||
|
||||
/**
|
||||
* create new FixedPool, random alloc/free fixed size memory
|
||||
*/
|
||||
swMemoryPool* swFixedPool_new(uint32_t slice_num, uint32_t slice_size, uint8_t shared)
|
||||
{
|
||||
size_t size = slice_size * slice_num + slice_num * sizeof(swFixedPool_slice);
|
||||
size_t alloc_size = size + sizeof(swFixedPool) + sizeof(swMemoryPool);
|
||||
void *memory = (shared == 1) ? sw_shm_malloc(alloc_size) : sw_malloc(alloc_size);
|
||||
|
||||
swFixedPool *object = memory;
|
||||
memory += sizeof(swFixedPool);
|
||||
bzero(object, sizeof(swFixedPool));
|
||||
|
||||
object->shared = shared;
|
||||
object->slice_num = slice_num;
|
||||
object->slice_size = slice_size;
|
||||
object->size = size;
|
||||
|
||||
swMemoryPool *pool = memory;
|
||||
memory += sizeof(swMemoryPool);
|
||||
pool->object = object;
|
||||
pool->alloc = swFixedPool_alloc;
|
||||
pool->free = swFixedPool_free;
|
||||
pool->destroy = swFixedPool_destroy;
|
||||
|
||||
object->memory = memory;
|
||||
|
||||
/**
|
||||
* init linked list
|
||||
*/
|
||||
swFixedPool_init(object);
|
||||
|
||||
return pool;
|
||||
}
|
||||
|
||||
/**
|
||||
* create new FixedPool, Using the given memory
|
||||
*/
|
||||
swMemoryPool* swFixedPool_new2(uint32_t slice_size, void *memory, size_t size)
|
||||
{
|
||||
swFixedPool *object = memory;
|
||||
memory += sizeof(swFixedPool);
|
||||
bzero(object, sizeof(swFixedPool));
|
||||
|
||||
object->slice_size = slice_size;
|
||||
object->size = size - sizeof(swMemoryPool) - sizeof(swFixedPool);
|
||||
object->slice_num = object->size / (slice_size + sizeof(swFixedPool_slice));
|
||||
|
||||
swMemoryPool *pool = memory;
|
||||
memory += sizeof(swMemoryPool);
|
||||
bzero(pool, sizeof(swMemoryPool));
|
||||
|
||||
pool->object = object;
|
||||
pool->alloc = swFixedPool_alloc;
|
||||
pool->free = swFixedPool_free;
|
||||
pool->destroy = swFixedPool_destroy;
|
||||
|
||||
object->memory = memory;
|
||||
|
||||
/**
|
||||
* init linked list
|
||||
*/
|
||||
swFixedPool_init(object);
|
||||
|
||||
return pool;
|
||||
}
|
||||
|
||||
/**
|
||||
* linked list
|
||||
*/
|
||||
static void swFixedPool_init(swFixedPool *object)
|
||||
{
|
||||
swFixedPool_slice *slice;
|
||||
void *cur = object->memory;
|
||||
void *max = object->memory + object->size;
|
||||
do
|
||||
{
|
||||
slice = (swFixedPool_slice *) cur;
|
||||
bzero(slice, sizeof(swFixedPool_slice));
|
||||
|
||||
if (object->head != NULL)
|
||||
{
|
||||
object->head->pre = slice;
|
||||
slice->next = object->head;
|
||||
}
|
||||
else
|
||||
{
|
||||
object->tail = slice;
|
||||
}
|
||||
|
||||
object->head = slice;
|
||||
cur += (sizeof(swFixedPool_slice) + object->slice_size);
|
||||
|
||||
if (cur < max)
|
||||
{
|
||||
slice->pre = (swFixedPool_slice *) cur;
|
||||
}
|
||||
else
|
||||
{
|
||||
slice->pre = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
} while (1);
|
||||
}
|
||||
|
||||
static void* swFixedPool_alloc(swMemoryPool *pool, uint32_t size)
|
||||
{
|
||||
swFixedPool *object = pool->object;
|
||||
swFixedPool_slice *slice;
|
||||
|
||||
slice = object->head;
|
||||
|
||||
if (slice->lock == 0)
|
||||
{
|
||||
slice->lock = 1;
|
||||
object->slice_use ++;
|
||||
/**
|
||||
* move next slice to head (idle list)
|
||||
*/
|
||||
object->head = slice->next;
|
||||
slice->next->pre = NULL;
|
||||
|
||||
/*
|
||||
* move this slice to tail (busy list)
|
||||
*/
|
||||
object->tail->next = slice;
|
||||
slice->next = NULL;
|
||||
slice->pre = object->tail;
|
||||
object->tail = slice;
|
||||
|
||||
return slice->data;
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void swFixedPool_free(swMemoryPool *pool, void *ptr)
|
||||
{
|
||||
swFixedPool *object = pool->object;
|
||||
swFixedPool_slice *slice;
|
||||
|
||||
assert(ptr > object->memory && ptr < object->memory + object->size);
|
||||
|
||||
slice = ptr - sizeof(swFixedPool_slice);
|
||||
|
||||
if (slice->lock)
|
||||
{
|
||||
object->slice_use--;
|
||||
}
|
||||
|
||||
slice->lock = 0;
|
||||
|
||||
//list head, AB
|
||||
if (slice->pre == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
//list tail, DE
|
||||
if (slice->next == NULL)
|
||||
{
|
||||
slice->pre->next = NULL;
|
||||
object->tail = slice->pre;
|
||||
}
|
||||
//middle BCD
|
||||
else
|
||||
{
|
||||
slice->pre->next = slice->next;
|
||||
slice->next->pre = slice->pre;
|
||||
}
|
||||
|
||||
slice->pre = NULL;
|
||||
slice->next = object->head;
|
||||
object->head->pre = slice;
|
||||
object->head = slice;
|
||||
}
|
||||
|
||||
static void swFixedPool_destroy(swMemoryPool *pool)
|
||||
{
|
||||
swFixedPool *object = pool->object;
|
||||
if (object->shared)
|
||||
{
|
||||
sw_shm_free(object);
|
||||
}
|
||||
else
|
||||
{
|
||||
sw_free(object);
|
||||
}
|
||||
}
|
||||
|
||||
void swFixedPool_debug(swMemoryPool *pool)
|
||||
{
|
||||
int line = 0;
|
||||
swFixedPool *object = pool->object;
|
||||
swFixedPool_slice *slice = object->head;
|
||||
|
||||
printf("===============================%s=================================\n", __FUNCTION__);
|
||||
while (slice != NULL)
|
||||
{
|
||||
if (slice->next == slice)
|
||||
{
|
||||
printf("-------------------@@@@@@@@@@@@@@@@@@@@@@----------------\n");
|
||||
|
||||
}
|
||||
printf("#%d\t", line);
|
||||
swFixedPool_debug_slice(slice);
|
||||
|
||||
slice = slice->next;
|
||||
line++;
|
||||
if (line > 100)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void swFixedPool_debug_slice(swFixedPool_slice *slice)
|
||||
{
|
||||
printf("Slab[%p]\t", slice);
|
||||
printf("pre=%p\t", slice->pre);
|
||||
printf("next=%p\t", slice->next);
|
||||
printf("tag=%d\t", slice->lock);
|
||||
printf("data=%p\n", slice->data);
|
||||
}
|
50
vendor/swoole/src/memory/Malloc.c
vendored
Executable file
50
vendor/swoole/src/memory/Malloc.c
vendored
Executable file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| 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 void* swMalloc_alloc(swMemoryPool *pool, uint32_t size);
|
||||
static void swMalloc_free(swMemoryPool *pool, void *ptr);
|
||||
static void swMalloc_destroy(swMemoryPool *pool);
|
||||
|
||||
swMemoryPool* swMalloc_new()
|
||||
{
|
||||
swMemoryPool *pool = sw_malloc(sizeof(swMemoryPool));
|
||||
if (pool == NULL)
|
||||
{
|
||||
swSysError("mallc(%ld) failed.", sizeof(swMemoryPool));
|
||||
return NULL;
|
||||
}
|
||||
pool->alloc = swMalloc_alloc;
|
||||
pool->free = swMalloc_free;
|
||||
pool->destroy = swMalloc_destroy;
|
||||
return pool;
|
||||
}
|
||||
|
||||
static void* swMalloc_alloc(swMemoryPool *pool, uint32_t size)
|
||||
{
|
||||
return sw_malloc(size);
|
||||
}
|
||||
|
||||
static void swMalloc_free(swMemoryPool *pool, void *ptr)
|
||||
{
|
||||
sw_free(ptr);
|
||||
}
|
||||
|
||||
static void swMalloc_destroy(swMemoryPool *pool)
|
||||
{
|
||||
sw_free(pool);
|
||||
}
|
143
vendor/swoole/src/memory/MemoryGlobal.c
vendored
Executable file
143
vendor/swoole/src/memory/MemoryGlobal.c
vendored
Executable file
@ -0,0 +1,143 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| 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 SW_MIN_PAGE_SIZE 4096
|
||||
|
||||
typedef struct _swMemoryGlobal_page
|
||||
{
|
||||
struct _swMemoryGlobal_page *next;
|
||||
char memory[0];
|
||||
} swMemoryGlobal_page;
|
||||
|
||||
typedef struct _swMemoryGlobal
|
||||
{
|
||||
uint8_t shared;
|
||||
uint32_t pagesize;
|
||||
swLock lock;
|
||||
swMemoryGlobal_page *root_page;
|
||||
swMemoryGlobal_page *current_page;
|
||||
uint32_t current_offset;
|
||||
} swMemoryGlobal;
|
||||
|
||||
static void *swMemoryGlobal_alloc(swMemoryPool *pool, uint32_t size);
|
||||
static void swMemoryGlobal_free(swMemoryPool *pool, void *ptr);
|
||||
static void swMemoryGlobal_destroy(swMemoryPool *poll);
|
||||
static swMemoryGlobal_page* swMemoryGlobal_new_page(swMemoryGlobal *gm);
|
||||
|
||||
swMemoryPool* swMemoryGlobal_new(uint32_t pagesize, uint8_t shared)
|
||||
{
|
||||
swMemoryGlobal gm, *gm_ptr;
|
||||
assert(pagesize >= SW_MIN_PAGE_SIZE);
|
||||
bzero(&gm, sizeof(swMemoryGlobal));
|
||||
|
||||
gm.shared = shared;
|
||||
gm.pagesize = pagesize;
|
||||
|
||||
swMemoryGlobal_page *page = swMemoryGlobal_new_page(&gm);
|
||||
if (page == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
if (swMutex_create(&gm.lock, shared) < 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gm.root_page = page;
|
||||
|
||||
gm_ptr = (swMemoryGlobal *) page->memory;
|
||||
gm.current_offset += sizeof(swMemoryGlobal);
|
||||
|
||||
swMemoryPool *allocator = (swMemoryPool *) (page->memory + gm.current_offset);
|
||||
gm.current_offset += sizeof(swMemoryPool);
|
||||
|
||||
allocator->object = gm_ptr;
|
||||
allocator->alloc = swMemoryGlobal_alloc;
|
||||
allocator->destroy = swMemoryGlobal_destroy;
|
||||
allocator->free = swMemoryGlobal_free;
|
||||
|
||||
memcpy(gm_ptr, &gm, sizeof(gm));
|
||||
return allocator;
|
||||
}
|
||||
|
||||
static swMemoryGlobal_page* swMemoryGlobal_new_page(swMemoryGlobal *gm)
|
||||
{
|
||||
swMemoryGlobal_page *page = (gm->shared == 1) ? sw_shm_malloc(gm->pagesize) : sw_malloc(gm->pagesize);
|
||||
if (page == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
bzero(page, gm->pagesize);
|
||||
page->next = NULL;
|
||||
|
||||
if (gm->current_page != NULL)
|
||||
{
|
||||
gm->current_page->next = page;
|
||||
}
|
||||
|
||||
gm->current_page = page;
|
||||
gm->current_offset = 0;
|
||||
|
||||
return page;
|
||||
}
|
||||
|
||||
static void *swMemoryGlobal_alloc(swMemoryPool *pool, uint32_t size)
|
||||
{
|
||||
swMemoryGlobal *gm = pool->object;
|
||||
gm->lock.lock(&gm->lock);
|
||||
if (size > gm->pagesize - sizeof(swMemoryGlobal_page))
|
||||
{
|
||||
swWarn("failed to alloc %d bytes, exceed the maximum size[%d].", size, gm->pagesize - (int) sizeof(swMemoryGlobal_page));
|
||||
gm->lock.unlock(&gm->lock);
|
||||
return NULL;
|
||||
}
|
||||
if (gm->current_offset + size > gm->pagesize - sizeof(swMemoryGlobal_page))
|
||||
{
|
||||
swMemoryGlobal_page *page = swMemoryGlobal_new_page(gm);
|
||||
if (page == NULL)
|
||||
{
|
||||
swWarn("swMemoryGlobal_alloc alloc memory error.");
|
||||
gm->lock.unlock(&gm->lock);
|
||||
return NULL;
|
||||
}
|
||||
gm->current_page = page;
|
||||
}
|
||||
void *mem = gm->current_page->memory + gm->current_offset;
|
||||
gm->current_offset += size;
|
||||
gm->lock.unlock(&gm->lock);
|
||||
return mem;
|
||||
}
|
||||
|
||||
static void swMemoryGlobal_free(swMemoryPool *pool, void *ptr)
|
||||
{
|
||||
swWarn("swMemoryGlobal Allocator don't need to release.");
|
||||
}
|
||||
|
||||
static void swMemoryGlobal_destroy(swMemoryPool *poll)
|
||||
{
|
||||
swMemoryGlobal *gm = poll->object;
|
||||
swMemoryGlobal_page *page = gm->root_page;
|
||||
swMemoryGlobal_page *next;
|
||||
|
||||
do
|
||||
{
|
||||
next = page->next;
|
||||
sw_shm_free(page);
|
||||
page = next;
|
||||
} while (page);
|
||||
}
|
211
vendor/swoole/src/memory/RingBuffer.c
vendored
Executable file
211
vendor/swoole/src/memory/RingBuffer.c
vendored
Executable file
@ -0,0 +1,211 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| 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"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t shared;
|
||||
uint8_t status;
|
||||
uint32_t size;
|
||||
uint32_t alloc_offset;
|
||||
uint32_t collect_offset;
|
||||
uint32_t alloc_count;
|
||||
sw_atomic_t free_count;
|
||||
void *memory;
|
||||
} swRingBuffer;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint16_t lock;
|
||||
uint16_t index;
|
||||
uint32_t length;
|
||||
char data[0];
|
||||
} swRingBuffer_item;
|
||||
|
||||
static void swRingBuffer_destory(swMemoryPool *pool);
|
||||
static void* swRingBuffer_alloc(swMemoryPool *pool, uint32_t size);
|
||||
static void swRingBuffer_free(swMemoryPool *pool, void *ptr);
|
||||
|
||||
#ifdef SW_RINGBUFFER_DEBUG
|
||||
static void swRingBuffer_print(swRingBuffer *object, char *prefix);
|
||||
|
||||
static void swRingBuffer_print(swRingBuffer *object, char *prefix)
|
||||
{
|
||||
printf("%s: size=%d, status=%d, alloc_count=%d, free_count=%d, offset=%d, next_offset=%d\n", prefix, object->size,
|
||||
object->status, object->alloc_count, object->free_count, object->alloc_offset, object->collect_offset);
|
||||
}
|
||||
#endif
|
||||
|
||||
swMemoryPool *swRingBuffer_new(uint32_t size, uint8_t shared)
|
||||
{
|
||||
void *mem = (shared == 1) ? sw_shm_malloc(size) : sw_malloc(size);
|
||||
if (mem == NULL)
|
||||
{
|
||||
swWarn("malloc(%d) failed.", size);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
swRingBuffer *object = mem;
|
||||
mem += sizeof(swRingBuffer);
|
||||
bzero(object, sizeof(swRingBuffer));
|
||||
|
||||
object->size = (size - sizeof(swRingBuffer) - sizeof(swMemoryPool));
|
||||
object->shared = shared;
|
||||
|
||||
swMemoryPool *pool = mem;
|
||||
mem += sizeof(swMemoryPool);
|
||||
|
||||
pool->object = object;
|
||||
pool->destroy = swRingBuffer_destory;
|
||||
pool->free = swRingBuffer_free;
|
||||
pool->alloc = swRingBuffer_alloc;
|
||||
|
||||
object->memory = mem;
|
||||
|
||||
swDebug("memory: ptr=%p", mem);
|
||||
|
||||
return pool;
|
||||
}
|
||||
|
||||
static void swRingBuffer_collect(swRingBuffer *object)
|
||||
{
|
||||
swRingBuffer_item *item;
|
||||
sw_atomic_t *free_count = &object->free_count;
|
||||
|
||||
int count = object->free_count;
|
||||
int i;
|
||||
uint32_t n_size;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
item = object->memory + object->collect_offset;
|
||||
if (item->lock == 0)
|
||||
{
|
||||
n_size = item->length + sizeof(swRingBuffer_item);
|
||||
|
||||
object->collect_offset += n_size;
|
||||
|
||||
if (object->collect_offset + sizeof(swRingBuffer_item) >object->size || object->collect_offset >= object->size)
|
||||
{
|
||||
object->collect_offset = 0;
|
||||
object->status = 0;
|
||||
}
|
||||
sw_atomic_fetch_sub(free_count, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void* swRingBuffer_alloc(swMemoryPool *pool, uint32_t size)
|
||||
{
|
||||
assert(size > 0);
|
||||
|
||||
swRingBuffer *object = pool->object;
|
||||
swRingBuffer_item *item;
|
||||
uint32_t capacity;
|
||||
|
||||
uint32_t alloc_size = size + sizeof(swRingBuffer_item);
|
||||
|
||||
if (object->free_count > 0)
|
||||
{
|
||||
swRingBuffer_collect(object);
|
||||
}
|
||||
|
||||
if (object->status == 0)
|
||||
{
|
||||
if (object->alloc_offset + alloc_size >= (object->size - sizeof(swRingBuffer_item)))
|
||||
{
|
||||
uint32_t skip_n = object->size - object->alloc_offset;
|
||||
if (skip_n >= sizeof(swRingBuffer_item))
|
||||
{
|
||||
item = object->memory + object->alloc_offset;
|
||||
item->lock = 0;
|
||||
item->length = skip_n - sizeof(swRingBuffer_item);
|
||||
sw_atomic_t *free_count = &object->free_count;
|
||||
sw_atomic_fetch_add(free_count, 1);
|
||||
}
|
||||
object->alloc_offset = 0;
|
||||
object->status = 1;
|
||||
capacity = object->collect_offset - object->alloc_offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
capacity = object->size - object->alloc_offset;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
capacity = object->collect_offset - object->alloc_offset;
|
||||
}
|
||||
|
||||
if (capacity < alloc_size)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
item = object->memory + object->alloc_offset;
|
||||
item->lock = 1;
|
||||
item->length = size;
|
||||
item->index = object->alloc_count;
|
||||
|
||||
object->alloc_offset += alloc_size;
|
||||
object->alloc_count ++;
|
||||
|
||||
swDebug("alloc: ptr=%p", (void * )((void * )item->data - object->memory));
|
||||
|
||||
return item->data;
|
||||
}
|
||||
|
||||
static void swRingBuffer_free(swMemoryPool *pool, void *ptr)
|
||||
{
|
||||
swRingBuffer *object = pool->object;
|
||||
swRingBuffer_item *item = ptr - sizeof(swRingBuffer_item);
|
||||
|
||||
assert(ptr >= object->memory);
|
||||
assert(ptr <= object->memory + object->size);
|
||||
assert(item->lock == 1);
|
||||
|
||||
if (item->lock != 1)
|
||||
{
|
||||
swDebug("invalid free: index=%d, ptr=%p", item->index, (void * )((void * )item->data - object->memory));
|
||||
}
|
||||
else
|
||||
{
|
||||
item->lock = 0;
|
||||
}
|
||||
|
||||
swDebug("free: ptr=%p", (void * )((void * )item->data - object->memory));
|
||||
|
||||
sw_atomic_t *free_count = &object->free_count;
|
||||
sw_atomic_fetch_add(free_count, 1);
|
||||
}
|
||||
|
||||
static void swRingBuffer_destory(swMemoryPool *pool)
|
||||
{
|
||||
swRingBuffer *object = pool->object;
|
||||
if (object->shared)
|
||||
{
|
||||
sw_shm_free(object);
|
||||
}
|
||||
else
|
||||
{
|
||||
sw_free(object);
|
||||
}
|
||||
}
|
178
vendor/swoole/src/memory/ShareMemory.c
vendored
Executable file
178
vendor/swoole/src/memory/ShareMemory.c
vendored
Executable file
@ -0,0 +1,178 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| 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 <sys/shm.h>
|
||||
|
||||
void* sw_shm_malloc(size_t size)
|
||||
{
|
||||
swShareMemory object;
|
||||
void *mem;
|
||||
size += sizeof(swShareMemory);
|
||||
mem = swShareMemory_mmap_create(&object, size, NULL);
|
||||
if (mem == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(mem, &object, sizeof(swShareMemory));
|
||||
return mem + sizeof(swShareMemory);
|
||||
}
|
||||
}
|
||||
|
||||
void* sw_shm_calloc(size_t num, size_t _size)
|
||||
{
|
||||
swShareMemory object;
|
||||
void *mem;
|
||||
void *ret_mem;
|
||||
int size = sizeof(swShareMemory) + (num * _size);
|
||||
mem = swShareMemory_mmap_create(&object, size, NULL);
|
||||
if (mem == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(mem, &object, sizeof(swShareMemory));
|
||||
ret_mem = mem + sizeof(swShareMemory);
|
||||
bzero(ret_mem, size - sizeof(swShareMemory));
|
||||
return ret_mem;
|
||||
}
|
||||
}
|
||||
|
||||
int sw_shm_protect(void *addr, int flags)
|
||||
{
|
||||
swShareMemory *object = (swShareMemory *) (addr - sizeof(swShareMemory));
|
||||
return mprotect(object, object->size, flags);
|
||||
}
|
||||
|
||||
void sw_shm_free(void *ptr)
|
||||
{
|
||||
swShareMemory *object = ptr - sizeof(swShareMemory);
|
||||
swShareMemory_mmap_free(object);
|
||||
}
|
||||
|
||||
void* sw_shm_realloc(void *ptr, size_t new_size)
|
||||
{
|
||||
swShareMemory *object = ptr - sizeof(swShareMemory);
|
||||
void *new_ptr;
|
||||
new_ptr = sw_shm_malloc(new_size);
|
||||
if (new_ptr == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(new_ptr, ptr, object->size);
|
||||
sw_shm_free(ptr);
|
||||
return new_ptr;
|
||||
}
|
||||
}
|
||||
|
||||
void *swShareMemory_mmap_create(swShareMemory *object, size_t size, char *mapfile)
|
||||
{
|
||||
void *mem;
|
||||
int tmpfd = -1;
|
||||
int flag = MAP_SHARED;
|
||||
bzero(object, sizeof(swShareMemory));
|
||||
|
||||
#ifdef MAP_ANONYMOUS
|
||||
flag |= MAP_ANONYMOUS;
|
||||
#else
|
||||
if (mapfile == NULL)
|
||||
{
|
||||
mapfile = "/dev/zero";
|
||||
}
|
||||
if ((tmpfd = open(mapfile, O_RDWR)) < 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
strncpy(object->mapfile, mapfile, SW_SHM_MMAP_FILE_LEN);
|
||||
object->tmpfd = tmpfd;
|
||||
#endif
|
||||
|
||||
#if defined(SW_USE_HUGEPAGE) && defined(MAP_HUGETLB)
|
||||
if (size > 2 * 1024 * 1024)
|
||||
{
|
||||
flag |= MAP_HUGETLB;
|
||||
}
|
||||
#endif
|
||||
|
||||
mem = mmap(NULL, size, PROT_READ | PROT_WRITE, flag, tmpfd, 0);
|
||||
#ifdef MAP_FAILED
|
||||
if (mem == MAP_FAILED)
|
||||
#else
|
||||
if (!mem)
|
||||
#endif
|
||||
{
|
||||
swWarn("mmap(%ld) failed. Error: %s[%d]", size, strerror(errno), errno);
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
object->size = size;
|
||||
object->mem = mem;
|
||||
return mem;
|
||||
}
|
||||
}
|
||||
|
||||
int swShareMemory_mmap_free(swShareMemory *object)
|
||||
{
|
||||
return munmap(object->mem, object->size);
|
||||
}
|
||||
|
||||
void *swShareMemory_sysv_create(swShareMemory *object, size_t size, int key)
|
||||
{
|
||||
int shmid;
|
||||
void *mem;
|
||||
bzero(object, sizeof(swShareMemory));
|
||||
|
||||
if (key == 0)
|
||||
{
|
||||
key = IPC_PRIVATE;
|
||||
}
|
||||
//SHM_R | SHM_W
|
||||
if ((shmid = shmget(key, size, IPC_CREAT)) < 0)
|
||||
{
|
||||
swSysError("shmget(%d, %ld) failed.", key, size);
|
||||
return NULL;
|
||||
}
|
||||
if ((mem = shmat(shmid, NULL, 0)) == (void *) -1)
|
||||
{
|
||||
swWarn("shmat() failed. Error: %s[%d]", strerror(errno), errno);
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
object->key = key;
|
||||
object->shmid = shmid;
|
||||
object->size = size;
|
||||
object->mem = mem;
|
||||
return mem;
|
||||
}
|
||||
}
|
||||
|
||||
int swShareMemory_sysv_free(swShareMemory *object, int rm)
|
||||
{
|
||||
int shmid = object->shmid;
|
||||
int ret = shmdt(object->mem);
|
||||
if (rm == 1)
|
||||
{
|
||||
shmctl(shmid, IPC_RMID, NULL);
|
||||
}
|
||||
return ret;
|
||||
}
|
483
vendor/swoole/src/memory/Table.c
vendored
Executable file
483
vendor/swoole/src/memory/Table.c
vendored
Executable file
@ -0,0 +1,483 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| 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 "table.h"
|
||||
|
||||
//#define SW_TABLE_DEBUG 1
|
||||
#define SW_TABLE_USE_PHP_HASH
|
||||
|
||||
#ifdef SW_TABLE_DEBUG
|
||||
static int conflict_count = 0;
|
||||
static int insert_count = 0;
|
||||
static int conflict_max_level = 0;
|
||||
#endif
|
||||
|
||||
static void swTableColumn_free(swTableColumn *col);
|
||||
|
||||
static void swTableColumn_free(swTableColumn *col)
|
||||
{
|
||||
swString_free(col->name);
|
||||
sw_free(col);
|
||||
}
|
||||
|
||||
swTable* swTable_new(uint32_t rows_size, float conflict_proportion)
|
||||
{
|
||||
if (rows_size >= 0x80000000)
|
||||
{
|
||||
rows_size = 0x80000000;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t i = 10;
|
||||
while ((1U << i) < rows_size)
|
||||
{
|
||||
i++;
|
||||
}
|
||||
rows_size = 1 << i;
|
||||
}
|
||||
|
||||
if (conflict_proportion > 1.0)
|
||||
{
|
||||
conflict_proportion = 1.0;
|
||||
}
|
||||
else if (conflict_proportion < SW_TABLE_CONFLICT_PROPORTION)
|
||||
{
|
||||
conflict_proportion = SW_TABLE_CONFLICT_PROPORTION;
|
||||
}
|
||||
|
||||
swTable *table = SwooleG.memory_pool->alloc(SwooleG.memory_pool, sizeof(swTable));
|
||||
if (table == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
if (swMutex_create(&table->lock, 1) < 0)
|
||||
{
|
||||
swWarn("mutex create failed.");
|
||||
return NULL;
|
||||
}
|
||||
table->iterator = sw_malloc(sizeof(swTable_iterator));
|
||||
if (!table->iterator)
|
||||
{
|
||||
swWarn("malloc failed.");
|
||||
return NULL;
|
||||
}
|
||||
table->columns = swHashMap_new(SW_HASHMAP_INIT_BUCKET_N, (swHashMap_dtor)swTableColumn_free);
|
||||
if (!table->columns)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
table->size = rows_size;
|
||||
table->mask = rows_size - 1;
|
||||
table->conflict_proportion = conflict_proportion;
|
||||
|
||||
bzero(table->iterator, sizeof(swTable_iterator));
|
||||
table->memory = NULL;
|
||||
return table;
|
||||
}
|
||||
|
||||
int swTableColumn_add(swTable *table, char *name, int len, int type, int size)
|
||||
{
|
||||
swTableColumn *col = sw_malloc(sizeof(swTableColumn));
|
||||
if (!col)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
col->name = swString_dup(name, len);
|
||||
if (!col->name)
|
||||
{
|
||||
sw_free(col);
|
||||
return SW_ERR;
|
||||
}
|
||||
switch(type)
|
||||
{
|
||||
case SW_TABLE_INT:
|
||||
switch(size)
|
||||
{
|
||||
case 1:
|
||||
col->size = 1;
|
||||
col->type = SW_TABLE_INT8;
|
||||
break;
|
||||
case 2:
|
||||
col->size = 2;
|
||||
col->type = SW_TABLE_INT16;
|
||||
break;
|
||||
#ifdef __x86_64__
|
||||
case 8:
|
||||
col->size = 8;
|
||||
col->type = SW_TABLE_INT64;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
col->size = 4;
|
||||
col->type = SW_TABLE_INT32;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case SW_TABLE_FLOAT:
|
||||
col->size = sizeof(double);
|
||||
col->type = SW_TABLE_FLOAT;
|
||||
break;
|
||||
case SW_TABLE_STRING:
|
||||
col->size = size + sizeof(swTable_string_length_t);
|
||||
col->type = SW_TABLE_STRING;
|
||||
break;
|
||||
default:
|
||||
swWarn("unkown column type.");
|
||||
swTableColumn_free(col);
|
||||
return SW_ERR;
|
||||
}
|
||||
col->index = table->item_size;
|
||||
table->item_size += col->size;
|
||||
table->column_num ++;
|
||||
return swHashMap_add(table->columns, name, len, col);
|
||||
}
|
||||
|
||||
size_t swTable_get_memory_size(swTable *table)
|
||||
{
|
||||
/**
|
||||
* table size + conflict size
|
||||
*/
|
||||
size_t row_num = table->size * (1 + table->conflict_proportion);
|
||||
|
||||
/*
|
||||
* header + data
|
||||
*/
|
||||
size_t row_memory_size = sizeof(swTableRow) + table->item_size;
|
||||
|
||||
/**
|
||||
* row data & header
|
||||
*/
|
||||
size_t memory_size = row_num * row_memory_size;
|
||||
|
||||
/**
|
||||
* memory pool for conflict rows
|
||||
*/
|
||||
memory_size += sizeof(swMemoryPool) + sizeof(swFixedPool) + ((row_num - table->size) * sizeof(swFixedPool_slice));
|
||||
|
||||
/**
|
||||
* for iterator, Iterate through all the elements
|
||||
*/
|
||||
memory_size += table->size * sizeof(swTableRow *);
|
||||
|
||||
return memory_size;
|
||||
}
|
||||
|
||||
int swTable_create(swTable *table)
|
||||
{
|
||||
size_t memory_size = swTable_get_memory_size(table);
|
||||
size_t row_memory_size = sizeof(swTableRow) + table->item_size;
|
||||
|
||||
void *memory = sw_shm_malloc(memory_size);
|
||||
if (memory == NULL)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
|
||||
table->memory_size = memory_size;
|
||||
table->memory = memory;
|
||||
|
||||
table->rows = memory;
|
||||
memory += table->size * sizeof(swTableRow *);
|
||||
memory_size -= table->size * sizeof(swTableRow *);
|
||||
|
||||
#if SW_TABLE_USE_SPINLOCK == 0
|
||||
pthread_mutexattr_t attr;
|
||||
pthread_mutexattr_init(&attr);
|
||||
pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
|
||||
pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_INHERIT);
|
||||
pthread_mutexattr_setrobust_np(&attr, PTHREAD_MUTEX_ROBUST_NP);
|
||||
#endif
|
||||
|
||||
int i;
|
||||
for (i = 0; i < table->size; i++)
|
||||
{
|
||||
table->rows[i] = memory + (row_memory_size * i);
|
||||
memset(table->rows[i], 0, sizeof(swTableRow));
|
||||
#if SW_TABLE_USE_SPINLOCK == 0
|
||||
pthread_mutex_init(&table->rows[i]->lock, &attr);
|
||||
#endif
|
||||
}
|
||||
|
||||
memory += row_memory_size * table->size;
|
||||
memory_size -= row_memory_size * table->size;
|
||||
table->pool = swFixedPool_new2(row_memory_size, memory, memory_size);
|
||||
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
void swTable_free(swTable *table)
|
||||
{
|
||||
#ifdef SW_TABLE_DEBUG
|
||||
printf("swoole_table: size=%d, conflict_count=%d, conflict_max_level=%d, insert_count=%d\n", table->size,
|
||||
conflict_count, conflict_max_level, insert_count);
|
||||
#endif
|
||||
|
||||
swHashMap_free(table->columns);
|
||||
sw_free(table->iterator);
|
||||
if (table->memory)
|
||||
{
|
||||
sw_shm_free(table->memory);
|
||||
}
|
||||
}
|
||||
|
||||
static sw_inline swTableRow* swTable_hash(swTable *table, char *key, int keylen)
|
||||
{
|
||||
#ifdef SW_TABLE_USE_PHP_HASH
|
||||
uint64_t hashv = swoole_hash_php(key, keylen);
|
||||
#else
|
||||
uint64_t hashv = swoole_hash_austin(key, keylen);
|
||||
#endif
|
||||
uint64_t index = hashv & table->mask;
|
||||
assert(index < table->size);
|
||||
return table->rows[index];
|
||||
}
|
||||
|
||||
void swTable_iterator_rewind(swTable *table)
|
||||
{
|
||||
bzero(table->iterator, sizeof(swTable_iterator));
|
||||
}
|
||||
|
||||
static sw_inline swTableRow* swTable_iterator_get(swTable *table, uint32_t index)
|
||||
{
|
||||
swTableRow *row = table->rows[index];
|
||||
return row->active ? row : NULL;
|
||||
}
|
||||
|
||||
swTableRow* swTable_iterator_current(swTable *table)
|
||||
{
|
||||
return table->iterator->row;
|
||||
}
|
||||
|
||||
void swTable_iterator_forward(swTable *table)
|
||||
{
|
||||
for (; table->iterator->absolute_index < table->size; table->iterator->absolute_index++)
|
||||
{
|
||||
swTableRow *row = swTable_iterator_get(table, table->iterator->absolute_index);
|
||||
if (row == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else if (row->next == NULL)
|
||||
{
|
||||
table->iterator->absolute_index++;
|
||||
table->iterator->row = row;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
int i = 0;
|
||||
for (;; i++)
|
||||
{
|
||||
if (row == NULL)
|
||||
{
|
||||
table->iterator->collision_index = 0;
|
||||
break;
|
||||
}
|
||||
if (i == table->iterator->collision_index)
|
||||
{
|
||||
table->iterator->collision_index++;
|
||||
table->iterator->row = row;
|
||||
return;
|
||||
}
|
||||
row = row->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
table->iterator->row = NULL;
|
||||
}
|
||||
|
||||
swTableRow* swTableRow_get(swTable *table, char *key, int keylen, swTableRow** rowlock)
|
||||
{
|
||||
if (keylen > SW_TABLE_KEY_SIZE)
|
||||
{
|
||||
keylen = SW_TABLE_KEY_SIZE;
|
||||
}
|
||||
|
||||
swTableRow *row = swTable_hash(table, key, keylen);
|
||||
*rowlock = row;
|
||||
swTableRow_lock(row);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (strncmp(row->key, key, keylen) == 0)
|
||||
{
|
||||
if (!row->active)
|
||||
{
|
||||
row = NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
else if (row->next == NULL)
|
||||
{
|
||||
row = NULL;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
row = row->next;
|
||||
}
|
||||
}
|
||||
|
||||
return row;
|
||||
}
|
||||
|
||||
swTableRow* swTableRow_set(swTable *table, char *key, int keylen, swTableRow **rowlock)
|
||||
{
|
||||
if (keylen > SW_TABLE_KEY_SIZE)
|
||||
{
|
||||
keylen = SW_TABLE_KEY_SIZE;
|
||||
}
|
||||
|
||||
swTableRow *row = swTable_hash(table, key, keylen);
|
||||
*rowlock = row;
|
||||
swTableRow_lock(row);
|
||||
|
||||
#ifdef SW_TABLE_DEBUG
|
||||
int _conflict_level = 0;
|
||||
#endif
|
||||
|
||||
if (row->active)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
if (strncmp(row->key, key, keylen) == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (row->next == NULL)
|
||||
{
|
||||
table->lock.lock(&table->lock);
|
||||
swTableRow *new_row = table->pool->alloc(table->pool, 0);
|
||||
|
||||
#ifdef SW_TABLE_DEBUG
|
||||
conflict_count ++;
|
||||
if (_conflict_level > conflict_max_level)
|
||||
{
|
||||
conflict_max_level = _conflict_level;
|
||||
}
|
||||
|
||||
#endif
|
||||
table->lock.unlock(&table->lock);
|
||||
|
||||
if (!new_row)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
//add row_num
|
||||
bzero(new_row, sizeof(swTableRow));
|
||||
sw_atomic_fetch_add(&(table->row_num), 1);
|
||||
row->next = new_row;
|
||||
row = new_row;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
row = row->next;
|
||||
#ifdef SW_TABLE_DEBUG
|
||||
_conflict_level++;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef SW_TABLE_DEBUG
|
||||
insert_count ++;
|
||||
#endif
|
||||
sw_atomic_fetch_add(&(table->row_num), 1);
|
||||
}
|
||||
|
||||
memcpy(row->key, key, keylen);
|
||||
row->active = 1;
|
||||
return row;
|
||||
}
|
||||
|
||||
int swTableRow_del(swTable *table, char *key, int keylen)
|
||||
{
|
||||
if (keylen > SW_TABLE_KEY_SIZE)
|
||||
{
|
||||
keylen = SW_TABLE_KEY_SIZE;
|
||||
}
|
||||
|
||||
swTableRow *row = swTable_hash(table, key, keylen);
|
||||
//no exists
|
||||
if (!row->active)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
|
||||
swTableRow_lock(row);
|
||||
if (row->next == NULL)
|
||||
{
|
||||
if (strncmp(row->key, key, keylen) == 0)
|
||||
{
|
||||
bzero(row, sizeof(swTableRow) + table->item_size);
|
||||
goto delete_element;
|
||||
}
|
||||
else
|
||||
{
|
||||
goto not_exists;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
swTableRow *tmp = row;
|
||||
swTableRow *prev = NULL;
|
||||
|
||||
while (tmp)
|
||||
{
|
||||
if ((strncmp(tmp->key, key, keylen) == 0))
|
||||
{
|
||||
break;
|
||||
}
|
||||
prev = tmp;
|
||||
tmp = tmp->next;
|
||||
}
|
||||
|
||||
if (tmp == NULL)
|
||||
{
|
||||
not_exists:
|
||||
swTableRow_unlock(row);
|
||||
return SW_ERR;
|
||||
}
|
||||
|
||||
//when the deleting element is root, we should move the first element's data to root,
|
||||
//and remove the element from the collision list.
|
||||
if (tmp == row)
|
||||
{
|
||||
tmp = tmp->next;
|
||||
row->next = tmp->next;
|
||||
memcpy(row->key, tmp->key, strlen(tmp->key));
|
||||
memcpy(row->data, tmp->data, table->item_size);
|
||||
}
|
||||
if (prev)
|
||||
{
|
||||
prev->next = tmp->next;
|
||||
}
|
||||
table->lock.lock(&table->lock);
|
||||
bzero(tmp, sizeof(swTableRow) + table->item_size);
|
||||
table->pool->free(table->pool, tmp);
|
||||
table->lock.unlock(&table->lock);
|
||||
}
|
||||
|
||||
delete_element:
|
||||
sw_atomic_fetch_sub(&(table->row_num), 1);
|
||||
swTableRow_unlock(row);
|
||||
|
||||
return SW_OK;
|
||||
}
|
1548
vendor/swoole/src/network/Client.c
vendored
Executable file
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
374
vendor/swoole/src/network/Connection.c
vendored
Executable 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
485
vendor/swoole/src/network/DNS.c
vendored
Executable 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
642
vendor/swoole/src/network/Manager.c
vendored
Executable 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
757
vendor/swoole/src/network/Port.c
vendored
Executable 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
828
vendor/swoole/src/network/ProcessPool.c
vendored
Executable 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
582
vendor/swoole/src/network/ReactorProcess.c
vendored
Executable 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(¬ify_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, ¬ify_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
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
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
169
vendor/swoole/src/network/Stream.c
vendored
Executable 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
320
vendor/swoole/src/network/TaskWorker.c
vendored
Executable 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
186
vendor/swoole/src/network/ThreadPool.c
vendored
Executable 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
135
vendor/swoole/src/network/TimeWheel.c
vendored
Executable 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
245
vendor/swoole/src/network/Timer.c
vendored
Executable 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
897
vendor/swoole/src/network/Worker.c
vendored
Executable 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;
|
||||
}
|
676
vendor/swoole/src/os/base.c
vendored
Executable file
676
vendor/swoole/src/os/base.c
vendored
Executable file
@ -0,0 +1,676 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| Swoole |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 2012-2018 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 "async.h"
|
||||
#include <sys/file.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
swAsyncIO SwooleAIO;
|
||||
swPipe swoole_aio_pipe;
|
||||
|
||||
static void swAioBase_destroy();
|
||||
static int swAioBase_read(int fd, void *inbuf, size_t size, off_t offset);
|
||||
static int swAioBase_write(int fd, void *inbuf, size_t size, off_t offset);
|
||||
static int swAioBase_thread_onTask(swThreadPool *pool, void *task, int task_len);
|
||||
static int swAioBase_onFinish(swReactor *reactor, swEvent *event);
|
||||
|
||||
static void swAio_handler_read(swAio_event *event);
|
||||
static void swAio_handler_write(swAio_event *event);
|
||||
static void swAio_handler_gethostbyname(swAio_event *event);
|
||||
static void swAio_handler_getaddrinfo(swAio_event *event);
|
||||
static void swAio_handler_stream_get_line(swAio_event *event);
|
||||
static void swAio_handler_read_file(swAio_event *event);
|
||||
static void swAio_handler_write_file(swAio_event *event);
|
||||
|
||||
static swThreadPool swAioBase_thread_pool;
|
||||
static int swAioBase_pipe_read;
|
||||
static int swAioBase_pipe_write;
|
||||
|
||||
int swAio_init(void)
|
||||
{
|
||||
if (SwooleAIO.init)
|
||||
{
|
||||
swWarn("AIO has already been initialized");
|
||||
return SW_ERR;
|
||||
}
|
||||
if (!SwooleG.main_reactor)
|
||||
{
|
||||
swWarn("No eventloop, cannot initialized");
|
||||
return SW_ERR;
|
||||
}
|
||||
return swAioBase_init(SW_AIO_EVENT_NUM);
|
||||
}
|
||||
|
||||
void swAio_free(void)
|
||||
{
|
||||
if (!SwooleAIO.init)
|
||||
{
|
||||
return;
|
||||
}
|
||||
SwooleAIO.destroy();
|
||||
SwooleAIO.init = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* for test
|
||||
*/
|
||||
void swAio_callback_test(swAio_event *aio_event)
|
||||
{
|
||||
printf("content=%s\n", (char *)aio_event->buf);
|
||||
printf("fd: %d, request_type: %s, offset: %ld, length: %lu\n", aio_event->fd,
|
||||
(aio_event == SW_AIO_READ) ? "READ" : "WRITE", (long)aio_event->offset, aio_event->nbytes);
|
||||
SwooleG.running = 0;
|
||||
}
|
||||
|
||||
#ifndef HAVE_DAEMON
|
||||
int daemon(int nochdir, int noclose)
|
||||
{
|
||||
pid_t pid;
|
||||
|
||||
if (!nochdir && chdir("/") != 0)
|
||||
{
|
||||
swWarn("chdir() failed. Error: %s[%d]", strerror(errno), errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!noclose)
|
||||
{
|
||||
int fd = open("/dev/null", O_RDWR);
|
||||
if (fd < 0)
|
||||
{
|
||||
swWarn("open() failed. Error: %s[%d]", strerror(errno), errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (dup2(fd, 0) < 0 || dup2(fd, 1) < 0 || dup2(fd, 2) < 0)
|
||||
{
|
||||
close(fd);
|
||||
swWarn("dup2() failed. Error: %s[%d]", strerror(errno), errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
pid = fork();
|
||||
if (pid < 0)
|
||||
{
|
||||
swWarn("fork() failed. Error: %s[%d]", strerror(errno), errno);
|
||||
return -1;
|
||||
}
|
||||
if (pid > 0)
|
||||
{
|
||||
_exit(0);
|
||||
}
|
||||
if (setsid() < 0)
|
||||
{
|
||||
swWarn("setsid() failed. Error: %s[%d]", strerror(errno), errno);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int swAioBase_onFinish(swReactor *reactor, swEvent *event)
|
||||
{
|
||||
int i;
|
||||
swAio_event *events[SW_AIO_EVENT_NUM];
|
||||
int n = read(event->fd, events, sizeof(swAio_event*) * SW_AIO_EVENT_NUM);
|
||||
if (n < 0)
|
||||
{
|
||||
swWarn("read() failed. Error: %s[%d]", strerror(errno), errno);
|
||||
return SW_ERR;
|
||||
}
|
||||
for (i = 0; i < n / sizeof(swAio_event*); i++)
|
||||
{
|
||||
if (events[i]->callback)
|
||||
{
|
||||
events[i]->callback(events[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
SwooleAIO.callback(events[i]);
|
||||
}
|
||||
SwooleAIO.task_num--;
|
||||
sw_free(events[i]);
|
||||
}
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
int swAioBase_init(int max_aio_events)
|
||||
{
|
||||
if (swPipeBase_create(&swoole_aio_pipe, 0) < 0)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
if (swMutex_create(&SwooleAIO.lock, 0) < 0)
|
||||
{
|
||||
swWarn("create mutex lock error.");
|
||||
return SW_ERR;
|
||||
}
|
||||
if (SwooleAIO.thread_num <= 0)
|
||||
{
|
||||
SwooleAIO.thread_num = SW_AIO_THREAD_NUM_DEFAULT;
|
||||
}
|
||||
if (swThreadPool_create(&swAioBase_thread_pool, SwooleAIO.thread_num) < 0)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
|
||||
swAioBase_thread_pool.onTask = swAioBase_thread_onTask;
|
||||
|
||||
swAioBase_pipe_read = swoole_aio_pipe.getFd(&swoole_aio_pipe, 0);
|
||||
swAioBase_pipe_write = swoole_aio_pipe.getFd(&swoole_aio_pipe, 1);
|
||||
|
||||
SwooleAIO.handlers[SW_AIO_READ] = swAio_handler_read;
|
||||
SwooleAIO.handlers[SW_AIO_WRITE] = swAio_handler_write;
|
||||
SwooleAIO.handlers[SW_AIO_GETHOSTBYNAME] = swAio_handler_gethostbyname;
|
||||
SwooleAIO.handlers[SW_AIO_GETADDRINFO] = swAio_handler_getaddrinfo;
|
||||
SwooleAIO.handlers[SW_AIO_STREAM_GET_LINE] = swAio_handler_stream_get_line;
|
||||
SwooleAIO.handlers[SW_AIO_READ_FILE] = swAio_handler_read_file;
|
||||
SwooleAIO.handlers[SW_AIO_WRITE_FILE] = swAio_handler_write_file;
|
||||
|
||||
SwooleG.main_reactor->setHandle(SwooleG.main_reactor, SW_FD_AIO, swAioBase_onFinish);
|
||||
SwooleG.main_reactor->add(SwooleG.main_reactor, swAioBase_pipe_read, SW_FD_AIO);
|
||||
|
||||
if (swThreadPool_run(&swAioBase_thread_pool) < 0)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
|
||||
SwooleAIO.destroy = swAioBase_destroy;
|
||||
SwooleAIO.read = swAioBase_read;
|
||||
SwooleAIO.write = swAioBase_write;
|
||||
SwooleAIO.init = 1;
|
||||
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
static void swAio_handler_read(swAio_event *event)
|
||||
{
|
||||
int ret = -1;
|
||||
if (flock(event->fd, LOCK_SH) < 0)
|
||||
{
|
||||
swSysError("flock(%d, LOCK_SH) failed.", event->fd);
|
||||
event->ret = -1;
|
||||
event->error = errno;
|
||||
return;
|
||||
}
|
||||
while (1)
|
||||
{
|
||||
ret = pread(event->fd, event->buf, event->nbytes, event->offset);
|
||||
if (ret < 0 && (errno == EINTR || errno == EAGAIN))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (flock(event->fd, LOCK_UN) < 0)
|
||||
{
|
||||
swSysError("flock(%d, LOCK_UN) failed.", event->fd);
|
||||
}
|
||||
event->ret = ret;
|
||||
}
|
||||
|
||||
static inline char* find_eol(char *buf, size_t size)
|
||||
{
|
||||
char *eol = memchr(buf, '\n', size);
|
||||
if (!eol)
|
||||
{
|
||||
eol = memchr(buf, '\r', size);
|
||||
}
|
||||
return eol;
|
||||
}
|
||||
|
||||
static void swAio_handler_stream_get_line(swAio_event *event)
|
||||
{
|
||||
int ret = -1;
|
||||
if (flock(event->fd, LOCK_SH) < 0)
|
||||
{
|
||||
swSysError("flock(%d, LOCK_SH) failed.", event->fd);
|
||||
event->ret = -1;
|
||||
event->error = errno;
|
||||
return;
|
||||
}
|
||||
|
||||
off_t readpos = event->offset;
|
||||
off_t writepos = (long) event->req;
|
||||
size_t avail = 0;
|
||||
char *eol;
|
||||
char *tmp;
|
||||
|
||||
char *read_buf = event->buf;
|
||||
int read_n = event->nbytes;
|
||||
|
||||
while (1)
|
||||
{
|
||||
avail = writepos - readpos;
|
||||
|
||||
swTraceLog(SW_TRACE_AIO, "readpos=%ld, writepos=%ld", (long)readpos, (long)writepos);
|
||||
|
||||
if (avail > 0)
|
||||
{
|
||||
tmp = event->buf + readpos;
|
||||
eol = find_eol(tmp, avail);
|
||||
if (eol)
|
||||
{
|
||||
event->buf = tmp;
|
||||
event->ret = (eol - tmp) + 1;
|
||||
readpos += event->ret;
|
||||
goto _return;
|
||||
}
|
||||
else if (readpos == 0)
|
||||
{
|
||||
if (writepos == event->nbytes)
|
||||
{
|
||||
writepos = 0;
|
||||
event->ret = event->nbytes;
|
||||
goto _return;
|
||||
}
|
||||
else
|
||||
{
|
||||
event->flags = SW_AIO_EOF;
|
||||
((char*) event->buf)[writepos] = '\0';
|
||||
event->ret = writepos;
|
||||
writepos = 0;
|
||||
goto _return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
memmove(event->buf, event->buf + readpos, avail);
|
||||
writepos = avail;
|
||||
read_buf = event->buf + writepos;
|
||||
read_n = event->nbytes - writepos;
|
||||
readpos = 0;
|
||||
goto _readfile;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_readfile: while (1)
|
||||
{
|
||||
ret = read(event->fd, read_buf, read_n);
|
||||
if (ret < 0 && (errno == EINTR || errno == EAGAIN))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (ret > 0)
|
||||
{
|
||||
writepos += ret;
|
||||
}
|
||||
else if (ret == 0)
|
||||
{
|
||||
event->flags = SW_AIO_EOF;
|
||||
if (writepos > 0)
|
||||
{
|
||||
event->ret = writepos;
|
||||
}
|
||||
else
|
||||
{
|
||||
((char*) event->buf)[0] = '\0';
|
||||
event->ret = 0;
|
||||
}
|
||||
readpos = writepos = 0;
|
||||
goto _return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_return:
|
||||
if (flock(event->fd, LOCK_UN) < 0)
|
||||
{
|
||||
swSysError("flock(%d, LOCK_UN) failed.", event->fd);
|
||||
}
|
||||
event->offset = readpos;
|
||||
event->req = (void *) (long) writepos;
|
||||
}
|
||||
|
||||
static void swAio_handler_read_file(swAio_event *event)
|
||||
{
|
||||
int ret = -1;
|
||||
int fd = open(event->req, O_RDONLY);
|
||||
if (fd < 0)
|
||||
{
|
||||
swSysError("open(%s, O_RDONLY) failed.", (char * )event->req);
|
||||
event->ret = ret;
|
||||
event->error = errno;
|
||||
return;
|
||||
}
|
||||
struct stat file_stat;
|
||||
if (fstat(fd, &file_stat) < 0)
|
||||
{
|
||||
swSysError("fstat(%s) failed.", (char * )event->req);
|
||||
_error: close(fd);
|
||||
event->ret = ret;
|
||||
event->error = errno;
|
||||
return;
|
||||
}
|
||||
if ((file_stat.st_mode & S_IFMT) != S_IFREG)
|
||||
{
|
||||
errno = EISDIR;
|
||||
goto _error;
|
||||
}
|
||||
|
||||
long filesize = file_stat.st_size;
|
||||
if (filesize == 0)
|
||||
{
|
||||
errno = SW_ERROR_FILE_EMPTY;
|
||||
goto _error;
|
||||
}
|
||||
|
||||
if (flock(fd, LOCK_SH) < 0)
|
||||
{
|
||||
swSysError("flock(%d, LOCK_SH) failed.", event->fd);
|
||||
goto _error;
|
||||
}
|
||||
|
||||
event->buf = sw_malloc(filesize);
|
||||
if (event->buf == NULL)
|
||||
{
|
||||
goto _error;
|
||||
}
|
||||
int readn = swoole_sync_readfile(fd, event->buf, (int) filesize);
|
||||
if (flock(fd, LOCK_UN) < 0)
|
||||
{
|
||||
swSysError("flock(%d, LOCK_UN) failed.", event->fd);
|
||||
}
|
||||
close(fd);
|
||||
event->ret = readn;
|
||||
event->error = 0;
|
||||
}
|
||||
|
||||
static void swAio_handler_write_file(swAio_event *event)
|
||||
{
|
||||
int ret = -1;
|
||||
int fd = open(event->req, event->flags, 0644);
|
||||
if (fd < 0)
|
||||
{
|
||||
swSysError("open(%s, %d) failed.", (char * )event->req, event->flags);
|
||||
event->ret = ret;
|
||||
event->error = errno;
|
||||
return;
|
||||
}
|
||||
if (flock(fd, LOCK_EX) < 0)
|
||||
{
|
||||
swSysError("flock(%d, LOCK_EX) failed.", event->fd);
|
||||
event->ret = ret;
|
||||
event->error = errno;
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
int written = swoole_sync_writefile(fd, event->buf, event->nbytes);
|
||||
if (event->flags & SW_AIO_WRITE_FSYNC)
|
||||
{
|
||||
if (fsync(fd) < 0)
|
||||
{
|
||||
swSysError("fsync(%d) failed.", event->fd);
|
||||
}
|
||||
}
|
||||
if (flock(fd, LOCK_UN) < 0)
|
||||
{
|
||||
swSysError("flock(%d, LOCK_UN) failed.", event->fd);
|
||||
}
|
||||
close(fd);
|
||||
event->ret = written;
|
||||
event->error = 0;
|
||||
}
|
||||
|
||||
static void swAio_handler_write(swAio_event *event)
|
||||
{
|
||||
int ret = -1;
|
||||
if (flock(event->fd, LOCK_EX) < 0)
|
||||
{
|
||||
swSysError("flock(%d, LOCK_EX) failed.", event->fd);
|
||||
return;
|
||||
}
|
||||
if (event->offset == 0)
|
||||
{
|
||||
ret = write(event->fd, event->buf, event->nbytes);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = pwrite(event->fd, event->buf, event->nbytes, event->offset);
|
||||
}
|
||||
if (event->flags & SW_AIO_WRITE_FSYNC)
|
||||
{
|
||||
if (fsync(event->fd) < 0)
|
||||
{
|
||||
swSysError("fsync(%d) failed.", event->fd);
|
||||
}
|
||||
}
|
||||
if (flock(event->fd, LOCK_UN) < 0)
|
||||
{
|
||||
swSysError("flock(%d, LOCK_UN) failed.", event->fd);
|
||||
}
|
||||
event->ret = ret;
|
||||
}
|
||||
|
||||
static void swAio_handler_gethostbyname(swAio_event *event)
|
||||
{
|
||||
struct in_addr addr_v4;
|
||||
struct in6_addr addr_v6;
|
||||
int ret;
|
||||
|
||||
#ifndef HAVE_GETHOSTBYNAME2_R
|
||||
SwooleAIO.lock.lock(&SwooleAIO.lock);
|
||||
#endif
|
||||
if (event->flags == AF_INET6)
|
||||
{
|
||||
ret = swoole_gethostbyname(AF_INET6, event->buf, (char *) &addr_v6);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = swoole_gethostbyname(AF_INET, event->buf, (char *) &addr_v4);
|
||||
}
|
||||
bzero(event->buf, event->nbytes);
|
||||
#ifndef HAVE_GETHOSTBYNAME2_R
|
||||
SwooleAIO.lock.unlock(&SwooleAIO.lock);
|
||||
#endif
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
event->error = h_errno;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (inet_ntop(event->flags == AF_INET6 ? AF_INET6 : AF_INET,
|
||||
event->flags == AF_INET6 ? (void *) &addr_v6 : (void *) &addr_v4, event->buf, event->nbytes) == NULL)
|
||||
{
|
||||
ret = -1;
|
||||
event->error = SW_ERROR_BAD_IPV6_ADDRESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
event->error = 0;
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
event->ret = ret;
|
||||
}
|
||||
|
||||
static void swAio_handler_getaddrinfo(swAio_event *event)
|
||||
{
|
||||
swRequest_getaddrinfo *req = (swRequest_getaddrinfo *) event->req;
|
||||
event->ret = swoole_getaddrinfo(req);
|
||||
event->error = req->error;
|
||||
}
|
||||
|
||||
static int swAioBase_thread_onTask(swThreadPool *pool, void *task, int task_len)
|
||||
{
|
||||
swAio_event *event = task;
|
||||
if (event->type >= SW_AIO_HANDLER_MAX_SIZE || SwooleAIO.handlers[event->type] == NULL)
|
||||
{
|
||||
event->error = SW_ERROR_AIO_BAD_REQUEST;
|
||||
event->ret = -1;
|
||||
goto _error;
|
||||
}
|
||||
|
||||
SwooleAIO.handlers[event->type](event);
|
||||
|
||||
swTrace("aio_thread ok. ret=%d, error=%d", event->ret, event->error);
|
||||
|
||||
_error: do
|
||||
{
|
||||
SwooleAIO.lock.lock(&SwooleAIO.lock);
|
||||
int ret = write(swAioBase_pipe_write, &task, sizeof(task));
|
||||
SwooleAIO.lock.unlock(&SwooleAIO.lock);
|
||||
if (ret < 0)
|
||||
{
|
||||
if (errno == EAGAIN)
|
||||
{
|
||||
swYield();
|
||||
continue;
|
||||
}
|
||||
else if (errno == EINTR)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
swSysError("sendto swoole_aio_pipe_write failed.");
|
||||
}
|
||||
}
|
||||
break;
|
||||
} while (1);
|
||||
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
static int swAioBase_write(int fd, void *inbuf, size_t size, off_t offset)
|
||||
{
|
||||
swAio_event *aio_ev = (swAio_event *) sw_malloc(sizeof(swAio_event));
|
||||
if (aio_ev == NULL)
|
||||
{
|
||||
swWarn("malloc failed.");
|
||||
return SW_ERR;
|
||||
}
|
||||
bzero(aio_ev, sizeof(swAio_event));
|
||||
aio_ev->fd = fd;
|
||||
aio_ev->buf = inbuf;
|
||||
aio_ev->type = SW_AIO_WRITE;
|
||||
aio_ev->nbytes = size;
|
||||
aio_ev->offset = offset;
|
||||
aio_ev->task_id = SwooleAIO.current_id++;
|
||||
|
||||
if (swThreadPool_dispatch(&swAioBase_thread_pool, aio_ev, sizeof(aio_ev)) < 0)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
else
|
||||
{
|
||||
SwooleAIO.task_num++;
|
||||
return aio_ev->task_id;
|
||||
}
|
||||
}
|
||||
|
||||
int swAio_dns_lookup(void *hostname, void *ip_addr, size_t size)
|
||||
{
|
||||
swAio_event *aio_ev = (swAio_event *) sw_malloc(sizeof(swAio_event));
|
||||
if (aio_ev == NULL)
|
||||
{
|
||||
swWarn("malloc failed.");
|
||||
return SW_ERR;
|
||||
}
|
||||
|
||||
bzero(aio_ev, sizeof(swAio_event));
|
||||
aio_ev->buf = ip_addr;
|
||||
aio_ev->req = hostname;
|
||||
aio_ev->type = SW_AIO_GETHOSTBYNAME;
|
||||
aio_ev->nbytes = size;
|
||||
aio_ev->task_id = SwooleAIO.current_id++;
|
||||
|
||||
if (swThreadPool_dispatch(&swAioBase_thread_pool, aio_ev, sizeof(aio_ev)) < 0)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
else
|
||||
{
|
||||
SwooleAIO.task_num++;
|
||||
return aio_ev->task_id;
|
||||
}
|
||||
}
|
||||
|
||||
int swAio_dispatch(swAio_event *_event)
|
||||
{
|
||||
if (SwooleAIO.init == 0)
|
||||
{
|
||||
swAio_init();
|
||||
}
|
||||
|
||||
_event->task_id = SwooleAIO.current_id++;
|
||||
|
||||
swAio_event *event = (swAio_event *) sw_malloc(sizeof(swAio_event));
|
||||
if (event == NULL)
|
||||
{
|
||||
swWarn("malloc failed.");
|
||||
return SW_ERR;
|
||||
}
|
||||
memcpy(event, _event, sizeof(swAio_event));
|
||||
|
||||
if (swThreadPool_dispatch(&swAioBase_thread_pool, event, sizeof(event)) < 0)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
else
|
||||
{
|
||||
SwooleAIO.task_num++;
|
||||
return _event->task_id;
|
||||
}
|
||||
}
|
||||
|
||||
static int swAioBase_read(int fd, void *inbuf, size_t size, off_t offset)
|
||||
{
|
||||
swAio_event *aio_ev = (swAio_event *) sw_malloc(sizeof(swAio_event));
|
||||
if (aio_ev == NULL)
|
||||
{
|
||||
swWarn("malloc failed.");
|
||||
return SW_ERR;
|
||||
}
|
||||
|
||||
bzero(aio_ev, sizeof(swAio_event));
|
||||
aio_ev->fd = fd;
|
||||
aio_ev->buf = inbuf;
|
||||
aio_ev->type = SW_AIO_READ;
|
||||
aio_ev->nbytes = size;
|
||||
aio_ev->offset = offset;
|
||||
aio_ev->task_id = SwooleAIO.current_id++;
|
||||
|
||||
if (swThreadPool_dispatch(&swAioBase_thread_pool, aio_ev, sizeof(aio_ev)) < 0)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
else
|
||||
{
|
||||
SwooleAIO.task_num++;
|
||||
return aio_ev->task_id;
|
||||
}
|
||||
}
|
||||
|
||||
void swAioBase_destroy()
|
||||
{
|
||||
swThreadPool_free(&swAioBase_thread_pool);
|
||||
if (SwooleG.main_reactor)
|
||||
{
|
||||
SwooleG.main_reactor->del(SwooleG.main_reactor, swAioBase_pipe_read);
|
||||
}
|
||||
swoole_aio_pipe.close(&swoole_aio_pipe);
|
||||
}
|
127
vendor/swoole/src/os/msg_queue.c
vendored
Executable file
127
vendor/swoole/src/os/msg_queue.c
vendored
Executable file
@ -0,0 +1,127 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| 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 <sys/types.h>
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/msg.h>
|
||||
|
||||
int swMsgQueue_free(swMsgQueue *q)
|
||||
{
|
||||
if (msgctl(q->msg_id, IPC_RMID, 0) < 0)
|
||||
{
|
||||
swSysError("msgctl(%d, IPC_RMID) failed.", q->msg_id);
|
||||
return SW_ERR;
|
||||
}
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
void swMsgQueue_set_blocking(swMsgQueue *q, uint8_t blocking)
|
||||
{
|
||||
if (blocking == 0)
|
||||
{
|
||||
q->flags = q->flags | IPC_NOWAIT;
|
||||
}
|
||||
else
|
||||
{
|
||||
q->flags = q->flags & (~IPC_NOWAIT);
|
||||
}
|
||||
}
|
||||
|
||||
int swMsgQueue_create(swMsgQueue *q, int blocking, key_t msg_key, int perms)
|
||||
{
|
||||
if (perms <= 0 || perms >= 01000)
|
||||
{
|
||||
perms = 0666;
|
||||
}
|
||||
int msg_id;
|
||||
msg_id = msgget(msg_key, IPC_CREAT | perms);
|
||||
if (msg_id < 0)
|
||||
{
|
||||
swSysError("msgget() failed.");
|
||||
return SW_ERR;
|
||||
}
|
||||
else
|
||||
{
|
||||
bzero(q, sizeof(swMsgQueue));
|
||||
q->msg_id = msg_id;
|
||||
q->perms = perms;
|
||||
q->blocking = blocking;
|
||||
swMsgQueue_set_blocking(q, blocking);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int swMsgQueue_pop(swMsgQueue *q, swQueue_data *data, int length)
|
||||
{
|
||||
int ret = msgrcv(q->msg_id, data, length, data->mtype, q->flags);
|
||||
if (ret < 0)
|
||||
{
|
||||
SwooleG.error = errno;
|
||||
if (errno != ENOMSG && errno != EINTR)
|
||||
{
|
||||
swSysError("msgrcv(%d, %d, %ld) failed.", q->msg_id, length, data->mtype);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int swMsgQueue_push(swMsgQueue *q, swQueue_data *in, int length)
|
||||
{
|
||||
int ret;
|
||||
|
||||
while (1)
|
||||
{
|
||||
ret = msgsnd(q->msg_id, in, length, q->flags);
|
||||
if (ret < 0)
|
||||
{
|
||||
SwooleG.error = errno;
|
||||
if (errno == EINTR)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else if (errno == EAGAIN)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
swSysError("msgsnd(%d, %d, %ld) failed.", q->msg_id, length, in->mtype);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int swMsgQueue_stat(swMsgQueue *q, int *queue_num, int *queue_bytes)
|
||||
{
|
||||
struct msqid_ds __stat;
|
||||
if (msgctl(q->msg_id, IPC_STAT, &__stat) == 0)
|
||||
{
|
||||
*queue_num = __stat.msg_qnum;
|
||||
*queue_bytes = __stat.msg_cbytes;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
101
vendor/swoole/src/os/sendfile.c
vendored
Executable file
101
vendor/swoole/src/os/sendfile.c
vendored
Executable file
@ -0,0 +1,101 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| 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 HAVE_KQUEUE
|
||||
|
||||
#include <sys/uio.h>
|
||||
|
||||
int swoole_sendfile(int out_fd, int in_fd, off_t *offset, size_t size)
|
||||
{
|
||||
off_t sent_bytes = 0;
|
||||
int ret;
|
||||
|
||||
#ifdef __MACH__
|
||||
struct sf_hdtr hdtr;
|
||||
hdtr.headers = NULL;
|
||||
hdtr.hdr_cnt = 0;
|
||||
hdtr.trailers = NULL;
|
||||
hdtr.trl_cnt = 0;
|
||||
#endif
|
||||
|
||||
//sent_bytes = (off_t)size;
|
||||
swTrace("send file, out_fd:%d, in_fd:%d, offset:%ld, size:%ld", out_fd, in_fd, (long)*offset, (long)size);
|
||||
|
||||
do_sendfile:
|
||||
#ifdef __MACH__
|
||||
ret = sendfile(in_fd, out_fd, *offset, (long long *) &size, &hdtr, 0);
|
||||
#else
|
||||
ret = sendfile(in_fd, out_fd, *offset, size, 0, &sent_bytes, 0);
|
||||
#endif
|
||||
if (ret == -1)
|
||||
{
|
||||
if (errno == EAGAIN)
|
||||
{
|
||||
*offset += sent_bytes;
|
||||
return sent_bytes;
|
||||
}
|
||||
else if (errno == EINTR)
|
||||
{
|
||||
goto do_sendfile;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if (ret == 0)
|
||||
{
|
||||
*offset += size;
|
||||
return size;
|
||||
}
|
||||
else
|
||||
{
|
||||
swWarn("sendfile failed. Error: %s[%d]", strerror(errno), errno);
|
||||
return SW_ERR;
|
||||
}
|
||||
return SW_OK;
|
||||
}
|
||||
#elif !defined(HAVE_SENDFILE)
|
||||
int swoole_sendfile(int out_fd, int in_fd, off_t *offset, size_t size)
|
||||
{
|
||||
char buf[SW_BUFFER_SIZE_BIG];
|
||||
int readn = size > sizeof(buf) ? sizeof(buf) : size;
|
||||
|
||||
int ret;
|
||||
int n = pread(in_fd, buf, readn, *offset);
|
||||
|
||||
if (n > 0)
|
||||
{
|
||||
ret = write(out_fd, buf, n);
|
||||
if (ret < 0)
|
||||
{
|
||||
swSysError("write() failed.");
|
||||
}
|
||||
else
|
||||
{
|
||||
*offset += ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
{
|
||||
swSysError("pread() failed.");
|
||||
return SW_ERR;
|
||||
}
|
||||
}
|
||||
#endif
|
262
vendor/swoole/src/os/signal.c
vendored
Executable file
262
vendor/swoole/src/os/signal.c
vendored
Executable file
@ -0,0 +1,262 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| 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 HAVE_SIGNALFD
|
||||
#include <sys/signalfd.h>
|
||||
static void swSignalfd_set(int signo, swSignalHander callback);
|
||||
static void swSignalfd_clear();
|
||||
static int swSignalfd_onSignal(swReactor *reactor, swEvent *event);
|
||||
|
||||
static sigset_t signalfd_mask;
|
||||
static int signal_fd = 0;
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
swSignalHander callback;
|
||||
uint16_t signo;
|
||||
uint16_t active;
|
||||
} swSignal;
|
||||
|
||||
static swSignal signals[SW_SIGNO_MAX];
|
||||
static int _lock = 0;
|
||||
|
||||
static void swSignal_async_handler(int signo);
|
||||
|
||||
/**
|
||||
* clear all singal
|
||||
*/
|
||||
void swSignal_none(void)
|
||||
{
|
||||
sigset_t mask;
|
||||
sigfillset(&mask);
|
||||
int ret = pthread_sigmask(SIG_BLOCK, &mask, NULL);
|
||||
if (ret < 0)
|
||||
{
|
||||
swWarn("pthread_sigmask() failed. Error: %s[%d]", strerror(ret), ret);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* setup signal
|
||||
*/
|
||||
swSignalHander swSignal_set(int sig, swSignalHander func, int restart, int mask)
|
||||
{
|
||||
//ignore
|
||||
if (func == NULL)
|
||||
{
|
||||
func = SIG_IGN;
|
||||
}
|
||||
//clear
|
||||
else if ((long) func == -1)
|
||||
{
|
||||
func = SIG_DFL;
|
||||
}
|
||||
|
||||
struct sigaction act, oact;
|
||||
act.sa_handler = func;
|
||||
if (mask)
|
||||
{
|
||||
sigfillset(&act.sa_mask);
|
||||
}
|
||||
else
|
||||
{
|
||||
sigemptyset(&act.sa_mask);
|
||||
}
|
||||
act.sa_flags = 0;
|
||||
if (sigaction(sig, &act, &oact) < 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
return oact.sa_handler;
|
||||
}
|
||||
|
||||
void swSignal_add(int signo, swSignalHander func)
|
||||
{
|
||||
#ifdef HAVE_SIGNALFD
|
||||
if (SwooleG.use_signalfd)
|
||||
{
|
||||
swSignalfd_set(signo, func);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
signals[signo].callback = func;
|
||||
signals[signo].active = 1;
|
||||
signals[signo].signo = signo;
|
||||
swSignal_set(signo, swSignal_async_handler, 1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void swSignal_async_handler(int signo)
|
||||
{
|
||||
if (SwooleG.main_reactor)
|
||||
{
|
||||
SwooleG.main_reactor->singal_no = signo;
|
||||
}
|
||||
else
|
||||
{
|
||||
//discard signal
|
||||
if (_lock)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_lock = 1;
|
||||
swSignal_callback(signo);
|
||||
_lock = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void swSignal_callback(int signo)
|
||||
{
|
||||
if (signo >= SW_SIGNO_MAX)
|
||||
{
|
||||
swWarn("signal[%d] numberis invalid.", signo);
|
||||
return;
|
||||
}
|
||||
swSignalHander callback = signals[signo].callback;
|
||||
if (!callback)
|
||||
{
|
||||
swWarn("signal[%d] callback is null.", signo);
|
||||
return;
|
||||
}
|
||||
callback(signo);
|
||||
}
|
||||
|
||||
void swSignal_clear(void)
|
||||
{
|
||||
#ifdef HAVE_SIGNALFD
|
||||
if (SwooleG.use_signalfd)
|
||||
{
|
||||
swSignalfd_clear();
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < SW_SIGNO_MAX; i++)
|
||||
{
|
||||
if (signals[i].active)
|
||||
{
|
||||
swSignal_set(signals[i].signo, (swSignalHander) -1, 1, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
bzero(&signals, sizeof(signals));
|
||||
}
|
||||
|
||||
#ifdef HAVE_SIGNALFD
|
||||
void swSignalfd_init()
|
||||
{
|
||||
sigemptyset(&signalfd_mask);
|
||||
bzero(&signals, sizeof(signals));
|
||||
}
|
||||
|
||||
static void swSignalfd_set(int signo, swSignalHander callback)
|
||||
{
|
||||
if (callback == NULL && signals[signo].active)
|
||||
{
|
||||
sigdelset(&signalfd_mask, signo);
|
||||
bzero(&signals[signo], sizeof(swSignal));
|
||||
}
|
||||
else
|
||||
{
|
||||
sigaddset(&signalfd_mask, signo);
|
||||
signals[signo].callback = callback;
|
||||
signals[signo].signo = signo;
|
||||
signals[signo].active = 1;
|
||||
}
|
||||
if (signal_fd > 0)
|
||||
{
|
||||
sigprocmask(SIG_BLOCK, &signalfd_mask, NULL);
|
||||
signalfd(signal_fd, &signalfd_mask, SFD_NONBLOCK | SFD_CLOEXEC);
|
||||
}
|
||||
}
|
||||
|
||||
int swSignalfd_setup(swReactor *reactor)
|
||||
{
|
||||
if (signal_fd == 0)
|
||||
{
|
||||
signal_fd = signalfd(-1, &signalfd_mask, SFD_NONBLOCK | SFD_CLOEXEC);
|
||||
if (signal_fd < 0)
|
||||
{
|
||||
swWarn("signalfd() failed. Error: %s[%d]", strerror(errno), errno);
|
||||
return SW_ERR;
|
||||
}
|
||||
SwooleG.signal_fd = signal_fd;
|
||||
if (sigprocmask(SIG_BLOCK, &signalfd_mask, NULL) == -1)
|
||||
{
|
||||
swWarn("sigprocmask() failed. Error: %s[%d]", strerror(errno), errno);
|
||||
return SW_ERR;
|
||||
}
|
||||
reactor->setHandle(reactor, SW_FD_SIGNAL, swSignalfd_onSignal);
|
||||
reactor->add(reactor, signal_fd, SW_FD_SIGNAL);
|
||||
return SW_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
swWarn("signalfd has been created");
|
||||
return SW_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
static void swSignalfd_clear()
|
||||
{
|
||||
if (signal_fd)
|
||||
{
|
||||
if (sigprocmask(SIG_UNBLOCK, &signalfd_mask, NULL) < 0)
|
||||
{
|
||||
swSysError("sigprocmask(SIG_UNBLOCK) failed.");
|
||||
}
|
||||
close(signal_fd);
|
||||
bzero(&signalfd_mask, sizeof(signalfd_mask));
|
||||
}
|
||||
signal_fd = 0;
|
||||
}
|
||||
|
||||
static int swSignalfd_onSignal(swReactor *reactor, swEvent *event)
|
||||
{
|
||||
int n;
|
||||
struct signalfd_siginfo siginfo;
|
||||
n = read(event->fd, &siginfo, sizeof(siginfo));
|
||||
if (n < 0)
|
||||
{
|
||||
swWarn("read from signalfd failed. Error: %s[%d]", strerror(errno), errno);
|
||||
return SW_OK;
|
||||
}
|
||||
if (siginfo.ssi_signo >= SW_SIGNO_MAX)
|
||||
{
|
||||
swWarn("unknown signal[%d].", siginfo.ssi_signo);
|
||||
return SW_OK;
|
||||
}
|
||||
if (signals[siginfo.ssi_signo].active)
|
||||
{
|
||||
if (signals[siginfo.ssi_signo].callback)
|
||||
{
|
||||
signals[siginfo.ssi_signo].callback(siginfo.ssi_signo);
|
||||
}
|
||||
else
|
||||
{
|
||||
swWarn("signal[%d] callback is null.", siginfo.ssi_signo);
|
||||
}
|
||||
}
|
||||
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
#endif
|
240
vendor/swoole/src/os/timer.c
vendored
Executable file
240
vendor/swoole/src/os/timer.c
vendored
Executable file
@ -0,0 +1,240 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| 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"
|
||||
|
||||
#ifdef HAVE_TIMERFD
|
||||
#include <sys/timerfd.h>
|
||||
#endif
|
||||
|
||||
static int swSystemTimer_signal_set(swTimer *timer, long interval);
|
||||
static int swSystemTimer_timerfd_set(swTimer *timer, long interval);
|
||||
static int swSystemTimer_set(swTimer *timer, long new_interval);
|
||||
|
||||
/**
|
||||
* create timer
|
||||
*/
|
||||
int swSystemTimer_init(int interval, int use_pipe)
|
||||
{
|
||||
swTimer *timer = &SwooleG.timer;
|
||||
timer->lasttime = interval;
|
||||
|
||||
#ifndef HAVE_TIMERFD
|
||||
SwooleG.use_timerfd = 0;
|
||||
#endif
|
||||
|
||||
if (SwooleG.use_timerfd)
|
||||
{
|
||||
if (swSystemTimer_timerfd_set(timer, interval) < 0)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
timer->use_pipe = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (use_pipe)
|
||||
{
|
||||
if (swPipeNotify_auto(&timer->pipe, 0, 0) < 0)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
timer->fd = timer->pipe.getFd(&timer->pipe, 0);
|
||||
timer->use_pipe = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
timer->fd = 1;
|
||||
timer->use_pipe = 0;
|
||||
}
|
||||
|
||||
if (swSystemTimer_signal_set(timer, interval) < 0)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
swSignal_add(SIGALRM, swSystemTimer_signal_handler);
|
||||
}
|
||||
|
||||
if (timer->fd > 1)
|
||||
{
|
||||
SwooleG.main_reactor->setHandle(SwooleG.main_reactor, SW_FD_TIMER, swSystemTimer_event_handler);
|
||||
SwooleG.main_reactor->add(SwooleG.main_reactor, SwooleG.timer.fd, SW_FD_TIMER);
|
||||
}
|
||||
timer->set = swSystemTimer_set;
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* timerfd
|
||||
*/
|
||||
static int swSystemTimer_timerfd_set(swTimer *timer, long interval)
|
||||
{
|
||||
#ifdef HAVE_TIMERFD
|
||||
struct timeval now;
|
||||
int sec = interval / 1000;
|
||||
int msec = (((float) interval / 1000) - sec) * 1000;
|
||||
|
||||
if (gettimeofday(&now, NULL) < 0)
|
||||
{
|
||||
swWarn("gettimeofday() failed. Error: %s[%d]", strerror(errno), errno);
|
||||
return SW_ERR;
|
||||
}
|
||||
|
||||
struct itimerspec timer_set;
|
||||
bzero(&timer_set, sizeof(timer_set));
|
||||
|
||||
if (interval < 0)
|
||||
{
|
||||
if (timer->fd == 0)
|
||||
{
|
||||
return SW_OK;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
timer_set.it_interval.tv_sec = sec;
|
||||
timer_set.it_interval.tv_nsec = msec * 1000 * 1000;
|
||||
|
||||
timer_set.it_value.tv_sec = now.tv_sec + sec;
|
||||
timer_set.it_value.tv_nsec = (now.tv_usec * 1000) + timer_set.it_interval.tv_nsec;
|
||||
|
||||
if (timer_set.it_value.tv_nsec > 1e9)
|
||||
{
|
||||
timer_set.it_value.tv_nsec = timer_set.it_value.tv_nsec - 1e9;
|
||||
timer_set.it_value.tv_sec += 1;
|
||||
}
|
||||
|
||||
if (timer->fd == 0)
|
||||
{
|
||||
timer->fd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK | TFD_CLOEXEC);
|
||||
if (timer->fd < 0)
|
||||
{
|
||||
swWarn("timerfd_create() failed. Error: %s[%d]", strerror(errno), errno);
|
||||
return SW_ERR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (timerfd_settime(timer->fd, TFD_TIMER_ABSTIME, &timer_set, NULL) == -1)
|
||||
{
|
||||
swWarn("timerfd_settime() failed. Error: %s[%d]", strerror(errno), errno);
|
||||
return SW_ERR;
|
||||
}
|
||||
return SW_OK;
|
||||
#else
|
||||
swWarn("kernel not support timerfd.");
|
||||
return SW_ERR;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* setitimer
|
||||
*/
|
||||
static int swSystemTimer_signal_set(swTimer *timer, long interval)
|
||||
{
|
||||
struct itimerval timer_set;
|
||||
int sec = interval / 1000;
|
||||
int msec = (((float) interval / 1000) - sec) * 1000;
|
||||
|
||||
struct timeval now;
|
||||
if (gettimeofday(&now, NULL) < 0)
|
||||
{
|
||||
swWarn("gettimeofday() failed. Error: %s[%d]", strerror(errno), errno);
|
||||
return SW_ERR;
|
||||
}
|
||||
bzero(&timer_set, sizeof(timer_set));
|
||||
|
||||
if (interval > 0)
|
||||
{
|
||||
timer_set.it_interval.tv_sec = sec;
|
||||
timer_set.it_interval.tv_usec = msec * 1000;
|
||||
|
||||
timer_set.it_value.tv_sec = sec;
|
||||
timer_set.it_value.tv_usec = timer_set.it_interval.tv_usec;
|
||||
|
||||
if (timer_set.it_value.tv_usec > 1e6)
|
||||
{
|
||||
timer_set.it_value.tv_usec = timer_set.it_value.tv_usec - 1e6;
|
||||
timer_set.it_value.tv_sec += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (setitimer(ITIMER_REAL, &timer_set, NULL) < 0)
|
||||
{
|
||||
swWarn("setitimer() failed. Error: %s[%d]", strerror(errno), errno);
|
||||
return SW_ERR;
|
||||
}
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
void swSystemTimer_free(swTimer *timer)
|
||||
{
|
||||
if (timer->use_pipe)
|
||||
{
|
||||
timer->pipe.close(&timer->pipe);
|
||||
}
|
||||
else if (timer->fd > 2)
|
||||
{
|
||||
if (close(timer->fd) < 0)
|
||||
{
|
||||
swSysError("close(%d) failed.", timer->fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static long current_interval = 0;
|
||||
|
||||
static int swSystemTimer_set(swTimer *timer, long new_interval)
|
||||
{
|
||||
if (new_interval == current_interval)
|
||||
{
|
||||
return SW_OK;
|
||||
}
|
||||
current_interval = new_interval;
|
||||
if (SwooleG.use_timerfd)
|
||||
{
|
||||
return swSystemTimer_timerfd_set(timer, new_interval);
|
||||
}
|
||||
else
|
||||
{
|
||||
return swSystemTimer_signal_set(timer, new_interval);
|
||||
}
|
||||
}
|
||||
|
||||
int swSystemTimer_event_handler(swReactor *reactor, swEvent *event)
|
||||
{
|
||||
uint64_t exp;
|
||||
swTimer *timer = &SwooleG.timer;
|
||||
|
||||
if (read(timer->fd, &exp, sizeof(uint64_t)) != sizeof(uint64_t))
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
SwooleG.signal_alarm = 0;
|
||||
return swTimer_select(timer);
|
||||
}
|
||||
|
||||
void swSystemTimer_signal_handler(int sig)
|
||||
{
|
||||
SwooleG.signal_alarm = 1;
|
||||
uint64_t flag = 1;
|
||||
|
||||
if (SwooleG.timer.use_pipe)
|
||||
{
|
||||
SwooleG.timer.pipe.write(&SwooleG.timer.pipe, &flag, sizeof(flag));
|
||||
}
|
||||
}
|
93
vendor/swoole/src/pipe/PipeBase.c
vendored
Executable file
93
vendor/swoole/src/pipe/PipeBase.c
vendored
Executable file
@ -0,0 +1,93 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| 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 swPipeBase_read(swPipe *p, void *data, int length);
|
||||
static int swPipeBase_write(swPipe *p, void *data, int length);
|
||||
static int swPipeBase_getFd(swPipe *p, int isWriteFd);
|
||||
static int swPipeBase_close(swPipe *p);
|
||||
|
||||
typedef struct _swPipeBase
|
||||
{
|
||||
int pipes[2];
|
||||
} swPipeBase;
|
||||
|
||||
int swPipeBase_create(swPipe *p, int blocking)
|
||||
{
|
||||
int ret;
|
||||
swPipeBase *object = sw_malloc(sizeof(swPipeBase));
|
||||
if (object == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
p->blocking = blocking;
|
||||
ret = pipe(object->pipes);
|
||||
if (ret < 0)
|
||||
{
|
||||
swWarn("pipe() failed. Error: %s[%d]", strerror(errno), errno);
|
||||
sw_free(object);
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Nonblock
|
||||
swSetNonBlock(object->pipes[0]);
|
||||
swSetNonBlock(object->pipes[1]);
|
||||
p->timeout = -1;
|
||||
p->object = object;
|
||||
p->read = swPipeBase_read;
|
||||
p->write = swPipeBase_write;
|
||||
p->getFd = swPipeBase_getFd;
|
||||
p->close = swPipeBase_close;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int swPipeBase_read(swPipe *p, void *data, int length)
|
||||
{
|
||||
swPipeBase *object = p->object;
|
||||
if (p->blocking == 1 && p->timeout > 0)
|
||||
{
|
||||
if (swSocket_wait(object->pipes[0], p->timeout * 1000, SW_EVENT_READ) < 0)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
}
|
||||
return read(object->pipes[0], data, length);
|
||||
}
|
||||
|
||||
static int swPipeBase_write(swPipe *p, void *data, int length)
|
||||
{
|
||||
swPipeBase *this = p->object;
|
||||
return write(this->pipes[1], data, length);
|
||||
}
|
||||
|
||||
static int swPipeBase_getFd(swPipe *p, int isWriteFd)
|
||||
{
|
||||
swPipeBase *this = p->object;
|
||||
return (isWriteFd == 0) ? this->pipes[0] : this->pipes[1];
|
||||
}
|
||||
|
||||
static int swPipeBase_close(swPipe *p)
|
||||
{
|
||||
int ret1, ret2;
|
||||
swPipeBase *this = p->object;
|
||||
ret1 = close(this->pipes[0]);
|
||||
ret2 = close(this->pipes[1]);
|
||||
sw_free(this);
|
||||
return 0 - ret1 - ret2;
|
||||
}
|
142
vendor/swoole/src/pipe/PipeEventfd.c
vendored
Executable file
142
vendor/swoole/src/pipe/PipeEventfd.c
vendored
Executable file
@ -0,0 +1,142 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| 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 HAVE_EVENTFD
|
||||
#include <sys/eventfd.h>
|
||||
|
||||
static int swPipeEventfd_read(swPipe *p, void *data, int length);
|
||||
static int swPipeEventfd_write(swPipe *p, void *data, int length);
|
||||
static int swPipeEventfd_getFd(swPipe *p, int isWriteFd);
|
||||
static int swPipeEventfd_close(swPipe *p);
|
||||
|
||||
typedef struct _swPipeEventfd
|
||||
{
|
||||
int event_fd;
|
||||
} swPipeEventfd;
|
||||
|
||||
int swPipeEventfd_create(swPipe *p, int blocking, int semaphore, int timeout)
|
||||
{
|
||||
int efd;
|
||||
int flag = 0;
|
||||
swPipeEventfd *object = sw_malloc(sizeof(swPipeEventfd));
|
||||
if (object == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
flag = EFD_NONBLOCK;
|
||||
|
||||
if (blocking == 1)
|
||||
{
|
||||
if (timeout > 0)
|
||||
{
|
||||
flag = 0;
|
||||
p->timeout = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
p->timeout = timeout;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef EFD_SEMAPHORE
|
||||
if (semaphore == 1)
|
||||
{
|
||||
flag |= EFD_SEMAPHORE;
|
||||
}
|
||||
#endif
|
||||
|
||||
p->blocking = blocking;
|
||||
efd = eventfd(0, flag);
|
||||
if (efd < 0)
|
||||
{
|
||||
swWarn("eventfd create failed. Error: %s[%d]", strerror(errno), errno);
|
||||
sw_free(object);
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
p->object = object;
|
||||
p->read = swPipeEventfd_read;
|
||||
p->write = swPipeEventfd_write;
|
||||
p->getFd = swPipeEventfd_getFd;
|
||||
p->close = swPipeEventfd_close;
|
||||
object->event_fd = efd;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int swPipeEventfd_read(swPipe *p, void *data, int length)
|
||||
{
|
||||
int ret = -1;
|
||||
swPipeEventfd *object = p->object;
|
||||
|
||||
//eventfd not support socket timeout
|
||||
if (p->blocking == 1 && p->timeout > 0)
|
||||
{
|
||||
if (swSocket_wait(object->event_fd, p->timeout * 1000, SW_EVENT_READ) < 0)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
ret = read(object->event_fd, data, sizeof(uint64_t));
|
||||
if (ret < 0 && errno == EINTR)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int swPipeEventfd_write(swPipe *p, void *data, int length)
|
||||
{
|
||||
int ret;
|
||||
swPipeEventfd *this = p->object;
|
||||
while (1)
|
||||
{
|
||||
ret = write(this->event_fd, data, sizeof(uint64_t));
|
||||
if (ret < 0)
|
||||
{
|
||||
if (errno == EINTR)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int swPipeEventfd_getFd(swPipe *p, int isWriteFd)
|
||||
{
|
||||
return ((swPipeEventfd *) (p->object))->event_fd;
|
||||
}
|
||||
|
||||
static int swPipeEventfd_close(swPipe *p)
|
||||
{
|
||||
int ret;
|
||||
ret = close(((swPipeEventfd *) (p->object))->event_fd);
|
||||
sw_free(p->object);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
135
vendor/swoole/src/pipe/PipeUnsock.c
vendored
Executable file
135
vendor/swoole/src/pipe/PipeUnsock.c
vendored
Executable 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"
|
||||
|
||||
static int swPipeUnsock_read(swPipe *p, void *data, int length);
|
||||
static int swPipeUnsock_write(swPipe *p, void *data, int length);
|
||||
static int swPipeUnsock_getFd(swPipe *p, int master);
|
||||
static int swPipeUnsock_close(swPipe *p);
|
||||
|
||||
typedef struct _swPipeUnsock
|
||||
{
|
||||
/**
|
||||
* master : socks[1]
|
||||
* worker : socks[0]
|
||||
*/
|
||||
int socks[2];
|
||||
/**
|
||||
* master pipe is closed
|
||||
*/
|
||||
uint8_t pipe_master_closed;
|
||||
/**
|
||||
* worker pipe is closed
|
||||
*/
|
||||
uint8_t pipe_worker_closed;
|
||||
} swPipeUnsock;
|
||||
|
||||
static int swPipeUnsock_getFd(swPipe *p, int master)
|
||||
{
|
||||
swPipeUnsock *this = p->object;
|
||||
return master == 1 ? this->socks[1] : this->socks[0];
|
||||
}
|
||||
|
||||
static int swPipeUnsock_close(swPipe *p)
|
||||
{
|
||||
swPipeUnsock *object = p->object;
|
||||
int ret = swPipeUnsock_close_ext(p, 0);
|
||||
sw_free(object);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int swPipeUnsock_close_ext(swPipe *p, int which)
|
||||
{
|
||||
int ret1 = 0, ret2 = 0;
|
||||
swPipeUnsock *object = p->object;
|
||||
|
||||
if (which == SW_PIPE_CLOSE_MASTER)
|
||||
{
|
||||
if (object->pipe_master_closed)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
ret1 = close(object->socks[1]);
|
||||
object->pipe_master_closed = 1;
|
||||
}
|
||||
else if (which == SW_PIPE_CLOSE_WORKER)
|
||||
{
|
||||
if (object->pipe_worker_closed)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
ret1 = close(object->socks[0]);
|
||||
object->pipe_worker_closed = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret1 = swPipeUnsock_close_ext(p, SW_PIPE_CLOSE_MASTER);
|
||||
ret2 = swPipeUnsock_close_ext(p, SW_PIPE_CLOSE_WORKER);
|
||||
}
|
||||
|
||||
return 0 - ret1 - ret2;
|
||||
}
|
||||
|
||||
int swPipeUnsock_create(swPipe *p, int blocking, int protocol)
|
||||
{
|
||||
int ret;
|
||||
swPipeUnsock *object = sw_malloc(sizeof(swPipeUnsock));
|
||||
if (object == NULL)
|
||||
{
|
||||
swWarn("malloc() failed.");
|
||||
return SW_ERR;
|
||||
}
|
||||
bzero(object, sizeof(swPipeUnsock));
|
||||
p->blocking = blocking;
|
||||
ret = socketpair(AF_UNIX, protocol, 0, object->socks);
|
||||
if (ret < 0)
|
||||
{
|
||||
swWarn("socketpair() failed. Error: %s [%d]", strerror(errno), errno);
|
||||
sw_free(object);
|
||||
return SW_ERR;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Nonblock
|
||||
if (blocking == 0)
|
||||
{
|
||||
swSetNonBlock(object->socks[0]);
|
||||
swSetNonBlock(object->socks[1]);
|
||||
}
|
||||
|
||||
int sbsize = SwooleG.socket_buffer_size;
|
||||
swSocket_set_buffer_size(object->socks[0], sbsize);
|
||||
swSocket_set_buffer_size(object->socks[1], sbsize);
|
||||
|
||||
p->object = object;
|
||||
p->read = swPipeUnsock_read;
|
||||
p->write = swPipeUnsock_write;
|
||||
p->getFd = swPipeUnsock_getFd;
|
||||
p->close = swPipeUnsock_close;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int swPipeUnsock_read(swPipe *p, void *data, int length)
|
||||
{
|
||||
return read(((swPipeUnsock *) p->object)->socks[0], data, length);
|
||||
}
|
||||
|
||||
static int swPipeUnsock_write(swPipe *p, void *data, int length)
|
||||
{
|
||||
return write(((swPipeUnsock *) p->object)->socks[1], data, length);
|
||||
}
|
365
vendor/swoole/src/protocol/Base.c
vendored
Executable file
365
vendor/swoole/src/protocol/Base.c
vendored
Executable file
@ -0,0 +1,365 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| Swoole |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 2012-2017 The Swoole Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 2.0 of the Apache license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.apache.org/licenses/LICENSE-2.0.html |
|
||||
| If you did not receive a copy of the Apache2.0 license and are unable|
|
||||
| to obtain it through the world-wide-web, please send a note to |
|
||||
| license@swoole.com so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Author: Tianfeng Han <mikan.tenny@gmail.com> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#include "swoole.h"
|
||||
#include "Connection.h"
|
||||
|
||||
/**
|
||||
* return the package total length
|
||||
*/
|
||||
int swProtocol_get_package_length(swProtocol *protocol, swConnection *conn, char *data, uint32_t size)
|
||||
{
|
||||
uint16_t length_offset = protocol->package_length_offset;
|
||||
int32_t body_length;
|
||||
/**
|
||||
* no have length field, wait more data
|
||||
*/
|
||||
if (size < length_offset + protocol->package_length_size)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
body_length = swoole_unpack(protocol->package_length_type, data + length_offset);
|
||||
//Length error
|
||||
//Protocol length is not legitimate, out of bounds or exceed the allocated length
|
||||
if (body_length < 0)
|
||||
{
|
||||
swWarn("invalid package, remote_addr=%s:%d, length=%d, size=%d.", swConnection_get_ip(conn), swConnection_get_port(conn), body_length, size);
|
||||
return SW_ERR;
|
||||
}
|
||||
//total package length
|
||||
return protocol->package_body_offset + body_length;
|
||||
}
|
||||
|
||||
static sw_inline int swProtocol_split_package_by_eof(swProtocol *protocol, swConnection *conn, swString *buffer)
|
||||
{
|
||||
#if SW_LOG_TRACE_OPEN > 0
|
||||
static int count;
|
||||
count++;
|
||||
#endif
|
||||
|
||||
int eof_pos;
|
||||
if (buffer->length - buffer->offset < protocol->package_eof_len)
|
||||
{
|
||||
eof_pos = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
eof_pos = swoole_strnpos(buffer->str + buffer->offset, buffer->length - buffer->offset, protocol->package_eof, protocol->package_eof_len);
|
||||
}
|
||||
|
||||
swTraceLog(SW_TRACE_EOF_PROTOCOL, "#[0] count=%d, length=%ld, size=%ld, offset=%ld.", count, buffer->length, buffer->size, (long)buffer->offset);
|
||||
|
||||
//waiting for more data
|
||||
if (eof_pos < 0)
|
||||
{
|
||||
buffer->offset = buffer->length - protocol->package_eof_len;
|
||||
return buffer->length;
|
||||
}
|
||||
|
||||
uint32_t length = buffer->offset + eof_pos + protocol->package_eof_len;
|
||||
swTraceLog(SW_TRACE_EOF_PROTOCOL, "#[4] count=%d, length=%d", count, length);
|
||||
if (protocol->onPackage(conn, buffer->str, length) < 0)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
if (conn->removed)
|
||||
{
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
//there are remaining data
|
||||
if (length < buffer->length)
|
||||
{
|
||||
uint32_t remaining_length = buffer->length - length;
|
||||
char *remaining_data = buffer->str + length;
|
||||
swTraceLog(SW_TRACE_EOF_PROTOCOL, "#[5] count=%d, remaining_length=%d", count, remaining_length);
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (remaining_length < protocol->package_eof_len)
|
||||
{
|
||||
goto wait_more_data;
|
||||
}
|
||||
eof_pos = swoole_strnpos(remaining_data, remaining_length, protocol->package_eof, protocol->package_eof_len);
|
||||
if (eof_pos < 0)
|
||||
{
|
||||
wait_more_data:
|
||||
swTraceLog(SW_TRACE_EOF_PROTOCOL, "#[1] count=%d, remaining_length=%d, length=%d", count, remaining_length, length);
|
||||
memmove(buffer->str, remaining_data, remaining_length);
|
||||
buffer->length = remaining_length;
|
||||
buffer->offset = 0;
|
||||
return SW_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
length = eof_pos + protocol->package_eof_len;
|
||||
if (protocol->onPackage(conn, remaining_data, length) < 0)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
if (conn->removed)
|
||||
{
|
||||
return SW_OK;
|
||||
}
|
||||
swTraceLog(SW_TRACE_EOF_PROTOCOL, "#[2] count=%d, remaining_length=%d, length=%d", count, remaining_length, length);
|
||||
remaining_data += length;
|
||||
remaining_length -= length;
|
||||
}
|
||||
}
|
||||
}
|
||||
swTraceLog(SW_TRACE_EOF_PROTOCOL, "#[3] length=%ld, size=%ld, offset=%ld", buffer->length, buffer->size, (long)buffer->offset);
|
||||
swString_clear(buffer);
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return SW_ERR: close the connection
|
||||
* @return SW_OK: continue
|
||||
*/
|
||||
int swProtocol_recv_check_length(swProtocol *protocol, swConnection *conn, swString *buffer)
|
||||
{
|
||||
int package_length;
|
||||
uint32_t recv_size;
|
||||
char swap[SW_BUFFER_SIZE_STD];
|
||||
|
||||
if (conn->skip_recv)
|
||||
{
|
||||
conn->skip_recv = 0;
|
||||
goto do_get_length;
|
||||
}
|
||||
|
||||
do_recv:
|
||||
if (conn->active == 0)
|
||||
{
|
||||
return SW_OK;
|
||||
}
|
||||
if (buffer->offset > 0)
|
||||
{
|
||||
recv_size = buffer->offset - buffer->length;
|
||||
}
|
||||
else
|
||||
{
|
||||
recv_size = protocol->package_length_offset + protocol->package_length_size;
|
||||
}
|
||||
|
||||
int n = swConnection_recv(conn, buffer->str + buffer->length, recv_size, 0);
|
||||
if (n < 0)
|
||||
{
|
||||
switch (swConnection_error(errno))
|
||||
{
|
||||
case SW_ERROR:
|
||||
swSysError("recv(%d, %d) failed.", conn->fd, recv_size);
|
||||
return SW_OK;
|
||||
case SW_CLOSE:
|
||||
conn->close_errno = errno;
|
||||
return SW_ERR;
|
||||
default:
|
||||
return SW_OK;
|
||||
}
|
||||
}
|
||||
else if (n == 0)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer->length += n;
|
||||
|
||||
if (conn->recv_wait)
|
||||
{
|
||||
if (buffer->length >= buffer->offset)
|
||||
{
|
||||
do_dispatch:
|
||||
if (protocol->onPackage(conn, buffer->str, buffer->offset) < 0)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
if (conn->removed)
|
||||
{
|
||||
return SW_OK;
|
||||
}
|
||||
conn->recv_wait = 0;
|
||||
|
||||
int remaining_length = buffer->length - buffer->offset;
|
||||
if (remaining_length > 0)
|
||||
{
|
||||
assert(remaining_length < sizeof(swap));
|
||||
memcpy(swap, buffer->str + buffer->offset, remaining_length);
|
||||
memcpy(buffer->str, swap, remaining_length);
|
||||
buffer->offset = 0;
|
||||
buffer->length = remaining_length;
|
||||
goto do_get_length;
|
||||
}
|
||||
else
|
||||
{
|
||||
swString_clear(buffer);
|
||||
goto do_recv;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return SW_OK;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
do_get_length: package_length = protocol->get_package_length(protocol, conn, buffer->str, buffer->length);
|
||||
//invalid package, close connection.
|
||||
if (package_length < 0)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
//no length
|
||||
else if (package_length == 0)
|
||||
{
|
||||
return SW_OK;
|
||||
}
|
||||
else if (package_length > protocol->package_max_length)
|
||||
{
|
||||
swWarn("package is too big, remote_addr=%s:%d, length=%d.", swConnection_get_ip(conn), swConnection_get_port(conn), package_length);
|
||||
return SW_ERR;
|
||||
}
|
||||
//get length success
|
||||
else
|
||||
{
|
||||
if (buffer->size < package_length)
|
||||
{
|
||||
if (swString_extend(buffer, package_length) < 0)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
}
|
||||
conn->recv_wait = 1;
|
||||
buffer->offset = package_length;
|
||||
|
||||
if (buffer->length >= package_length)
|
||||
{
|
||||
goto do_dispatch;
|
||||
}
|
||||
else
|
||||
{
|
||||
goto do_recv;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return SW_ERR: close the connection
|
||||
* @return SW_OK: continue
|
||||
*/
|
||||
int swProtocol_recv_check_eof(swProtocol *protocol, swConnection *conn, swString *buffer)
|
||||
{
|
||||
int recv_again = SW_FALSE;
|
||||
int buf_size;
|
||||
|
||||
recv_data: buf_size = buffer->size - buffer->length;
|
||||
char *buf_ptr = buffer->str + buffer->length;
|
||||
|
||||
if (buf_size > SW_BUFFER_SIZE_STD)
|
||||
{
|
||||
buf_size = SW_BUFFER_SIZE_STD;
|
||||
}
|
||||
|
||||
int n = swConnection_recv(conn, buf_ptr, buf_size, 0);
|
||||
if (n < 0)
|
||||
{
|
||||
switch (swConnection_error(errno))
|
||||
{
|
||||
case SW_ERROR:
|
||||
swSysError("recv from socket#%d failed.", conn->fd);
|
||||
return SW_OK;
|
||||
case SW_CLOSE:
|
||||
conn->close_errno = errno;
|
||||
return SW_ERR;
|
||||
default:
|
||||
return SW_OK;
|
||||
}
|
||||
}
|
||||
else if (n == 0)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer->length += n;
|
||||
|
||||
if (buffer->length < protocol->package_eof_len)
|
||||
{
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
if (protocol->split_by_eof)
|
||||
{
|
||||
if (swProtocol_split_package_by_eof(protocol, conn, buffer) == 0)
|
||||
{
|
||||
return SW_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
recv_again = SW_TRUE;
|
||||
}
|
||||
}
|
||||
else if (memcmp(buffer->str + buffer->length - protocol->package_eof_len, protocol->package_eof, protocol->package_eof_len) == 0)
|
||||
{
|
||||
if (protocol->onPackage(conn, buffer->str, buffer->length) < 0)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
if (conn->removed)
|
||||
{
|
||||
return SW_OK;
|
||||
}
|
||||
swString_clear(buffer);
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
//over max length, will discard
|
||||
if (buffer->length == protocol->package_max_length)
|
||||
{
|
||||
swWarn("Package is too big. package_length=%d", (int )buffer->length);
|
||||
return SW_ERR;
|
||||
}
|
||||
|
||||
//buffer is full, may have not read data
|
||||
if (buffer->length == buffer->size)
|
||||
{
|
||||
recv_again = SW_TRUE;
|
||||
if (buffer->size < protocol->package_max_length)
|
||||
{
|
||||
uint32_t extend_size = swoole_size_align(buffer->size * 2, SwooleG.pagesize);
|
||||
if (extend_size > protocol->package_max_length)
|
||||
{
|
||||
extend_size = protocol->package_max_length;
|
||||
}
|
||||
if (swString_extend(buffer, extend_size) < 0)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
}
|
||||
}
|
||||
//no eof
|
||||
if (recv_again)
|
||||
{
|
||||
goto recv_data;
|
||||
}
|
||||
}
|
||||
return SW_OK;
|
||||
}
|
133
vendor/swoole/src/protocol/Base64.c
vendored
Executable file
133
vendor/swoole/src/protocol/Base64.c
vendored
Executable file
@ -0,0 +1,133 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| Swoole |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 2012-2017 The Swoole Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 2.0 of the Apache license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.apache.org/licenses/LICENSE-2.0.html |
|
||||
| If you did not receive a copy of the Apache2.0 license and are unable|
|
||||
| to obtain it through the world-wide-web, please send a note to |
|
||||
| license@swoole.com so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Author: Tianfeng Han <mikan.tenny@gmail.com> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "base64.h"
|
||||
|
||||
/* BASE 64 encode table */
|
||||
static char base64en[] =
|
||||
{ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
|
||||
'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
|
||||
't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/', };
|
||||
|
||||
#define BASE64_PAD '='
|
||||
#define BASE64DE_FIRST '+'
|
||||
#define BASE64DE_LAST 'z'
|
||||
|
||||
/* ASCII order for BASE 64 decode, -1 in unused character */
|
||||
static signed char base64de[] = {
|
||||
/* '+', ',', '-', '.', '/', '0', '1', '2', */
|
||||
62, -1, -1, -1, 63, 52, 53, 54,
|
||||
/* '3', '4', '5', '6', '7', '8', '9', ':', */
|
||||
55, 56, 57, 58, 59, 60, 61, -1,
|
||||
/* ';', '<', '=', '>', '?', '@', 'A', 'B', */
|
||||
-1, -1, -1, -1, -1, -1, 0, 1,
|
||||
/* 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', */
|
||||
2, 3, 4, 5, 6, 7, 8, 9,
|
||||
/* 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', */
|
||||
10, 11, 12, 13, 14, 15, 16, 17,
|
||||
/* 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', */
|
||||
18, 19, 20, 21, 22, 23, 24, 25,
|
||||
/* '[', '\', ']', '^', '_', '`', 'a', 'b', */
|
||||
-1, -1, -1, -1, -1, -1, 26, 27,
|
||||
/* 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', */
|
||||
28, 29, 30, 31, 32, 33, 34, 35,
|
||||
/* 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', */
|
||||
36, 37, 38, 39, 40, 41, 42, 43,
|
||||
/* 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', */
|
||||
44, 45, 46, 47, 48, 49, 50, 51,
|
||||
};
|
||||
|
||||
int swBase64_encode(unsigned char *in, int inlen, char *out)
|
||||
{
|
||||
int i, j;
|
||||
for (i = j = 0; i < inlen; i++)
|
||||
{
|
||||
int s = i % 3; /* from 6/gcd(6, 8) */
|
||||
switch (s)
|
||||
{
|
||||
case 0:
|
||||
out[j++] = base64en[(in[i] >> 2) & 0x3F];
|
||||
continue;
|
||||
case 1:
|
||||
out[j++] = base64en[((in[i - 1] & 0x3) << 4) + ((in[i] >> 4) & 0xF)];
|
||||
continue;
|
||||
case 2:
|
||||
out[j++] = base64en[((in[i - 1] & 0xF) << 2) + ((in[i] >> 6) & 0x3)];
|
||||
out[j++] = base64en[in[i] & 0x3F];
|
||||
}
|
||||
}
|
||||
/* move back */
|
||||
i -= 1;
|
||||
/* check the last and add padding */
|
||||
if ((i % 3) == 0)
|
||||
{
|
||||
out[j++] = base64en[(in[i] & 0x3) << 4];
|
||||
out[j++] = BASE64_PAD;
|
||||
out[j++] = BASE64_PAD;
|
||||
}
|
||||
else if ((i % 3) == 1)
|
||||
{
|
||||
out[j++] = base64en[(in[i] & 0xF) << 2];
|
||||
out[j++] = BASE64_PAD;
|
||||
}
|
||||
return BASE64_OK;
|
||||
}
|
||||
|
||||
int swBase64_decode(char *in, int inlen, unsigned char *out)
|
||||
{
|
||||
int i, j;
|
||||
for (i = j = 0; i < inlen; i++)
|
||||
{
|
||||
int c;
|
||||
int s = i % 4; /* from 8/gcd(6, 8) */
|
||||
|
||||
if (in[i] == '=')
|
||||
{
|
||||
return BASE64_OK;
|
||||
}
|
||||
|
||||
if (in[i] < BASE64DE_FIRST || in[i] > BASE64DE_LAST || (c = base64de[in[i] - BASE64DE_FIRST]) == -1)
|
||||
{
|
||||
return BASE64_INVALID;
|
||||
}
|
||||
|
||||
switch (s)
|
||||
{
|
||||
case 0:
|
||||
out[j] = c << 2;
|
||||
continue;
|
||||
case 1:
|
||||
out[j++] += (c >> 4) & 0x3;
|
||||
/* if not last char with padding */
|
||||
if (i < (inlen - 3) || in[inlen - 2] != '=')
|
||||
out[j] = (c & 0xF) << 4;
|
||||
continue;
|
||||
case 2:
|
||||
out[j++] += (c >> 2) & 0xF;
|
||||
/* if not last char with padding */
|
||||
if (i < (inlen - 2) || in[inlen - 1] != '=')
|
||||
out[j] = (c & 0x3) << 6;
|
||||
continue;
|
||||
case 3:
|
||||
out[j++] += c;
|
||||
}
|
||||
}
|
||||
return BASE64_OK;
|
||||
}
|
302
vendor/swoole/src/protocol/Http.c
vendored
Executable file
302
vendor/swoole/src/protocol/Http.c
vendored
Executable file
@ -0,0 +1,302 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| Swoole |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 2.0 of the Apache license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.apache.org/licenses/LICENSE-2.0.html |
|
||||
| If you did not receive a copy of the Apache2.0 license and are unable|
|
||||
| to obtain it through the world-wide-web, please send a note to |
|
||||
| license@swoole.com so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Author: Tianfeng Han <mikan.tenny@gmail.com> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
#include "swoole.h"
|
||||
#include "http.h"
|
||||
#include "http2.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
|
||||
static const char *method_strings[] =
|
||||
{
|
||||
"DELETE", "GET", "HEAD", "POST", "PUT", "PATCH", "CONNECT", "OPTIONS", "TRACE", "COPY", "LOCK", "MKCOL", "MOVE",
|
||||
"PROPFIND", "PROPPATCH", "UNLOCK", "REPORT", "MKACTIVITY", "CHECKOUT", "MERGE", "M-SEARCH", "NOTIFY",
|
||||
"SUBSCRIBE", "UNSUBSCRIBE", "PRI",
|
||||
};
|
||||
|
||||
int swHttp_get_method(const char *method_str, int method_len)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < HTTP_PRI; i++)
|
||||
{
|
||||
if (strncasecmp(method_strings[i], method_str, method_len) == 0)
|
||||
{
|
||||
return i + 1;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
const char* swHttp_get_method_string(int method)
|
||||
{
|
||||
if (method < 0 || method > HTTP_PRI)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
return method_strings[method - 1];
|
||||
}
|
||||
|
||||
/**
|
||||
* only GET/POST
|
||||
*/
|
||||
int swHttpRequest_get_protocol(swHttpRequest *request)
|
||||
{
|
||||
char *buf = request->buffer->str;
|
||||
char *pe = buf + request->buffer->length;
|
||||
|
||||
if (request->buffer->length < 16)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
|
||||
//http method
|
||||
if (memcmp(buf, "GET", 3) == 0)
|
||||
{
|
||||
request->method = HTTP_GET;
|
||||
request->offset = 4;
|
||||
buf += 4;
|
||||
}
|
||||
else if (memcmp(buf, "POST", 4) == 0)
|
||||
{
|
||||
request->method = HTTP_POST;
|
||||
request->offset = 5;
|
||||
buf += 5;
|
||||
}
|
||||
else if (memcmp(buf, "PUT", 3) == 0)
|
||||
{
|
||||
request->method = HTTP_PUT;
|
||||
request->offset = 4;
|
||||
buf += 4;
|
||||
}
|
||||
else if (memcmp(buf, "PATCH", 5) == 0)
|
||||
{
|
||||
request->method = HTTP_PATCH;
|
||||
request->offset = 6;
|
||||
buf += 6;
|
||||
}
|
||||
else if (memcmp(buf, "DELETE", 6) == 0)
|
||||
{
|
||||
request->method = HTTP_DELETE;
|
||||
request->offset = 7;
|
||||
buf += 7;
|
||||
}
|
||||
else if (memcmp(buf, "HEAD", 4) == 0)
|
||||
{
|
||||
request->method = HTTP_HEAD;
|
||||
request->offset = 5;
|
||||
buf += 5;
|
||||
}
|
||||
else if (memcmp(buf, "OPTIONS", 7) == 0)
|
||||
{
|
||||
request->method = HTTP_OPTIONS;
|
||||
request->offset = 8;
|
||||
buf += 8;
|
||||
}
|
||||
#ifdef SW_USE_HTTP2
|
||||
//HTTP2 Connection Preface
|
||||
else if (memcmp(buf, "PRI", 3) == 0)
|
||||
{
|
||||
request->method = HTTP_PRI;
|
||||
if (memcmp(buf, SW_HTTP2_PRI_STRING, sizeof(SW_HTTP2_PRI_STRING) - 1) == 0)
|
||||
{
|
||||
request->buffer->offset = sizeof(SW_HTTP2_PRI_STRING) - 1;
|
||||
return SW_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
goto _excepted;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
_excepted: request->excepted = 1;
|
||||
return SW_ERR;
|
||||
}
|
||||
|
||||
//http version
|
||||
char *p;
|
||||
char state = 0;
|
||||
for (p = buf; p < pe; p++)
|
||||
{
|
||||
switch(state)
|
||||
{
|
||||
case 0:
|
||||
if (isspace(*p))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
state = 1;
|
||||
request->url_offset = p - request->buffer->str;
|
||||
break;
|
||||
case 1:
|
||||
if (isspace(*p))
|
||||
{
|
||||
state = 2;
|
||||
request->url_length = p - request->buffer->str - request->url_offset;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (isspace(*p))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (pe - p < 8)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
if (memcmp(p, "HTTP/1.1", 8) == 0)
|
||||
{
|
||||
request->version = HTTP_VERSION_11;
|
||||
goto end;
|
||||
}
|
||||
else if (memcmp(p, "HTTP/1.0", 8) == 0)
|
||||
{
|
||||
request->version = HTTP_VERSION_10;
|
||||
goto end;
|
||||
}
|
||||
else
|
||||
{
|
||||
goto _excepted;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
end: p += 8;
|
||||
request->buffer->offset = p - request->buffer->str;
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
void swHttpRequest_free(swConnection *conn)
|
||||
{
|
||||
swHttpRequest *request = conn->object;
|
||||
if (!request)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (request->buffer)
|
||||
{
|
||||
swString_free(request->buffer);
|
||||
}
|
||||
bzero(request, sizeof(swHttpRequest));
|
||||
sw_free(request);
|
||||
conn->object = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* POST content-length
|
||||
*/
|
||||
int swHttpRequest_get_content_length(swHttpRequest *request)
|
||||
{
|
||||
swString *buffer = request->buffer;
|
||||
char *buf = buffer->str + buffer->offset;
|
||||
int len = buffer->length - buffer->offset;
|
||||
|
||||
char *pe = buf + len;
|
||||
char *p;
|
||||
char *eol;
|
||||
|
||||
for (p = buf; p < pe; p++)
|
||||
{
|
||||
if (*p == '\r' && pe - p > sizeof("Content-Length"))
|
||||
{
|
||||
if (strncasecmp(p, SW_STRL("\r\nContent-Length") - 1) == 0)
|
||||
{
|
||||
//strlen("\r\n") + strlen("Content-Length")
|
||||
p += (2 + (sizeof("Content-Length:") - 1));
|
||||
//skip space
|
||||
if (*p == ' ')
|
||||
{
|
||||
p++;
|
||||
}
|
||||
eol = strstr(p, "\r\n");
|
||||
if (eol == NULL)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
request->content_length = atoi(p);
|
||||
return SW_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return SW_ERR;
|
||||
}
|
||||
|
||||
#ifdef SW_HTTP_100_CONTINUE
|
||||
int swHttpRequest_has_expect_header(swHttpRequest *request)
|
||||
{
|
||||
swString *buffer = request->buffer;
|
||||
//char *buf = buffer->str + buffer->offset;
|
||||
char *buf = buffer->str;
|
||||
//int len = buffer->length - buffer->offset;
|
||||
int len = buffer->length;
|
||||
|
||||
char *pe = buf + len;
|
||||
char *p;
|
||||
|
||||
for (p = buf; p < pe; p++)
|
||||
{
|
||||
if (*p == '\r' && pe - p > sizeof("\r\nExpect"))
|
||||
{
|
||||
p += 2;
|
||||
if (strncasecmp(p, SW_STRL("Expect") - 1) == 0)
|
||||
{
|
||||
p += sizeof("Expect: ") - 1;
|
||||
if (strncasecmp(p, SW_STRL("100-continue") - 1) == 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
p++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* header-length
|
||||
*/
|
||||
int swHttpRequest_get_header_length(swHttpRequest *request)
|
||||
{
|
||||
swString *buffer = request->buffer;
|
||||
char *buf = buffer->str + buffer->offset;
|
||||
int len = buffer->length - buffer->offset;
|
||||
|
||||
char *pe = buf + len;
|
||||
char *p;
|
||||
|
||||
for (p = buf; p < pe; p++)
|
||||
{
|
||||
if (*p == '\r' && p + 4 <= pe && memcmp(p, "\r\n\r\n", 4) == 0)
|
||||
{
|
||||
//strlen(header) + strlen("\r\n\r\n")
|
||||
request->header_length = p - buffer->str + 4;
|
||||
return SW_OK;
|
||||
}
|
||||
}
|
||||
return SW_ERR;
|
||||
}
|
142
vendor/swoole/src/protocol/Http2.c
vendored
Executable file
142
vendor/swoole/src/protocol/Http2.c
vendored
Executable file
@ -0,0 +1,142 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| Swoole |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 2012-2017 The Swoole Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 2.0 of the Apache license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.apache.org/licenses/LICENSE-2.0.html |
|
||||
| If you did not receive a copy of the Apache2.0 license and are unable|
|
||||
| to obtain it through the world-wide-web, please send a note to |
|
||||
| license@swoole.com so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Author: Tianfeng Han <mikan.tenny@gmail.com> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#include "swoole.h"
|
||||
#include "Connection.h"
|
||||
#include "http2.h"
|
||||
|
||||
int swHttp2_parse_frame(swProtocol *protocol, swConnection *conn, char *data, uint32_t length)
|
||||
{
|
||||
int wait_body = 0;
|
||||
int package_length = 0;
|
||||
|
||||
while (length > 0)
|
||||
{
|
||||
if (wait_body)
|
||||
{
|
||||
if (length >= package_length)
|
||||
{
|
||||
protocol->onPackage(conn, data, package_length);
|
||||
wait_body = 0;
|
||||
data += package_length;
|
||||
length -= package_length;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
package_length = protocol->get_package_length(protocol, conn, data, length);
|
||||
if (package_length < 0)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
else if (package_length == 0)
|
||||
{
|
||||
return SW_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
wait_body = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
int swHttp2_send_setting_frame(swProtocol *protocol, swConnection *conn)
|
||||
{
|
||||
char setting_frame[SW_HTTP2_FRAME_HEADER_SIZE + SW_HTTP2_SETTING_OPTION_SIZE * 3];
|
||||
char *p = setting_frame;
|
||||
uint16_t id;
|
||||
uint32_t value;
|
||||
|
||||
swHttp2_set_frame_header(p, SW_HTTP2_TYPE_SETTINGS, SW_HTTP2_SETTING_OPTION_SIZE * 3, 0, 0);
|
||||
p += SW_HTTP2_FRAME_HEADER_SIZE;
|
||||
|
||||
id = htons(SW_HTTP2_SETTINGS_MAX_CONCURRENT_STREAMS);
|
||||
memcpy(p, &id, sizeof(id));
|
||||
value = htonl(SW_HTTP2_MAX_CONCURRENT_STREAMS);
|
||||
memcpy(p + 2, &value, sizeof(value));
|
||||
p += SW_HTTP2_SETTING_OPTION_SIZE;
|
||||
|
||||
id = htons(SW_HTTP2_SETTINGS_INIT_WINDOW_SIZE);
|
||||
memcpy(p, &id, sizeof(id));
|
||||
value = htonl(SW_HTTP2_MAX_WINDOW);
|
||||
memcpy(p + 2, &value, sizeof(value));
|
||||
p += SW_HTTP2_SETTING_OPTION_SIZE;
|
||||
|
||||
id = htons(SW_HTTP2_SETTINGS_MAX_FRAME_SIZE);
|
||||
memcpy(p, &id, sizeof(id));
|
||||
value = htonl(SW_HTTP2_MAX_FRAME_SIZE);
|
||||
memcpy(p + 2, &value, sizeof(value));
|
||||
|
||||
return swConnection_send(conn, setting_frame, sizeof(setting_frame), 0);
|
||||
}
|
||||
|
||||
/**
|
||||
+-----------------------------------------------+
|
||||
| Length (24) |
|
||||
+---------------+---------------+---------------+
|
||||
| Type (8) | Flags (8) |
|
||||
+-+-------------+---------------+-------------------------------+
|
||||
|R| Stream Identifier (31) |
|
||||
+=+=============================================================+
|
||||
| Frame Payload (0...) ...
|
||||
+---------------------------------------------------------------+
|
||||
*/
|
||||
int swHttp2_get_frame_length(swProtocol *protocol, swConnection *conn, char *buf, uint32_t length)
|
||||
{
|
||||
if (length < SW_HTTP2_FRAME_HEADER_SIZE)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return swHttp2_get_length(buf) + SW_HTTP2_FRAME_HEADER_SIZE;
|
||||
}
|
||||
|
||||
char* swHttp2_get_type(int type)
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case SW_HTTP2_TYPE_DATA:
|
||||
return "DATA";
|
||||
case SW_HTTP2_TYPE_HEADERS:
|
||||
return "HEADERS";
|
||||
case SW_HTTP2_TYPE_PRIORITY:
|
||||
return "PRIORITY";
|
||||
case SW_HTTP2_TYPE_RST_STREAM:
|
||||
return "RST_STREAM";
|
||||
case SW_HTTP2_TYPE_SETTINGS:
|
||||
return "SETTINGS";
|
||||
case SW_HTTP2_TYPE_PUSH_PROMISE:
|
||||
return "PUSH_PROMISE";
|
||||
case SW_HTTP2_TYPE_PING:
|
||||
return "PING";
|
||||
case SW_HTTP2_TYPE_GOAWAY:
|
||||
return "GOAWAY";
|
||||
case SW_HTTP2_TYPE_WINDOW_UPDATE:
|
||||
return "WINDOW_UPDATE";
|
||||
case SW_HTTP2_TYPE_CONTINUATION:
|
||||
return "CONTINUATION";
|
||||
default:
|
||||
return "UNKOWN";
|
||||
}
|
||||
}
|
131
vendor/swoole/src/protocol/MimeTypes.c
vendored
Executable file
131
vendor/swoole/src/protocol/MimeTypes.c
vendored
Executable file
@ -0,0 +1,131 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| Swoole |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 2012-2015 The Swoole Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 2.0 of the Apache license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.apache.org/licenses/LICENSE-2.0.html |
|
||||
| If you did not receive a copy of the Apache2.0 license and are unable|
|
||||
| to obtain it through the world-wide-web, please send a note to |
|
||||
| license@swoole.com so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Author: Tianfeng Han <mikan.tenny@gmail.com> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#include "swoole.h"
|
||||
|
||||
char* swoole_get_mimetype(char *file)
|
||||
{
|
||||
char *dot;
|
||||
dot = strrchr(file, '.');
|
||||
if (dot == NULL)
|
||||
{
|
||||
return "text/plain";
|
||||
}
|
||||
if (strcasecmp(dot, ".html") == 0 || strcasecmp(dot, ".htm") == 0)
|
||||
{
|
||||
return "text/html";
|
||||
}
|
||||
else if (strcasecmp(dot, ".xml") == 0)
|
||||
{
|
||||
return "text/xml";
|
||||
}
|
||||
else if (strcasecmp(dot, ".css") == 0)
|
||||
{
|
||||
return "text/css";
|
||||
}
|
||||
else if (strcasecmp(dot, ".text") == 0 || strcasecmp(dot, ".txt") == 0)
|
||||
{
|
||||
return "text/plain";
|
||||
}
|
||||
else if (strcasecmp(dot, ".jpeg") == 0 || strcasecmp(dot, ".jpg") == 0)
|
||||
{
|
||||
return "image/jpeg";
|
||||
}
|
||||
else if (strcasecmp(dot, ".png") == 0)
|
||||
{
|
||||
return "image/png";
|
||||
}
|
||||
else if (strcasecmp(dot, ".gif") == 0)
|
||||
{
|
||||
return "image/gif";
|
||||
}
|
||||
else if (strcasecmp(dot, ".json") == 0)
|
||||
{
|
||||
return "application/json";
|
||||
}
|
||||
else if (strcasecmp(dot, ".js") == 0)
|
||||
{
|
||||
return "application/javascript";
|
||||
}
|
||||
else if (strcasecmp(dot, ".pdf") == 0)
|
||||
{
|
||||
return "application/pdf";
|
||||
}
|
||||
else if (strcasecmp(dot, ".doc") == 0)
|
||||
{
|
||||
return "application/msword";
|
||||
}
|
||||
else if (strcasecmp(dot, ".xls") == 0)
|
||||
{
|
||||
return "application/vnd.ms-excel";
|
||||
}
|
||||
else if (strcasecmp(dot, ".ppt") == 0)
|
||||
{
|
||||
return "application/vnd.ms-powerpoint";
|
||||
}
|
||||
else if (strcasecmp(dot, ".docx") == 0)
|
||||
{
|
||||
return "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
|
||||
}
|
||||
else if (strcasecmp(dot, ".xlsx") == 0)
|
||||
{
|
||||
return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
|
||||
}
|
||||
else if (strcasecmp(dot, ".pptx") == 0)
|
||||
{
|
||||
return "application/vnd.openxmlformats-officedocument.presentationml.presentation";
|
||||
}
|
||||
else if (strcasecmp(dot, ".swf") == 0)
|
||||
{
|
||||
return "application/x-shockwave-flash";
|
||||
}
|
||||
else if (strcasecmp(dot, ".zip") == 0)
|
||||
{
|
||||
return "application/zip";
|
||||
}
|
||||
else if (strcasecmp(dot, ".mp3") == 0)
|
||||
{
|
||||
return "audio/mpeg";
|
||||
}
|
||||
else if (strcasecmp(dot, ".mp4") == 0)
|
||||
{
|
||||
return "video/mp4";
|
||||
}
|
||||
else if (strcasecmp(dot, ".mpeg") == 0 || strcasecmp(dot, ".mpg") == 0)
|
||||
{
|
||||
return "video/mpeg";
|
||||
}
|
||||
else if (strcasecmp(dot, ".mov") == 0)
|
||||
{
|
||||
return "video/quicktime";
|
||||
}
|
||||
else if (strcasecmp(dot, ".flv") == 0)
|
||||
{
|
||||
return "video/x-flv";
|
||||
}
|
||||
else if (strcasecmp(dot, ".wmv") == 0)
|
||||
{
|
||||
return "video/x-ms-wmv";
|
||||
}
|
||||
else if (strcasecmp(dot, ".avi") == 0)
|
||||
{
|
||||
return "video/x-msvideo";
|
||||
}
|
||||
return "application/octet-stream";
|
||||
}
|
||||
|
70
vendor/swoole/src/protocol/Mqtt.c
vendored
Executable file
70
vendor/swoole/src/protocol/Mqtt.c
vendored
Executable file
@ -0,0 +1,70 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| Swoole |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 2012-2015 The Swoole Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 2.0 of the Apache license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.apache.org/licenses/LICENSE-2.0.html |
|
||||
| If you did not receive a copy of the Apache2.0 license and are unable|
|
||||
| to obtain it through the world-wide-web, please send a note to |
|
||||
| license@swoole.com so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Author: Tianfeng Han <mikan.tenny@gmail.com> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#include "mqtt.h"
|
||||
|
||||
void swMqtt_print_package(swMqtt_package *pkg)
|
||||
{
|
||||
printf("type=%d, length=%d\n", pkg->type, pkg->length);
|
||||
}
|
||||
|
||||
static sw_inline int swMqtt_get_length(char *data, uint32_t size, int *count)
|
||||
{
|
||||
uint8_t byte;
|
||||
int mul = 1;
|
||||
int length = 0;
|
||||
|
||||
*count = 0;
|
||||
do
|
||||
{
|
||||
byte = data[*count + 1];
|
||||
length += (byte & 127) * mul;
|
||||
mul *= 128;
|
||||
(*count)++;
|
||||
} while ((byte & 128) != 0);
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
//int swMqtt_unpack(swMqtt_package *pkg, char *data, uint32_t size)
|
||||
//{
|
||||
// uint8_t byte = data[0];
|
||||
// off_t offset;
|
||||
//
|
||||
// pkg->type = (byte & 0xF0) >> 4;
|
||||
// pkg->dup = (byte & 0x08) >> 3;
|
||||
// pkg->qos = (byte & 0x06) >> 1;
|
||||
// pkg->retain = byte & 0x01;
|
||||
//
|
||||
// offset += 1;
|
||||
//
|
||||
// int count = 0;
|
||||
// pkg->length = swMqtt_get_length(data, size, &count);
|
||||
// offset += count + 1;
|
||||
//}
|
||||
|
||||
int swMqtt_get_package_length(swProtocol *protocol, swConnection *conn, char *data, uint32_t size)
|
||||
{
|
||||
if (size < SW_MQTT_MIN_LENGTH)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
int count = 0;
|
||||
int length = swMqtt_get_length(data, size, &count);
|
||||
return length + count + 1;
|
||||
}
|
182
vendor/swoole/src/protocol/Redis.c
vendored
Executable file
182
vendor/swoole/src/protocol/Redis.c
vendored
Executable file
@ -0,0 +1,182 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| Swoole |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 2012-2015 The Swoole Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 2.0 of the Apache license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.apache.org/licenses/LICENSE-2.0.html |
|
||||
| If you did not receive a copy of the Apache2.0 license and are unable|
|
||||
| to obtain it through the world-wide-web, please send a note to |
|
||||
| license@swoole.com so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Author: Tianfeng Han <mikan.tenny@gmail.com> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#include "swoole.h"
|
||||
#include "redis.h"
|
||||
#include "Connection.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t state;
|
||||
|
||||
int n_lines_total;
|
||||
int n_lines_received;
|
||||
|
||||
int n_bytes_total;
|
||||
int n_bytes_received;
|
||||
|
||||
int offset;
|
||||
|
||||
} swRedis_request;
|
||||
|
||||
int swRedis_recv(swProtocol *protocol, swConnection *conn, swString *buffer)
|
||||
{
|
||||
char *p, *pe;
|
||||
int ret;
|
||||
char *buf_ptr;
|
||||
size_t buf_size;
|
||||
|
||||
swRedis_request *request;
|
||||
|
||||
if (conn->object == NULL)
|
||||
{
|
||||
request = sw_malloc(sizeof(swRedis_request));
|
||||
bzero(request, sizeof(swRedis_request));
|
||||
conn->object = request;
|
||||
}
|
||||
else
|
||||
{
|
||||
request = (swRedis_request *) conn->object;
|
||||
}
|
||||
|
||||
recv_data: buf_ptr = buffer->str + buffer->length;
|
||||
buf_size = buffer->size - buffer->length;
|
||||
|
||||
int n = swConnection_recv(conn, buf_ptr, buf_size, 0);
|
||||
if (n < 0)
|
||||
{
|
||||
switch (swConnection_error(errno))
|
||||
{
|
||||
case SW_ERROR:
|
||||
swSysError("recv from socket#%d failed.", conn->fd);
|
||||
return SW_OK;
|
||||
case SW_CLOSE:
|
||||
conn->close_errno = errno;
|
||||
return SW_ERR;
|
||||
default:
|
||||
return SW_OK;
|
||||
}
|
||||
}
|
||||
else if (n == 0)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer->length += n;
|
||||
|
||||
if (strncmp(buffer->str + buffer->length - SW_CRLF_LEN, SW_CRLF, SW_CRLF_LEN) != 0)
|
||||
{
|
||||
if (buffer->size < protocol->package_max_length)
|
||||
{
|
||||
uint32_t extend_size = swoole_size_align(buffer->size * 2, SwooleG.pagesize);
|
||||
if (extend_size > protocol->package_max_length)
|
||||
{
|
||||
extend_size = protocol->package_max_length;
|
||||
}
|
||||
if (swString_extend(buffer, extend_size) < 0)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
}
|
||||
else if (buffer->length == buffer->size)
|
||||
{
|
||||
package_too_big:
|
||||
swWarn("Package is too big. package_length=%ld.", buffer->length);
|
||||
return SW_ERR;
|
||||
}
|
||||
goto recv_data;
|
||||
}
|
||||
|
||||
p = buffer->str;
|
||||
pe = p + buffer->length;
|
||||
|
||||
do
|
||||
{
|
||||
switch(request->state)
|
||||
{
|
||||
case SW_REDIS_RECEIVE_TOTAL_LINE:
|
||||
if (*p == '*' && (p = swRedis_get_number(p, &ret)))
|
||||
{
|
||||
request->n_lines_total = ret;
|
||||
request->state = SW_REDIS_RECEIVE_LENGTH;
|
||||
break;
|
||||
}
|
||||
/* no break */
|
||||
|
||||
case SW_REDIS_RECEIVE_LENGTH:
|
||||
if (*p == '$' && (p = swRedis_get_number(p, &ret)))
|
||||
{
|
||||
if (ret < 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (ret + (p - buffer->str) > protocol->package_max_length)
|
||||
{
|
||||
goto package_too_big;
|
||||
}
|
||||
request->n_bytes_total = ret;
|
||||
request->state = SW_REDIS_RECEIVE_STRING;
|
||||
break;
|
||||
}
|
||||
//integer
|
||||
else if (*p == ':' && (p = swRedis_get_number(p, &ret)))
|
||||
{
|
||||
break;
|
||||
}
|
||||
/* no break */
|
||||
|
||||
case SW_REDIS_RECEIVE_STRING:
|
||||
if (pe - p < request->n_bytes_total - request->n_bytes_received)
|
||||
{
|
||||
request->n_bytes_received += pe - p;
|
||||
return SW_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
p += request->n_bytes_total + SW_CRLF_LEN;
|
||||
request->n_bytes_total = 0;
|
||||
request->n_lines_received++;
|
||||
request->state = SW_REDIS_RECEIVE_LENGTH;
|
||||
|
||||
if (request->n_lines_received == request->n_lines_total)
|
||||
{
|
||||
if (protocol->onPackage(conn, buffer->str, buffer->length) < 0)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
if (conn->removed)
|
||||
{
|
||||
return SW_OK;
|
||||
}
|
||||
swString_clear(buffer);
|
||||
bzero(request, sizeof(swRedis_request));
|
||||
return SW_OK;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
goto failed;
|
||||
}
|
||||
} while(p < pe);
|
||||
}
|
||||
failed:
|
||||
swWarn("redis protocol error.");
|
||||
return SW_ERR;
|
||||
}
|
1160
vendor/swoole/src/protocol/SSL.c
vendored
Executable file
1160
vendor/swoole/src/protocol/SSL.c
vendored
Executable file
File diff suppressed because it is too large
Load Diff
150
vendor/swoole/src/protocol/Sha1.c
vendored
Executable file
150
vendor/swoole/src/protocol/Sha1.c
vendored
Executable file
@ -0,0 +1,150 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| Swoole |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 2.0 of the Apache license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.apache.org/licenses/LICENSE-2.0.html |
|
||||
| If you did not receive a copy of the Apache2.0 license and are unable|
|
||||
| to obtain it through the world-wide-web, please send a note to |
|
||||
| license@swoole.com so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Author: Tianfeng Han <mikan.tenny@gmail.com> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
#include <string.h>
|
||||
|
||||
#include "sha1.h"
|
||||
|
||||
#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
|
||||
|
||||
/* blk0() and blk() perform the initial expand. */
|
||||
/* I got the idea of expanding during the round function from SSLeay */
|
||||
|
||||
#ifdef LITTLE_ENDIAN
|
||||
#define blk0(i) (block->l[i] = (rol(block->l[i],24)&(sha1_quadbyte)0xFF00FF00) \
|
||||
|(rol(block->l[i],8)&(sha1_quadbyte)0x00FF00FF))
|
||||
#else
|
||||
#define blk0(i) block->l[i]
|
||||
#endif
|
||||
|
||||
#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
|
||||
^block->l[(i+2)&15]^block->l[i&15],1))
|
||||
|
||||
/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
|
||||
#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
|
||||
#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
|
||||
#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
|
||||
#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
|
||||
#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
|
||||
|
||||
typedef union _BYTE64QUAD16 {
|
||||
sha1_byte c[64];
|
||||
sha1_quadbyte l[16];
|
||||
} BYTE64QUAD16;
|
||||
static void swSha1_transform(sha1_quadbyte state[5], sha1_byte buffer[64]);
|
||||
/* Hash a single 512-bit block. This is the core of the algorithm. */
|
||||
static void swSha1_transform(sha1_quadbyte state[5], sha1_byte buffer[64]) {
|
||||
sha1_quadbyte a, b, c, d, e;
|
||||
BYTE64QUAD16 src;
|
||||
BYTE64QUAD16 *block;
|
||||
|
||||
/* slow but cast-align */
|
||||
memcpy(src.c, buffer, sizeof(sha1_byte) * 64);
|
||||
block = &src;
|
||||
/* Copy context->state[] to working vars */
|
||||
a = state[0];
|
||||
b = state[1];
|
||||
c = state[2];
|
||||
d = state[3];
|
||||
e = state[4];
|
||||
/* 4 rounds of 20 operations each. Loop unrolled. */
|
||||
R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
|
||||
R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
|
||||
R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
|
||||
R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
|
||||
R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
|
||||
R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
|
||||
R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
|
||||
R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
|
||||
R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
|
||||
R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
|
||||
R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
|
||||
R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
|
||||
R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
|
||||
R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
|
||||
R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
|
||||
R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
|
||||
R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
|
||||
R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
|
||||
R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
|
||||
R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
|
||||
/* Add the working vars back into context.state[] */
|
||||
state[0] += a;
|
||||
state[1] += b;
|
||||
state[2] += c;
|
||||
state[3] += d;
|
||||
state[4] += e;
|
||||
/* Wipe variables */
|
||||
a = b = c = d = e = 0;
|
||||
}
|
||||
|
||||
|
||||
/* swSha1_init - Initialize new context */
|
||||
void swSha1_init(SHA_CTX* context) {
|
||||
/* SHA1 initialization constants */
|
||||
context->state[0] = 0x67452301;
|
||||
context->state[1] = 0xEFCDAB89;
|
||||
context->state[2] = 0x98BADCFE;
|
||||
context->state[3] = 0x10325476;
|
||||
context->state[4] = 0xC3D2E1F0;
|
||||
context->count[0] = context->count[1] = 0;
|
||||
}
|
||||
|
||||
/* Run your data through this. */
|
||||
void swSha1_update(SHA_CTX *context, sha1_byte *data, unsigned int len) {
|
||||
unsigned int i, j;
|
||||
|
||||
j = (context->count[0] >> 3) & 63;
|
||||
if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++;
|
||||
context->count[1] += (len >> 29);
|
||||
if ((j + len) > 63) {
|
||||
memcpy(&context->buffer[j], data, (i = 64-j));
|
||||
swSha1_transform(context->state, context->buffer);
|
||||
for ( ; i + 63 < len; i += 64) {
|
||||
swSha1_transform(context->state, &data[i]);
|
||||
}
|
||||
j = 0;
|
||||
}
|
||||
else i = 0;
|
||||
memcpy(&context->buffer[j], &data[i], len - i);
|
||||
}
|
||||
|
||||
|
||||
/* Add padding and return the message digest. */
|
||||
void swSha1_final(sha1_byte digest[SHA1_DIGEST_LENGTH], SHA_CTX *context) {
|
||||
sha1_quadbyte i, j;
|
||||
sha1_byte finalcount[8];
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
finalcount[i] = (sha1_byte)((context->count[(i >= 4 ? 0 : 1)]
|
||||
>> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */
|
||||
}
|
||||
swSha1_update(context, (sha1_byte *)"\200", 1);
|
||||
while ((context->count[0] & 504) != 448) {
|
||||
swSha1_update(context, (sha1_byte *)"\0", 1);
|
||||
}
|
||||
/* Should cause a swSha1_Transform() */
|
||||
swSha1_update(context, finalcount, 8);
|
||||
for (i = 0; i < SHA1_DIGEST_LENGTH; i++) {
|
||||
digest[i] = (sha1_byte)
|
||||
((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
|
||||
}
|
||||
/* Wipe variables */
|
||||
i = j = 0;
|
||||
memset(context->buffer, 0, SHA1_BLOCK_LENGTH);
|
||||
memset(context->state, 0, SHA1_DIGEST_LENGTH);
|
||||
memset(context->count, 0, 8);
|
||||
memset(&finalcount, 0, 8);
|
||||
}
|
154
vendor/swoole/src/protocol/Socks5.c
vendored
Executable file
154
vendor/swoole/src/protocol/Socks5.c
vendored
Executable file
@ -0,0 +1,154 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| Swoole |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 2012-2017 The Swoole Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 2.0 of the Apache license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.apache.org/licenses/LICENSE-2.0.html |
|
||||
| If you did not receive a copy of the Apache2.0 license and are unable|
|
||||
| to obtain it through the world-wide-web, please send a note to |
|
||||
| license@swoole.com so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Author: Tianfeng Han <mikan.tenny@gmail.com> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#include "swoole.h"
|
||||
#include "Client.h"
|
||||
#include "socks5.h"
|
||||
|
||||
char* swSocks5_strerror(int code)
|
||||
{
|
||||
switch (code)
|
||||
{
|
||||
case 0x01:
|
||||
return "General failure";
|
||||
case 0x02:
|
||||
return "Connection not allowed by ruleset";
|
||||
case 0x03:
|
||||
return "Network unreachable";
|
||||
case 0x04:
|
||||
return "Host unreachable";
|
||||
case 0x05:
|
||||
return "Connection refused by destination host";
|
||||
case 0x06:
|
||||
return "TTL expired";
|
||||
case 0x07:
|
||||
return "command not supported / protocol error";
|
||||
case 0x08:
|
||||
return "address type not supported";
|
||||
default:
|
||||
return "Unknown error";
|
||||
}
|
||||
}
|
||||
|
||||
int swSocks5_connect(swClient *cli, char *recv_data, int length)
|
||||
{
|
||||
swSocks5 *ctx = cli->socks5_proxy;
|
||||
char *buf = ctx->buf;
|
||||
|
||||
if (ctx->state == SW_SOCKS5_STATE_HANDSHAKE)
|
||||
{
|
||||
uchar version = recv_data[0];
|
||||
uchar method = recv_data[1];
|
||||
if (version != SW_SOCKS5_VERSION_CODE)
|
||||
{
|
||||
swoole_error_log(SW_LOG_NOTICE, SW_ERROR_SOCKS5_UNSUPPORT_VERSION, "SOCKS version is not supported.");
|
||||
return SW_ERR;
|
||||
}
|
||||
if (method != ctx->method)
|
||||
{
|
||||
swoole_error_log(SW_LOG_NOTICE, SW_ERROR_SOCKS5_UNSUPPORT_METHOD, "SOCKS authentication method not supported.");
|
||||
return SW_ERR;
|
||||
}
|
||||
//authenticate request
|
||||
if (method == SW_SOCKS5_METHOD_AUTH)
|
||||
{
|
||||
buf[0] = 0x01;
|
||||
buf[1] = ctx->l_username;
|
||||
|
||||
buf += 2;
|
||||
memcpy(buf, ctx->username, ctx->l_username);
|
||||
buf += ctx->l_username;
|
||||
buf[0] = ctx->l_password;
|
||||
memcpy(buf + 1, ctx->password, ctx->l_password);
|
||||
|
||||
ctx->state = SW_SOCKS5_STATE_AUTH;
|
||||
|
||||
return cli->send(cli, ctx->buf, ctx->l_username + ctx->l_password + 3, 0);
|
||||
}
|
||||
//send connect request
|
||||
else
|
||||
{
|
||||
send_connect_request:
|
||||
buf[0] = SW_SOCKS5_VERSION_CODE;
|
||||
buf[1] = 0x01;
|
||||
buf[2] = 0x00;
|
||||
|
||||
ctx->state = SW_SOCKS5_STATE_CONNECT;
|
||||
|
||||
if (ctx->dns_tunnel)
|
||||
{
|
||||
buf[3] = 0x03;
|
||||
buf[4] = ctx->l_target_host;
|
||||
buf += 5;
|
||||
memcpy(buf, ctx->target_host, ctx->l_target_host);
|
||||
buf += ctx->l_target_host;
|
||||
*(uint16_t *) buf = htons(ctx->target_port);
|
||||
return cli->send(cli, ctx->buf, ctx->l_target_host + 7, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
buf[3] = 0x01;
|
||||
buf += 4;
|
||||
*(uint32_t *) buf = htons(ctx->l_target_host);
|
||||
buf += 4;
|
||||
*(uint16_t *) buf = htons(ctx->target_port);
|
||||
return cli->send(cli, ctx->buf, ctx->l_target_host + 7, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (ctx->state == SW_SOCKS5_STATE_AUTH)
|
||||
{
|
||||
uchar version = recv_data[0];
|
||||
uchar status = recv_data[1];
|
||||
if (version != 0x01)
|
||||
{
|
||||
swoole_error_log(SW_LOG_NOTICE, SW_ERROR_SOCKS5_UNSUPPORT_VERSION, "SOCKS version is not supported.");
|
||||
return SW_ERR;
|
||||
}
|
||||
if (status != 0)
|
||||
{
|
||||
swoole_error_log(SW_LOG_NOTICE, SW_ERROR_SOCKS5_AUTH_FAILED, "SOCKS username/password authentication failed.");
|
||||
return SW_ERR;
|
||||
}
|
||||
goto send_connect_request;
|
||||
}
|
||||
else if (ctx->state == SW_SOCKS5_STATE_CONNECT)
|
||||
{
|
||||
uchar version = recv_data[0];
|
||||
if (version != SW_SOCKS5_VERSION_CODE)
|
||||
{
|
||||
swoole_error_log(SW_LOG_NOTICE, SW_ERROR_SOCKS5_UNSUPPORT_VERSION, "SOCKS version is not supported.");
|
||||
return SW_ERR;
|
||||
}
|
||||
uchar result = recv_data[1];
|
||||
// uchar reg = recv_data[2];
|
||||
// uchar type = recv_data[3];
|
||||
// uint32_t ip = *(uint32_t *) (recv_data + 4);
|
||||
// uint16_t port = *(uint16_t *) (recv_data + 8);
|
||||
if (result == 0)
|
||||
{
|
||||
ctx->state = SW_SOCKS5_STATE_READY;
|
||||
}
|
||||
else
|
||||
{
|
||||
swoole_error_log(SW_LOG_NOTICE, SW_ERROR_SOCKS5_SERVER_ERROR, "Socks5 server error, reason :%s.", swSocks5_strerror(result));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return SW_OK;
|
||||
}
|
312
vendor/swoole/src/protocol/WebSocket.c
vendored
Executable file
312
vendor/swoole/src/protocol/WebSocket.c
vendored
Executable file
@ -0,0 +1,312 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| Swoole |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 2.0 of the Apache license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.apache.org/licenses/LICENSE-2.0.html |
|
||||
| If you did not receive a copy of the Apache2.0 license and are unable|
|
||||
| to obtain it through the world-wide-web, please send a note to |
|
||||
| license@swoole.com so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Author: Tianfeng Han <mikan.tenny@gmail.com> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#include "swoole.h"
|
||||
#include "Server.h"
|
||||
#include "websocket.h"
|
||||
#include "Connection.h"
|
||||
|
||||
#include <sys/time.h>
|
||||
|
||||
/* The following is websocket data frame:
|
||||
+-+-+-+-+-------+-+-------------+-------------------------------+
|
||||
0 1 2 3 |
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 |
|
||||
+-+-+-+-+-------+-+-------------+-------------------------------+
|
||||
|F|R|R|R| opcode|M| Payload len | Extended payload length |
|
||||
|I|S|S|S| (4) |A| (7) | (16/64) |
|
||||
|N|V|V|V| |S| | (if payload len==126/127) |
|
||||
| |1|2|3| |K| | |
|
||||
+-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
|
||||
| Extended payload length continued, if payload len == 127 |
|
||||
+ - - - - - - - - - - - - - - - +-------------------------------+
|
||||
| |Masking-key, if MASK set to 1 |
|
||||
+-------------------------------+-------------------------------+
|
||||
| Masking-key (continued) | Payload Data |
|
||||
+-------------------------------- - - - - - - - - - - - - - - - +
|
||||
: Payload Data continued ... :
|
||||
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
|
||||
| Payload Data continued ... |
|
||||
+---------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
int swWebSocket_get_package_length(swProtocol *protocol, swConnection *conn, char *buf, uint32_t length)
|
||||
{
|
||||
//need more data
|
||||
if (length < SW_WEBSOCKET_HEADER_LEN)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
char mask = (buf[1] >> 7) & 0x1;
|
||||
//0-125
|
||||
uint64_t payload_length = buf[1] & 0x7f;
|
||||
int header_length = SW_WEBSOCKET_HEADER_LEN;
|
||||
buf += SW_WEBSOCKET_HEADER_LEN;
|
||||
|
||||
//uint16_t, 2byte
|
||||
if (payload_length == 0x7e)
|
||||
{
|
||||
if (length < 4)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
payload_length = ntohs(*((uint16_t *) buf));
|
||||
header_length += sizeof(uint16_t);
|
||||
buf += sizeof(uint16_t);
|
||||
}
|
||||
//uint64_t, 8byte
|
||||
else if (payload_length > 0x7e)
|
||||
{
|
||||
if (length < 10)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
payload_length = swoole_ntoh64(*((uint64_t *) buf));
|
||||
header_length += sizeof(uint64_t);
|
||||
buf += sizeof(uint64_t);
|
||||
}
|
||||
if (mask)
|
||||
{
|
||||
if (length < header_length + 4)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
header_length += SW_WEBSOCKET_MASK_LEN;
|
||||
}
|
||||
swTrace("header_length=%d, payload_length=%d", (int)header_length, (int)payload_length);
|
||||
return header_length + payload_length;
|
||||
}
|
||||
|
||||
void swWebSocket_encode(swString *buffer, char *data, size_t length, char opcode, int finish, int mask)
|
||||
{
|
||||
int pos = 0;
|
||||
char frame_header[16];
|
||||
|
||||
/**
|
||||
* frame header
|
||||
*/
|
||||
frame_header[pos++] = FRAME_SET_FIN(finish) | FRAME_SET_OPCODE(opcode);
|
||||
if (length < 126)
|
||||
{
|
||||
frame_header[pos++] = FRAME_SET_MASK(mask) | FRAME_SET_LENGTH(length, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (length < 65536)
|
||||
{
|
||||
frame_header[pos++] = FRAME_SET_MASK(mask) | 126;
|
||||
}
|
||||
else
|
||||
{
|
||||
frame_header[pos++] = FRAME_SET_MASK(mask) | 127;
|
||||
frame_header[pos++] = FRAME_SET_LENGTH(length, 7);
|
||||
frame_header[pos++] = FRAME_SET_LENGTH(length, 6);
|
||||
frame_header[pos++] = FRAME_SET_LENGTH(length, 5);
|
||||
frame_header[pos++] = FRAME_SET_LENGTH(length, 4);
|
||||
frame_header[pos++] = FRAME_SET_LENGTH(length, 3);
|
||||
frame_header[pos++] = FRAME_SET_LENGTH(length, 2);
|
||||
}
|
||||
frame_header[pos++] = FRAME_SET_LENGTH(length, 1);
|
||||
frame_header[pos++] = FRAME_SET_LENGTH(length, 0);
|
||||
}
|
||||
swString_append_ptr(buffer, frame_header, pos);
|
||||
|
||||
/**
|
||||
* frame body
|
||||
*/
|
||||
if (data && length > 0)
|
||||
{
|
||||
if (mask)
|
||||
{
|
||||
char *_mask_data = SW_WEBSOCKET_MASK_DATA;
|
||||
swString_append_ptr(buffer, _mask_data, SW_WEBSOCKET_MASK_LEN);
|
||||
|
||||
char *_data = buffer->str + buffer->length;
|
||||
swString_append_ptr(buffer, data, length);
|
||||
|
||||
int i;
|
||||
for (i = 0; i < length; i++)
|
||||
{
|
||||
_data[i] ^= _mask_data[i % SW_WEBSOCKET_MASK_LEN];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
swString_append_ptr(buffer, data, length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void swWebSocket_decode(swWebSocket_frame *frame, swString *data)
|
||||
{
|
||||
memcpy(frame, data->str, SW_WEBSOCKET_HEADER_LEN);
|
||||
|
||||
//0-125
|
||||
size_t payload_length = frame->header.LENGTH;
|
||||
uint8_t header_length = SW_WEBSOCKET_HEADER_LEN;
|
||||
char *buf = data->str + SW_WEBSOCKET_HEADER_LEN;
|
||||
|
||||
//uint16_t, 2byte
|
||||
if (frame->header.LENGTH == 0x7e)
|
||||
{
|
||||
payload_length = ntohs(*((uint16_t *) buf));
|
||||
header_length += 2;
|
||||
}
|
||||
//uint64_t, 8byte
|
||||
else if (frame->header.LENGTH > 0x7e)
|
||||
{
|
||||
payload_length = swoole_ntoh64(*((uint64_t *) buf));
|
||||
header_length += 8;
|
||||
}
|
||||
|
||||
if (frame->header.MASK)
|
||||
{
|
||||
char *mask_key = frame->mask_key;
|
||||
memcpy(mask_key, data->str + header_length, SW_WEBSOCKET_MASK_LEN);
|
||||
header_length += SW_WEBSOCKET_MASK_LEN;
|
||||
buf = data->str + header_length;
|
||||
int i;
|
||||
for (i = 0; i < payload_length; i++)
|
||||
{
|
||||
buf[i] ^= mask_key[i % SW_WEBSOCKET_MASK_LEN];
|
||||
}
|
||||
}
|
||||
frame->payload_length = payload_length;
|
||||
frame->header_length = header_length;
|
||||
frame->payload = data->str + header_length;
|
||||
}
|
||||
|
||||
void swWebSocket_print_frame(swWebSocket_frame *frame)
|
||||
{
|
||||
printf("FIN: %x, RSV1: %d, RSV2: %d, RSV3: %d, opcode: %d, MASK: %d, length: %ld\n", frame->header.FIN,
|
||||
frame->header.RSV1, frame->header.RSV2, frame->header.RSV3, frame->header.OPCODE, frame->header.MASK,
|
||||
frame->payload_length);
|
||||
|
||||
if (frame->payload_length)
|
||||
{
|
||||
printf("payload: %s\n", frame->payload);
|
||||
}
|
||||
}
|
||||
|
||||
int swWebSocket_dispatch_frame(swConnection *conn, char *data, uint32_t length)
|
||||
{
|
||||
swString frame;
|
||||
bzero(&frame, sizeof(frame));
|
||||
frame.str = data;
|
||||
frame.length = length;
|
||||
|
||||
swString send_frame;
|
||||
bzero(&send_frame, sizeof(send_frame));
|
||||
char buf[128];
|
||||
send_frame.str = buf;
|
||||
send_frame.size = sizeof(buf);
|
||||
|
||||
swWebSocket_frame ws;
|
||||
swWebSocket_decode(&ws, &frame);
|
||||
|
||||
swString *frame_buffer;
|
||||
int frame_length;
|
||||
swListenPort *port;
|
||||
|
||||
size_t offset;
|
||||
switch (ws.header.OPCODE)
|
||||
{
|
||||
case WEBSOCKET_OPCODE_CONTINUATION_FRAME:
|
||||
frame_buffer = conn->websocket_buffer;
|
||||
if (frame_buffer == NULL)
|
||||
{
|
||||
swWarn("bad frame[opcode=0]. remote_addr=%s:%d.", swConnection_get_ip(conn), swConnection_get_port(conn));
|
||||
return SW_ERR;
|
||||
}
|
||||
offset = length - ws.payload_length;
|
||||
frame_length = length - offset;
|
||||
port = swServer_get_port(SwooleG.serv, conn->fd);
|
||||
//frame data overflow
|
||||
if (frame_buffer->length + frame_length > port->protocol.package_max_length)
|
||||
{
|
||||
swWarn("websocket frame is too big, remote_addr=%s:%d.", swConnection_get_ip(conn), swConnection_get_port(conn));
|
||||
return SW_ERR;
|
||||
}
|
||||
//merge incomplete data
|
||||
swString_append_ptr(frame_buffer, data + offset, frame_length);
|
||||
//frame is finished, do dispatch
|
||||
if (ws.header.FIN)
|
||||
{
|
||||
swReactorThread_dispatch(conn, frame_buffer->str, frame_buffer->length);
|
||||
swString_free(frame_buffer);
|
||||
conn->websocket_buffer = NULL;
|
||||
}
|
||||
break;
|
||||
|
||||
case WEBSOCKET_OPCODE_TEXT_FRAME:
|
||||
case WEBSOCKET_OPCODE_BINARY_FRAME:
|
||||
offset = length - ws.payload_length - SW_WEBSOCKET_HEADER_LEN;
|
||||
data[offset] = 1;
|
||||
data[offset + 1] = ws.header.OPCODE;
|
||||
if (!ws.header.FIN)
|
||||
{
|
||||
if (conn->websocket_buffer)
|
||||
{
|
||||
swWarn("merging incomplete frame, bad request. remote_addr=%s:%d.", swConnection_get_ip(conn), swConnection_get_port(conn));
|
||||
return SW_ERR;
|
||||
}
|
||||
conn->websocket_buffer = swString_dup(data + offset, length - offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
swReactorThread_dispatch(conn, data + offset, length - offset);
|
||||
}
|
||||
break;
|
||||
|
||||
case WEBSOCKET_OPCODE_PING:
|
||||
if (length >= (sizeof(buf) - SW_WEBSOCKET_HEADER_LEN))
|
||||
{
|
||||
swWarn("ping frame application data is too big. remote_addr=%s:%d.", swConnection_get_ip(conn), swConnection_get_port(conn));
|
||||
return SW_ERR;
|
||||
}
|
||||
else if (length == SW_WEBSOCKET_HEADER_LEN)
|
||||
{
|
||||
swWebSocket_encode(&send_frame, NULL, 0, WEBSOCKET_OPCODE_PONG, 1, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
offset = ws.header.MASK ? SW_WEBSOCKET_HEADER_LEN + SW_WEBSOCKET_MASK_LEN : SW_WEBSOCKET_HEADER_LEN;
|
||||
swWebSocket_encode(&send_frame, data += offset, length - offset, WEBSOCKET_OPCODE_PONG, 1, 0);
|
||||
}
|
||||
swConnection_send(conn, send_frame.str, send_frame.length, 0);
|
||||
break;
|
||||
|
||||
case WEBSOCKET_OPCODE_PONG:
|
||||
break;
|
||||
|
||||
case WEBSOCKET_OPCODE_CONNECTION_CLOSE:
|
||||
if (0x7d < (length - 2))
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
send_frame.str[0] = 0x88;
|
||||
send_frame.str[1] = 0x00;
|
||||
send_frame.length = 2;
|
||||
swConnection_send(conn, send_frame.str, 2, 0);
|
||||
return SW_ERR;
|
||||
|
||||
default:
|
||||
swWarn("unknown opcode [%d].", ws.header.OPCODE);
|
||||
break;
|
||||
}
|
||||
return SW_OK;
|
||||
}
|
461
vendor/swoole/src/reactor/ReactorBase.c
vendored
Executable file
461
vendor/swoole/src/reactor/ReactorBase.c
vendored
Executable file
@ -0,0 +1,461 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| 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 "Connection.h"
|
||||
#include "async.h"
|
||||
#include "Server.h"
|
||||
|
||||
#ifdef SW_USE_MALLOC_TRIM
|
||||
#ifdef __APPLE__
|
||||
#include <sys/malloc.h>
|
||||
#else
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef SW_COROUTINE
|
||||
#include "coroutine.h"
|
||||
#endif
|
||||
|
||||
static void swReactor_onTimeout_and_Finish(swReactor *reactor);
|
||||
static void swReactor_onTimeout(swReactor *reactor);
|
||||
static void swReactor_onFinish(swReactor *reactor);
|
||||
static void swReactor_onBegin(swReactor *reactor);
|
||||
static int swReactor_defer(swReactor *reactor, swCallback callback, void *data);
|
||||
|
||||
int swReactor_create(swReactor *reactor, int max_event)
|
||||
{
|
||||
int ret;
|
||||
bzero(reactor, sizeof(swReactor));
|
||||
|
||||
#ifdef HAVE_EPOLL
|
||||
ret = swReactorEpoll_create(reactor, max_event);
|
||||
#elif defined(HAVE_KQUEUE)
|
||||
ret = swReactorKqueue_create(reactor, max_event);
|
||||
#elif defined(HAVE_POLL)
|
||||
ret = swReactorPoll_create(reactor, max_event);
|
||||
#else
|
||||
ret = swReactorSelect_create(reactor);
|
||||
#endif
|
||||
|
||||
reactor->running = 1;
|
||||
|
||||
reactor->setHandle = swReactor_setHandle;
|
||||
|
||||
reactor->onFinish = swReactor_onFinish;
|
||||
reactor->onTimeout = swReactor_onTimeout;
|
||||
|
||||
reactor->write = swReactor_write;
|
||||
reactor->defer = swReactor_defer;
|
||||
reactor->close = swReactor_close;
|
||||
|
||||
reactor->socket_array = swArray_new(1024, sizeof(swConnection));
|
||||
if (!reactor->socket_array)
|
||||
{
|
||||
swWarn("create socket array failed.");
|
||||
return SW_ERR;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int swReactor_setHandle(swReactor *reactor, int _fdtype, swReactor_handle handle)
|
||||
{
|
||||
int fdtype = swReactor_fdtype(_fdtype);
|
||||
|
||||
if (fdtype >= SW_MAX_FDTYPE)
|
||||
{
|
||||
swWarn("fdtype > SW_MAX_FDTYPE[%d]", SW_MAX_FDTYPE);
|
||||
return SW_ERR;
|
||||
}
|
||||
|
||||
if (swReactor_event_read(_fdtype))
|
||||
{
|
||||
reactor->handle[fdtype] = handle;
|
||||
}
|
||||
else if (swReactor_event_write(_fdtype))
|
||||
{
|
||||
reactor->write_handle[fdtype] = handle;
|
||||
}
|
||||
else if (swReactor_event_error(_fdtype))
|
||||
{
|
||||
reactor->error_handle[fdtype] = handle;
|
||||
}
|
||||
else
|
||||
{
|
||||
swWarn("unknow fdtype");
|
||||
return SW_ERR;
|
||||
}
|
||||
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
static int swReactor_defer(swReactor *reactor, swCallback callback, void *data)
|
||||
{
|
||||
swDefer_callback *cb = sw_malloc(sizeof(swDefer_callback));
|
||||
if (!cb)
|
||||
{
|
||||
swWarn("malloc(%ld) failed.", sizeof(swDefer_callback));
|
||||
return SW_ERR;
|
||||
}
|
||||
cb->callback = callback;
|
||||
cb->data = data;
|
||||
LL_APPEND(reactor->defer_callback_list, cb);
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
int swReactor_empty(swReactor *reactor)
|
||||
{
|
||||
//timer
|
||||
if (SwooleG.timer.num > 0)
|
||||
{
|
||||
return SW_FALSE;
|
||||
}
|
||||
|
||||
int empty = SW_FALSE;
|
||||
//thread pool
|
||||
if (SwooleAIO.init && reactor->event_num == 1 && SwooleAIO.task_num == 0)
|
||||
{
|
||||
empty = SW_TRUE;
|
||||
}
|
||||
//no event
|
||||
else if (reactor->event_num == 0)
|
||||
{
|
||||
empty = SW_TRUE;
|
||||
}
|
||||
//coroutine
|
||||
if (empty && reactor->can_exit && reactor->can_exit(reactor))
|
||||
{
|
||||
empty = SW_TRUE;
|
||||
}
|
||||
return empty;
|
||||
}
|
||||
|
||||
/**
|
||||
* execute when reactor timeout and reactor finish
|
||||
*/
|
||||
static void swReactor_onTimeout_and_Finish(swReactor *reactor)
|
||||
{
|
||||
//check timer
|
||||
if (reactor->check_timer)
|
||||
{
|
||||
swTimer_select(&SwooleG.timer);
|
||||
}
|
||||
//defer callback
|
||||
swDefer_callback *cb, *tmp;
|
||||
swDefer_callback *defer_callback_list = reactor->defer_callback_list;
|
||||
reactor->defer_callback_list = NULL;
|
||||
LL_FOREACH(defer_callback_list, cb)
|
||||
{
|
||||
cb->callback(cb->data);
|
||||
}
|
||||
LL_FOREACH_SAFE(defer_callback_list, cb, tmp)
|
||||
{
|
||||
sw_free(cb);
|
||||
}
|
||||
//callback at the end
|
||||
if (reactor->idle_task.callback)
|
||||
{
|
||||
reactor->idle_task.callback(reactor->idle_task.data);
|
||||
}
|
||||
#ifdef SW_COROUTINE
|
||||
//coro timeout
|
||||
if (!swIsMaster())
|
||||
{
|
||||
coro_handle_timeout();
|
||||
}
|
||||
#endif
|
||||
//server worker
|
||||
swWorker *worker = SwooleWG.worker;
|
||||
if (worker != NULL)
|
||||
{
|
||||
if (SwooleWG.wait_exit == 1)
|
||||
{
|
||||
swWorker_try_to_exit();
|
||||
}
|
||||
}
|
||||
//not server, the event loop is empty
|
||||
if (SwooleG.serv == NULL && swReactor_empty(reactor))
|
||||
{
|
||||
reactor->running = 0;
|
||||
}
|
||||
|
||||
#ifdef SW_USE_MALLOC_TRIM
|
||||
if (SwooleG.serv && reactor->last_malloc_trim_time < SwooleG.serv->gs->now - SW_MALLOC_TRIM_INTERVAL)
|
||||
{
|
||||
malloc_trim(SW_MALLOC_TRIM_PAD);
|
||||
reactor->last_malloc_trim_time = SwooleG.serv->gs->now;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void swReactor_onTimeout(swReactor *reactor)
|
||||
{
|
||||
swReactor_onTimeout_and_Finish(reactor);
|
||||
|
||||
if (reactor->disable_accept)
|
||||
{
|
||||
reactor->enable_accept(reactor);
|
||||
reactor->disable_accept = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void swReactor_onFinish(swReactor *reactor)
|
||||
{
|
||||
//check signal
|
||||
if (reactor->singal_no)
|
||||
{
|
||||
swSignal_callback(reactor->singal_no);
|
||||
reactor->singal_no = 0;
|
||||
}
|
||||
swReactor_onTimeout_and_Finish(reactor);
|
||||
}
|
||||
|
||||
void swReactor_activate_future_task(swReactor *reactor)
|
||||
{
|
||||
reactor->onBegin = swReactor_onBegin;
|
||||
}
|
||||
|
||||
static void swReactor_onBegin(swReactor *reactor)
|
||||
{
|
||||
if (reactor->future_task.callback)
|
||||
{
|
||||
reactor->future_task.callback(reactor->future_task.data);
|
||||
}
|
||||
}
|
||||
|
||||
int swReactor_close(swReactor *reactor, int fd)
|
||||
{
|
||||
swConnection *socket = swReactor_get(reactor, fd);
|
||||
if (socket->out_buffer)
|
||||
{
|
||||
swBuffer_free(socket->out_buffer);
|
||||
}
|
||||
if (socket->in_buffer)
|
||||
{
|
||||
swBuffer_free(socket->in_buffer);
|
||||
}
|
||||
if (socket->websocket_buffer)
|
||||
{
|
||||
swString_free(socket->websocket_buffer);
|
||||
}
|
||||
bzero(socket, sizeof(swConnection));
|
||||
socket->removed = 1;
|
||||
swTraceLog(SW_TRACE_CLOSE, "fd=%d.", fd);
|
||||
return close(fd);
|
||||
}
|
||||
|
||||
int swReactor_write(swReactor *reactor, int fd, void *buf, int n)
|
||||
{
|
||||
int ret;
|
||||
swConnection *socket = swReactor_get(reactor, fd);
|
||||
swBuffer *buffer = socket->out_buffer;
|
||||
|
||||
if (socket->fd == 0)
|
||||
{
|
||||
socket->fd = fd;
|
||||
}
|
||||
|
||||
if (socket->buffer_size == 0)
|
||||
{
|
||||
socket->buffer_size = SwooleG.socket_buffer_size;
|
||||
}
|
||||
|
||||
if (socket->nonblock == 0)
|
||||
{
|
||||
swoole_fcntl_set_option(fd, 1, -1);
|
||||
socket->nonblock = 1;
|
||||
}
|
||||
|
||||
if (n > socket->buffer_size)
|
||||
{
|
||||
swoole_error_log(SW_LOG_WARNING, SW_ERROR_PACKAGE_LENGTH_TOO_LARGE, "data is too large, cannot exceed buffer size.");
|
||||
return SW_ERR;
|
||||
}
|
||||
|
||||
if (swBuffer_empty(buffer))
|
||||
{
|
||||
if (socket->ssl_send)
|
||||
{
|
||||
goto do_buffer;
|
||||
}
|
||||
|
||||
do_send:
|
||||
ret = swConnection_send(socket, buf, n, 0);
|
||||
|
||||
if (ret > 0)
|
||||
{
|
||||
if (n == ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
{
|
||||
buf += ret;
|
||||
n -= ret;
|
||||
goto do_buffer;
|
||||
}
|
||||
}
|
||||
#ifdef HAVE_KQUEUE
|
||||
else if (errno == EAGAIN || errno == ENOBUFS)
|
||||
#else
|
||||
else if (errno == EAGAIN)
|
||||
#endif
|
||||
{
|
||||
do_buffer:
|
||||
if (!socket->out_buffer)
|
||||
{
|
||||
buffer = swBuffer_new(sizeof(swEventData));
|
||||
if (!buffer)
|
||||
{
|
||||
swWarn("create worker buffer failed.");
|
||||
return SW_ERR;
|
||||
}
|
||||
socket->out_buffer = buffer;
|
||||
}
|
||||
|
||||
socket->events |= SW_EVENT_WRITE;
|
||||
|
||||
if (socket->events & SW_EVENT_READ)
|
||||
{
|
||||
if (reactor->set(reactor, fd, socket->fdtype | socket->events) < 0)
|
||||
{
|
||||
swSysError("reactor->set(%d, SW_EVENT_WRITE) failed.", fd);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (reactor->add(reactor, fd, socket->fdtype | SW_EVENT_WRITE) < 0)
|
||||
{
|
||||
swSysError("reactor->add(%d, SW_EVENT_WRITE) failed.", fd);
|
||||
}
|
||||
}
|
||||
|
||||
goto append_buffer;
|
||||
}
|
||||
else if (errno == EINTR)
|
||||
{
|
||||
goto do_send;
|
||||
}
|
||||
else
|
||||
{
|
||||
SwooleG.error = errno;
|
||||
return SW_ERR;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
append_buffer: if (buffer->length > socket->buffer_size)
|
||||
{
|
||||
if (socket->dontwait)
|
||||
{
|
||||
SwooleG.error = SW_ERROR_OUTPUT_BUFFER_OVERFLOW;
|
||||
return SW_ERR;
|
||||
}
|
||||
else
|
||||
{
|
||||
swoole_error_log(SW_LOG_WARNING, SW_ERROR_OUTPUT_BUFFER_OVERFLOW, "socket#%d output buffer overflow.", fd);
|
||||
swYield();
|
||||
swSocket_wait(fd, SW_SOCKET_OVERFLOW_WAIT, SW_EVENT_WRITE);
|
||||
}
|
||||
}
|
||||
|
||||
if (swBuffer_append(buffer, buf, n) < 0)
|
||||
{
|
||||
return SW_ERR;
|
||||
}
|
||||
}
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
int swReactor_onWrite(swReactor *reactor, swEvent *ev)
|
||||
{
|
||||
int ret;
|
||||
int fd = ev->fd;
|
||||
|
||||
swConnection *socket = swReactor_get(reactor, fd);
|
||||
swBuffer_trunk *chunk = NULL;
|
||||
swBuffer *buffer = socket->out_buffer;
|
||||
|
||||
//send to socket
|
||||
while (!swBuffer_empty(buffer))
|
||||
{
|
||||
chunk = swBuffer_get_trunk(buffer);
|
||||
if (chunk->type == SW_CHUNK_CLOSE)
|
||||
{
|
||||
close_fd:
|
||||
reactor->close(reactor, ev->fd);
|
||||
return SW_OK;
|
||||
}
|
||||
else if (chunk->type == SW_CHUNK_SENDFILE)
|
||||
{
|
||||
ret = swConnection_onSendfile(socket, chunk);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = swConnection_buffer_send(socket);
|
||||
}
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
if (socket->close_wait)
|
||||
{
|
||||
goto close_fd;
|
||||
}
|
||||
else if (socket->send_wait)
|
||||
{
|
||||
return SW_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//remove EPOLLOUT event
|
||||
if (swBuffer_empty(buffer))
|
||||
{
|
||||
if (socket->events & SW_EVENT_READ)
|
||||
{
|
||||
socket->events &= (~SW_EVENT_WRITE);
|
||||
if (reactor->set(reactor, fd, socket->fdtype | socket->events) < 0)
|
||||
{
|
||||
swSysError("reactor->set(%d, SW_EVENT_READ) failed.", fd);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (reactor->del(reactor, fd) < 0)
|
||||
{
|
||||
swSysError("reactor->del(%d) failed.", fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
int swReactor_wait_write_buffer(swReactor *reactor, int fd)
|
||||
{
|
||||
swConnection *conn = swReactor_get(reactor, fd);
|
||||
swEvent event;
|
||||
|
||||
if (conn->out_buffer)
|
||||
{
|
||||
swSetBlock(fd);
|
||||
event.fd = fd;
|
||||
return swReactor_onWrite(reactor, &event);
|
||||
}
|
||||
return SW_OK;
|
||||
}
|
304
vendor/swoole/src/reactor/ReactorEpoll.c
vendored
Executable file
304
vendor/swoole/src/reactor/ReactorEpoll.c
vendored
Executable file
@ -0,0 +1,304 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| 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 HAVE_EPOLL
|
||||
#include <sys/epoll.h>
|
||||
#ifndef EPOLLRDHUP
|
||||
#define EPOLLRDHUP 0x2000
|
||||
#define NO_EPOLLRDHUP
|
||||
#endif
|
||||
|
||||
#ifndef EPOLLONESHOT
|
||||
#define EPOLLONESHOT (1u << 30)
|
||||
#endif
|
||||
|
||||
typedef struct swReactorEpoll_s swReactorEpoll;
|
||||
|
||||
typedef struct _swFd
|
||||
{
|
||||
uint32_t fd;
|
||||
uint32_t fdtype;
|
||||
} swFd;
|
||||
|
||||
static int swReactorEpoll_add(swReactor *reactor, int fd, int fdtype);
|
||||
static int swReactorEpoll_set(swReactor *reactor, int fd, int fdtype);
|
||||
static int swReactorEpoll_del(swReactor *reactor, int fd);
|
||||
static int swReactorEpoll_wait(swReactor *reactor, struct timeval *timeo);
|
||||
static void swReactorEpoll_free(swReactor *reactor);
|
||||
|
||||
static sw_inline int swReactorEpoll_event_set(int fdtype)
|
||||
{
|
||||
uint32_t flag = 0;
|
||||
if (swReactor_event_read(fdtype))
|
||||
{
|
||||
flag |= EPOLLIN;
|
||||
}
|
||||
if (swReactor_event_write(fdtype))
|
||||
{
|
||||
flag |= EPOLLOUT;
|
||||
}
|
||||
if (swReactor_event_error(fdtype))
|
||||
{
|
||||
//flag |= (EPOLLRDHUP);
|
||||
flag |= (EPOLLRDHUP | EPOLLHUP | EPOLLERR);
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
struct swReactorEpoll_s
|
||||
{
|
||||
int epfd;
|
||||
struct epoll_event *events;
|
||||
};
|
||||
|
||||
int swReactorEpoll_create(swReactor *reactor, int max_event_num)
|
||||
{
|
||||
//create reactor object
|
||||
swReactorEpoll *reactor_object = sw_malloc(sizeof(swReactorEpoll));
|
||||
if (reactor_object == NULL)
|
||||
{
|
||||
swWarn("malloc[0] failed.");
|
||||
return SW_ERR;
|
||||
}
|
||||
bzero(reactor_object, sizeof(swReactorEpoll));
|
||||
reactor->object = reactor_object;
|
||||
reactor->max_event_num = max_event_num;
|
||||
|
||||
reactor_object->events = sw_calloc(max_event_num, sizeof(struct epoll_event));
|
||||
|
||||
if (reactor_object->events == NULL)
|
||||
{
|
||||
swWarn("malloc[1] failed.");
|
||||
sw_free(reactor_object);
|
||||
return SW_ERR;
|
||||
}
|
||||
//epoll create
|
||||
reactor_object->epfd = epoll_create(512);
|
||||
if (reactor_object->epfd < 0)
|
||||
{
|
||||
swWarn("epoll_create failed. Error: %s[%d]", strerror(errno), errno);
|
||||
sw_free(reactor_object);
|
||||
return SW_ERR;
|
||||
}
|
||||
//binding method
|
||||
reactor->add = swReactorEpoll_add;
|
||||
reactor->set = swReactorEpoll_set;
|
||||
reactor->del = swReactorEpoll_del;
|
||||
reactor->wait = swReactorEpoll_wait;
|
||||
reactor->free = swReactorEpoll_free;
|
||||
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
static void swReactorEpoll_free(swReactor *reactor)
|
||||
{
|
||||
swReactorEpoll *object = reactor->object;
|
||||
close(object->epfd);
|
||||
sw_free(object->events);
|
||||
sw_free(object);
|
||||
}
|
||||
|
||||
static int swReactorEpoll_add(swReactor *reactor, int fd, int fdtype)
|
||||
{
|
||||
swReactorEpoll *object = reactor->object;
|
||||
struct epoll_event e;
|
||||
swFd fd_;
|
||||
bzero(&e, sizeof(struct epoll_event));
|
||||
|
||||
fd_.fd = fd;
|
||||
fd_.fdtype = swReactor_fdtype(fdtype);
|
||||
e.events = swReactorEpoll_event_set(fdtype);
|
||||
|
||||
swReactor_add(reactor, fd, fdtype);
|
||||
|
||||
memcpy(&(e.data.u64), &fd_, sizeof(fd_));
|
||||
if (epoll_ctl(object->epfd, EPOLL_CTL_ADD, fd, &e) < 0)
|
||||
{
|
||||
swSysError("add events[fd=%d#%d, type=%d, events=%d] failed.", fd, reactor->id, fd_.fdtype, e.events);
|
||||
swReactor_del(reactor, fd);
|
||||
return SW_ERR;
|
||||
}
|
||||
|
||||
swTraceLog(SW_TRACE_EVENT, "add event[reactor_id=%d, fd=%d, events=%d]", reactor->id, fd, swReactor_events(fdtype));
|
||||
reactor->event_num++;
|
||||
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
static int swReactorEpoll_del(swReactor *reactor, int fd)
|
||||
{
|
||||
swReactorEpoll *object = reactor->object;
|
||||
if (epoll_ctl(object->epfd, EPOLL_CTL_DEL, fd, NULL) < 0)
|
||||
{
|
||||
swSysError("epoll remove fd[%d#%d] failed.", fd, reactor->id);
|
||||
return SW_ERR;
|
||||
}
|
||||
|
||||
swTraceLog(SW_TRACE_REACTOR, "remove event[reactor_id=%d|fd=%d]", reactor->id, fd);
|
||||
reactor->event_num = reactor->event_num <= 0 ? 0 : reactor->event_num - 1;
|
||||
swReactor_del(reactor, fd);
|
||||
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
static int swReactorEpoll_set(swReactor *reactor, int fd, int fdtype)
|
||||
{
|
||||
swReactorEpoll *object = reactor->object;
|
||||
swFd fd_;
|
||||
struct epoll_event e;
|
||||
int ret;
|
||||
|
||||
bzero(&e, sizeof(struct epoll_event));
|
||||
e.events = swReactorEpoll_event_set(fdtype);
|
||||
|
||||
if (e.events & EPOLLOUT)
|
||||
{
|
||||
assert(fd > 2);
|
||||
}
|
||||
|
||||
fd_.fd = fd;
|
||||
fd_.fdtype = swReactor_fdtype(fdtype);
|
||||
memcpy(&(e.data.u64), &fd_, sizeof(fd_));
|
||||
|
||||
ret = epoll_ctl(object->epfd, EPOLL_CTL_MOD, fd, &e);
|
||||
if (ret < 0)
|
||||
{
|
||||
swSysError("reactor#%d->set(fd=%d|type=%d|events=%d) failed.", reactor->id, fd, fd_.fdtype, e.events);
|
||||
return SW_ERR;
|
||||
}
|
||||
swTraceLog(SW_TRACE_EVENT, "set event[reactor_id=%d, fd=%d, events=%d]", reactor->id, fd, swReactor_events(fdtype));
|
||||
//execute parent method
|
||||
swReactor_set(reactor, fd, fdtype);
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
static int swReactorEpoll_wait(swReactor *reactor, struct timeval *timeo)
|
||||
{
|
||||
swEvent event;
|
||||
swReactorEpoll *object = reactor->object;
|
||||
swReactor_handle handle;
|
||||
int i, n, ret, msec;
|
||||
|
||||
int reactor_id = reactor->id;
|
||||
int epoll_fd = object->epfd;
|
||||
int max_event_num = reactor->max_event_num;
|
||||
struct epoll_event *events = object->events;
|
||||
|
||||
if (reactor->timeout_msec == 0)
|
||||
{
|
||||
if (timeo == NULL)
|
||||
{
|
||||
reactor->timeout_msec = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
reactor->timeout_msec = timeo->tv_sec * 1000 + timeo->tv_usec / 1000;
|
||||
}
|
||||
}
|
||||
|
||||
reactor->start = 1;
|
||||
|
||||
while (reactor->running > 0)
|
||||
{
|
||||
if (reactor->onBegin != NULL)
|
||||
{
|
||||
reactor->onBegin(reactor);
|
||||
}
|
||||
msec = reactor->timeout_msec;
|
||||
n = epoll_wait(epoll_fd, events, max_event_num, msec);
|
||||
if (n < 0)
|
||||
{
|
||||
if (swReactor_error(reactor) < 0)
|
||||
{
|
||||
swWarn("[Reactor#%d] epoll_wait failed. Error: %s[%d]", reactor_id, strerror(errno), errno);
|
||||
return SW_ERR;
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (n == 0)
|
||||
{
|
||||
if (reactor->onTimeout != NULL)
|
||||
{
|
||||
reactor->onTimeout(reactor);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
event.fd = events[i].data.u64;
|
||||
event.from_id = reactor_id;
|
||||
event.type = events[i].data.u64 >> 32;
|
||||
event.socket = swReactor_get(reactor, event.fd);
|
||||
|
||||
//read
|
||||
if ((events[i].events & EPOLLIN) && !event.socket->removed)
|
||||
{
|
||||
handle = swReactor_getHandle(reactor, SW_EVENT_READ, event.type);
|
||||
ret = handle(reactor, &event);
|
||||
if (ret < 0)
|
||||
{
|
||||
swSysError("EPOLLIN handle failed. fd=%d.", event.fd);
|
||||
}
|
||||
}
|
||||
//write
|
||||
if ((events[i].events & EPOLLOUT) && !event.socket->removed)
|
||||
{
|
||||
handle = swReactor_getHandle(reactor, SW_EVENT_WRITE, event.type);
|
||||
ret = handle(reactor, &event);
|
||||
if (ret < 0)
|
||||
{
|
||||
swSysError("EPOLLOUT handle failed. fd=%d.", event.fd);
|
||||
}
|
||||
}
|
||||
//error
|
||||
#ifndef NO_EPOLLRDHUP
|
||||
if ((events[i].events & (EPOLLRDHUP | EPOLLERR | EPOLLHUP)) && !event.socket->removed)
|
||||
#else
|
||||
if ((events[i].events & (EPOLLERR | EPOLLHUP)) && !event.socket->removed)
|
||||
#endif
|
||||
{
|
||||
//ignore ERR and HUP, because event is already processed at IN and OUT handler.
|
||||
if ((events[i].events & EPOLLIN) || (events[i].events & EPOLLOUT))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
handle = swReactor_getHandle(reactor, SW_EVENT_ERROR, event.type);
|
||||
ret = handle(reactor, &event);
|
||||
if (ret < 0)
|
||||
{
|
||||
swSysError("EPOLLERR handle failed. fd=%d.", event.fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (reactor->onFinish != NULL)
|
||||
{
|
||||
reactor->onFinish(reactor);
|
||||
}
|
||||
if (reactor->once)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
375
vendor/swoole/src/reactor/ReactorKqueue.c
vendored
Executable file
375
vendor/swoole/src/reactor/ReactorKqueue.c
vendored
Executable file
@ -0,0 +1,375 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| 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 <string.h>
|
||||
|
||||
#ifdef IDE_HELPER
|
||||
#ifdef HAVE_KQUEUE
|
||||
#include <sys/event.h>
|
||||
#else
|
||||
#include "helper/kqueue.h"
|
||||
#define HAVE_KQUEUE
|
||||
#endif
|
||||
#else
|
||||
#ifdef HAVE_KQUEUE
|
||||
#include <sys/event.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_KQUEUE
|
||||
|
||||
typedef struct swReactorKqueue_s swReactorKqueue;
|
||||
typedef struct _swFd
|
||||
{
|
||||
uint32_t fd;
|
||||
uint32_t fdtype;
|
||||
} swFd;
|
||||
|
||||
static int swReactorKqueue_add(swReactor *reactor, int fd, int fdtype);
|
||||
static int swReactorKqueue_set(swReactor *reactor, int fd, int fdtype);
|
||||
static int swReactorKqueue_del(swReactor *reactor, int fd);
|
||||
static int swReactorKqueue_wait(swReactor *reactor, struct timeval *timeo);
|
||||
static void swReactorKqueue_free(swReactor *reactor);
|
||||
|
||||
struct swReactorKqueue_s
|
||||
{
|
||||
int epfd;
|
||||
int event_max;
|
||||
struct kevent *events;
|
||||
};
|
||||
|
||||
int swReactorKqueue_create(swReactor *reactor, int max_event_num)
|
||||
{
|
||||
//create reactor object
|
||||
swReactorKqueue *reactor_object = sw_malloc(sizeof(swReactorKqueue));
|
||||
if (reactor_object == NULL)
|
||||
{
|
||||
swTrace("[swReactorKqueueCreate] malloc[0] fail\n");
|
||||
return SW_ERR;
|
||||
}
|
||||
bzero(reactor_object, sizeof(swReactorKqueue));
|
||||
|
||||
reactor->object = reactor_object;
|
||||
reactor->max_event_num = max_event_num;
|
||||
reactor_object->events = sw_calloc(max_event_num, sizeof(struct kevent));
|
||||
|
||||
if (reactor_object->events == NULL)
|
||||
{
|
||||
swTrace("[swReactorKqueueCreate] malloc[1] fail\n");
|
||||
return SW_ERR;
|
||||
}
|
||||
//kqueue create
|
||||
reactor_object->event_max = max_event_num;
|
||||
reactor_object->epfd = kqueue();
|
||||
if (reactor_object->epfd < 0)
|
||||
{
|
||||
swTrace("[swReactorKqueueCreate] kqueue_create[0] fail\n");
|
||||
return SW_ERR;
|
||||
}
|
||||
|
||||
//binding method
|
||||
reactor->add = swReactorKqueue_add;
|
||||
reactor->set = swReactorKqueue_set;
|
||||
reactor->del = swReactorKqueue_del;
|
||||
reactor->wait = swReactorKqueue_wait;
|
||||
reactor->free = swReactorKqueue_free;
|
||||
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
static void swReactorKqueue_free(swReactor *reactor)
|
||||
{
|
||||
swReactorKqueue *this = reactor->object;
|
||||
close(this->epfd);
|
||||
sw_free(this->events);
|
||||
sw_free(this);
|
||||
}
|
||||
|
||||
static int swReactorKqueue_add(swReactor *reactor, int fd, int fdtype)
|
||||
{
|
||||
swReactorKqueue *this = reactor->object;
|
||||
struct kevent e;
|
||||
swFd fd_;
|
||||
int ret;
|
||||
bzero(&e, sizeof(e));
|
||||
|
||||
int fflags = 0;
|
||||
fd_.fd = fd;
|
||||
fd_.fdtype = swReactor_fdtype(fdtype);
|
||||
|
||||
swReactor_add(reactor, fd, fdtype);
|
||||
|
||||
if (swReactor_event_read(fdtype))
|
||||
{
|
||||
#ifdef NOTE_EOF
|
||||
fflags = NOTE_EOF;
|
||||
#endif
|
||||
EV_SET(&e, fd, EVFILT_READ, EV_ADD, fflags, 0, NULL);
|
||||
memcpy(&e.udata, &fd_, sizeof(swFd));
|
||||
ret = kevent(this->epfd, &e, 1, NULL, 0, NULL);
|
||||
if (ret < 0)
|
||||
{
|
||||
swSysError("add events[fd=%d#%d, type=%d, events=read] failed.", fd, reactor->id, fd_.fdtype);
|
||||
swReactor_del(reactor, fd);
|
||||
return SW_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
if (swReactor_event_write(fdtype))
|
||||
{
|
||||
EV_SET(&e, fd, EVFILT_WRITE, EV_ADD, 0, 0, NULL);
|
||||
memcpy(&e.udata, &fd_, sizeof(swFd));
|
||||
ret = kevent(this->epfd, &e, 1, NULL, 0, NULL);
|
||||
if (ret < 0)
|
||||
{
|
||||
swSysError("add events[fd=%d#%d, type=%d, events=write] failed.", fd, reactor->id, fd_.fdtype);
|
||||
swReactor_del(reactor, fd);
|
||||
return SW_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
swTrace("[THREAD #%d]EP=%d|FD=%d, events=%d", SwooleTG.id, this->epfd, fd, fdtype);
|
||||
reactor->event_num++;
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
static int swReactorKqueue_set(swReactor *reactor, int fd, int fdtype)
|
||||
{
|
||||
swReactorKqueue *this = reactor->object;
|
||||
struct kevent e;
|
||||
swFd fd_;
|
||||
int ret;
|
||||
bzero(&e, sizeof(e));
|
||||
|
||||
int fflags = 0;
|
||||
fd_.fd = fd;
|
||||
fd_.fdtype = swReactor_fdtype(fdtype);
|
||||
|
||||
if (swReactor_event_read(fdtype))
|
||||
{
|
||||
#ifdef NOTE_EOF
|
||||
fflags = NOTE_EOF;
|
||||
#endif
|
||||
EV_SET(&e, fd, EVFILT_READ, EV_ADD, fflags, 0, NULL);
|
||||
memcpy(&e.udata, &fd_, sizeof(swFd));
|
||||
ret = kevent(this->epfd, &e, 1, NULL, 0, NULL);
|
||||
if (ret < 0)
|
||||
{
|
||||
swSysError("kqueue->set(%d, SW_EVENT_READ) failed.", fd);
|
||||
return SW_ERR;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
EV_SET(&e, fd, EVFILT_READ, EV_DELETE, 0, 0, NULL);
|
||||
memcpy(&e.udata, &fd_, sizeof(swFd));
|
||||
ret = kevent(this->epfd, &e, 1, NULL, 0, NULL);
|
||||
if (ret < 0)
|
||||
{
|
||||
swSysError("kqueue->del(%d, SW_EVENT_READ) failed.", fd);
|
||||
return SW_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
if (swReactor_event_write(fdtype))
|
||||
{
|
||||
EV_SET(&e, fd, EVFILT_WRITE, EV_ADD, 0, 0, NULL);
|
||||
memcpy(&e.udata, &fd_, sizeof(swFd));
|
||||
ret = kevent(this->epfd, &e, 1, NULL, 0, NULL);
|
||||
if (ret < 0)
|
||||
{
|
||||
swSysError("kqueue->set(%d, SW_EVENT_WRITE) failed.", fd);
|
||||
return SW_ERR;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
EV_SET(&e, fd, EVFILT_WRITE, EV_DELETE, 0, 0, NULL);
|
||||
memcpy(&e.udata, &fd_, sizeof(swFd));
|
||||
ret = kevent(this->epfd, &e, 1, NULL, 0, NULL);
|
||||
if (ret < 0)
|
||||
{
|
||||
swSysError("kqueue->del(%d, SW_EVENT_WRITE) failed.", fd);
|
||||
return SW_ERR;
|
||||
}
|
||||
}
|
||||
swTrace("[THREAD #%d]EP=%d|FD=%d, events=%d", SwooleTG.id, this->epfd, fd, fdtype);
|
||||
//execute parent method
|
||||
swReactor_set(reactor, fd, fdtype);
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
static int swReactorKqueue_del(swReactor *reactor, int fd)
|
||||
{
|
||||
swReactorKqueue *this = reactor->object;
|
||||
struct kevent e;
|
||||
int ret;
|
||||
|
||||
swConnection *socket = swReactor_get(reactor, fd);
|
||||
|
||||
if (socket->events & SW_EVENT_READ)
|
||||
{
|
||||
EV_SET(&e, fd, EVFILT_READ, EV_DELETE, 0, 0, NULL);
|
||||
ret = kevent(this->epfd, &e, 1, NULL, 0, NULL);
|
||||
if (ret < 0)
|
||||
{
|
||||
swSysError("kqueue->del(%d, SW_EVENT_READ) failed.", fd);
|
||||
return SW_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
if (socket->events & SW_EVENT_WRITE)
|
||||
{
|
||||
EV_SET(&e, fd, EVFILT_WRITE, EV_DELETE, 0, 0, NULL);
|
||||
ret = kevent(this->epfd, &e, 1, NULL, 0, NULL);
|
||||
if (ret < 0)
|
||||
{
|
||||
swSysError("kqueue->del(%d, SW_EVENT_WRITE) failed.", fd);
|
||||
return SW_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
swTrace("[THREAD #%d]EP=%d|FD=%d", SwooleTG.id, this->epfd, fd);
|
||||
reactor->event_num = reactor->event_num <= 0 ? 0 : reactor->event_num - 1;
|
||||
swReactor_del(reactor, fd);
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
static int swReactorKqueue_wait(swReactor *reactor, struct timeval *timeo)
|
||||
{
|
||||
swEvent event;
|
||||
swFd fd_;
|
||||
swReactorKqueue *object = reactor->object;
|
||||
swReactor_handle handle;
|
||||
|
||||
int i, n, ret;
|
||||
struct timespec t;
|
||||
struct timespec *t_ptr;
|
||||
bzero(&t, sizeof(t));
|
||||
|
||||
if (reactor->timeout_msec == 0)
|
||||
{
|
||||
if (timeo == NULL)
|
||||
{
|
||||
reactor->timeout_msec = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
reactor->timeout_msec = timeo->tv_sec * 1000 + timeo->tv_usec / 1000;
|
||||
}
|
||||
}
|
||||
|
||||
reactor->start = 1;
|
||||
|
||||
while (reactor->running > 0)
|
||||
{
|
||||
if (reactor->onBegin != NULL)
|
||||
{
|
||||
reactor->onBegin(reactor);
|
||||
}
|
||||
if (reactor->timeout_msec > 0)
|
||||
{
|
||||
t.tv_sec = reactor->timeout_msec / 1000;
|
||||
t.tv_nsec = (reactor->timeout_msec - t.tv_sec * 1000) * 1000;
|
||||
t_ptr = &t;
|
||||
}
|
||||
else
|
||||
{
|
||||
t_ptr = NULL;
|
||||
}
|
||||
|
||||
n = kevent(object->epfd, NULL, 0, object->events, object->event_max, t_ptr);
|
||||
if (n < 0)
|
||||
{
|
||||
swTrace("kqueue error.EP=%d | Errno=%d\n", object->epfd, errno);
|
||||
if (swReactor_error(reactor) < 0)
|
||||
{
|
||||
swWarn("Kqueue[#%d] Error: %s[%d]", reactor->id, strerror(errno), errno);
|
||||
return SW_ERR;
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (n == 0)
|
||||
{
|
||||
if (reactor->onTimeout != NULL)
|
||||
{
|
||||
reactor->onTimeout(reactor);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
swTrace("n %d events.", n);
|
||||
if (object->events[i].udata)
|
||||
{
|
||||
memcpy(&fd_, &(object->events[i].udata), sizeof(fd_));
|
||||
event.fd = fd_.fd;
|
||||
event.from_id = reactor->id;
|
||||
event.type = fd_.fdtype;
|
||||
event.socket = swReactor_get(reactor, event.fd);
|
||||
|
||||
//read
|
||||
if (object->events[i].filter == EVFILT_READ)
|
||||
{
|
||||
if (event.socket->removed)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
handle = swReactor_getHandle(reactor, SW_EVENT_READ, event.type);
|
||||
ret = handle(reactor, &event);
|
||||
if (ret < 0)
|
||||
{
|
||||
swSysError("kqueue event read socket#%d handler failed.", event.fd);
|
||||
}
|
||||
}
|
||||
//write
|
||||
else if (object->events[i].filter == EVFILT_WRITE)
|
||||
{
|
||||
if (event.socket->removed)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
handle = swReactor_getHandle(reactor, SW_EVENT_WRITE, event.type);
|
||||
ret = handle(reactor, &event);
|
||||
if (ret < 0)
|
||||
{
|
||||
swSysError("kqueue event write socket#%d handler failed.", event.fd);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
swWarn("unknown event filter[%d].", object->events[i].filter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (reactor->onFinish != NULL)
|
||||
{
|
||||
reactor->onFinish(reactor);
|
||||
}
|
||||
if (reactor->once)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
306
vendor/swoole/src/reactor/ReactorPoll.c
vendored
Executable file
306
vendor/swoole/src/reactor/ReactorPoll.c
vendored
Executable file
@ -0,0 +1,306 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| 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 <poll.h>
|
||||
|
||||
static int swReactorPoll_add(swReactor *reactor, int fd, int fdtype);
|
||||
static int swReactorPoll_set(swReactor *reactor, int fd, int fdtype);
|
||||
static int swReactorPoll_del(swReactor *reactor, int fd);
|
||||
static int swReactorPoll_wait(swReactor *reactor, struct timeval *timeo);
|
||||
static void swReactorPoll_free(swReactor *reactor);
|
||||
static int swReactorPoll_exist(swReactor *reactor, int fd);
|
||||
|
||||
typedef struct _swPollFdInfo
|
||||
{
|
||||
int fdtype;
|
||||
} swPollFdInfo;
|
||||
|
||||
typedef struct _swReactorPoll
|
||||
{
|
||||
int max_fd_num;
|
||||
swPollFdInfo *fds;
|
||||
struct pollfd *events;
|
||||
} swReactorPoll;
|
||||
|
||||
int swReactorPoll_create(swReactor *reactor, int max_fd_num)
|
||||
{
|
||||
//create reactor object
|
||||
swReactorPoll *object = sw_malloc(sizeof(swReactorPoll));
|
||||
if (object == NULL)
|
||||
{
|
||||
swWarn("malloc[0] failed");
|
||||
return SW_ERR;
|
||||
}
|
||||
bzero(object, sizeof(swReactorPoll));
|
||||
|
||||
object->fds = sw_calloc(max_fd_num, sizeof(swPollFdInfo));
|
||||
if (object->fds == NULL)
|
||||
{
|
||||
swWarn("malloc[1] failed");
|
||||
sw_free(object);
|
||||
return SW_ERR;
|
||||
}
|
||||
object->events = sw_calloc(max_fd_num, sizeof(struct pollfd));
|
||||
if (object->events == NULL)
|
||||
{
|
||||
swWarn("malloc[2] failed");
|
||||
sw_free(object);
|
||||
return SW_ERR;
|
||||
}
|
||||
object->max_fd_num = max_fd_num;
|
||||
reactor->max_event_num = max_fd_num;
|
||||
bzero(reactor->handle, sizeof(reactor->handle));
|
||||
reactor->object = object;
|
||||
//binding method
|
||||
reactor->add = swReactorPoll_add;
|
||||
reactor->del = swReactorPoll_del;
|
||||
reactor->set = swReactorPoll_set;
|
||||
reactor->wait = swReactorPoll_wait;
|
||||
reactor->free = swReactorPoll_free;
|
||||
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
static void swReactorPoll_free(swReactor *reactor)
|
||||
{
|
||||
swReactorPoll *object = reactor->object;
|
||||
sw_free(object->fds);
|
||||
sw_free(reactor->object);
|
||||
}
|
||||
|
||||
static int swReactorPoll_add(swReactor *reactor, int fd, int fdtype)
|
||||
{
|
||||
if (swReactorPoll_exist(reactor, fd))
|
||||
{
|
||||
swWarn("fd#%d is already exists.", fd);
|
||||
return SW_ERR;
|
||||
}
|
||||
|
||||
swReactorPoll *object = reactor->object;
|
||||
int cur = reactor->event_num;
|
||||
if (reactor->event_num == object->max_fd_num)
|
||||
{
|
||||
swWarn("too many connection, more than %d", object->max_fd_num);
|
||||
return SW_ERR;
|
||||
}
|
||||
|
||||
swReactor_add(reactor, fd, fdtype);
|
||||
|
||||
swTrace("fd=%d, fdtype=%d", fd, fdtype);
|
||||
|
||||
object->fds[cur].fdtype = swReactor_fdtype(fdtype);
|
||||
object->events[cur].fd = fd;
|
||||
object->events[cur].events = 0;
|
||||
|
||||
if (swReactor_event_read(fdtype))
|
||||
{
|
||||
object->events[cur].events |= POLLIN;
|
||||
}
|
||||
if (swReactor_event_write(fdtype))
|
||||
{
|
||||
object->events[cur].events |= POLLOUT;
|
||||
}
|
||||
if (swReactor_event_error(fdtype))
|
||||
{
|
||||
object->events[cur].events |= POLLHUP;
|
||||
}
|
||||
|
||||
reactor->event_num++;
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
static int swReactorPoll_set(swReactor *reactor, int fd, int fdtype)
|
||||
{
|
||||
uint32_t i;
|
||||
swReactorPoll *object = reactor->object;
|
||||
|
||||
swTrace("fd=%d, fdtype=%d", fd, fdtype);
|
||||
|
||||
for (i = 0; i < reactor->event_num; i++)
|
||||
{
|
||||
//found
|
||||
if (object->events[i].fd == fd)
|
||||
{
|
||||
object->fds[i].fdtype = swReactor_fdtype(fdtype);
|
||||
//object->events[i].events = POLLRDHUP;
|
||||
object->events[i].events = 0;
|
||||
if (swReactor_event_read(fdtype))
|
||||
{
|
||||
object->events[i].events |= POLLIN;
|
||||
}
|
||||
if (swReactor_event_write(fdtype))
|
||||
{
|
||||
object->events[i].events |= POLLOUT;
|
||||
}
|
||||
//execute parent method
|
||||
swReactor_set(reactor, fd, fdtype);
|
||||
return SW_OK;
|
||||
}
|
||||
}
|
||||
return SW_ERR;
|
||||
}
|
||||
|
||||
static int swReactorPoll_del(swReactor *reactor, int fd)
|
||||
{
|
||||
uint32_t i;
|
||||
swReactorPoll *object = reactor->object;
|
||||
|
||||
for (i = 0; i < reactor->event_num; i++)
|
||||
{
|
||||
if (object->events[i].fd == fd)
|
||||
{
|
||||
uint32_t old_num = reactor->event_num;
|
||||
reactor->event_num = reactor->event_num <= 0 ? 0 : reactor->event_num - 1;
|
||||
for (; i < old_num; i++)
|
||||
{
|
||||
if (i == old_num)
|
||||
{
|
||||
object->fds[i].fdtype = 0;
|
||||
object->events[i].fd = 0;
|
||||
object->events[i].events = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
object->fds[i] = object->fds[i + 1];
|
||||
object->events[i] = object->events[i + 1];
|
||||
}
|
||||
}
|
||||
swReactor_del(reactor, fd);
|
||||
return SW_OK;
|
||||
}
|
||||
}
|
||||
return SW_ERR;
|
||||
}
|
||||
|
||||
static int swReactorPoll_wait(swReactor *reactor, struct timeval *timeo)
|
||||
{
|
||||
swReactorPoll *object = reactor->object;
|
||||
swEvent event;
|
||||
swReactor_handle handle;
|
||||
|
||||
int ret, msec, i;
|
||||
|
||||
if (reactor->timeout_msec == 0)
|
||||
{
|
||||
if (timeo == NULL)
|
||||
{
|
||||
reactor->timeout_msec = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
reactor->timeout_msec = timeo->tv_sec * 1000 + timeo->tv_usec / 1000;
|
||||
}
|
||||
}
|
||||
|
||||
reactor->start = 1;
|
||||
|
||||
while (reactor->running > 0)
|
||||
{
|
||||
if (reactor->onBegin != NULL)
|
||||
{
|
||||
reactor->onBegin(reactor);
|
||||
}
|
||||
msec = reactor->timeout_msec;
|
||||
ret = poll(object->events, reactor->event_num, msec);
|
||||
if (ret < 0)
|
||||
{
|
||||
if (swReactor_error(reactor) < 0)
|
||||
{
|
||||
swWarn("poll error. Error: %s[%d]", strerror(errno), errno);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else if (ret == 0)
|
||||
{
|
||||
if (reactor->onTimeout != NULL)
|
||||
{
|
||||
reactor->onTimeout(reactor);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < reactor->event_num; i++)
|
||||
{
|
||||
event.fd = object->events[i].fd;
|
||||
event.from_id = reactor->id;
|
||||
event.type = object->fds[i].fdtype;
|
||||
event.socket = swReactor_get(reactor, event.fd);
|
||||
|
||||
swTrace("Event: fd=%d|from_id=%d|type=%d", event.fd, reactor->id, object->fds[i].fdtype);
|
||||
//in
|
||||
if ((object->events[i].revents & POLLIN) && !event.socket->removed)
|
||||
{
|
||||
handle = swReactor_getHandle(reactor, SW_EVENT_READ, event.type);
|
||||
ret = handle(reactor, &event);
|
||||
if (ret < 0)
|
||||
{
|
||||
swWarn("poll[POLLIN] handler failed. fd=%d. Error: %s[%d]", event.fd, strerror(errno), errno);
|
||||
}
|
||||
}
|
||||
//out
|
||||
if ((object->events[i].revents & POLLOUT) && !event.socket->removed)
|
||||
{
|
||||
handle = swReactor_getHandle(reactor, SW_EVENT_WRITE, event.type);
|
||||
ret = handle(reactor, &event);
|
||||
if (ret < 0)
|
||||
{
|
||||
swWarn("poll[POLLOUT] handler failed. fd=%d. Error: %s[%d]", event.fd, strerror(errno), errno);
|
||||
}
|
||||
}
|
||||
//error
|
||||
if ((object->events[i].revents & (POLLHUP | POLLERR)) && !event.socket->removed)
|
||||
{
|
||||
//ignore ERR and HUP, because event is already processed at IN and OUT handler.
|
||||
if ((object->events[i].revents & POLLIN) || (object->events[i].revents & POLLOUT))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
handle = swReactor_getHandle(reactor, SW_EVENT_ERROR, event.type);
|
||||
ret = handle(reactor, &event);
|
||||
if (ret < 0)
|
||||
{
|
||||
swWarn("poll[POLLERR] handler failed. fd=%d. Error: %s[%d]", event.fd, strerror(errno), errno);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (reactor->onFinish != NULL)
|
||||
{
|
||||
reactor->onFinish(reactor);
|
||||
}
|
||||
if (reactor->once)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
static int swReactorPoll_exist(swReactor *reactor, int fd)
|
||||
{
|
||||
swReactorPoll *object = reactor->object;
|
||||
int i;
|
||||
for (i = 0; i < reactor->event_num; i++)
|
||||
{
|
||||
if (object->events[i].fd == fd )
|
||||
{
|
||||
return SW_TRUE;
|
||||
}
|
||||
}
|
||||
return SW_FALSE;
|
||||
}
|
286
vendor/swoole/src/reactor/ReactorSelect.c
vendored
Executable file
286
vendor/swoole/src/reactor/ReactorSelect.c
vendored
Executable file
@ -0,0 +1,286 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| 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 <sys/select.h>
|
||||
|
||||
typedef struct _swFdList_node
|
||||
{
|
||||
struct _swFdList_node *next, *prev;
|
||||
int fd;
|
||||
int fdtype;
|
||||
} swFdList_node;
|
||||
|
||||
typedef struct _swReactorSelect
|
||||
{
|
||||
fd_set rfds;
|
||||
fd_set wfds;
|
||||
fd_set efds;
|
||||
swFdList_node *fds;
|
||||
int maxfd;
|
||||
} swReactorSelect;
|
||||
|
||||
#define SW_FD_SET(fd, set) do{ if (fd<FD_SETSIZE) FD_SET(fd, set);} while(0)
|
||||
#define SW_FD_CLR(fd, set) do{ if (fd<FD_SETSIZE) FD_CLR(fd, set);} while(0)
|
||||
#define SW_FD_ISSET(fd, set) ((fd < FD_SETSIZE) && FD_ISSET(fd, set))
|
||||
|
||||
static int swReactorSelect_add(swReactor *reactor, int fd, int fdtype);
|
||||
static int swReactorSelect_wait(swReactor *reactor, struct timeval *timeo);
|
||||
static void swReactorSelect_free(swReactor *reactor);
|
||||
static int swReactorSelect_del(swReactor *reactor, int fd);
|
||||
static int swReactorSelect_set(swReactor *reactor, int fd, int fdtype);
|
||||
static int swReactorSelect_cmp(swFdList_node *a, swFdList_node *b);
|
||||
|
||||
int swReactorSelect_create(swReactor *reactor)
|
||||
{
|
||||
//create reactor object
|
||||
swReactorSelect *object = sw_malloc(sizeof(swReactorSelect));
|
||||
if (object == NULL)
|
||||
{
|
||||
swWarn("[swReactorSelect_create] malloc[0] fail\n");
|
||||
return SW_ERR;
|
||||
}
|
||||
bzero(object, sizeof(swReactorSelect));
|
||||
|
||||
object->fds = NULL;
|
||||
object->maxfd = 0;
|
||||
bzero(reactor->handle, sizeof(reactor->handle));
|
||||
reactor->object = object;
|
||||
//binding method
|
||||
reactor->add = swReactorSelect_add;
|
||||
reactor->set = swReactorSelect_set;
|
||||
reactor->del = swReactorSelect_del;
|
||||
reactor->wait = swReactorSelect_wait;
|
||||
reactor->free = swReactorSelect_free;
|
||||
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
void swReactorSelect_free(swReactor *reactor)
|
||||
{
|
||||
swReactorSelect *object = reactor->object;
|
||||
swFdList_node *ev, *tmp;
|
||||
LL_FOREACH_SAFE(object->fds, ev, tmp)
|
||||
{
|
||||
LL_DELETE(object->fds, ev);
|
||||
sw_free(ev);
|
||||
}
|
||||
sw_free(reactor->object);
|
||||
}
|
||||
|
||||
int swReactorSelect_add(swReactor *reactor, int fd, int fdtype)
|
||||
{
|
||||
if (fd > FD_SETSIZE)
|
||||
{
|
||||
swWarn("max fd value is FD_SETSIZE(%d).\n", FD_SETSIZE);
|
||||
return SW_ERR;
|
||||
}
|
||||
swReactorSelect *object = reactor->object;
|
||||
swFdList_node *ev = sw_malloc(sizeof(swFdList_node));
|
||||
if (ev == NULL)
|
||||
{
|
||||
swWarn("malloc(%ld) failed.", sizeof(swFdList_node));
|
||||
return SW_ERR;
|
||||
}
|
||||
|
||||
swReactor_add(reactor, fd, fdtype);
|
||||
|
||||
ev->fd = fd;
|
||||
ev->fdtype = fdtype;
|
||||
LL_APPEND(object->fds, ev);
|
||||
reactor->event_num++;
|
||||
if (fd > object->maxfd)
|
||||
{
|
||||
object->maxfd = fd;
|
||||
}
|
||||
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
static int swReactorSelect_cmp(swFdList_node *a, swFdList_node *b)
|
||||
{
|
||||
return a->fd == b->fd ? 0 : (a->fd > b->fd ? -1 : 1);
|
||||
}
|
||||
|
||||
int swReactorSelect_del(swReactor *reactor, int fd)
|
||||
{
|
||||
swReactorSelect *object = reactor->object;
|
||||
swFdList_node ev, *s_ev = NULL;
|
||||
ev.fd = fd;
|
||||
LL_SEARCH(object->fds, s_ev, &ev, swReactorSelect_cmp);
|
||||
if (s_ev == NULL)
|
||||
{
|
||||
swWarn("swReactorSelect: fd[%d] not found", fd);
|
||||
return SW_ERR;
|
||||
}
|
||||
LL_DELETE(object->fds, s_ev);
|
||||
SW_FD_CLR(fd, &object->rfds);
|
||||
SW_FD_CLR(fd, &object->wfds);
|
||||
SW_FD_CLR(fd, &object->efds);
|
||||
reactor->event_num = reactor->event_num <= 0 ? 0 : reactor->event_num - 1;
|
||||
sw_free(s_ev);
|
||||
swReactor_del(reactor, fd);
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
int swReactorSelect_set(swReactor *reactor, int fd, int fdtype)
|
||||
{
|
||||
swReactorSelect *object = reactor->object;
|
||||
swFdList_node ev, *s_ev = NULL;
|
||||
ev.fd = fd;
|
||||
LL_SEARCH(object->fds, s_ev, &ev, swReactorSelect_cmp);
|
||||
if (s_ev == NULL)
|
||||
{
|
||||
swWarn("swReactorSelect: sock[%d] not found.", fd);
|
||||
return SW_ERR;
|
||||
}
|
||||
s_ev->fdtype = fdtype;
|
||||
//execute parent method
|
||||
swReactor_set(reactor, fd, fdtype);
|
||||
return SW_OK;
|
||||
}
|
||||
|
||||
int swReactorSelect_wait(swReactor *reactor, struct timeval *timeo)
|
||||
{
|
||||
swReactorSelect *object = reactor->object;
|
||||
swFdList_node *ev;
|
||||
swFdList_node *tmp;
|
||||
swEvent event;
|
||||
swReactor_handle handle;
|
||||
struct timeval timeout;
|
||||
int ret;
|
||||
|
||||
if (reactor->timeout_msec == 0)
|
||||
{
|
||||
if (timeo == NULL)
|
||||
{
|
||||
reactor->timeout_msec = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
reactor->timeout_msec = timeo->tv_sec * 1000 + timeo->tv_usec / 1000;
|
||||
}
|
||||
}
|
||||
|
||||
reactor->start = 1;
|
||||
|
||||
while (reactor->running > 0)
|
||||
{
|
||||
FD_ZERO(&(object->rfds));
|
||||
FD_ZERO(&(object->wfds));
|
||||
FD_ZERO(&(object->efds));
|
||||
|
||||
if (reactor->onBegin != NULL)
|
||||
{
|
||||
reactor->onBegin(reactor);
|
||||
}
|
||||
|
||||
LL_FOREACH(object->fds, ev)
|
||||
{
|
||||
if (swReactor_event_read(ev->fdtype))
|
||||
{
|
||||
SW_FD_SET(ev->fd, &(object->rfds));
|
||||
}
|
||||
if (swReactor_event_write(ev->fdtype))
|
||||
{
|
||||
SW_FD_SET(ev->fd, &(object->wfds));
|
||||
}
|
||||
if (swReactor_event_error(ev->fdtype))
|
||||
{
|
||||
SW_FD_SET(ev->fd, &(object->efds));
|
||||
}
|
||||
}
|
||||
|
||||
if (reactor->timeout_msec < 0)
|
||||
{
|
||||
timeout.tv_sec = SW_MAX_UINT;
|
||||
timeout.tv_usec = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
timeout.tv_sec = reactor->timeout_msec / 1000;
|
||||
timeout.tv_usec = reactor->timeout_msec - timeout.tv_sec * 1000;
|
||||
}
|
||||
|
||||
ret = select(object->maxfd + 1, &(object->rfds), &(object->wfds), &(object->efds), &timeout);
|
||||
if (ret < 0)
|
||||
{
|
||||
if (swReactor_error(reactor) < 0)
|
||||
{
|
||||
swWarn("select error. Error: %s[%d]", strerror(errno), errno);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else if (ret == 0)
|
||||
{
|
||||
if (reactor->onTimeout != NULL)
|
||||
{
|
||||
reactor->onTimeout(reactor);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_FOREACH_SAFE(object->fds, ev, tmp)
|
||||
{
|
||||
event.fd = ev->fd;
|
||||
event.from_id = reactor->id;
|
||||
event.type = swReactor_fdtype(ev->fdtype);
|
||||
event.socket = swReactor_get(reactor, event.fd);
|
||||
|
||||
//read
|
||||
if (SW_FD_ISSET(event.fd, &(object->rfds)) && !event.socket->removed)
|
||||
{
|
||||
handle = swReactor_getHandle(reactor, SW_EVENT_READ, event.type);
|
||||
ret = handle(reactor, &event);
|
||||
if (ret < 0)
|
||||
{
|
||||
swSysError("[Reactor#%d] select event[type=READ, fd=%d] handler fail.", reactor->id, event.fd);
|
||||
}
|
||||
}
|
||||
//write
|
||||
if (SW_FD_ISSET(event.fd, &(object->wfds)) && !event.socket->removed)
|
||||
{
|
||||
handle = swReactor_getHandle(reactor, SW_EVENT_WRITE, event.type);
|
||||
ret = handle(reactor, &event);
|
||||
if (ret < 0)
|
||||
{
|
||||
swSysError("[Reactor#%d] select event[type=WRITE, fd=%d] handler fail.", reactor->id, event.fd);
|
||||
}
|
||||
}
|
||||
//error
|
||||
if (SW_FD_ISSET(event.fd, &(object->efds)) && !event.socket->removed)
|
||||
{
|
||||
handle = swReactor_getHandle(reactor, SW_EVENT_ERROR, event.type);
|
||||
ret = handle(reactor, &event);
|
||||
if (ret < 0)
|
||||
{
|
||||
swSysError("[Reactor#%d] select event[type=ERROR, fd=%d] handler fail.", reactor->id, event.fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (reactor->onFinish != NULL)
|
||||
{
|
||||
reactor->onFinish(reactor);
|
||||
}
|
||||
if (reactor->once)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
return SW_OK;
|
||||
}
|
Reference in New Issue
Block a user