Init Repo

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

249
vendor/swoole/src/core/Channel.c vendored Executable file
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

40
vendor/swoole/src/core/error.cc vendored Executable file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View File

@ -0,0 +1,245 @@
/*
+----------------------------------------------------------------------+
| Swoole |
+----------------------------------------------------------------------+
| This source file is subject to version 2.0 of the Apache license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.apache.org/licenses/LICENSE-2.0.html |
| If you did not receive a copy of the Apache2.0 license and are unable|
| to obtain it through the world-wide-web, please send a note to |
| license@swoole.com so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Author: Tianfeng Han <mikan.tenny@gmail.com> |
+----------------------------------------------------------------------+
*/
#include "swoole.h"
#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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

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

@ -0,0 +1,374 @@
/*
+----------------------------------------------------------------------+
| Swoole |
+----------------------------------------------------------------------+
| Copyright (c) 2012-2015 The Swoole Group |
+----------------------------------------------------------------------+
| This source file is subject to version 2.0 of the Apache license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.apache.org/licenses/LICENSE-2.0.html |
| If you did not receive a copy of the Apache2.0 license and are unable|
| to obtain it through the world-wide-web, please send a note to |
| license@swoole.com so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Author: Tianfeng Han <mikan.tenny@gmail.com> |
+----------------------------------------------------------------------+
*/
#include "swoole.h"
#include "Server.h"
#include <sys/stat.h>
#ifndef MSG_NOSIGNAL
#define MSG_NOSIGNAL 0
#endif
int swConnection_onSendfile(swConnection *conn, swBuffer_trunk *chunk)
{
int ret;
swTask_sendfile *task = chunk->store.ptr;
#ifdef HAVE_TCP_NOPUSH
if (task->offset == 0 && conn->tcp_nopush == 0)
{
/**
* disable tcp_nodelay
*/
if (conn->tcp_nodelay)
{
int tcp_nodelay = 0;
if (setsockopt(conn->fd, IPPROTO_TCP, TCP_NODELAY, (const void *) &tcp_nodelay, sizeof(int)) == -1)
{
swWarn("setsockopt(TCP_NODELAY) failed. Error: %s[%d]", strerror(errno), errno);
}
}
/**
* enable tcp_nopush
*/
if (swSocket_tcp_nopush(conn->fd, 1) == -1)
{
swWarn("swSocket_tcp_nopush() failed. Error: %s[%d]", strerror(errno), errno);
}
conn->tcp_nopush = 1;
}
#endif
int sendn = (task->length - task->offset > SW_SENDFILE_CHUNK_SIZE) ? SW_SENDFILE_CHUNK_SIZE : task->length - task->offset;
#ifdef SW_USE_OPENSSL
if (conn->ssl)
{
ret = swSSL_sendfile(conn, task->fd, &task->offset, sendn);
}
else
#endif
{
ret = swoole_sendfile(conn->fd, task->fd, &task->offset, sendn);
}
swTrace("ret=%d|task->offset=%ld|sendn=%d|filesize=%ld", ret, (long)task->offset, sendn, task->length);
if (ret <= 0)
{
switch (swConnection_error(errno))
{
case SW_ERROR:
swSysError("sendfile(%s, %ld, %d) failed.", task->filename, (long)task->offset, sendn);
swBuffer_pop_trunk(conn->out_buffer, chunk);
return SW_OK;
case SW_CLOSE:
conn->close_wait = 1;
return SW_ERR;
case SW_WAIT:
conn->send_wait = 1;
return SW_ERR;
default:
break;
}
}
//sendfile finish
if (task->offset >= task->length)
{
swBuffer_pop_trunk(conn->out_buffer, chunk);
#ifdef HAVE_TCP_NOPUSH
/**
* disable tcp_nopush
*/
if (swSocket_tcp_nopush(conn->fd, 0) == -1)
{
swWarn("swSocket_tcp_nopush() failed. Error: %s[%d]", strerror(errno), errno);
}
conn->tcp_nopush = 0;
/**
* enable tcp_nodelay
*/
if (conn->tcp_nodelay)
{
int value = 1;
if (setsockopt(conn->fd, IPPROTO_TCP, TCP_NODELAY, (const void *) &value, sizeof(int)) == -1)
{
swWarn("setsockopt(TCP_NODELAY) failed. Error: %s[%d]", strerror(errno), errno);
}
}
#endif
}
return SW_OK;
}
/**
* send buffer to client
*/
int swConnection_buffer_send(swConnection *conn)
{
int ret, sendn;
swBuffer *buffer = conn->out_buffer;
swBuffer_trunk *trunk = swBuffer_get_trunk(buffer);
sendn = trunk->length - trunk->offset;
if (sendn == 0)
{
swBuffer_pop_trunk(buffer, trunk);
return SW_OK;
}
ret = swConnection_send(conn, trunk->store.ptr + trunk->offset, sendn, 0);
if (ret < 0)
{
switch (swConnection_error(errno))
{
case SW_ERROR:
swWarn("send to fd[%d] failed. Error: %s[%d]", conn->fd, strerror(errno), errno);
break;
case SW_CLOSE:
conn->close_errno = errno;
conn->close_wait = 1;
return SW_ERR;
case SW_WAIT:
conn->send_wait = 1;
return SW_ERR;
default:
break;
}
return SW_OK;
}
//trunk full send
else if (ret == sendn || sendn == 0)
{
swBuffer_pop_trunk(buffer, trunk);
}
else
{
trunk->offset += ret;
}
return SW_OK;
}
swString* swConnection_get_string_buffer(swConnection *conn)
{
swString *buffer = conn->object;
if (buffer == NULL)
{
return swString_new(SW_BUFFER_SIZE);
}
else
{
return buffer;
}
}
static char tmp_address[INET6_ADDRSTRLEN];
char* swConnection_get_ip(swConnection *conn)
{
if (conn->socket_type == SW_SOCK_TCP)
{
return inet_ntoa(conn->info.addr.inet_v4.sin_addr);
}
else if (conn->socket_type == SW_SOCK_TCP6)
{
if (inet_ntop(AF_INET6, &conn->info.addr.inet_v6.sin6_addr, tmp_address, sizeof(tmp_address)) == NULL)
{
return "unknown";
}
else
{
return tmp_address;
}
}
else if (conn->socket_type == SW_SOCK_UNIX_STREAM)
{
return conn->info.addr.un.sun_path;
}
else
{
return "unknown";
}
}
int swConnection_get_port(swConnection *conn)
{
if (conn->socket_type == SW_SOCK_TCP)
{
return ntohs(conn->info.addr.inet_v4.sin_port);
}
else
{
return ntohs(conn->info.addr.inet_v6.sin6_port);
}
}
void swConnection_sendfile_destructor(swBuffer_trunk *chunk)
{
swTask_sendfile *task = chunk->store.ptr;
close(task->fd);
sw_free(task->filename);
sw_free(task);
}
int swConnection_sendfile(swConnection *conn, char *filename, off_t offset, size_t length)
{
if (conn->out_buffer == NULL)
{
conn->out_buffer = swBuffer_new(SW_BUFFER_SIZE);
if (conn->out_buffer == NULL)
{
return SW_ERR;
}
}
swBuffer_trunk error_chunk;
swTask_sendfile *task = sw_malloc(sizeof(swTask_sendfile));
if (task == NULL)
{
swWarn("malloc for swTask_sendfile failed.");
return SW_ERR;
}
bzero(task, sizeof(swTask_sendfile));
task->filename = sw_strdup(filename);
int file_fd = open(filename, O_RDONLY);
if (file_fd < 0)
{
sw_free(task->filename);
sw_free(task);
swSysError("open(%s) failed.", filename);
return SW_OK;
}
task->fd = file_fd;
task->offset = offset;
struct stat file_stat;
if (fstat(file_fd, &file_stat) < 0)
{
swSysError("fstat(%s) failed.", filename);
error_chunk.store.ptr = task;
swConnection_sendfile_destructor(&error_chunk);
return SW_ERR;
}
if (offset < 0 || (length + offset > file_stat.st_size))
{
swoole_error_log(SW_LOG_WARNING, SW_ERROR_INVALID_PARAMS, "length or offset is invalid.");
error_chunk.store.ptr = task;
swConnection_sendfile_destructor(&error_chunk);
return SW_OK;
}
if (length == 0)
{
task->length = file_stat.st_size;
}
else
{
task->length = length + offset;
}
swBuffer_trunk *chunk = swBuffer_new_trunk(conn->out_buffer, SW_CHUNK_SENDFILE, 0);
if (chunk == NULL)
{
swWarn("get out_buffer trunk failed.");
error_chunk.store.ptr = task;
swConnection_sendfile_destructor(&error_chunk);
return SW_ERR;
}
chunk->store.ptr = (void *) task;
chunk->destroy = swConnection_sendfile_destructor;
return SW_OK;
}
void swConnection_clear_string_buffer(swConnection *conn)
{
swString *buffer = conn->object;
if (buffer != NULL)
{
swString_free(buffer);
conn->object = NULL;
}
}
swBuffer_trunk* swConnection_get_in_buffer(swConnection *conn)
{
swBuffer_trunk *trunk = NULL;
swBuffer *buffer;
if (conn->in_buffer == NULL)
{
buffer = swBuffer_new(SW_BUFFER_SIZE);
//buffer create failed
if (buffer == NULL)
{
return NULL;
}
//new trunk
trunk = swBuffer_new_trunk(buffer, SW_CHUNK_DATA, buffer->trunk_size);
if (trunk == NULL)
{
sw_free(buffer);
return NULL;
}
conn->in_buffer = buffer;
}
else
{
buffer = conn->in_buffer;
trunk = buffer->tail;
if (trunk == NULL || trunk->length == buffer->trunk_size)
{
trunk = swBuffer_new_trunk(buffer, SW_CHUNK_DATA, buffer->trunk_size);
}
}
return trunk;
}
swBuffer_trunk* swConnection_get_out_buffer(swConnection *conn, uint32_t type)
{
swBuffer_trunk *trunk;
if (conn->out_buffer == NULL)
{
conn->out_buffer = swBuffer_new(SW_BUFFER_SIZE);
if (conn->out_buffer == NULL)
{
return NULL;
}
}
if (type == SW_CHUNK_SENDFILE)
{
trunk = swBuffer_new_trunk(conn->out_buffer, SW_CHUNK_SENDFILE, 0);
}
else
{
trunk = swBuffer_get_trunk(conn->out_buffer);
if (trunk == NULL)
{
trunk = swBuffer_new_trunk(conn->out_buffer, SW_CHUNK_DATA, conn->out_buffer->trunk_size);
}
}
return trunk;
}

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

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

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

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

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

@ -0,0 +1,757 @@
/*
+----------------------------------------------------------------------+
| Swoole |
+----------------------------------------------------------------------+
| This source file is subject to version 2.0 of the Apache license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.apache.org/licenses/LICENSE-2.0.html |
| If you did not receive a copy of the Apache2.0 license and are unable|
| to obtain it through the world-wide-web, please send a note to |
| license@swoole.com so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Author: Tianfeng Han <mikan.tenny@gmail.com> |
+----------------------------------------------------------------------+
*/
#include "Server.h"
#include "http.h"
#include "http2.h"
#include "websocket.h"
#include "mqtt.h"
#include "redis.h"
#include <sys/stat.h>
static int swPort_onRead_raw(swReactor *reactor, swListenPort *lp, swEvent *event);
static int swPort_onRead_check_length(swReactor *reactor, swListenPort *lp, swEvent *event);
static int swPort_onRead_check_eof(swReactor *reactor, swListenPort *lp, swEvent *event);
static int swPort_onRead_http(swReactor *reactor, swListenPort *lp, swEvent *event);
static int swPort_onRead_redis(swReactor *reactor, swListenPort *lp, swEvent *event);
static int swPort_http_static_handler(swHttpRequest *request, swConnection *conn);
void swPort_init(swListenPort *port)
{
port->sock = 0;
port->ssl = 0;
//listen backlog
port->backlog = SW_BACKLOG;
//tcp keepalive
port->tcp_keepcount = SW_TCP_KEEPCOUNT;
port->tcp_keepinterval = SW_TCP_KEEPINTERVAL;
port->tcp_keepidle = SW_TCP_KEEPIDLE;
port->open_tcp_nopush = 1;
port->protocol.package_length_type = 'N';
port->protocol.package_length_size = 4;
port->protocol.package_body_offset = 4;
port->protocol.package_max_length = SW_BUFFER_INPUT_SIZE;
port->socket_buffer_size = SwooleG.socket_buffer_size;
char eof[] = SW_DATA_EOF;
port->protocol.package_eof_len = sizeof(SW_DATA_EOF) - 1;
memcpy(port->protocol.package_eof, eof, port->protocol.package_eof_len);
}
#ifdef SW_USE_OPENSSL
int swPort_enable_ssl_encrypt(swListenPort *ls)
{
if (ls->ssl_option.cert_file == NULL || ls->ssl_option.key_file == NULL)
{
swWarn("SSL error, require ssl_cert_file and ssl_key_file.");
return SW_ERR;
}
ls->ssl_context = swSSL_get_context(&ls->ssl_option);
if (ls->ssl_context == NULL)
{
swWarn("swSSL_get_context() error.");
return SW_ERR;
}
/**
* OpenSSL thread-safe
*/
swSSL_init_thread_safety();
if (ls->ssl_option.client_cert_file
&& swSSL_set_client_certificate(ls->ssl_context, ls->ssl_option.client_cert_file,
ls->ssl_option.verify_depth) == SW_ERR)
{
swWarn("swSSL_set_client_certificate() error.");
return SW_ERR;
}
if (ls->open_http_protocol)
{
ls->ssl_config.http = 1;
}
if (ls->open_http2_protocol)
{
ls->ssl_config.http_v2 = 1;
swSSL_server_http_advise(ls->ssl_context, &ls->ssl_config);
}
if (swSSL_server_set_cipher(ls->ssl_context, &ls->ssl_config) < 0)
{
swWarn("swSSL_server_set_cipher() error.");
return SW_ERR;
}
return SW_OK;
}
#endif
int swPort_listen(swListenPort *ls)
{
int sock = ls->sock;
int option = 1;
//listen stream socket
if (listen(sock, ls->backlog) < 0)
{
swWarn("listen(%s:%d, %d) failed. Error: %s[%d]", ls->host, ls->port, ls->backlog, strerror(errno), errno);
return SW_ERR;
}
#ifdef TCP_DEFER_ACCEPT
if (ls->tcp_defer_accept)
{
if (setsockopt(sock, IPPROTO_TCP, TCP_DEFER_ACCEPT, (const void*) &ls->tcp_defer_accept, sizeof(int)) < 0)
{
swSysError("setsockopt(TCP_DEFER_ACCEPT) failed.");
}
}
#endif
#ifdef TCP_FASTOPEN
if (ls->tcp_fastopen)
{
if (setsockopt(sock, IPPROTO_TCP, TCP_FASTOPEN, (const void*) &ls->tcp_fastopen, sizeof(int)) < 0)
{
swSysError("setsockopt(TCP_FASTOPEN) failed.");
}
}
#endif
#ifdef SO_KEEPALIVE
if (ls->open_tcp_keepalive == 1)
{
if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void *) &option, sizeof(option)) < 0)
{
swSysError("setsockopt(SO_KEEPALIVE) failed.");
}
#ifdef TCP_KEEPIDLE
setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, (void*) &ls->tcp_keepidle, sizeof(int));
setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, (void *) &ls->tcp_keepinterval, sizeof(int));
setsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT, (void *) &ls->tcp_keepcount, sizeof(int));
#endif
}
#endif
ls->buffer_high_watermark = ls->socket_buffer_size * 0.8;
ls->buffer_low_watermark = 0;
return SW_OK;
}
void swPort_set_protocol(swListenPort *ls)
{
//Thread mode must copy the data.
//will free after onFinish
if (ls->open_eof_check)
{
if (ls->protocol.package_eof_len > sizeof(ls->protocol.package_eof))
{
ls->protocol.package_eof_len = sizeof(ls->protocol.package_eof);
}
ls->protocol.onPackage = swReactorThread_dispatch;
ls->onRead = swPort_onRead_check_eof;
}
else if (ls->open_length_check)
{
if (ls->protocol.package_length_type != '\0')
{
ls->protocol.get_package_length = swProtocol_get_package_length;
}
ls->protocol.onPackage = swReactorThread_dispatch;
ls->onRead = swPort_onRead_check_length;
}
else if (ls->open_http_protocol)
{
if (ls->open_websocket_protocol)
{
ls->protocol.get_package_length = swWebSocket_get_package_length;
ls->protocol.onPackage = swWebSocket_dispatch_frame;
ls->protocol.package_length_size = SW_WEBSOCKET_HEADER_LEN + SW_WEBSOCKET_MASK_LEN + sizeof(uint64_t);
}
#ifdef SW_USE_HTTP2
else if (ls->open_http2_protocol)
{
ls->protocol.get_package_length = swHttp2_get_frame_length;
ls->protocol.package_length_size = SW_HTTP2_FRAME_HEADER_SIZE;
ls->protocol.onPackage = swReactorThread_dispatch;
}
#endif
ls->onRead = swPort_onRead_http;
}
else if (ls->open_mqtt_protocol)
{
ls->protocol.get_package_length = swMqtt_get_package_length;
ls->protocol.onPackage = swReactorThread_dispatch;
ls->onRead = swPort_onRead_check_length;
}
else if (ls->open_redis_protocol)
{
ls->protocol.onPackage = swReactorThread_dispatch;
ls->onRead = swPort_onRead_redis;
}
else
{
ls->onRead = swPort_onRead_raw;
}
}
void swPort_clear_protocol(swListenPort *ls)
{
ls->open_eof_check = 0;
ls->open_length_check = 0;
ls->open_http_protocol = 0;
ls->open_websocket_protocol = 0;
#ifdef SW_USE_HTTP2
ls->open_http2_protocol = 0;
#endif
ls->open_mqtt_protocol = 0;
ls->open_redis_protocol = 0;
}
static int swPort_onRead_raw(swReactor *reactor, swListenPort *port, swEvent *event)
{
int n;
swDispatchData task;
swConnection *conn = event->socket;
n = swConnection_recv(conn, task.data.data, SW_BUFFER_SIZE, 0);
if (n < 0)
{
switch (swConnection_error(errno))
{
case SW_ERROR:
swSysError("recv from connection#%d failed.", event->fd);
return SW_OK;
case SW_CLOSE:
conn->close_errno = errno;
goto close_fd;
default:
return SW_OK;
}
}
else if (n == 0)
{
close_fd: swReactorThread_onClose(reactor, event);
return SW_OK;
}
else
{
task.data.info.fd = event->fd;
task.data.info.from_id = event->from_id;
task.data.info.len = n;
task.data.info.type = SW_EVENT_TCP;
task.target_worker_id = -1;
return swReactorThread_dispatch(conn, task.data.data, task.data.info.len);
}
return SW_OK;
}
static int swPort_onRead_check_length(swReactor *reactor, swListenPort *port, swEvent *event)
{
swServer *serv = reactor->ptr;
swConnection *conn = event->socket;
swProtocol *protocol = &port->protocol;
swString *buffer = swServer_get_buffer(serv, event->fd);
if (!buffer)
{
return SW_ERR;
}
if (swProtocol_recv_check_length(protocol, conn, buffer) < 0)
{
swTrace("Close Event.FD=%d|From=%d", event->fd, event->from_id);
swReactorThread_onClose(reactor, event);
}
return SW_OK;
}
/**
* For Http Protocol
*/
static int swPort_onRead_http(swReactor *reactor, swListenPort *port, swEvent *event)
{
swConnection *conn = event->socket;
swServer *serv = reactor->ptr;
if (conn->websocket_status >= WEBSOCKET_STATUS_HANDSHAKE)
{
if (conn->http_upgrade == 0)
{
swHttpRequest_free(conn);
conn->websocket_status = WEBSOCKET_STATUS_ACTIVE;
conn->http_upgrade = 1;
}
return swPort_onRead_check_length(reactor, port, event);
}
#ifdef SW_USE_HTTP2
if (conn->http2_stream)
{
return swPort_onRead_check_length(reactor, port, event);
}
#endif
int n = 0;
char *buf;
int buf_len;
swHttpRequest *request = NULL;
swProtocol *protocol = &port->protocol;
//new http request
if (conn->object == NULL)
{
request = sw_malloc(sizeof(swHttpRequest));
bzero(request, sizeof(swHttpRequest));
conn->object = request;
}
else
{
request = (swHttpRequest *) conn->object;
}
if (!request->buffer)
{
request->buffer = swString_new(SW_HTTP_HEADER_MAX_SIZE);
//alloc memory failed.
if (!request->buffer)
{
swReactorThread_onClose(reactor, event);
return SW_ERR;
}
}
swString *buffer = request->buffer;
recv_data:
buf = buffer->str + buffer->length;
buf_len = buffer->size - buffer->length;
n = swConnection_recv(conn, buf, buf_len, 0);
if (n < 0)
{
switch (swConnection_error(errno))
{
case SW_ERROR:
swSysError("recv from connection#%d failed.", event->fd);
return SW_OK;
case SW_CLOSE:
conn->close_errno = errno;
goto close_fd;
default:
return SW_OK;
}
}
else if (n == 0)
{
close_fd:
swHttpRequest_free(conn);
swReactorThread_onClose(reactor, event);
return SW_OK;
}
else
{
buffer->length += n;
if (request->method == 0 && swHttpRequest_get_protocol(request) < 0)
{
if (request->excepted == 0 && request->buffer->length < SW_HTTP_HEADER_MAX_SIZE)
{
return SW_OK;
}
swoole_error_log(SW_LOG_TRACE, SW_ERROR_HTTP_INVALID_PROTOCOL, "get protocol failed.");
#ifdef SW_HTTP_BAD_REQUEST
if (swConnection_send(conn, SW_STRL(SW_HTTP_BAD_REQUEST) - 1, 0) < 0)
{
swSysError("send() failed.");
}
#endif
goto close_fd;
}
if (request->method > HTTP_PRI)
{
swWarn("method no support");
goto close_fd;
}
#ifdef SW_USE_HTTP2
else if (request->method == HTTP_PRI)
{
conn->http2_stream = 1;
swHttp2_send_setting_frame(protocol, conn);
if (n == sizeof(SW_HTTP2_PRI_STRING) - 1)
{
swHttpRequest_free(conn);
return SW_OK;
}
swHttp2_parse_frame(protocol, conn, buf + (sizeof(SW_HTTP2_PRI_STRING) - 1), n - (sizeof(SW_HTTP2_PRI_STRING) - 1));
swHttpRequest_free(conn);
return SW_OK;
}
#endif
//http header is not the end
if (request->header_length == 0)
{
if (swHttpRequest_get_header_length(request) < 0)
{
if (buffer->size == buffer->length)
{
swWarn("[2]http header is too long.");
goto close_fd;
}
else
{
goto recv_data;
}
}
}
//http body
if (request->content_length == 0)
{
if (swHttpRequest_get_content_length(request) < 0)
{
if (memcmp(buffer->str + buffer->length - 4, "\r\n\r\n", 4) == 0)
{
/**
* send static file content directly in the reactor thread
*/
if (!(serv->enable_static_handler && swPort_http_static_handler(request, conn)))
{
/**
* dynamic request, dispatch to worker
*/
swReactorThread_dispatch(conn, buffer->str, buffer->length);
}
swHttpRequest_free(conn);
return SW_OK;
}
else if (buffer->size == buffer->length)
{
swWarn("[0]http header is too long.");
goto close_fd;
}
//wait more data
else
{
goto recv_data;
}
}
else if (request->content_length > (protocol->package_max_length - SW_HTTP_HEADER_MAX_SIZE))
{
swWarn("Content-Length is too big, MaxSize=[%d].", protocol->package_max_length - SW_HTTP_HEADER_MAX_SIZE);
goto close_fd;
}
}
//total length
uint32_t request_size = request->header_length + request->content_length;
if (request_size > buffer->size && swString_extend(buffer, request_size) < 0)
{
goto close_fd;
}
//discard the redundant data
if (buffer->length > request_size)
{
buffer->length = request_size;
}
if (buffer->length == request_size)
{
swReactorThread_dispatch(conn, buffer->str, buffer->length);
swHttpRequest_free(conn);
}
else
{
#ifdef SW_HTTP_100_CONTINUE
//Expect: 100-continue
if (swHttpRequest_has_expect_header(request))
{
swSendData _send;
_send.data = "HTTP/1.1 100 Continue\r\n\r\n";
_send.length = strlen(_send.data);
int send_times = 0;
direct_send:
n = swConnection_send(conn, _send.data, _send.length, 0);
if (n < _send.length)
{
_send.data += n;
_send.length -= n;
send_times++;
if (send_times < 10)
{
goto direct_send;
}
else
{
swWarn("send http header failed");
}
}
}
else
{
swTrace("PostWait: request->content_length=%d, buffer->length=%zd, request->header_length=%d\n",
request->content_length, buffer->length, request->header_length);
}
#endif
goto recv_data;
}
}
return SW_OK;
}
static int swPort_onRead_redis(swReactor *reactor, swListenPort *port, swEvent *event)
{
swConnection *conn = event->socket;
swProtocol *protocol = &port->protocol;
swServer *serv = reactor->ptr;
swString *buffer = swServer_get_buffer(serv, event->fd);
if (!buffer)
{
return SW_ERR;
}
if (swRedis_recv(protocol, conn, buffer) < 0)
{
swReactorThread_onClose(reactor, event);
}
return SW_OK;
}
static int swPort_onRead_check_eof(swReactor *reactor, swListenPort *port, swEvent *event)
{
swConnection *conn = event->socket;
swProtocol *protocol = &port->protocol;
swServer *serv = reactor->ptr;
swString *buffer = swServer_get_buffer(serv, event->fd);
if (!buffer)
{
return SW_ERR;
}
if (swProtocol_recv_check_eof(protocol, conn, buffer) < 0)
{
swReactorThread_onClose(reactor, event);
}
return SW_OK;
}
void swPort_free(swListenPort *port)
{
#ifdef SW_USE_OPENSSL
if (port->ssl)
{
swSSL_free_context(port->ssl_context);
sw_free(port->ssl_option.cert_file);
sw_free(port->ssl_option.key_file);
if (port->ssl_option.client_cert_file)
{
sw_free(port->ssl_option.client_cert_file);
}
}
#endif
close(port->sock);
//remove unix socket file
if (port->type == SW_SOCK_UNIX_STREAM || port->type == SW_SOCK_UNIX_DGRAM)
{
unlink(port->host);
}
}
#ifndef PATH_MAX
#define PATH_MAX 4096
#endif
int swPort_http_static_handler(swHttpRequest *request, swConnection *conn)
{
swServer *serv = SwooleG.serv;
char *url = request->buffer->str + request->url_offset;
char *params = memchr(url, '?', request->url_length);
struct
{
off_t offset;
size_t length;
char filename[PATH_MAX];
} buffer;
char *p = buffer.filename;
memcpy(p, serv->document_root, serv->document_root_len);
p += serv->document_root_len;
uint32_t n = params ? params - url : request->url_length;
memcpy(p, url, n);
p += n;
*p = 0;
struct stat file_stat;
if (lstat(buffer.filename, &file_stat) < 0)
{
return SW_FALSE;
}
if ((file_stat.st_mode & S_IFMT) != S_IFREG)
{
return SW_FALSE;
}
char header_buffer[1024];
swSendData response;
response.info.fd = conn->session_id;
response.info.type = SW_EVENT_TCP;
p = request->buffer->str + request->url_offset + request->url_length + 10;
char *pe = request->buffer->str + request->header_length;
char *date_if_modified_since = NULL;
int length_if_modified_since = 0;
int state = 0;
for (; p < pe; p++)
{
switch(state)
{
case 0:
if (strncasecmp(p, SW_STRL("If-Modified-Since") - 1) == 0)
{
p += sizeof("If-Modified-Since");
state = 1;
}
break;
case 1:
if (!isspace(*p))
{
date_if_modified_since = p;
state = 2;
}
break;
case 2:
if (strncasecmp(p, SW_STRL("\r\n") - 1) == 0)
{
length_if_modified_since = p - date_if_modified_since;
goto check_modify_date;
}
break;
default:
break;
}
}
char date_[64];
struct tm *tm1;
check_modify_date: tm1 = gmtime(&serv->gs->now);
strftime(date_, sizeof(date_), "%a, %d %b %Y %H:%M:%S %Z", tm1);
char date_last_modified[64];
#ifdef __MACH__
time_t file_mtime = file_stat.st_mtimespec.tv_sec;
#else
time_t file_mtime = file_stat.st_mtim.tv_sec;
#endif
struct tm *tm2 = gmtime(&file_mtime);
strftime(date_last_modified, sizeof(date_last_modified), "%a, %d %b %Y %H:%M:%S %Z", tm2);
if (state == 2)
{
struct tm tm3;
char date_tmp[64];
memcpy(date_tmp, date_if_modified_since, length_if_modified_since);
date_tmp[length_if_modified_since] = 0;
char *date_format = NULL;
if (strptime(date_tmp, SW_HTTP_RFC1123_DATE_GMT, &tm3) != NULL)
{
date_format = SW_HTTP_RFC1123_DATE_GMT;
}
else if (strptime(date_tmp, SW_HTTP_RFC1123_DATE_UTC, &tm3) != NULL)
{
date_format = SW_HTTP_RFC1123_DATE_UTC;
}
else if (strptime(date_tmp, SW_HTTP_RFC850_DATE, &tm3) != NULL)
{
date_format = SW_HTTP_RFC850_DATE;
}
else if (strptime(date_tmp, SW_HTTP_ASCTIME_DATE, &tm3) != NULL)
{
date_format = SW_HTTP_ASCTIME_DATE;
}
if (date_format && mktime(&tm3) - (int) timezone >= file_mtime)
{
response.length = response.info.len = snprintf(header_buffer, sizeof(header_buffer),
"HTTP/1.1 304 Not Modified\r\n"
"Connection: Keep-Alive\r\n"
"Date: %s\r\n"
"Last-Modified: %s\r\n"
"Server: %s\r\n\r\n", date_, date_last_modified,
SW_HTTP_SERVER_SOFTWARE);
response.data = header_buffer;
swReactorThread_send(&response);
return SW_TRUE;
}
}
response.length = response.info.len = snprintf(header_buffer, sizeof(header_buffer),
"HTTP/1.1 200 OK\r\n"
"Connection: Keep-Alive\r\n"
"Content-Length: %ld\r\n"
"Content-Type: %s\r\n"
"Date: %s\r\n"
"Last-Modified: %s\r\n"
"Server: %s\r\n\r\n", (long) file_stat.st_size, swoole_get_mimetype(buffer.filename),
date_,
date_last_modified,
SW_HTTP_SERVER_SOFTWARE);
response.data = header_buffer;
#ifdef HAVE_TCP_NOPUSH
if (conn->tcp_nopush == 0)
{
if (swSocket_tcp_nopush(conn->fd, 1) == -1)
{
swWarn("swSocket_tcp_nopush() failed. Error: %s[%d]", strerror(errno), errno);
}
conn->tcp_nopush = 1;
}
#endif
swReactorThread_send(&response);
buffer.offset = 0;
buffer.length = file_stat.st_size;
response.info.type = SW_EVENT_SENDFILE;
response.length = response.info.len = sizeof(swSendFile_request) + buffer.length + 1;
response.data = (void*) &buffer;
swReactorThread_send(&response);
return SW_TRUE;
}

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

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

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

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

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

File diff suppressed because it is too large Load Diff

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

File diff suppressed because it is too large Load Diff

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

@ -0,0 +1,169 @@
/*
+----------------------------------------------------------------------+
| Swoole |
+----------------------------------------------------------------------+
| This source file is subject to version 2.0 of the Apache license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.apache.org/licenses/LICENSE-2.0.html |
| If you did not receive a copy of the Apache2.0 license and are unable|
| to obtain it through the world-wide-web, please send a note to |
| license@swoole.com so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Author: Tianfeng Han <mikan.tenny@gmail.com> |
+----------------------------------------------------------------------+
*/
#include "swoole.h"
#include "Client.h"
static void swStream_free(swStream *stream);
static void swStream_onConnect(swClient *cli)
{
swStream *stream = (swStream*) cli->object;
if (stream->cancel)
{
cli->close(cli);
}
*((uint32_t *) stream->buffer->str) = ntohl(stream->buffer->length - 4);
if (cli->send(cli, stream->buffer->str, stream->buffer->length, 0) < 0)
{
cli->close(cli);
}
else
{
swString_free(stream->buffer);
stream->buffer = NULL;
}
}
static void swStream_onError(swClient *cli)
{
swStream_free(cli->object);
}
static void swStream_onReceive(swClient *cli, char *data, uint32_t length)
{
swStream *stream = (swStream*) cli->object;
if (length == 4)
{
cli->socket->close_wait = 1;
}
else
{
stream->response(stream, data + 4, length - 4);
}
}
static void swStream_onClose(swClient *cli)
{
swStream_free(cli->object);
}
static void swStream_free(swStream *stream)
{
if (stream->buffer)
{
swString_free(stream->buffer);
}
sw_free(stream);
}
swStream* swStream_new(char *dst_host, int dst_port, int type)
{
swStream *stream = (swStream*) sw_malloc(sizeof(swStream));
bzero(stream, sizeof(swStream));
swClient *cli = &stream->client;
if (swClient_create(cli, type, 1) < 0)
{
swStream_free(stream);
return NULL;
}
cli->onConnect = swStream_onConnect;
cli->onReceive = swStream_onReceive;
cli->onError = swStream_onError;
cli->onClose = swStream_onClose;
cli->object = stream;
cli->open_length_check = 1;
swStream_set_protocol(&cli->protocol);
if (cli->connect(cli, dst_host, dst_port, -1, 0) < 0)
{
swSysError("failed to connect to [%s:%d].", dst_host, dst_port);
swStream_free(stream);
return NULL;
}
else
{
return stream;
}
}
/**
* Stream Protocol: Length(32bit/Network Byte Order) + Body
*/
void swStream_set_protocol(swProtocol *protocol)
{
protocol->get_package_length = swProtocol_get_package_length;
protocol->package_length_size = 4;
protocol->package_length_type = 'N';
protocol->package_body_offset = 4;
protocol->package_length_offset = 0;
}
void swStream_set_max_length(swStream *stream, uint32_t max_length)
{
stream->client.protocol.package_max_length = max_length;
}
int swStream_send(swStream *stream, char *data, size_t length)
{
if (stream->buffer == NULL)
{
stream->buffer = swString_new(swoole_size_align(length + 4, SwooleG.pagesize));
if (stream->buffer == NULL)
{
return SW_ERR;
}
stream->buffer->length = 4;
}
if (swString_append_ptr(stream->buffer, data, length) < 0)
{
return SW_ERR;
}
return SW_OK;
}
int swStream_recv_blocking(int fd, void *__buf, size_t __len)
{
int tmp = 0;
int ret = swSocket_recv_blocking(fd, &tmp, sizeof(tmp), MSG_WAITALL);
if (ret <= 0)
{
return SW_CLOSE;
}
int length = ntohl(tmp);
if (length <= 0)
{
return SW_CLOSE;
}
else if (length > __len)
{
return SW_CLOSE;
}
ret = swSocket_recv_blocking(fd, __buf, length, MSG_WAITALL);
if (ret <= 0)
{
return SW_CLOSE;
}
else
{
return SW_READY;
}
}

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

@ -0,0 +1,320 @@
/*
+----------------------------------------------------------------------+
| Swoole |
+----------------------------------------------------------------------+
| This source file is subject to version 2.0 of the Apache license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.apache.org/licenses/LICENSE-2.0.html |
| If you did not receive a copy of the Apache2.0 license and are unable|
| to obtain it through the world-wide-web, please send a note to |
| license@swoole.com so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Author: Tianfeng Han <mikan.tenny@gmail.com> |
+----------------------------------------------------------------------+
*/
#include "swoole.h"
#include "Server.h"
static swEventData *current_task = NULL;
static void swTaskWorker_signal_init(void);
void swTaskWorker_init(swProcessPool *pool)
{
swServer *serv = SwooleG.serv;
pool->ptr = serv;
pool->onTask = swTaskWorker_onTask;
pool->onWorkerStart = swTaskWorker_onStart;
pool->onWorkerStop = swTaskWorker_onStop;
pool->type = SW_PROCESS_TASKWORKER;
pool->start_id = serv->worker_num;
pool->run_worker_num = serv->task_worker_num;
if (serv->task_ipc_mode == SW_TASK_IPC_PREEMPTIVE)
{
pool->dispatch_mode = SW_DISPATCH_QUEUE;
}
}
/**
* in worker process
*/
int swTaskWorker_onFinish(swReactor *reactor, swEvent *event)
{
swServer *serv = reactor->ptr;
swEventData task;
int n;
do
{
n = read(event->fd, &task, sizeof(task));
} while (n < 0 && errno == EINTR);
return serv->onFinish(serv, &task);
}
int swTaskWorker_onTask(swProcessPool *pool, swEventData *task)
{
int ret = SW_OK;
swServer *serv = pool->ptr;
current_task = task;
if (task->info.type == SW_EVENT_PIPE_MESSAGE)
{
serv->onPipeMessage(serv, task);
}
else
{
ret = serv->onTask(serv, task);
}
return ret;
}
int swTaskWorker_large_pack(swEventData *task, void *data, int data_len)
{
swPackage_task pkg;
bzero(&pkg, sizeof(pkg));
memcpy(pkg.tmpfile, SwooleG.task_tmpdir, SwooleG.task_tmpdir_len);
//create temp file
int tmp_fd = swoole_tmpfile(pkg.tmpfile);
if (tmp_fd < 0)
{
return SW_ERR;
}
//write to file
if (swoole_sync_writefile(tmp_fd, data, data_len) <= 0)
{
swWarn("write to tmpfile failed.");
return SW_ERR;
}
task->info.len = sizeof(swPackage_task);
//use tmp file
swTask_type(task) |= SW_TASK_TMPFILE;
pkg.length = data_len;
memcpy(task->data, &pkg, sizeof(swPackage_task));
close(tmp_fd);
return SW_OK;
}
static void swTaskWorker_signal_init(void)
{
swSignal_set(SIGHUP, NULL, 1, 0);
swSignal_set(SIGPIPE, NULL, 1, 0);
swSignal_set(SIGUSR1, swWorker_signal_handler, 1, 0);
swSignal_set(SIGUSR2, NULL, 1, 0);
swSignal_set(SIGTERM, swWorker_signal_handler, 1, 0);
swSignal_set(SIGALRM, swSystemTimer_signal_handler, 1, 0);
#ifdef SIGRTMIN
swSignal_set(SIGRTMIN, swWorker_signal_handler, 1, 0);
#endif
}
void swTaskWorker_onStart(swProcessPool *pool, int worker_id)
{
swServer *serv = pool->ptr;
SwooleWG.id = worker_id;
SwooleG.pid = getpid();
SwooleG.use_timer_pipe = 0;
SwooleG.use_timerfd = 0;
swServer_close_port(serv, SW_TRUE);
swTaskWorker_signal_init();
swWorker_onStart(serv);
SwooleG.main_reactor = NULL;
swWorker *worker = swProcessPool_get_worker(pool, worker_id);
worker->start_time = serv->gs->now;
worker->request_count = 0;
worker->traced = 0;
SwooleWG.worker = worker;
SwooleWG.worker->status = SW_WORKER_IDLE;
}
void swTaskWorker_onStop(swProcessPool *pool, int worker_id)
{
swServer *serv = pool->ptr;
swWorker_onStop(serv);
}
/**
* Send the task result to worker
*/
int swTaskWorker_finish(swServer *serv, char *data, int data_len, int flags)
{
swEventData buf;
if (!current_task)
{
swWarn("cannot use finish in worker");
return SW_ERR;
}
if (serv->task_worker_num < 1)
{
swWarn("cannot use task/finish, because no set serv->task_worker_num.");
return SW_ERR;
}
if (current_task->info.type == SW_EVENT_PIPE_MESSAGE)
{
swWarn("task/finish is not supported in onPipeMessage callback.");
return SW_ERR;
}
uint16_t source_worker_id = current_task->info.from_id;
swWorker *worker = swServer_get_worker(serv, source_worker_id);
if (worker == NULL)
{
swWarn("invalid worker_id[%d].", source_worker_id);
return SW_ERR;
}
int ret;
//for swoole_server_task
if (swTask_type(current_task) & SW_TASK_NONBLOCK)
{
buf.info.type = SW_EVENT_FINISH;
buf.info.fd = current_task->info.fd;
//callback function
if (swTask_type(current_task) & SW_TASK_CALLBACK)
{
flags |= SW_TASK_CALLBACK;
}
else if (swTask_type(current_task) & SW_TASK_COROUTINE)
{
flags |= SW_TASK_COROUTINE;
}
swTask_type(&buf) = flags;
//write to file
if (data_len >= SW_IPC_MAX_SIZE - sizeof(buf.info))
{
if (swTaskWorker_large_pack(&buf, data, data_len) < 0 )
{
swWarn("large task pack failed()");
return SW_ERR;
}
}
else
{
memcpy(buf.data, data, data_len);
buf.info.len = data_len;
}
if (worker->pool->use_socket && worker->pool->stream->last_connection > 0)
{
int32_t _len = htonl(data_len);
ret = swSocket_write_blocking(worker->pool->stream->last_connection, (void *) &_len, sizeof(_len));
if (ret > 0)
{
ret = swSocket_write_blocking(worker->pool->stream->last_connection, data, data_len);
}
}
else
{
ret = swWorker_send2worker(worker, &buf, sizeof(buf.info) + buf.info.len, SW_PIPE_MASTER);
}
}
else
{
uint64_t flag = 1;
/**
* Use worker shm store the result
*/
swEventData *result = &(serv->task_result[source_worker_id]);
swPipe *task_notify_pipe = &(serv->task_notify[source_worker_id]);
//lock worker
worker->lock.lock(&worker->lock);
if (swTask_type(current_task) & SW_TASK_WAITALL)
{
sw_atomic_t *finish_count = (sw_atomic_t*) result->data;
char *_tmpfile = result->data + 4;
int fd = open(_tmpfile, O_APPEND | O_WRONLY);
if (fd >= 0)
{
buf.info.type = SW_EVENT_FINISH;
buf.info.fd = current_task->info.fd;
swTask_type(&buf) = flags;
//result pack
if (data_len >= SW_IPC_MAX_SIZE - sizeof(buf.info))
{
if (swTaskWorker_large_pack(&buf, data, data_len) < 0)
{
swWarn("large task pack failed()");
buf.info.len = 0;
}
}
else
{
buf.info.len = data_len;
memcpy(buf.data, data, data_len);
}
//write to tmpfile
if (swoole_sync_writefile(fd, &buf, sizeof(buf.info) + buf.info.len) < 0)
{
swSysError("write(%s, %ld) failed.", result->data, sizeof(buf.info) + buf.info.len);
}
sw_atomic_fetch_add(finish_count, 1);
close(fd);
}
}
else
{
result->info.type = SW_EVENT_FINISH;
result->info.fd = current_task->info.fd;
swTask_type(result) = flags;
if (data_len >= SW_IPC_MAX_SIZE - sizeof(buf.info))
{
if (swTaskWorker_large_pack(result, data, data_len) < 0)
{
//unlock worker
worker->lock.unlock(&worker->lock);
swWarn("large task pack failed()");
return SW_ERR;
}
}
else
{
memcpy(result->data, data, data_len);
result->info.len = data_len;
}
}
//unlock worker
worker->lock.unlock(&worker->lock);
while (1)
{
ret = task_notify_pipe->write(task_notify_pipe, &flag, sizeof(flag));
#ifdef HAVE_KQUEUE
if (ret < 0 && (errno == EAGAIN || errno == ENOBUFS))
#else
if (ret < 0 && errno == EAGAIN)
#endif
{
if (swSocket_wait(task_notify_pipe->getFd(task_notify_pipe, 1), -1, SW_EVENT_WRITE) == 0)
{
continue;
}
}
break;
}
}
if (ret < 0)
{
swWarn("TaskWorker: send result to worker failed. Error: %s[%d]", strerror(errno), errno);
}
return ret;
}

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

@ -0,0 +1,186 @@
/*
+----------------------------------------------------------------------+
| Swoole |
+----------------------------------------------------------------------+
| This source file is subject to version 2.0 of the Apache license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.apache.org/licenses/LICENSE-2.0.html |
| If you did not receive a copy of the Apache2.0 license and are unable|
| to obtain it through the world-wide-web, please send a note to |
| license@swoole.com so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Author: Tianfeng Han <mikan.tenny@gmail.com> |
+----------------------------------------------------------------------+
*/
#include "swoole.h"
#define swThreadPool_thread(p,id) (&p->threads[id])
static void* swThreadPool_loop(void *arg);
int swThreadPool_create(swThreadPool *pool, int thread_num)
{
bzero(pool, sizeof(swThreadPool));
pool->threads = (swThread *) sw_calloc(thread_num, sizeof(swThread));
pool->params = (swThreadParam *) sw_calloc(thread_num, sizeof(swThreadParam));
if (pool->threads == NULL || pool->params == NULL)
{
swWarn("swThreadPool_create malloc fail");
return SW_ERR;
}
swTrace("threads=%p|params=%p", pool->threads, pool->params);
#ifdef SW_THREADPOOL_USE_CHANNEL
pool->chan = swChannel_create(1024 * 256, 512, 0);
if (pool->chan == NULL)
{
swWarn("swThreadPool_create create channel failed");
return SW_ERR;
}
#else
int size = SwooleG.max_sockets >= SW_THREADPOOL_QUEUE_LEN ? SwooleG.max_sockets + 1 : SW_THREADPOOL_QUEUE_LEN;
if (swRingQueue_init(&pool->queue, size) < 0)
{
return SW_ERR;
}
#endif
if (swCond_create(&pool->cond) < 0)
{
return SW_ERR;
}
pool->thread_num = thread_num;
return SW_OK;
}
int swThreadPool_dispatch(swThreadPool *pool, void *task, int task_len)
{
int ret;
pool->cond.lock(&pool->cond);
#ifdef SW_THREADPOOL_USE_CHANNEL
ret = swChannel_in(pool->chan, task, task_len);
#else
ret = swRingQueue_push(&pool->queue, task);
#endif
pool->cond.unlock(&pool->cond);
if (ret < 0)
{
swoole_error_log(SW_LOG_ERROR, SW_ERROR_QUEUE_FULL, "the queue of thread pool is full.");
return SW_ERR;
}
sw_atomic_t *task_num = &pool->task_num;
sw_atomic_fetch_add(task_num, 1);
return pool->cond.notify(&pool->cond);
}
int swThreadPool_run(swThreadPool *pool)
{
int i;
for (i = 0; i < pool->thread_num; i++)
{
pool->params[i].pti = i;
pool->params[i].object = pool;
if (pthread_create(&(swThreadPool_thread(pool,i)->tid), NULL, swThreadPool_loop, &pool->params[i]) < 0)
{
swWarn("pthread_create failed. Error: %s[%d]", strerror(errno), errno);
return SW_ERR;
}
}
return SW_OK;
}
int swThreadPool_free(swThreadPool *pool)
{
int i;
if (pool->shutdown)
{
return -1;
}
pool->shutdown = 1;
//broadcast all thread
pool->cond.broadcast(&(pool->cond));
for (i = 0; i < pool->thread_num; i++)
{
pthread_join((swThreadPool_thread(pool,i)->tid), NULL);
}
#ifdef SW_THREADPOOL_USE_CHANNEL
swChannel_free(pool->chan);
#else
swRingQueue_free(&pool->queue);
#endif
pool->cond.free(&pool->cond);
return SW_OK;
}
static void* swThreadPool_loop(void *arg)
{
swThreadParam *param = arg;
swThreadPool *pool = param->object;
int id = param->pti;
int ret;
void *task;
SwooleTG.buffer_stack = swString_new(8192);
if (SwooleTG.buffer_stack == NULL)
{
return NULL;
}
if (pool->onStart)
{
pool->onStart(pool, id);
}
while (SwooleG.running)
{
pool->cond.lock(&pool->cond);
if (pool->shutdown)
{
pool->cond.unlock(&pool->cond);
swTrace("thread [%d] will exit\n", id);
pthread_exit(NULL);
}
if (pool->task_num == 0)
{
pool->cond.wait(&pool->cond);
}
swTrace("thread [%d] is starting to work\n", id);
ret = swRingQueue_pop(&pool->queue, &task);
pool->cond.unlock(&pool->cond);
if (ret >= 0)
{
sw_atomic_t *task_num = &pool->task_num;
sw_atomic_fetch_sub(task_num, 1);
pool->onTask(pool, (void *) task, ret);
}
}
if (pool->onStop)
{
pool->onStop(pool, id);
}
swString_free(SwooleTG.buffer_stack);
pthread_exit(NULL);
return NULL;
}

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

@ -0,0 +1,135 @@
/*
+----------------------------------------------------------------------+
| Swoole |
+----------------------------------------------------------------------+
| This source file is subject to version 2.0 of the Apache license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.apache.org/licenses/LICENSE-2.0.html |
| If you did not receive a copy of the Apache2.0 license and are unable|
| to obtain it through the world-wide-web, please send a note to |
| license@swoole.com so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Author: Tianfeng Han <mikan.tenny@gmail.com> |
+----------------------------------------------------------------------+
*/
#include "swoole.h"
#ifdef SW_USE_TIMEWHEEL
swTimeWheel* swTimeWheel_new(uint16_t size)
{
swTimeWheel *tw = sw_malloc(sizeof(swTimeWheel));
if (!tw)
{
swWarn("malloc(%ld) failed.", sizeof(swTimeWheel));
return NULL;
}
tw->size = size;
tw->current = 0;
tw->wheel = sw_calloc(size, sizeof(void*));
if (tw->wheel == NULL)
{
swWarn("malloc(%ld) failed.", sizeof(void*) * size);
sw_free(tw);
return NULL;
}
int i;
for (i = 0; i < size; i++)
{
tw->wheel[i] = swHashMap_new(16, NULL);
if (tw->wheel[i] == NULL)
{
swTimeWheel_free(tw);
return NULL;
}
}
return tw;
}
void swTimeWheel_free(swTimeWheel *tw)
{
int i;
for (i = 0; i < tw->size; i++)
{
if (tw->wheel[i] != NULL)
{
swHashMap_free(tw->wheel[i]);
tw->wheel[i] = NULL;
}
}
sw_free(tw->wheel);
sw_free(tw);
}
void swTimeWheel_forward(swTimeWheel *tw, swReactor *reactor)
{
swHashMap *set = tw->wheel[tw->current];
tw->current = tw->current == tw->size - 1 ? 0 : tw->current + 1;
swTraceLog(SW_TRACE_REACTOR, "current=%d.", tw->current);
swConnection *conn;
uint64_t fd;
while (1)
{
conn = swHashMap_each_int(set, &fd);
if (conn == NULL)
{
break;
}
conn->close_force = 1;
conn->close_notify = 1;
conn->close_wait = 1;
conn->close_actively = 1;
//notify to reactor thread
if (conn->removed)
{
reactor->close(reactor, (int) fd);
}
else
{
reactor->set(reactor, fd, SW_FD_TCP | SW_EVENT_WRITE);
}
}
}
void swTimeWheel_add(swTimeWheel *tw, swConnection *conn)
{
uint16_t index = tw->current == 0 ? tw->size - 1 : tw->current - 1;
swHashMap *new_set = tw->wheel[index];
swHashMap_add_int(new_set, conn->fd, conn);
conn->timewheel_index = index;
swTraceLog(SW_TRACE_REACTOR, "current=%d, fd=%d, index=%d.", tw->current, conn->fd, index);
}
void swTimeWheel_update(swTimeWheel *tw, swConnection *conn)
{
uint16_t new_index = swTimeWheel_new_index(tw);
swHashMap *new_set = tw->wheel[new_index];
swHashMap_add_int(new_set, conn->fd, conn);
swHashMap *old_set = tw->wheel[conn->timewheel_index];
swHashMap_del_int(old_set, conn->fd);
swTraceLog(SW_TRACE_REACTOR, "current=%d, fd=%d, old_index=%d, new_index=%d.", tw->current, conn->fd, new_index, conn->timewheel_index);
conn->timewheel_index = new_index;
}
void swTimeWheel_remove(swTimeWheel *tw, swConnection *conn)
{
swHashMap *set = tw->wheel[conn->timewheel_index];
swHashMap_del_int(set, conn->fd);
swTraceLog(SW_TRACE_REACTOR, "current=%d, fd=%d.", tw->current, conn->fd);
}
#endif

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

@ -0,0 +1,245 @@
/*
+----------------------------------------------------------------------+
| Swoole |
+----------------------------------------------------------------------+
| This source file is subject to version 2.0 of the Apache license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.apache.org/licenses/LICENSE-2.0.html |
| If you did not receive a copy of the Apache2.0 license and are unable|
| to obtain it through the world-wide-web, please send a note to |
| license@swoole.com so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Author: Tianfeng Han <mikan.tenny@gmail.com> |
+----------------------------------------------------------------------+
*/
#include "swoole.h"
static int swReactorTimer_init(long msec);
static int swReactorTimer_set(swTimer *timer, long exec_msec);
static swTimer_node* swTimer_add(swTimer *timer, int _msec, int interval, void *data, swTimerCallback callback);
int swTimer_now(struct timeval *time)
{
#if defined(SW_USE_MONOTONIC_TIME) && defined(CLOCK_MONOTONIC)
struct timespec _now;
if (clock_gettime(CLOCK_MONOTONIC, &_now) < 0)
{
swSysError("clock_gettime(CLOCK_MONOTONIC) failed.");
return SW_ERR;
}
time->tv_sec = _now.tv_sec;
time->tv_usec = _now.tv_nsec / 1000;
#else
if (gettimeofday(time, NULL) < 0)
{
swSysError("gettimeofday() failed.");
return SW_ERR;
}
#endif
return SW_OK;
}
static sw_inline int64_t swTimer_get_relative_msec()
{
struct timeval now;
if (swTimer_now(&now) < 0)
{
return SW_ERR;
}
int64_t msec1 = (now.tv_sec - SwooleG.timer.basetime.tv_sec) * 1000;
int64_t msec2 = (now.tv_usec - SwooleG.timer.basetime.tv_usec) / 1000;
return msec1 + msec2;
}
int swTimer_init(long msec)
{
if (swTimer_now(&SwooleG.timer.basetime) < 0)
{
return SW_ERR;
}
SwooleG.timer.heap = swHeap_new(1024, SW_MIN_HEAP);
if (!SwooleG.timer.heap)
{
return SW_ERR;
}
SwooleG.timer.map = swHashMap_new(SW_HASHMAP_INIT_BUCKET_N, NULL);
if (!SwooleG.timer.map)
{
swHeap_free(SwooleG.timer.heap);
SwooleG.timer.heap = NULL;
return SW_ERR;
}
SwooleG.timer._current_id = -1;
SwooleG.timer._next_msec = msec;
SwooleG.timer._next_id = 1;
SwooleG.timer.add = swTimer_add;
if (swIsTaskWorker())
{
swSystemTimer_init(msec, SwooleG.use_timer_pipe);
}
else
{
swReactorTimer_init(msec);
}
return SW_OK;
}
void swTimer_free(swTimer *timer)
{
if (timer->heap)
{
swHeap_free(timer->heap);
}
}
static int swReactorTimer_init(long exec_msec)
{
SwooleG.main_reactor->check_timer = SW_TRUE;
SwooleG.main_reactor->timeout_msec = exec_msec;
SwooleG.timer.set = swReactorTimer_set;
SwooleG.timer.fd = -1;
return SW_OK;
}
static int swReactorTimer_set(swTimer *timer, long exec_msec)
{
SwooleG.main_reactor->timeout_msec = exec_msec;
return SW_OK;
}
static swTimer_node* swTimer_add(swTimer *timer, int _msec, int interval, void *data, swTimerCallback callback)
{
swTimer_node *tnode = sw_malloc(sizeof(swTimer_node));
if (!tnode)
{
swSysError("malloc(%ld) failed.", sizeof(swTimer_node));
return NULL;
}
int64_t now_msec = swTimer_get_relative_msec();
if (now_msec < 0)
{
sw_free(tnode);
return NULL;
}
tnode->data = data;
tnode->type = SW_TIMER_TYPE_KERNEL;
tnode->exec_msec = now_msec + _msec;
tnode->interval = interval ? _msec : 0;
tnode->remove = 0;
tnode->callback = callback;
if (timer->_next_msec < 0 || timer->_next_msec > _msec)
{
timer->set(timer, _msec);
timer->_next_msec = _msec;
}
tnode->id = timer->_next_id++;
if (unlikely(tnode->id < 0))
{
tnode->id = 1;
timer->_next_id = 2;
}
timer->num++;
tnode->heap_node = swHeap_push(timer->heap, tnode->exec_msec, tnode);
if (tnode->heap_node == NULL)
{
sw_free(tnode);
return NULL;
}
swHashMap_add_int(timer->map, tnode->id, tnode);
return tnode;
}
int swTimer_del(swTimer *timer, swTimer_node *tnode)
{
if (tnode->remove)
{
return SW_FALSE;
}
if (SwooleG.timer._current_id > 0 && tnode->id == SwooleG.timer._current_id)
{
tnode->remove = 1;
return SW_TRUE;
}
if (swHashMap_del_int(timer->map, tnode->id) < 0)
{
return SW_ERR;
}
if (tnode->heap_node)
{
//remove from min-heap
swHeap_remove(timer->heap, tnode->heap_node);
sw_free(tnode->heap_node);
}
sw_free(tnode);
timer->num --;
return SW_TRUE;
}
int swTimer_select(swTimer *timer)
{
int64_t now_msec = swTimer_get_relative_msec();
if (now_msec < 0)
{
return SW_ERR;
}
swTimer_node *tnode = NULL;
swHeap_node *tmp;
long timer_id;
while ((tmp = swHeap_top(timer->heap)))
{
tnode = tmp->data;
if (tnode->exec_msec > now_msec)
{
break;
}
timer_id = timer->_current_id = tnode->id;
if (!tnode->remove)
{
tnode->callback(timer, tnode);
}
timer->_current_id = -1;
//persistent timer
if (tnode->interval > 0 && !tnode->remove)
{
while (tnode->exec_msec <= now_msec)
{
tnode->exec_msec += tnode->interval;
}
swHeap_change_priority(timer->heap, tnode->exec_msec, tmp);
continue;
}
timer->num--;
swHeap_pop(timer->heap);
swHashMap_del_int(timer->map, timer_id);
sw_free(tnode);
}
if (!tnode || !tmp)
{
timer->_next_msec = -1;
timer->set(timer, -1);
}
else
{
timer->set(timer, tnode->exec_msec - now_msec);
}
return SW_OK;
}

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

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

676
vendor/swoole/src/os/base.c vendored Executable file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View File

@ -0,0 +1,135 @@
/*
+----------------------------------------------------------------------+
| Swoole |
+----------------------------------------------------------------------+
| This source file is subject to version 2.0 of the Apache license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.apache.org/licenses/LICENSE-2.0.html |
| If you did not receive a copy of the Apache2.0 license and are unable|
| to obtain it through the world-wide-web, please send a note to |
| license@swoole.com so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Author: Tianfeng Han <mikan.tenny@gmail.com> |
+----------------------------------------------------------------------+
*/
#include "swoole.h"
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
View 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
View 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
View 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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

150
vendor/swoole/src/protocol/Sha1.c vendored Executable file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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;
}