├── words ├── src ├── co_alloc.h ├── co_utf8.h ├── co_ctx.c ├── co_ctx.h ├── co_dnsutils.h ├── co_queue.h ├── co_pqueue.h ├── co_loop.h ├── co_routine.h ├── co_utf8.c ├── co_str.h ├── co_falloc.h ├── co_timerservice.h ├── co_routineex.h ├── co_str.c ├── co_loop.c ├── co_list.h ├── coctx_swap.S ├── co_utils.h ├── co_clink.h ├── co_timingwheel.h ├── co_queue.c ├── co_falloc.c ├── co_set.h ├── co_vec.h ├── co_timerservice.c ├── co_pqueue.c ├── co_dict.h ├── co_endian.h ├── co_list.c ├── co_timingwheel.c ├── co_buffer.h ├── co_vec.c ├── co_dnsutils.c ├── co_routine.c ├── co_poll.h ├── co_dict.c ├── co_ioservice.h ├── co_routineex.c ├── co_buffer.c ├── co_set.c └── co_ioservice.c ├── test ├── test_misc.c ├── test_utf8.c ├── test_queue.c ├── test_timerservice.c ├── test_wordfilter.c ├── test_falloc.c ├── test_echo_server.c ├── test_vec.c ├── test_pqueue.c ├── test_dict.c ├── test_list.c ├── test_echo_client.c ├── test_echo_client2.c ├── test_echo_server2.c ├── test_timingwheel.c ├── test_echo_tps.c ├── test_udp_dns.c ├── test_udp_dns2.c ├── test_buffer.c ├── test_coroutine.c └── test_set.c ├── .gitignore ├── misc ├── co_wordfilter.h └── co_wordfilter.c ├── LICENSE ├── README.md └── Makefile /words: -------------------------------------------------------------------------------- 1 | 特朗普 2 | today 3 | fuck 4 | 非常bad -------------------------------------------------------------------------------- /src/co_alloc.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 内存分配单元,方便后续替换 3 | * by colin 4 | */ 5 | #ifndef __CO_ALLOC__ 6 | #define __CO_ALLOC__ 7 | #include 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | #define CO_MALLOC malloc 14 | #define CO_CALLOC calloc 15 | #define CO_REALLOC realloc 16 | #define CO_FREE free 17 | 18 | #ifdef __cplusplus 19 | } 20 | #endif 21 | #endif -------------------------------------------------------------------------------- /src/co_utf8.h: -------------------------------------------------------------------------------- 1 | /** 2 | * utf-8函数 3 | * by colin 4 | */ 5 | #ifndef __CO_UTF8__ 6 | #define __CO_UTF8__ 7 | #include "co_utils.h" 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | // utf8解码,如果格式错误返回NULL;code为返回的码点,可以为NULL 14 | const char *coutf8_decode(const char *s, int *code); 15 | // 计算一个utf8字符串的长度 16 | int coutf8_len(const char *s); 17 | 18 | #ifdef __cplusplus 19 | } 20 | #endif 21 | #endif -------------------------------------------------------------------------------- /test/test_misc.c: -------------------------------------------------------------------------------- 1 | #include "../src/co_utils.h" 2 | 3 | int main(int argc, char const *argv[]) 4 | { 5 | FILE * f = fopen("LICENSE", "r"); 6 | if (f) { 7 | char word[256]; // 关键字最多支持这么长 8 | while (fgets(word, 256, f)) { 9 | int len = strlen(word) - 1; 10 | if (word[len] == '\n') 11 | word[len] = '\0'; 12 | if (len > 0) 13 | printf("%s\n", word); 14 | } 15 | fclose(f); 16 | } 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /src/co_ctx.c: -------------------------------------------------------------------------------- 1 | #include "co_ctx.h" 2 | 3 | int coctx_make(coctx_t *ctx, coctx_func_t fn, uint32_t p1, uint32_t p2) { 4 | #if defined(__x86_64__) 5 | char *sp = ctx->ss_sp + ctx->ss_size; 6 | sp = (char*) ((uintptr_t)sp & -16LL); 7 | memset(ctx->regs, 0, sizeof(ctx->regs)); 8 | ctx->regs[6] = (void*)(intptr_t)p1; // p1 9 | ctx->regs[7] = (void*)(intptr_t)p2; // p2 10 | ctx->regs[12] = fn; // rip 11 | ctx->regs[13] = sp - 8; // rsp 12 | #else 13 | #error "platform not support" 14 | #endif 15 | return 0; 16 | } -------------------------------------------------------------------------------- /test/test_utf8.c: -------------------------------------------------------------------------------- 1 | #include "../src/co_utf8.h" 2 | 3 | void print_utf8_codepoint(const char *s) { 4 | int code; 5 | const char *p = s; 6 | while (*p) { 7 | p = coutf8_decode(p, &code); 8 | if (!p) { 9 | printf("decode error\n"); 10 | break; 11 | } 12 | printf("U+%04X ", code); 13 | } 14 | printf("\n"); 15 | } 16 | 17 | int main(int argc, char const *argv[]) 18 | { 19 | char *s = "你好hello世界"; 20 | print_utf8_codepoint(s); 21 | printf("len=%d\n", coutf8_len(s)); 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /src/co_ctx.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 协程环境 3 | * by colin 4 | */ 5 | #ifndef __CO_CTX__ 6 | #define __CO_CTX__ 7 | #include "co_utils.h" 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | typedef struct { 14 | void *regs[16]; 15 | size_t ss_size; 16 | char *ss_sp; 17 | } coctx_t; 18 | 19 | typedef void (*coctx_func_t)(uint32_t p1, uint32_t p2); 20 | 21 | extern int coctx_make(coctx_t *ctx, coctx_func_t fn, uint32_t p1, uint32_t p2); 22 | extern int coctx_swap(coctx_t *octx, coctx_t *ctx) asm("coctx_swap"); 23 | 24 | #ifdef __cplusplus 25 | } 26 | #endif 27 | #endif -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | # Linker output 11 | *.ilk 12 | *.map 13 | *.exp 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Libraries 20 | *.lib 21 | *.a 22 | *.la 23 | *.lo 24 | 25 | # Shared objects (inc. Windows DLLs) 26 | *.dll 27 | *.so 28 | *.so.* 29 | *.dylib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | *.i*86 36 | *.x86_64 37 | *.hex 38 | 39 | # Debug files 40 | *.dSYM/ 41 | *.su 42 | *.idb 43 | *.pdb 44 | 45 | # Kernel Module Compile Results 46 | *.mod* 47 | *.cmd 48 | .tmp_versions/ 49 | modules.order 50 | Module.symvers 51 | Mkfile.old 52 | dkms.conf 53 | -------------------------------------------------------------------------------- /test/test_queue.c: -------------------------------------------------------------------------------- 1 | #include "../src/co_queue.h" 2 | 3 | int main(int argc, char const *argv[]) 4 | { 5 | coqueue_t *queue = coqueue_new(sizeof(int)); 6 | 7 | int i, v; 8 | for (i = 0; i < 100; ++i) { 9 | coqueue_push(queue, &i); 10 | } 11 | for (i = 0; i < 90; ++i) { 12 | coqueue_pop(queue, &v); 13 | } 14 | for (i = 0; i < 20; ++i) { 15 | if (coqueue_pop(queue, &v)) 16 | printf(">>>>>>%d\n", v); 17 | } 18 | 19 | for (i = 0; i < 10; ++i) { 20 | coqueue_push(queue, &i); 21 | } 22 | coqueue_peek(queue, -1, &v); 23 | printf("peek: %d\n", v); 24 | coqueue_peek(queue, 0, &v); 25 | printf("peek: %d\n", v); 26 | 27 | coqueue_free(queue); 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /test/test_timerservice.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "../src/co_timerservice.h" 4 | 5 | cots_t *sv; 6 | void *thandle; 7 | int count; 8 | 9 | void on_timer(cots_t *ts, void *th, void *ud1, void *ud2) { 10 | printf("on_timer: %ju\n", co_gettime()); 11 | ++count; 12 | if (count == 10) 13 | cots_del_timer(sv, &thandle); 14 | } 15 | 16 | void run() { 17 | while (1) { 18 | usleep(1000); 19 | cots_update(sv, co_gettime()); 20 | } 21 | } 22 | 23 | 24 | int main(int argc, char const *argv[]) 25 | { 26 | sv = cots_new(10, co_gettime()); 27 | 28 | thandle = cots_add_timer(sv, 100, 100, on_timer, NULL, NULL); 29 | 30 | run(); 31 | 32 | cots_del_timer(sv, &thandle); 33 | cots_free(sv); 34 | return 0; 35 | } 36 | -------------------------------------------------------------------------------- /src/co_dnsutils.h: -------------------------------------------------------------------------------- 1 | /** 2 | * DNS解析函数 3 | * by colin 4 | */ 5 | #ifndef __CO_DNSUTILS__ 6 | #define __CO_DNSUTILS__ 7 | #include "co_utils.h" 8 | #include 9 | 10 | #ifdef __cplusplus 11 | extern "C" { 12 | #endif 13 | 14 | // IP地址结构 15 | typedef struct ipaddr { 16 | int af; 17 | union { 18 | struct in_addr a4; 19 | struct in6_addr a6; 20 | } addr; 21 | } ipaddr_t; 22 | 23 | // 取DNS服务器,成功返为0 24 | int codns_get_server(char *dnssvr, int n); 25 | 26 | // 生成DNS请求包,成功返回0 27 | int codns_pack_request(uint8_t *buf, int *size, const char *name); 28 | 29 | // 解析DNS回应包,成功返回0,addrs和addrnum,外部须free(addrs) 30 | int codns_parse_response(const uint8_t *buf, int size, ipaddr_t **addrs, int *addrnum); 31 | 32 | 33 | #ifdef __cplusplus 34 | } 35 | #endif 36 | #endif -------------------------------------------------------------------------------- /misc/co_wordfilter.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 关键词过滤 3 | * 文本默认是utf8格式的 4 | * by colin 5 | */ 6 | 7 | #include "../src/co_utils.h" 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | // 新建句柄 14 | void* cowf_new(); 15 | // 释放句柄 16 | void* cowf_free(void *handle); 17 | // 清除所有的关键词 18 | void cowf_clear(void *handle); 19 | // 加载关键词:path是文本路径,格式是一行一个关键词 20 | bool cowf_loadwords(void *handle, const char *path); 21 | // 增加关键词 22 | void cowf_addword(void *handle, const char *word); 23 | // 删除关键词 24 | void cowf_delword(void *handle, const char *word); 25 | // 判断关键词是否存在 26 | bool cowf_exist(void *handle, const char *word); 27 | // 检查文本是否存在关键词 28 | bool cowf_check(void *handle, const char *text); 29 | // 过滤文本中的关键词,ch为代替的字符 30 | bool cowf_fitler(void *handle, char *text, char ch); 31 | 32 | #ifdef __cplusplus 33 | } 34 | #endif -------------------------------------------------------------------------------- /src/co_queue.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 先进先出队列,基于环形队列 3 | * by colin 4 | */ 5 | #ifndef __CO_QUEUE__ 6 | #define __CO_QUEUE__ 7 | #include "co_utils.h" 8 | #include "co_vec.h" 9 | 10 | #ifdef __cplusplus 11 | extern "C" { 12 | #endif 13 | 14 | // 队列结构 15 | typedef struct coqueue { 16 | covec_t *vec; // 向量 17 | int head; // 头 18 | int tail; // 尾 19 | } coqueue_t; 20 | 21 | // 初始化队列,itemsize为元素大小 22 | coqueue_t* coqueue_new(uint16_t itemsize); 23 | // 释放队列 24 | void* coqueue_free(coqueue_t *queue); 25 | // 队列大小 26 | int coqueue_size(coqueue_t *queue); 27 | // 压入元素 28 | void coqueue_push(coqueue_t *queue, const void *data); 29 | // 弹出元素 30 | bool coqueue_pop(coqueue_t *queue, void *data); 31 | // 取某个元素,0表示第1个,-1表示最后一个 32 | bool coqueue_peek(coqueue_t *queue, int index, void *data); 33 | 34 | #ifdef __cplusplus 35 | } 36 | #endif 37 | #endif -------------------------------------------------------------------------------- /test/test_wordfilter.c: -------------------------------------------------------------------------------- 1 | #include "../misc/co_wordfilter.h" 2 | 3 | 4 | int main(int argc, char const *argv[]) 5 | { 6 | void *wf = cowf_new(); 7 | 8 | cowf_loadwords(wf, "words"); 9 | 10 | char text[] = "今天非常bad啊, 非常bad"; 11 | cowf_fitler(wf, text, '*'); 12 | printf("%s\n", text); 13 | bool find = cowf_check(wf, "today"); 14 | printf("find=%d\n", find); 15 | 16 | cowf_addword(wf, "queue"); 17 | find = cowf_check(wf, "queue event"); 18 | printf("find=%d\n", find); 19 | 20 | cowf_delword(wf, "queue"); 21 | find = cowf_check(wf, "queue event"); 22 | printf("find=%d\n", find); 23 | 24 | char text2[] = "hello 请问你是特朗普吗,你好啊特朗普,我有点事件找你呢"; 25 | cowf_fitler(wf, text2, '*'); 26 | printf("%s\n", text2); 27 | 28 | char text3[] = "我fuck,这是什么玩意儿"; 29 | cowf_fitler(wf, text3, '*'); 30 | printf("%s\n", text3); 31 | 32 | cowf_free(wf); 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /test/test_falloc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../src/co_falloc.h" 3 | 4 | typedef struct myitem { 5 | int v1; 6 | int v2; 7 | } myitem_t; 8 | 9 | static myitem_t* items[1000]; 10 | 11 | int main(int argc, char const *argv[]) 12 | { 13 | cofalloc_t alloc; 14 | cofalloc_init(&alloc, 0, sizeof(myitem_t)); 15 | 16 | int i; 17 | int c = sizeof(items) / sizeof(items[0]); 18 | for (i = 0; i < c; ++i) { 19 | items[i] = cofalloc_newitem(&alloc); 20 | items[i]->v1 = i; 21 | items[i]->v1 = i * i; 22 | } 23 | 24 | for (i = 0; i < 500; ++i) { 25 | if (!cofalloc_freeitem(&alloc, items[i%c])) { 26 | printf("CO_FREE failed: %d\n", i); 27 | } 28 | } 29 | 30 | for (i = 0; i < c; ++i) { 31 | items[i] = cofalloc_newitem(&alloc); 32 | items[i]->v1 = i; 33 | items[i]->v1 = i * i; 34 | } 35 | 36 | cofalloc_free(&alloc); 37 | return 0; 38 | } 39 | -------------------------------------------------------------------------------- /src/co_pqueue.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 优先队列 3 | * by colin 4 | */ 5 | #ifndef __CO_PQUEUE__ 6 | #define __CO_PQUEUE__ 7 | #include "co_utils.h" 8 | #include "co_vec.h" 9 | 10 | #ifdef __cplusplus 11 | extern "C" { 12 | #endif 13 | 14 | // 比较回调 15 | // < 0 item1 < item2 16 | // = 0 item1 == item2 17 | // > 0 item1 > item2 18 | typedef int (*copqueue_comp_t)(void *ud, const void *item1, const void *item2); 19 | 20 | typedef struct copqueue { 21 | covec_t *vec; // 向量 22 | copqueue_comp_t fn_comp; // 比较函数 23 | void *ud; // 用户函数 24 | } copqueue_t; 25 | 26 | // 创建 27 | copqueue_t* copqueue_new(uint16_t itemsize, copqueue_comp_t fn, void *ud); 28 | // 释放 29 | void *copqueue_free(copqueue_t *pq); 30 | // 队列大小 31 | int copqueue_size(copqueue_t *pq); 32 | // 压入元素 33 | void copqueue_push(copqueue_t *pq, const void *data); 34 | // 弹出元素 35 | bool copqueue_pop(copqueue_t *pq, void *data); 36 | // 取某个元素 37 | bool copqueue_get(copqueue_t *pq, int index, void *data); 38 | 39 | #ifdef __cplusplus 40 | } 41 | #endif 42 | #endif -------------------------------------------------------------------------------- /src/co_loop.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 事件循环 3 | * by colin 4 | */ 5 | #ifndef __CO_LOOP__ 6 | #define __CO_LOOP__ 7 | #include "co_utils.h" 8 | #include "co_timerservice.h" 9 | #include "co_ioservice.h" 10 | #include "co_poll.h" 11 | 12 | #ifdef __cplusplus 13 | extern "C" { 14 | #endif 15 | 16 | typedef void (*fn_idle_t)(coloop_t *loop); 17 | typedef void (*fn_process_t)(coloop_t *loop, copollevent_t *ev); 18 | 19 | typedef struct coloop { 20 | void *poll; 21 | cots_t *timeservice; 22 | coios_t *ioserivce; 23 | fn_idle_t fn_idle; 24 | fn_process_t fn_process; 25 | uint64_t currtime; 26 | uint32_t timeout; 27 | bool stop; 28 | } coloop_t; 29 | 30 | coloop_t* coloop_new(uint16_t interval); 31 | void* coloop_free(coloop_t *loop); 32 | void coloop_idlecb(coloop_t *loop, fn_idle_t fn); 33 | void coloop_processcb(coloop_t *loop, fn_process_t fn); 34 | void coloop_runonce(coloop_t *loop); 35 | void coloop_run(coloop_t *loop); 36 | void coloop_stop(coloop_t *loop); 37 | 38 | 39 | #ifdef __cplusplus 40 | } 41 | #endif 42 | #endif -------------------------------------------------------------------------------- /src/co_routine.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 协程库 3 | * by colin 4 | */ 5 | #ifndef __CO_ROUTINE__ 6 | #define __CO_ROUTINE__ 7 | #include "co_utils.h" 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | // 协程执行结束 14 | #define CO_STATUS_DEAD 0 15 | // 协程创建后未resume,或yield后处的状态 16 | #define CO_STATUS_SUSPEND 1 17 | // 协程当前正在运行 18 | #define CO_STATUS_RUNNING 2 19 | // 当前协程resume了其他协程,此时处于这个状态 20 | #define CO_STATUS_NORMAL 3 21 | 22 | // 类型声明 23 | struct cosched; 24 | typedef struct cosched cosched_t; 25 | typedef void (*cort_func_t)(cosched_t *, void *ud); 26 | 27 | // 打开一个调度器,每个线程一个:stsize为栈大小,传0为默认 28 | cosched_t* cort_open(int stsize); 29 | // 关闭调度器 30 | void cort_close(cosched_t *); 31 | // 新建协程 32 | int cort_new(cosched_t *, cort_func_t, void *ud); 33 | // 启动协程 34 | int cort_resume(cosched_t *, int id); 35 | // 取协程状态 36 | int cort_status(cosched_t *, int id); 37 | // 取当前正在运行的协程ID 38 | int cort_running(cosched_t *); 39 | // 调用yield让出执行权 40 | int cort_yield(cosched_t *); 41 | // 当前是否是主协程 42 | bool cort_ismain(int co); 43 | 44 | #ifdef __cplusplus 45 | } 46 | #endif 47 | #endif -------------------------------------------------------------------------------- /src/co_utf8.c: -------------------------------------------------------------------------------- 1 | #include "co_utf8.h" 2 | 3 | #define MAXUNICODE 0x10FFFF 4 | static const unsigned int limits[] = {0xFF, 0x7F, 0x7FF, 0xFFFF}; 5 | 6 | const char *coutf8_decode(const char *s, int *code) { 7 | const uint8_t *b = (const uint8_t *)s; 8 | uint32_t ch = b[0]; 9 | uint32_t res = 0; 10 | if (ch < 0x80) { 11 | res = ch; 12 | } else { 13 | int count = 0; 14 | while (ch & 0x40) { 15 | int cc = b[++count]; 16 | if ((cc & 0xc0) != 0x80) return NULL; 17 | res = (res << 6) | (cc & 0x3f); 18 | ch <<= 1; 19 | } 20 | res |= ((ch & 0x7f) << (count * 5)); 21 | if (count > 3 || res > MAXUNICODE || res <= limits[count]) 22 | return NULL; 23 | b += count; 24 | } 25 | if (code) 26 | *code = res; 27 | return (const char *)b + 1; 28 | } 29 | 30 | int coutf8_len(const char *s) { 31 | int count = 0; 32 | const char *p = s; 33 | while (*p) { 34 | p = coutf8_decode(p, NULL); 35 | if (!p) break; 36 | ++count; 37 | } 38 | return count; 39 | } -------------------------------------------------------------------------------- /src/co_str.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 字符串函数 3 | * by colin 4 | */ 5 | #ifndef __CO_STR__ 6 | #define __CO_STR__ 7 | #include "co_utils.h" 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | typedef char cochar; 14 | 15 | // 字符串头 16 | typedef struct costrheader { 17 | int len; // 字符串长度, 不包括\0 18 | int cap; // 字符串内存的容量 19 | } costrheader_t; 20 | 21 | static inline costrheader_t* costr_getheader(cochar *s) { 22 | return (costrheader_t*)(s - sizeof(costrheader_t*)); 23 | } 24 | 25 | // 字符串长度 26 | static inline int costr_len(cochar *s) { 27 | return costr_getheader(s)->len; 28 | } 29 | 30 | // 创建字符串,len如果为-1,则默认调用strlen(s) 31 | cochar* costr_new(const char *s, int len); 32 | // 释放 33 | void costr_free(char *s); 34 | // 格式化字符串,返回的字符串必须使用costr_free释放,如果有错误,返回NULL 35 | cochar* costr_format(const char *fmt, ...); 36 | cochar* costr_formatv(const char *fmt, va_list ap); 37 | // TODO: 38 | // costr_startwith 39 | // costr_endwidth 40 | // costr_find 41 | // costr_replace 42 | // costr_lower 43 | // costr_upper 44 | // costr_repeat 45 | 46 | #ifdef __cplusplus 47 | } 48 | #endif 49 | #endif -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 colin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/co_falloc.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 固定长度的内存分配器 3 | * by colin 4 | */ 5 | #ifndef __CO_FALLOC__ 6 | #define __CO_FALLOC__ 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | 11 | #include "co_utils.h" 12 | 13 | // 内存项 14 | typedef struct co_blockitem { 15 | struct co_blockitem *next; 16 | uint32_t flag; 17 | uint32_t dummy; 18 | } co_blockitem_t; 19 | 20 | // 内存块 21 | typedef struct co_memblock { 22 | struct co_memblock *next; 23 | char buffer[0]; 24 | } co_memblock_t; 25 | 26 | // 分配器 27 | typedef struct cofalloc { 28 | co_memblock_t *memblock; 29 | uint32_t blocksize; 30 | uint32_t itemsize; 31 | co_blockitem_t *freeitem; 32 | } cofalloc_t; 33 | 34 | // 初始化分配器: blocksize为内存块的长度,itemsize为分配项的大小 35 | void cofalloc_init(cofalloc_t *alloc, uint32_t blocksize, uint32_t itemsize); 36 | // 释放分配器 37 | void cofalloc_free(cofalloc_t *alloc); 38 | // 创建内存项 39 | void* cofalloc_newitem(cofalloc_t *alloc); 40 | // 释放内存项 41 | bool cofalloc_freeitem(cofalloc_t *alloc, void *item); 42 | // 判断内存项是否已经释放 43 | bool cofalloc_isfree(cofalloc_t *alloc, void *item); 44 | 45 | #ifdef __cplusplus 46 | } 47 | #endif 48 | #endif -------------------------------------------------------------------------------- /src/co_timerservice.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 定时器服务 3 | * by colin 4 | */ 5 | #ifndef __CO__TIMERSERVICE__ 6 | #define __CO__TIMERSERVICE__ 7 | #include "co_utils.h" 8 | #include "co_falloc.h" 9 | #include "co_timingwheel.h" 10 | 11 | #ifdef __cplusplus 12 | extern "C" { 13 | #endif 14 | 15 | // 定时器服务 16 | typedef struct cots { 17 | cofalloc_t alloc; 18 | cotw_t twheel; 19 | } cots_t; 20 | 21 | typedef void (*fn_timer_t)(cots_t *ts, void *th, void *ud1, void *ud2); 22 | 23 | // 初始化定时器服务 24 | cots_t* cots_new(uint16_t interval, uint64_t currtime); 25 | // 释放定时器服务 26 | void* cots_free(cots_t* sv); 27 | // 增加定时器 28 | void* cots_add_timer(cots_t *sv, 29 | uint32_t delay, // 首次延迟 30 | uint32_t loop, // 后续的间隔,如果为0就没有后续 31 | fn_timer_t cb, // 回调函数 32 | void *ud1, void *ud2); // 用户数据 33 | // 删除定时器 34 | void cots_del_timer(cots_t *sv, void **handle); 35 | // 更新定时器 36 | void cots_update(cots_t *sv, uint64_t currtime); 37 | 38 | 39 | ///////////////////////////////////////////////////////////////////////////////////////////// 40 | // 调试用 41 | void cots_print(cots_t *sv); 42 | 43 | 44 | #ifdef __cplusplus 45 | } 46 | #endif 47 | #endif -------------------------------------------------------------------------------- /src/co_routineex.h: -------------------------------------------------------------------------------- 1 | #ifndef __CO__ROUTINEEX__ 2 | #define __CO__ROUTINEEX__ 3 | #include "co_utils.h" 4 | #include "co_loop.h" 5 | #include "co_routine.h" 6 | 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | 11 | // 协程环境 12 | typedef struct cortenv { 13 | coloop_t *loop; // 消息循环 14 | cosched_t *sch; // 协程调度器 15 | } cortenv_t; 16 | 17 | // 初始化和释放 18 | cortenv_t* cortenv_new(coloop_t *loop, int stsize); 19 | void* cortenv_free(cortenv_t *env); 20 | // 休眠ms毫秒 21 | void cort_sleep(cortenv_t *env, uint32_t ms); 22 | 23 | // 绑定TCP 24 | void cort_tcp_bind(cortenv_t *env, cotcp_t *tcp); 25 | // 从TCP读数据:阻塞直到有数据或出错或关闭 26 | bool cort_tcp_read(cortenv_t *env, cotcp_t *tcp, cobuffer_t *buff); 27 | // 连接服务器,阻塞直到连接上或连接不上 28 | cotcp_t* cort_tcp_connect(cortenv_t *env, const char *ip, const char *port); 29 | 30 | // UDP 31 | void cort_udp_bind(cortenv_t *env, coudp_t *udp); 32 | // 从UDP读数据 33 | bool cort_udp_read(cortenv_t *env, coudp_t *udp, cobuffer_t *buff); 34 | 35 | // FD绑定 36 | void cort_fd_bind(cortenv_t *env, cofd_t *fd); 37 | // 从FD读数据 38 | bool cort_fd_read(cortenv_t *env, cofd_t *fd, cobuffer_t *buff); 39 | 40 | 41 | 42 | #ifdef __cplusplus 43 | } 44 | #endif 45 | #endif -------------------------------------------------------------------------------- /src/co_str.c: -------------------------------------------------------------------------------- 1 | #include "co_str.h" 2 | 3 | cochar* costr_new(const char *s, int len) { 4 | int sz = len >= 0 ? len+1 : strlen(s)+1; 5 | int cap = sz + sizeof(costrheader_t); 6 | costrheader_t *header = CO_CALLOC(cap, 1); 7 | header->len = sz; 8 | header->cap = cap; 9 | cochar *str = (cochar*)header + sizeof(costrheader_t); 10 | if (s) memcpy(str, s, sz); 11 | return str; 12 | } 13 | 14 | void costr_free(char *s) { 15 | CO_FREE(s-sizeof(costrheader_t)); 16 | } 17 | 18 | cochar* costr_format(const char *fmt, ...) { 19 | va_list ap; 20 | va_start(ap, fmt); 21 | cochar *res = costr_formatv(fmt, ap); 22 | va_end(ap); 23 | return res; 24 | } 25 | 26 | cochar* costr_formatv(const char *fmt, va_list ap) { 27 | va_list cpy; 28 | int maxsz = 256; 29 | while (1) { 30 | cochar *costr = costr_new(NULL, maxsz); 31 | va_copy(cpy,ap); 32 | int len = vsnprintf(costr, maxsz, fmt, cpy); 33 | va_end(cpy); 34 | if (len < 0) { 35 | costr_free(costr); 36 | return NULL; 37 | } else if (len >= maxsz) { 38 | costr_free(costr); 39 | maxsz *= 2; 40 | } else { 41 | return costr; 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /test/test_echo_server.c: -------------------------------------------------------------------------------- 1 | #include "../src/co_loop.h" 2 | 3 | void on_client_close(coios_t *ss, cotcp_t* tcp) { 4 | printf("on_client_close: %d\n", tcp->fd); 5 | } 6 | 7 | void on_client_error(coios_t *ss, cotcp_t* tcp, const char *msg) { 8 | fprintf(stderr, "on_client_error: %s\n", msg); 9 | } 10 | 11 | void on_client_recv(coios_t *ss, cotcp_t* tcp, const void *buff, int size) { 12 | cotcp_send(ss, tcp, buff, size); 13 | } 14 | 15 | void on_new_client(coios_t *ss, cotcp_t* tcp) { 16 | printf("on_new_client: %d\n", tcp->fd); 17 | cotcp_on_error(ss, tcp, on_client_error); 18 | cotcp_on_close(ss, tcp, on_client_close); 19 | cotcp_on_recv(ss, tcp, on_client_recv); 20 | } 21 | 22 | static void run_server(coloop_t *loop) { 23 | char *ip = "127.0.0.1"; 24 | char *port = "3458"; 25 | cotcp_t * tcp = cotcp_listen(loop->ioserivce, ip, port, NULL, on_new_client); 26 | if (tcp) { 27 | printf("listen on %s:%s, fd=%d\n", ip, port, tcp->fd); 28 | } else { 29 | fprintf(stderr, "listen failed\n"); 30 | } 31 | } 32 | 33 | int main(int argc, char const *argv[]) 34 | { 35 | coios_ignsigpipe(); 36 | coloop_t *loop = coloop_new(10); 37 | run_server(loop); 38 | coloop_run(loop); 39 | coloop_free(loop); 40 | return 0; 41 | } 42 | -------------------------------------------------------------------------------- /test/test_vec.c: -------------------------------------------------------------------------------- 1 | #include "../src/co_vec.h" 2 | 3 | int main(int argc, char const *argv[]) 4 | { 5 | covec_t *vec = covec_new(sizeof(int)); 6 | 7 | int i, v; 8 | for (i = 0; i < 20; ++i) { 9 | covec_push_tail(vec, &i); 10 | } 11 | for (i = 20; i < 40; ++i) { 12 | covec_push_head(vec, &i); 13 | } 14 | for (i = 40; i < 60; ++i) { 15 | covec_push(vec, -1, &i); 16 | } 17 | 18 | for (i = 0; i < covec_size(vec); ++i) { 19 | covec_get(vec, i, &v); 20 | printf("index=%d, value=%d\n", i, v); 21 | } 22 | 23 | v = 100; 24 | covec_set(vec, 0, &v); 25 | covec_set(vec, 1, &v); 26 | 27 | for (i = 0; i < 2; ++i) { 28 | covec_get(vec, i, &v); 29 | printf("index=%d, value=%d\n", i, v); 30 | } 31 | 32 | for (i = 0; i < 50; ++i) { 33 | covec_del(vec, 0, NULL); 34 | } 35 | 36 | for (i = 0; i < covec_size(vec); ++i) { 37 | covec_get(vec, i, &v); 38 | printf("index=%d, value=%d\n", i, v); 39 | } 40 | 41 | covec_t *vec2 = covec_new(sizeof(int)); 42 | covec_copy(vec, vec2); 43 | 44 | for (i = 0; i < covec_size(vec2); ++i) { 45 | covec_get(vec2, i, &v); 46 | printf("index=%d, value=%d\n", i, v); 47 | } 48 | 49 | covec_free(vec); 50 | covec_free(vec2); 51 | return 0; 52 | } 53 | -------------------------------------------------------------------------------- /test/test_pqueue.c: -------------------------------------------------------------------------------- 1 | #include "../src/co_pqueue.h" 2 | 3 | // 随机数范围[mi, ma] 4 | int randint(int mi, int ma) { 5 | double r = (double)rand() * (1.0 / ((double)RAND_MAX + 1.0)); 6 | r *= (double)(ma - mi) + 1.0; 7 | return (int)r + mi; 8 | } 9 | 10 | // 打印堆中的元素 11 | void printq(copqueue_t *queue) { 12 | int i; 13 | for (i = 0; i < copqueue_size(queue); ++i) { 14 | int v; 15 | copqueue_get(queue, i, &v); 16 | printf("%d ", v); 17 | } 18 | printf("\n"); 19 | } 20 | 21 | // 最大值在前面 22 | static int compare1(void *ud, const void *item1, const void *item2) { 23 | int v1 = *((int*)item1); 24 | int v2 = *((int*)item2); 25 | return v1 - v2; 26 | } 27 | 28 | // 最小值在前面 29 | static int compare2(void *ud, const void *item1, const void *item2) { 30 | int v1 = *((int*)item1); 31 | int v2 = *((int*)item2); 32 | return v2 - v1; 33 | } 34 | 35 | void test_pqeue(int maxinum) { 36 | copqueue_comp_t fn = maxinum ? compare1 : compare2; 37 | copqueue_t *queue = copqueue_new(sizeof(int), fn, NULL); 38 | int i, v; 39 | for (i = 0; i < 11; ++i) { 40 | v = randint(0, 40); 41 | copqueue_push(queue, &v); 42 | } 43 | printq(queue); 44 | 45 | while (copqueue_size(queue)) { 46 | int v; 47 | if (copqueue_pop(queue, &v)) { 48 | printf("%d\n", v); 49 | printq(queue); 50 | } 51 | } 52 | copqueue_free(queue); 53 | } 54 | 55 | int main(int argc, char const *argv[]) 56 | { 57 | test_pqeue(1); 58 | test_pqeue(0); 59 | return 0; 60 | } 61 | -------------------------------------------------------------------------------- /src/co_loop.c: -------------------------------------------------------------------------------- 1 | #include "co_loop.h" 2 | 3 | 4 | coloop_t* coloop_new(uint16_t interval) { 5 | coloop_t *loop = CO_MALLOC(sizeof(*loop)); 6 | loop->timeout = interval; 7 | loop->currtime = co_gettime(); 8 | loop->fn_idle = NULL; 9 | loop->fn_process = NULL; 10 | loop->stop = false; 11 | loop->timeservice = cots_new(interval, loop->currtime); 12 | loop->ioserivce = coios_new(loop); 13 | loop->poll = copoll_new(); 14 | return loop; 15 | } 16 | 17 | void* coloop_free(coloop_t *loop) { 18 | cots_free(loop->timeservice); 19 | coios_free(loop->ioserivce); 20 | copoll_free(loop->poll); 21 | CO_FREE(loop); 22 | return NULL; 23 | } 24 | 25 | void coloop_idlecb(coloop_t *loop, fn_idle_t fn) { 26 | loop->fn_idle = fn; 27 | } 28 | 29 | void coloop_processcb(coloop_t *loop, fn_process_t fn) { 30 | loop->fn_process = fn; 31 | } 32 | 33 | void coloop_stop(coloop_t *loop) { 34 | loop->stop = true; 35 | } 36 | 37 | static void _copoll_callback(void *copoll, copollevent_t *ev, void *ud) { 38 | coloop_t *loop = ud; 39 | if (loop->fn_process) { 40 | loop->fn_process(loop, ev); 41 | } 42 | } 43 | 44 | void coloop_runonce(coloop_t *loop) { 45 | copoll_wait(loop->poll, loop->timeout, _copoll_callback, loop); 46 | loop->currtime = co_gettime(); 47 | cots_update(loop->timeservice, loop->currtime); 48 | } 49 | 50 | void coloop_run(coloop_t *loop) { 51 | while (!loop->stop) { 52 | coloop_runonce(loop); 53 | if (loop->fn_idle) 54 | loop->fn_idle(loop); 55 | } 56 | } 57 | 58 | -------------------------------------------------------------------------------- /test/test_dict.c: -------------------------------------------------------------------------------- 1 | #include "../src/co_dict.h" 2 | 3 | void test_int_dict() { 4 | 5 | typedef struct mydata { 6 | int v1; 7 | int v2; 8 | } mydata_t; 9 | 10 | mydata_t data1 = {10, 20}; 11 | mydata_t data2 = {30, 40}; 12 | mydata_t data3 = {50, 60}; 13 | 14 | codict_t *dict = codict_new(codict_int_hash, codict_int_equal, sizeof(int), sizeof(mydata_t)); 15 | 16 | // set data 17 | printf("set data======================================\n"); 18 | codict_set_tp(dict, 1, &data1, int); 19 | codict_set_tp(dict, 2, &data2, int); 20 | codict_set_tp(dict, 3, &data3, int); 21 | codict_set_tp(dict, 0xFF01, &data1, int); 22 | 23 | // get data 24 | printf("get data======================================\n"); 25 | int key = 1; 26 | for (key = 1; key <= 3; ++key) { 27 | mydata_t data = codict_value(codict_get(dict, &key), mydata_t); 28 | printf(">>>>>key=%d, v1=%d, v2=%d\n", key, data.v1, data.v2); 29 | } 30 | 31 | // delete 32 | printf("del data======================================\n"); 33 | codict_del_tp(dict, 2, int); 34 | 35 | // iterate 36 | printf("iterate dict======================================\n"); 37 | codict_node_t *node; 38 | for (node = codict_begin(dict); node != NULL; node = codict_next(node)) { 39 | int key = codict_key(node, int); 40 | mydata_t data = codict_value(node, mydata_t); 41 | printf(">>>>>key=%d, v1=%d, v2=%d\n", key, data.v1, data.v2); 42 | } 43 | 44 | codict_free(dict); 45 | } 46 | 47 | 48 | int main(int argc, char const *argv[]) 49 | { 50 | test_int_dict(); 51 | return 0; 52 | } 53 | -------------------------------------------------------------------------------- /test/test_list.c: -------------------------------------------------------------------------------- 1 | #include "../src/co_list.h" 2 | 3 | void print_list(colist_t *list) { 4 | colist_node_t *node; 5 | int v; 6 | for (node = colist_begin(list); node != NULL; node = node->next) { 7 | colist_getvalue(list, node, &v); 8 | printf("%d ", v); 9 | } 10 | printf("\n"); 11 | } 12 | 13 | int main(int argc, char const *argv[]) 14 | { 15 | int v; 16 | colist_t *list = colist_new(sizeof(int)); 17 | 18 | for (v = 1; v <= 3; v++) 19 | colist_push_tail(list, &v); 20 | print_list(list); 21 | for (v = 4; v <= 6; v++) 22 | colist_push_head(list, &v); 23 | print_list(list); 24 | 25 | v = 7; 26 | colist_push_at(list, list->head, &v, true); 27 | v = 8; 28 | colist_push_at(list, list->head, &v, false); 29 | v = 9; 30 | colist_push_at(list, list->tail, &v, false); 31 | v = 10; 32 | colist_push_at(list, list->tail, &v, true); 33 | print_list(list); 34 | 35 | colist_node_t *node; 36 | for (node = colist_begin(list); node != NULL; node = node->next) { 37 | colist_getvalue(list, node, &v); 38 | if (v == 5) { 39 | v = 11; 40 | colist_push_at(list, node, &v, true); 41 | colist_push_at(list, node, &v, false); 42 | } else if (v == 6) { 43 | v = 66; 44 | colist_setvalue(list, node, &v); 45 | } 46 | if (v == 3) { 47 | colist_pop_at(list, node->next, NULL); 48 | } 49 | } 50 | print_list(list); 51 | 52 | while (list->head != list->tail) { 53 | colist_pop_head(list, NULL); 54 | } 55 | print_list(list); 56 | 57 | colist_pop_head(list, NULL); 58 | print_list(list); 59 | 60 | colist_free(list); 61 | return 0; 62 | } 63 | -------------------------------------------------------------------------------- /src/co_list.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 双向链表 3 | * by colin 4 | */ 5 | #ifndef __CO_LIST__ 6 | #define __CO_LIST__ 7 | #include "co_utils.h" 8 | #ifdef __cplusplus 9 | extern "C" { 10 | #endif 11 | 12 | // 链表结点 13 | typedef struct colist_node { 14 | struct colist_node *prev; 15 | struct colist_node *next; 16 | } colist_node_t; 17 | 18 | // 链表结构 19 | typedef struct colist { 20 | colist_node_t *head; 21 | colist_node_t *tail; 22 | uint32_t itemsize; 23 | } colist_t; 24 | 25 | // 初始化和释放, itemsize为结点数据的大小 26 | colist_t* colist_new(uint16_t itemsize); 27 | void* colist_free(colist_t *list); 28 | 29 | // 压入链表 30 | void colist_push_head(colist_t *list, const void *data); 31 | void colist_push_tail(colist_t *list, const void *data); 32 | void colist_push_at(colist_t *list, colist_node_t *node, const void *data, bool before); 33 | 34 | // 弹出链表 35 | bool colist_pop_head(colist_t *list, void *data); 36 | bool colist_pop_tail(colist_t *list, void *data); 37 | bool colist_pop_at(colist_t *list, colist_node_t *node, void *data); 38 | 39 | // 遍历 40 | static inline colist_node_t* colist_begin(colist_t *list) { return list->head; } 41 | static inline colist_node_t* colist_end(colist_t *list) { return list->tail; } 42 | // 取结点值 43 | static inline void colist_getvalue(colist_t *list, colist_node_t *node, void *data) { 44 | memcpy(data, (char*)node + sizeof(colist_node_t), list->itemsize); 45 | } 46 | static inline void colist_setvalue(colist_t *list, colist_node_t *node, const void *data) { 47 | memcpy((char*)node + sizeof(colist_node_t), data, list->itemsize); 48 | } 49 | // 取结点值指针 50 | static inline void* colist_getptr(colist_t *list, colist_node_t *node) { 51 | return (char*)node + sizeof(colist_node_t); 52 | } 53 | 54 | #ifdef __cplusplus 55 | } 56 | #endif 57 | #endif -------------------------------------------------------------------------------- /test/test_echo_client.c: -------------------------------------------------------------------------------- 1 | #include "../src/co_loop.h" 2 | 3 | cotcp_t *client_tcp = NULL; 4 | void on_recv(coios_t *ss, cotcp_t* tcp, const void *buff, int size) { 5 | write(STDOUT_FILENO, buff, size); 6 | } 7 | 8 | void on_close(coios_t *ss, cotcp_t* tcp) { 9 | printf("on_close: %d\n", tcp->fd); 10 | coloop_stop(ss->loop); 11 | } 12 | 13 | void on_error(coios_t *ss, cotcp_t* tcp, const char *msg) { 14 | fprintf(stderr, "on_error: %s\n", msg); 15 | coloop_stop(ss->loop); 16 | } 17 | 18 | void on_connected(coios_t *ss, cotcp_t* tcp) { 19 | char ip[128] = {0}; 20 | char port[32] = {0}; 21 | coios_getpeername(tcp->fd, ip, 128, port, 32); 22 | printf("connected to %s:%s\n", ip, port); 23 | client_tcp = tcp; 24 | // 连接成功,监听事件 25 | cotcp_on_recv(ss, tcp, on_recv); 26 | cotcp_on_close(ss, tcp, on_close); 27 | cotcp_on_error(ss, tcp, on_error); 28 | } 29 | 30 | void on_connect_error(coios_t *ss, cotcp_t* tcp, const char *msg) { 31 | fprintf(stderr, "on_connect_error: %s\n", msg); 32 | coloop_stop(ss->loop); 33 | } 34 | 35 | void on_stdin_input(coios_t *ss, cofd_t *fd, const void *buf, int size) { 36 | // 从stdin得到数据,发送给服务器 37 | if (client_tcp) cotcp_send(ss, client_tcp, buf, size); 38 | } 39 | 40 | void run_client(coloop_t *loop) { 41 | // 绑定stdin到异步IO 42 | cofd_t *fd = cofd_bind(loop->ioserivce, STDIN_FILENO, NULL); 43 | cofd_on_recv(loop->ioserivce, fd, on_stdin_input); 44 | // 连接服务器 45 | cotcp_connect(loop->ioserivce, "127.0.0.1", "3458", NULL, on_connected, on_connect_error); 46 | } 47 | 48 | int main(int argc, char const *argv[]) { 49 | coios_ignsigpipe(); 50 | coloop_t *loop = coloop_new(10); 51 | run_client(loop); 52 | coloop_run(loop); 53 | coloop_free(loop); 54 | return 0; 55 | } 56 | -------------------------------------------------------------------------------- /src/coctx_swap.S: -------------------------------------------------------------------------------- 1 | /** 2 | * 协程环切换 3 | * by colin 4 | */ 5 | .globl coctx_swap 6 | #if !defined( __APPLE__ ) && !defined( __FreeBSD__ ) 7 | .type coctx_swap, @function 8 | #endif 9 | 10 | coctx_swap: 11 | 12 | #if defined(__x86_64__) 13 | /* 保存当前环境 */ 14 | movq %rbx, 0(%rdi) 15 | movq %rbp, 8(%rdi) 16 | movq %r12, 16(%rdi) 17 | movq %r13, 24(%rdi) 18 | movq %r14, 32(%rdi) 19 | movq %r15, 40(%rdi) 20 | movq %rdi, 48(%rdi) 21 | movq %rsi, 56(%rdi) 22 | movq %rdx, 64(%rdi) 23 | movq %rcx, 72(%rdi) 24 | movq %r8, 80(%rdi) 25 | movq %r9, 88(%rdi) 26 | 27 | movq (%rsp), %rcx /* 返回地址 */ 28 | movq %rcx, 96(%rdi) 29 | leaq 8(%rsp), %rcx /* 栈顶 */ 30 | movq %rcx, 104(%rdi) 31 | 32 | fnstcw 112(%rdi) /* 浮点数环境 */ 33 | stmxcsr 116(%rdi) 34 | 35 | /* 恢复将启动的协程环境 */ 36 | movq %rsi, %rax 37 | movq 0(%rax), %rbx 38 | movq 8(%rax), %rbp 39 | movq 16(%rax), %r12 40 | movq 24(%rax), %r13 41 | movq 32(%rax), %r14 42 | movq 40(%rax), %r15 43 | movq 48(%rax), %rdi 44 | movq 56(%rax), %rsi 45 | movq 64(%rax), %rdx 46 | movq 80(%rax), %r8 47 | movq 88(%rax), %r9 48 | fldcw 112(%rax) /* 浮点数环境 */ 49 | ldmxcsr 116(%rax) 50 | 51 | movq 104(%rax), %rsp /* 栈顶 */ 52 | movq 96(%rax), %rcx /* 弹出返回地址到栈顶 */ 53 | pushq %rcx 54 | 55 | movq 72(%rax), %rcx 56 | 57 | /* Clear rax to indicate success. */ 58 | xorl %eax, %eax 59 | ret /* ret时就弹出栈顶的地址并跳过去 */ 60 | #else 61 | #error "platform not support" 62 | #endif -------------------------------------------------------------------------------- /src/co_utils.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 基础单元,一些常用的宏和函数 3 | * by colin 4 | */ 5 | #ifndef __CO_UTILS__ 6 | #define __CO_UTILS__ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include "co_alloc.h" 22 | 23 | #ifdef __cplusplus 24 | extern "C" { 25 | #endif 26 | 27 | // 取最小值 28 | #define CO_MIN(a, b) ((a) > (b) ? (b) : (a)) 29 | // 取最大值 30 | #define CO_MAX(a, b) ((a) > (b) ? (a) : (b)) 31 | // 把V限定在[mi, ma] 32 | #define CO_CLAMP(v, mi, ma) CO_MAX(CO_MIN(v, ma), mi) 33 | // 取结构成员的偏移 34 | #define CO_OFFSETOF(type, member) ((size_t)&((type*)0)->member) 35 | // 通过结构的成员指针,向上取向结构指针 36 | #define CO_CONTAINEROF(ptr, type, member) (type*)(((char*)((type*)ptr)) - CO_OFFSETOF(type, member))) 37 | // 取数组长度 38 | #define CO_ARRAY_COUNT(ary) (sizeof(ary) / sizeof(ary[0])) 39 | 40 | // 取下一个2的幂 41 | static inline uint32_t roundup_pow2(uint32_t size) { 42 | --size; 43 | size |= size >> 1; 44 | size |= size >> 2; 45 | size |= size >> 4; 46 | size |= size >> 8; 47 | size |= size >> 16; 48 | return ++size; 49 | } 50 | 51 | // 取当前时间,毫秒单位 52 | static inline uint64_t co_gettime() { 53 | struct timeval tm; 54 | gettimeofday(&tm, NULL); 55 | return (tm.tv_sec * 1000 + tm.tv_usec / 1000); 56 | } 57 | 58 | // 取a到b的随机值[a, b] 59 | static inline int co_randrange(int a, int b) { 60 | double d = (double)rand() / ((double)RAND_MAX + 1.0); 61 | d *= (double)(b - a) + 1.0; 62 | return (int)d + a; 63 | } 64 | 65 | // 取一个随机值[0, 1) 66 | static inline double co_random() { 67 | return (double)rand() / ((double)RAND_MAX + 1.0); 68 | } 69 | 70 | #ifdef __cplusplus 71 | } 72 | #endif 73 | #endif -------------------------------------------------------------------------------- /test/test_echo_client2.c: -------------------------------------------------------------------------------- 1 | #include "../src/co_routineex.h" 2 | 3 | /** 4 | * 协程版的echo客户端 5 | */ 6 | 7 | cotcp_t *client_tcp = NULL; 8 | 9 | void client_rountine(cosched_t *sch, void *ud) { 10 | cortenv_t *env = ud; 11 | char *ip = "127.0.0.1"; 12 | char *port = "3458"; 13 | printf("connect to %s:%s\n", ip, port); 14 | cotcp_t *tcp = cort_tcp_connect(env, ip, port); 15 | if (!tcp) { 16 | coloop_stop(env->loop); 17 | return; 18 | } 19 | cort_tcp_bind(env, tcp); 20 | client_tcp = tcp; 21 | 22 | cobuffer_t *buff = cobuffer_new(NULL, 256, 0); 23 | while (true) { 24 | if (cort_tcp_read(env, tcp, buff)) { 25 | write(STDOUT_FILENO, cobuffer_buffer(buff), cobuffer_pos(buff)); 26 | } else { 27 | break; 28 | } 29 | } 30 | cobuffer_free(buff); 31 | } 32 | 33 | void io_rountine(cosched_t *sch, void *ud) { 34 | cortenv_t *env = ud; 35 | cofd_t *fd = cofd_bind(env->loop->ioserivce, STDIN_FILENO, NULL); 36 | cort_fd_bind(env, fd); 37 | 38 | cobuffer_t *buff = cobuffer_new(NULL, 256, 0); 39 | while (true) { 40 | if (cort_fd_read(env, fd, buff) && client_tcp) { 41 | cotcp_send(env->loop->ioserivce, client_tcp, cobuffer_buffer(buff), cobuffer_pos(buff)); 42 | } else { 43 | break; 44 | } 45 | } 46 | cobuffer_free(buff); 47 | } 48 | 49 | void test_client(cortenv_t *env) { 50 | int co = cort_new(env->sch, client_rountine, env); 51 | cort_resume(env->sch, co); 52 | co = cort_new(env->sch, io_rountine, env); 53 | cort_resume(env->sch, co); 54 | } 55 | 56 | 57 | int main(int argc, char const *argv[]) 58 | { 59 | coloop_t *loop = coloop_new(1); 60 | cortenv_t *env = cortenv_new(loop, 0); 61 | 62 | test_client(env); 63 | coloop_run(loop); 64 | 65 | cortenv_free(env); 66 | coloop_free(loop); 67 | return 0; 68 | } 69 | -------------------------------------------------------------------------------- /src/co_clink.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 循环双向链表 3 | * by colin 4 | */ 5 | #ifndef __CO_CLINK__ 6 | #define __CO_CLINK__ 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | 11 | // 链表结点 12 | typedef struct coclink_node { 13 | struct coclink_node *next; 14 | struct coclink_node *prev; 15 | } coclink_node_t; 16 | 17 | // 初始化链表头:前后都指向自己 18 | static inline void coclink_init(coclink_node_t *head) { 19 | head->prev = head; 20 | head->next = head; 21 | } 22 | 23 | // 插入结点到链表的前面,因为是循环链表,其实是在head的后面 24 | static inline void coclink_add_front(coclink_node_t *head, coclink_node_t *node) { 25 | node->prev = head; 26 | node->next = head->next; 27 | head->next->prev = node; 28 | head->next = node; 29 | } 30 | 31 | // 插入结点到链表的后面,因为是循环链表,所以其实是在head的前面 32 | static inline void coclink_add_back(coclink_node_t *head, coclink_node_t *node) { 33 | node->prev = head->prev; 34 | node->next = head; 35 | node->prev->next = node; 36 | head->prev = node; 37 | } 38 | 39 | // 判断链表是否为空:循环链表为空是头的下一个和上一个都指向自己 40 | static inline int coclink_is_empty(coclink_node_t *head) { 41 | return head == head->next; 42 | } 43 | 44 | // 从链表中移除自己,同时会重设结点 45 | static inline void coclink_remote(coclink_node_t *node) { 46 | node->next->prev = node->prev; 47 | node->prev->next = node->next; 48 | coclink_init(node); 49 | } 50 | 51 | // 将链表1的结点取出来,放到链表2 52 | static inline void coclink_splice(coclink_node_t *head1, coclink_node_t *head2) { 53 | if (!coclink_is_empty(head1)) { 54 | coclink_node_t *first = head1->next; // 第1个结点 55 | coclink_node_t *last = head1->prev; // 最后1个结点 56 | coclink_node_t *at = head2->next; // 插在第2个链表的这个结点前面 57 | first->prev = head2; 58 | head2->next = first; 59 | last->next = at; 60 | at->prev = last; 61 | coclink_init(head1); 62 | } 63 | } 64 | 65 | #ifdef __cplusplus 66 | } 67 | #endif 68 | #endif -------------------------------------------------------------------------------- /test/test_echo_server2.c: -------------------------------------------------------------------------------- 1 | #include "../src/co_routineex.h" 2 | 3 | /** 4 | * 协程版的echo服务器 5 | */ 6 | 7 | ////////////////////////////////////////////////////////////////////////// 8 | // 测试sleep 9 | void on_test_sleep(cosched_t *sch, void *ud) { 10 | cortenv_t *env = ud; 11 | int i = 0; 12 | for (i = 0; i < 10; ++i) { 13 | cort_sleep(env, 1000); 14 | printf(">>>>sleep:%d\n", i); 15 | } 16 | } 17 | 18 | void test_sleep(cortenv_t *env) { 19 | int co = cort_new(env->sch, on_test_sleep, env); 20 | cort_resume(env->sch, co); 21 | } 22 | 23 | ////////////////////////////////////////////////////////////////////////// 24 | // 测试socket 25 | 26 | void on_client_routine(cosched_t *sch, void *ud) { 27 | cotcp_t *tcp = ud; 28 | cortenv_t *env = tcp->ud; 29 | cort_tcp_bind(env, tcp); 30 | cobuffer_t *buff = cobuffer_new(NULL, 256, 0); 31 | while (true) { 32 | if (cort_tcp_read(env, tcp, buff)) { 33 | cotcp_send(tcp->ioservice, tcp, cobuffer_buffer(buff), cobuffer_pos(buff)); 34 | } else { 35 | break; 36 | } 37 | } 38 | cobuffer_free(buff); 39 | } 40 | 41 | void on_new_client(coios_t *ss, cotcp_t* tcp) { 42 | printf("on_new_client: %d\n", tcp->fd); 43 | cortenv_t *env = tcp->ud; 44 | int co = cort_new(env->sch, on_client_routine, tcp); 45 | cort_resume(env->sch, co); 46 | } 47 | 48 | void test_socket(cortenv_t *env) { 49 | char *ip = "127.0.0.1"; 50 | char *port = "3458"; 51 | printf("listen on %s:%s\n", ip, port); 52 | cotcp_listen(env->loop->ioserivce, ip, port, env, on_new_client); 53 | } 54 | 55 | 56 | int main(int argc, char const *argv[]) { 57 | coloop_t *loop = coloop_new(1); 58 | cortenv_t *env = cortenv_new(loop, 0); 59 | 60 | test_sleep(env); 61 | test_socket(env); 62 | coloop_run(loop); 63 | 64 | cortenv_free(env); 65 | coloop_free(loop); 66 | return 0; 67 | } 68 | -------------------------------------------------------------------------------- /src/co_timingwheel.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 时间轮算法 3 | * by colin 4 | */ 5 | #ifndef __CO_TIMINGWHEEL__ 6 | #define __CO_TIMINGWHEEL__ 7 | #include "co_utils.h" 8 | #include "co_clink.h" 9 | 10 | #ifdef __cplusplus 11 | extern "C" { 12 | #endif 13 | 14 | // 第1个轮占的位数 15 | #define TVR_BITS 8 16 | // 第1个轮的长度 17 | #define TVR_SIZE (1 << TVR_BITS) 18 | // 第n个轮占的位数 19 | #define TVN_BITS 6 20 | // 第n个轮的长度 21 | #define TVN_SIZE (1 << TVN_BITS) 22 | // 掩码:取模或整除用 23 | #define TVR_MASK (TVR_SIZE - 1) 24 | #define TVN_MASK (TVN_SIZE - 1) 25 | 26 | // 定时器回调函数 27 | typedef void (*timer_cb_t)(void*); 28 | 29 | // 定时器结点 30 | typedef struct cotnode { 31 | coclink_node_t *next; // 下一个结点 32 | coclink_node_t *prev; // 上一个结点 33 | void *userdata; // 用户数据 34 | timer_cb_t callback; // 回调函数 35 | uint32_t expire; // 到期时间 36 | } cotnode_t; 37 | 38 | // 第1个轮 39 | typedef struct tvroot { 40 | coclink_node_t vec[TVR_SIZE]; 41 | } tvroot_t; 42 | 43 | // 后面几个轮 44 | typedef struct tvnum { 45 | coclink_node_t vec[TVN_SIZE]; 46 | } tvnum_t; 47 | 48 | // 时间轮定时器 49 | typedef struct cotw { 50 | tvroot_t tvroot; // 第1个轮 51 | tvnum_t tv[4]; // 后面4个轮 52 | uint64_t lasttime; // 上一次的时间毫秒 53 | uint32_t currtick; // 当前的tick 54 | uint16_t interval; // 每个时间点的毫秒间隔 55 | uint16_t remainder; // 剩余的毫秒 56 | } cotw_t; 57 | 58 | // 初始化时间轮,interval为每帧的间隔,currtime为当前时间 59 | void cotw_init(cotw_t *tw, uint16_t interval, uint64_t currtime); 60 | // 初始化时间结点:cb为回调,ud为用户数据 61 | void cotw_node_init(cotnode_t *node, timer_cb_t cb, void *ud); 62 | // 增加时间结点,ticks为触发间隔(注意是以interval为单位) 63 | void cotw_add(cotw_t *tw, cotnode_t *node, uint32_t ticks); 64 | // 删除结点 65 | int cotw_del(cotw_t *tw, cotnode_t *node); 66 | // 更新时间轮 67 | void cotw_update(cotw_t *tw, uint64_t currtime); 68 | 69 | #ifdef __cplusplus 70 | } 71 | #endif 72 | #endif -------------------------------------------------------------------------------- /src/co_queue.c: -------------------------------------------------------------------------------- 1 | #include "co_queue.h" 2 | 3 | #define INIT_SIZE 8 4 | 5 | coqueue_t* coqueue_new(uint16_t itemsize) { 6 | coqueue_t *queue = CO_MALLOC(sizeof(*queue)); 7 | queue->head = 0; 8 | queue->tail = 0; 9 | queue->vec = covec_new(itemsize); 10 | covec_resize(queue->vec, INIT_SIZE); 11 | return queue; 12 | } 13 | 14 | void* coqueue_free(coqueue_t *queue) { 15 | covec_free(queue->vec); 16 | CO_FREE(queue); 17 | return NULL; 18 | } 19 | 20 | int coqueue_size(coqueue_t *queue) { 21 | int head = queue->head; 22 | int tail = queue->tail; 23 | return tail >= head ? tail - head : covec_size(queue->vec) - (head - tail); 24 | } 25 | 26 | static void _check_and_grow(coqueue_t *queue) { 27 | int size = coqueue_size(queue); 28 | int vecsize = queue->vec->size; 29 | if (size + 1 >= vecsize) { 30 | covec_resize(queue->vec, vecsize * 2); 31 | if (queue->tail < queue->head) { 32 | int count = vecsize - queue->head; 33 | int newhead = queue->vec->size - count; 34 | covec_move(queue->vec, queue->head, newhead, count); 35 | queue->head = newhead; 36 | } 37 | } 38 | } 39 | 40 | void coqueue_push(coqueue_t *queue, const void *data) { 41 | _check_and_grow(queue); 42 | covec_set(queue->vec, queue->tail, data); 43 | queue->tail = (queue->tail + 1) % queue->vec->size; 44 | } 45 | 46 | bool coqueue_pop(coqueue_t *queue, void *data) { 47 | int size = coqueue_size(queue); 48 | if (size) { 49 | covec_get(queue->vec, queue->head, data); 50 | queue->head = (queue->head + 1) % queue->vec->size; 51 | return true; 52 | } 53 | return false; 54 | } 55 | 56 | bool coqueue_peek(coqueue_t *queue, int index, void *data) { 57 | int size = coqueue_size(queue); 58 | if (index < 0) 59 | index = size + index; 60 | if (index < 0 || index >= size) 61 | return false; 62 | index = (queue->head + index) % queue->vec->size; 63 | covec_get(queue->vec, index, data); 64 | return true; 65 | } 66 | 67 | -------------------------------------------------------------------------------- /test/test_timingwheel.c: -------------------------------------------------------------------------------- 1 | #include "../src/co_timingwheel.h" 2 | #include 3 | #include 4 | #include 5 | 6 | static cotw_t tw; 7 | static cotnode_t node; 8 | static cotnode_t node2; 9 | static cotnode_t node3; 10 | static cotnode_t node4; 11 | 12 | void _print_timerwheel(coclink_node_t *vec, int idx, int size) { 13 | int i; 14 | printf("========================================%d\n", idx); 15 | for (i = 0;i < size; ++i) { 16 | coclink_node_t *head = vec + i; 17 | if (!coclink_is_empty(head)) { 18 | coclink_node_t *node = head->next; 19 | while (node != head) { 20 | cotnode_t *tnode = (cotnode_t*)node; 21 | printf(" %d: (expire=%u)\n", i, tnode->expire); 22 | node = node->next; 23 | } 24 | } 25 | } 26 | } 27 | 28 | void print_timerwheel() { 29 | _print_timerwheel(tw.tvroot.vec, 0, TVR_SIZE); 30 | _print_timerwheel(tw.tv[0].vec, 1, TVN_SIZE); 31 | _print_timerwheel(tw.tv[1].vec, 2, TVN_SIZE); 32 | _print_timerwheel(tw.tv[2].vec, 3, TVN_SIZE); 33 | _print_timerwheel(tw.tv[3].vec, 4, TVN_SIZE); 34 | } 35 | 36 | 37 | void on_timer(void *ud) { 38 | printf("on_timer: %u, data: %jd\n", tw.currtick, ((intptr_t)ud)); 39 | cotw_del(&tw, &node2); 40 | 41 | cotw_node_init(&node3, on_timer, NULL); 42 | cotw_add(&tw, &node3, 1000); 43 | } 44 | 45 | void run() { 46 | int i = 0; 47 | while (1) { 48 | ++i; 49 | usleep(1000); 50 | cotw_update(&tw, co_gettime()); 51 | } 52 | } 53 | 54 | int main(int argc, char const *argv[]) 55 | { 56 | cotw_init(&tw, 1, co_gettime()); 57 | tw.currtick = 0xFFFFFFFF; 58 | 59 | cotw_node_init(&node, on_timer, (void*)(intptr_t)1); 60 | cotw_add(&tw, &node, 400); 61 | 62 | cotw_node_init(&node2, on_timer, NULL); 63 | cotw_add(&tw, &node2, 400); 64 | 65 | cotw_node_init(&node4, on_timer, NULL); 66 | cotw_add(&tw, &node4, 0xF0FFFFFF); 67 | 68 | print_timerwheel(); 69 | run(); 70 | return 0; 71 | } 72 | -------------------------------------------------------------------------------- /src/co_falloc.c: -------------------------------------------------------------------------------- 1 | #include "co_falloc.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #define MAX_BLOCK_SIZE 16*1024 8 | #define MIN_BLOCK_SIZE 4096 9 | #define MIN_ITEM_SIZE sizeof(co_blockitem_t) 10 | #define FREE_FLAG 0xC0C0C0C0 11 | 12 | void cofalloc_init(cofalloc_t *alloc, uint32_t blocksize, uint32_t itemsize) { 13 | memset(alloc, 0, sizeof(*alloc)); 14 | alloc->blocksize = CO_CLAMP(blocksize, MIN_BLOCK_SIZE, MAX_BLOCK_SIZE); 15 | alloc->itemsize = CO_MAX(MIN_ITEM_SIZE, itemsize); 16 | } 17 | 18 | void cofalloc_free(cofalloc_t *alloc) { 19 | co_memblock_t *block = alloc->memblock; 20 | while (block) { 21 | co_memblock_t *temp = block->next; 22 | CO_FREE(block); 23 | block = temp; 24 | } 25 | } 26 | 27 | void* cofalloc_newitem(cofalloc_t *alloc) { 28 | if (!alloc->freeitem) { 29 | co_memblock_t *block = (co_memblock_t*)CO_MALLOC(alloc->blocksize); 30 | block->next = alloc->memblock; 31 | alloc->memblock = block; 32 | int idx = 0; 33 | int itemsize = alloc->itemsize; 34 | int blocksize = alloc->blocksize - offsetof(co_memblock_t, buffer); 35 | while (idx + itemsize <= blocksize) { 36 | co_blockitem_t *item = (co_blockitem_t*)(block->buffer + idx); 37 | item->next = alloc->freeitem; 38 | item->flag = 0; 39 | alloc->freeitem = item; 40 | idx += itemsize; 41 | } 42 | } 43 | co_blockitem_t *item = alloc->freeitem; 44 | alloc->freeitem = alloc->freeitem->next; 45 | return item; 46 | } 47 | 48 | bool cofalloc_freeitem(cofalloc_t *alloc, void *item) { 49 | co_blockitem_t *bitem = (co_blockitem_t *)item; 50 | if (bitem->flag == FREE_FLAG) 51 | return false; 52 | bitem->flag = FREE_FLAG; 53 | bitem->next = alloc->freeitem; 54 | alloc->freeitem = bitem; 55 | return true; 56 | } 57 | 58 | bool cofalloc_isfree(cofalloc_t *alloc, void *item) { 59 | co_blockitem_t *bitem = (co_blockitem_t *)item; 60 | return bitem->flag == FREE_FLAG; 61 | } -------------------------------------------------------------------------------- /src/co_set.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 集合:由红黑树实现 3 | * by colin 4 | */ 5 | #ifndef __CO_SET__ 6 | #define __CO_SET__ 7 | #include "co_utils.h" 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | typedef struct coset_node { 14 | struct coset_node *parent; 15 | struct coset_node *left; 16 | struct coset_node *right; 17 | void *data; 18 | int color; 19 | } coset_node_t; 20 | 21 | // 比较回调 22 | // < 0 data1 < data2 23 | // = 0 data1 == data2 24 | // > 0 data1 > data2 25 | typedef int (*coset_comp_t)(void *ud, const void *data1, const void *data2); 26 | 27 | typedef struct coset { 28 | coset_node_t nilnode; // 代表空结点 29 | coset_node_t *root; // 根结点 30 | coset_node_t *nil; // 指向空结点 31 | coset_comp_t fn_comp; 32 | void *ud; 33 | int size; 34 | uint32_t datasize; 35 | } coset_t; 36 | 37 | 38 | // 创建和翻译 39 | coset_t* coset_new(uint16_t datasize, coset_comp_t fn, void *ud); 40 | void* coset_free(coset_t *set); 41 | // 集合大小 42 | static inline int coset_size(coset_t *set) { return set->size; } 43 | // 清除内容 44 | void coset_clear(coset_t *set); 45 | // 增加元素 46 | void coset_add(coset_t *set, void *data); 47 | // 删除元素 48 | void coset_delete(coset_t *set, void *data); 49 | // 判断元素是否存在 50 | bool coset_exist(coset_t *set, void *data); 51 | // 并集 52 | void coset_union(coset_t *set, coset_t *set2); 53 | // 交集 54 | void coset_intersect(coset_t *set, coset_t *set2); 55 | // 差集 56 | void coset_minus(coset_t *set, coset_t *set2); 57 | // 遍历 58 | coset_node_t* coset_begin(coset_t *set); 59 | coset_node_t* coset_next(coset_t *set, coset_node_t *curr); 60 | coset_node_t* coset_prev(coset_t *set, coset_node_t *curr); 61 | coset_node_t* coset_end(coset_t *set); 62 | // 取值 63 | #define coset_data(node, type) (*(type*)((node)->data)) 64 | #define coset_data_ptr(node, type) ((type*)((node)->data)) 65 | // 简化操作 66 | #define coset_add_tp(set, data, type) {type v = data; coset_add(set, &v);} while(0) 67 | #define coset_del_tp(set, data, type) {type v = data; coset_delete(set, &v);} while(0) 68 | 69 | 70 | // 取nil结点,调试用 71 | coset_node_t* coset_nil(coset_t *set); 72 | 73 | #ifdef __cplusplus 74 | } 75 | #endif 76 | #endif -------------------------------------------------------------------------------- /src/co_vec.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 向量 3 | * by colin 4 | */ 5 | #ifndef __CO_VEC__ 6 | #define __CO_VEC__ 7 | #include "co_utils.h" 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | // 向量结构 14 | typedef struct covec { 15 | void * data; // 数据 16 | int cap; // 容量 17 | int size; // 当前大小 18 | uint32_t itemsize; // 项大小 19 | } covec_t; 20 | 21 | // 初始化向量,itemsize为子项大小 22 | covec_t* covec_new(uint16_t itemsize); 23 | // 释放向量 24 | void* covec_free(covec_t *vec); 25 | // 清除向量内容 26 | void covec_clear(covec_t *vec); 27 | // 取向量大小 28 | static inline int covec_size(covec_t *vec) { return vec->size; } 29 | // 取向量容量 30 | static inline int covec_cap(covec_t *vec) { return vec->cap; } 31 | // 设置向量大小 32 | void covec_resize(covec_t *vec, int size); 33 | // 增加向量容量 34 | void covec_growcap(covec_t *vec, int cap); 35 | 36 | // 压入子项,index可以为-1, -2..,表示从最后一个计算 37 | bool covec_push(covec_t *vec, int index, const void *data); 38 | // 压入最前面 39 | bool covec_push_head(covec_t *vec, const void *data); 40 | // 压入最后面 41 | bool covec_push_tail(covec_t *vec, const void *data); 42 | 43 | // 取子项,index可以为-1, -2..,表示从最后一个计算 44 | bool covec_get(covec_t *vec, int index, void *data); 45 | // 取第1个 46 | bool covec_get_head(covec_t *vec, void *data); 47 | // 取最后1个 48 | bool covec_get_tail(covec_t *vec, void *data); 49 | // 取子项指针,如果失败返回NULL,谨慎使用该函数 50 | void *covec_get_ptr(covec_t *vec, int index); 51 | 52 | // 设子项,index和上面一样 53 | bool covec_set(covec_t *vec, int index, const void *data); 54 | // 设第1个 55 | bool covec_set_head(covec_t *vec, const void *data); 56 | // 设最后1个 57 | bool covec_set_tail(covec_t *vec, const void *data); 58 | 59 | // 删除子项,index和上面一样, data可以为NULL, 也可以有值,表示删除的同时取值 60 | bool covec_del(covec_t *vec, int index, void *data); 61 | // 删除第1个 62 | bool covec_del_head(covec_t *vec, void *data); 63 | // 删除最后1个 64 | bool covec_del_tail(covec_t *vec, void *data); 65 | 66 | // 拷贝向量 67 | void covec_copy(covec_t *vfrom, covec_t *vto); 68 | // 批量将from的元素移到to的位置,to的内容会被覆盖:要特别小心溢出 69 | void covec_move(covec_t *vec, int from, int to, int count); 70 | // 交换两个元素 71 | void covec_swap(covec_t *vec, int idx1, int idx2); 72 | 73 | // 简化基本类型取值操作 74 | #define covec_get_tp(vec, index, type) (*(type*)covec_get_ptr((vec), (index))) 75 | 76 | #ifdef __cplusplus 77 | } 78 | #endif 79 | #endif -------------------------------------------------------------------------------- /test/test_echo_tps.c: -------------------------------------------------------------------------------- 1 | #include "../src/co_loop.h" 2 | 3 | coloop_t *loop = NULL; 4 | cotcp_t *client_tcp = NULL; 5 | void * thandler = NULL; 6 | char *buff = NULL; 7 | int buffsize = 1024; 8 | int64_t sendcount = 0; 9 | int64_t recvcount = 0; 10 | bool done = false; 11 | uint64_t starttime = 0; 12 | 13 | void on_close(coios_t *ss, cotcp_t* tcp) { 14 | printf("on_close: %d\n", tcp->fd); 15 | coloop_stop(ss->loop); 16 | } 17 | 18 | void on_error(coios_t *ss, cotcp_t* tcp, const char *msg) { 19 | fprintf(stderr, "on_error: %s\n", msg); 20 | coloop_stop(ss->loop); 21 | } 22 | 23 | void on_recv(coios_t *ss, cotcp_t* tcp, const void *buff, int size) { 24 | recvcount += size; 25 | if (done && recvcount == sendcount) { 26 | uint64_t tm = co_gettime(); 27 | printf("done: %ju\n", tm - starttime); 28 | cotcp_close(ss, tcp, true); 29 | // coloop_stop(ss->loop); 30 | } 31 | } 32 | 33 | void on_connect_error(coios_t *ss, cotcp_t* tcp, const char *msg) { 34 | fprintf(stderr, "on_connect_error: %s\n", msg); 35 | coloop_stop(ss->loop); 36 | } 37 | 38 | void on_timer(cots_t *ts, void *th, void *ud1, void *ud2) { 39 | int i; 40 | for (i = 0; i < 200; ++i) { 41 | int size = co_randrange(128, buffsize); 42 | cotcp_send(loop->ioserivce, client_tcp, buff, size); 43 | sendcount += size; 44 | } 45 | if (sendcount > 0xFFFFFFF) { 46 | done = true; 47 | cots_del_timer(loop->timeservice, &thandler); 48 | } 49 | } 50 | 51 | void on_connected(coios_t *ss, cotcp_t* tcp) { 52 | printf("Start testing, please wait...\n"); 53 | client_tcp = tcp; 54 | cotcp_on_recv(ss, tcp, on_recv); 55 | cotcp_on_close(ss, tcp, on_close); 56 | cotcp_on_error(ss, tcp, on_error); 57 | 58 | buff = CO_MALLOC(buffsize); 59 | memset(buff, 'a', buffsize); 60 | starttime = co_gettime(); 61 | thandler = cots_add_timer(ss->loop->timeservice, 1, 1, on_timer, NULL, NULL); 62 | } 63 | 64 | void run_test(coloop_t *loop) { 65 | cotcp_connect(loop->ioserivce, "127.0.0.1", "3458", NULL, on_connected, on_connect_error); 66 | } 67 | 68 | int main(int argc, char const *argv[]) { 69 | loop = coloop_new(1); 70 | run_test(loop); 71 | coloop_run(loop); 72 | coloop_free(loop); 73 | CO_FREE(buff); 74 | return 0; 75 | } 76 | -------------------------------------------------------------------------------- /src/co_timerservice.c: -------------------------------------------------------------------------------- 1 | #include "co_timerservice.h" 2 | 3 | typedef struct cotitem { 4 | cots_t *sv; 5 | fn_timer_t cb; 6 | cotnode_t node; 7 | void *ud1; 8 | void *ud2; 9 | uint32_t loop; 10 | } cotitem_t; 11 | 12 | cots_t* cots_new(uint16_t interval, uint64_t currtime) { 13 | cots_t* sv = CO_MALLOC(sizeof(cots_t)); 14 | cofalloc_init(&sv->alloc, 4096, sizeof(cotitem_t)); 15 | cotw_init(&sv->twheel, interval, currtime); 16 | return sv; 17 | } 18 | 19 | void* cots_free(cots_t* sv) { 20 | cofalloc_free(&sv->alloc); 21 | CO_FREE(sv); 22 | return NULL; 23 | } 24 | 25 | void _on_timer(void *ud) { 26 | cotitem_t *item = ud; 27 | cots_t *sv = item->sv; 28 | if (item->loop) { 29 | cotw_add(&sv->twheel, &item->node, item->loop); 30 | } 31 | if (item->cb) { 32 | item->cb(sv, item, item->ud1, item->ud2); 33 | } 34 | } 35 | 36 | void* cots_add_timer(cots_t *sv, uint32_t delay, uint32_t loop, fn_timer_t cb, void *ud1, void *ud2) { 37 | cotitem_t *item = cofalloc_newitem(&sv->alloc); 38 | item->sv = sv; 39 | item->loop = loop; 40 | item->cb = cb; 41 | item->ud1 = ud1; 42 | item->ud2 = ud2; 43 | cotw_node_init(&item->node, _on_timer, item); 44 | cotw_add(&sv->twheel, &item->node, delay); 45 | return item; 46 | } 47 | 48 | void cots_del_timer(cots_t *sv, void **handle) { 49 | if (!handle || !*handle) 50 | return; 51 | if (!cofalloc_isfree(&sv->alloc, *handle)) { 52 | cotitem_t *item = *handle; 53 | cotw_del(&sv->twheel, &item->node); 54 | cofalloc_freeitem(&sv->alloc, item); 55 | *handle = NULL; 56 | } 57 | } 58 | 59 | void cots_update(cots_t *sv, uint64_t currtime) { 60 | cotw_update(&sv->twheel, currtime); 61 | } 62 | 63 | static void _cots_print(coclink_node_t *vec, int idx, int size) { 64 | int i; 65 | printf("========================================%d\n", idx); 66 | for (i = 0;i < size; ++i) { 67 | coclink_node_t *head = vec + i; 68 | if (!coclink_is_empty(head)) { 69 | coclink_node_t *node = head->next; 70 | while (node != head) { 71 | cotnode_t *tnode = (cotnode_t*)node; 72 | printf(" %d: (expire=%u)\n", i, tnode->expire); 73 | node = node->next; 74 | } 75 | } 76 | } 77 | } 78 | 79 | void cots_print(cots_t *sv) { 80 | _cots_print(sv->twheel.tvroot.vec, 0, TVR_SIZE); 81 | _cots_print(sv->twheel.tv[0].vec, 1, TVN_SIZE); 82 | _cots_print(sv->twheel.tv[1].vec, 2, TVN_SIZE); 83 | _cots_print(sv->twheel.tv[2].vec, 3, TVN_SIZE); 84 | _cots_print(sv->twheel.tv[3].vec, 4, TVN_SIZE); 85 | } -------------------------------------------------------------------------------- /src/co_pqueue.c: -------------------------------------------------------------------------------- 1 | #include "co_pqueue.h" 2 | 3 | #define HEAP_PARENT(child) (((child) - 1) / 2) 4 | #define HEAP_LCHILD(parent) ((parent) * 2 + 1) 5 | #define HEAP_RCHILD(parent) ((parent) * 2 + 2) 6 | 7 | copqueue_t* copqueue_new(uint16_t itemsize, copqueue_comp_t fn, void *ud) { 8 | assert(fn); 9 | copqueue_t* pq = malloc(sizeof(*pq)); 10 | pq->vec = covec_new(itemsize); 11 | pq->fn_comp = fn; 12 | pq->ud = ud; 13 | return pq; 14 | } 15 | 16 | void *copqueue_free(copqueue_t *pq) { 17 | covec_free(pq->vec); 18 | CO_FREE(pq); 19 | return NULL; 20 | } 21 | 22 | int copqueue_size(copqueue_t *pq) { 23 | return covec_size(pq->vec); 24 | } 25 | 26 | static void _heap_up_tail(copqueue_t *pq) { 27 | int size = covec_size(pq->vec); 28 | if (size <= 1) 29 | return; 30 | int child = size-1; 31 | int parent, ret; 32 | const void *item1, *item2; 33 | while (child > 0) { 34 | parent = HEAP_PARENT(child); 35 | item1 = covec_get_ptr(pq->vec, parent); 36 | item2 = covec_get_ptr(pq->vec, child); 37 | ret = pq->fn_comp(pq->ud, item1, item2); 38 | if (ret >= 0) 39 | break; 40 | covec_swap(pq->vec, child, parent); 41 | child = parent; 42 | } 43 | } 44 | 45 | static void _heap_down_head(copqueue_t *pq) { 46 | int size = covec_size(pq->vec); 47 | if (size <= 1) 48 | return; 49 | int parent = 0; 50 | int child = HEAP_LCHILD(parent); 51 | int ret, rchild; 52 | const void *item1, *item2; 53 | while (child < size) { 54 | // 取左右孩子较大者作为比较元素 55 | rchild = HEAP_RCHILD(parent); 56 | if (rchild < size) { 57 | item1 = covec_get_ptr(pq->vec, child); 58 | item2 = covec_get_ptr(pq->vec, rchild); 59 | ret = pq->fn_comp(pq->ud, item1, item2); 60 | if (ret < 0) { 61 | child = rchild; 62 | } 63 | } 64 | item1 = covec_get_ptr(pq->vec, parent); 65 | item2 = covec_get_ptr(pq->vec, child); 66 | ret = pq->fn_comp(pq->ud, item1, item2); 67 | if (ret >= 0) 68 | break; 69 | covec_swap(pq->vec, child, parent); 70 | parent = child; 71 | child = HEAP_LCHILD(parent); 72 | } 73 | } 74 | 75 | void copqueue_push(copqueue_t *pq, const void *data) { 76 | // 压入最后 77 | covec_push_tail(pq->vec, data); 78 | // 上浮尾元素 79 | _heap_up_tail(pq); 80 | } 81 | 82 | bool copqueue_pop(copqueue_t *pq, void *data) { 83 | int size = covec_size(pq->vec); 84 | if (size > 0) { 85 | // 先首尾交换 86 | covec_swap(pq->vec, 0, size-1); 87 | // 然后删除最后一个 88 | covec_del_tail(pq->vec, data); 89 | // 下沉头元素 90 | _heap_down_head(pq); 91 | return true; 92 | } 93 | return false; 94 | } 95 | 96 | bool copqueue_get(copqueue_t *pq, int index, void *data) { 97 | return covec_get(pq->vec, index, data); 98 | } -------------------------------------------------------------------------------- /src/co_dict.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 字典 3 | * by colin 4 | */ 5 | #ifndef __CO_DICT__ 6 | #define __CO_DICT__ 7 | #include "co_utils.h" 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | // 计算hash,以前判断相等性的回调 14 | typedef uint64_t (*copfn_hash)(const void *key); 15 | typedef bool (*copfn_equal)(const void *key1, const void *key2); 16 | 17 | // 哈希结点 18 | typedef struct codict_node { 19 | struct codict_node *next; // 哈希桶的下一个结点 20 | struct codict_node *listprev, *listnext; // 链表的下一个结点,遍历用 21 | void *key; // 指向key的内容 22 | void *value; // 指向value的内容 23 | uint64_t hash; // hash值 24 | } codict_node_t; 25 | 26 | // 字典结构 27 | typedef struct codict { 28 | codict_node_t **buckets; // 哈希桶 29 | codict_node_t *listhead; // 链表头,遍历用 30 | codict_node_t *listtail; // 链表尾,遍历用 31 | copfn_hash fn_hash; // 哈希函数 32 | copfn_equal fn_equal; // 判断相等函数 33 | uint32_t cap; // 桶位容量 34 | uint32_t count; // 结点数量 35 | uint16_t keysz; // key的大小 36 | uint16_t valsz; // value的大小 37 | } codict_t; 38 | 39 | // 初始化字典 40 | codict_t* codict_new(copfn_hash fn_hash, copfn_equal fn_equal, uint16_t keysz, uint16_t valsz); 41 | // 释放字典 42 | void* codict_free(codict_t *dict); 43 | // 取结点 44 | codict_node_t* codict_get(codict_t *dict, const void *key); 45 | // 设值 46 | codict_node_t* codict_set(codict_t *dict, const void *key, const void *val); 47 | // 删除 48 | bool codict_del(codict_t *dict, const void *key); 49 | // 清除字典内容 50 | void codict_clear(codict_t *dict); 51 | // 将结点移到链表头或尾 52 | void codict_move(codict_t *dict, codict_node_t *node, bool head); 53 | // 字典大小 54 | static inline size_t codict_count(codict_t *dict) { return dict->count; } 55 | // 取结点的值 56 | #define codict_value(node, type) (*(type*)((node)->value)) 57 | #define codict_value_ptr(node, type) ((type*)((node)->value)) 58 | #define codict_key(node, type) (*(type*)((node)->key)) 59 | #define codict_key_ptr(node, type) ((type*)((node)->key)) 60 | 61 | // 简化操作:key为基础类型的立即数 62 | #define codict_get_tp(dict, key, type) {type k = key; codict_get(dict, &k);} while(0) 63 | #define codict_set_tp(dict, key, val, type) {type k = key; codict_set(dict, &k, val);} while(0) 64 | #define codict_del_tp(dict, key, type) {type k = key; codict_del(dict, &k);} while(0) 65 | 66 | // 遍历 67 | static inline codict_node_t* codict_begin(codict_t *dict) { return dict->listhead; } 68 | static inline codict_node_t* codict_end(codict_t *dict) { return dict->listtail; } 69 | static inline codict_node_t* codict_next(codict_node_t *node) { return node->listnext; } 70 | static inline codict_node_t* codict_prev(codict_node_t *node) { return node->listprev; } 71 | 72 | // 一些常用类型的回函调数,字符串必须0结尾,否则请自行提供 73 | bool codict_str_equal(const void *key1, const void *key2); 74 | bool codict_int_equal(const void *key1, const void *key2); 75 | bool codict_ptr_equal(const void *key1, const void *key2); 76 | uint64_t codict_str_hash(const void *key); 77 | uint64_t codict_int_hash(const void *key); 78 | uint64_t codict_ptr_hash(const void *key); 79 | 80 | #ifdef __cplusplus 81 | } 82 | #endif 83 | 84 | #endif -------------------------------------------------------------------------------- /test/test_udp_dns.c: -------------------------------------------------------------------------------- 1 | #include "../src/co_loop.h" 2 | #include "../src/co_dnsutils.h" 3 | 4 | #define MAX_NAME_LEN 255 5 | #define DEFAULT_PORT "53" 6 | #define MAX_PACKET_LEN 512 7 | 8 | coudp_t *udpclient = NULL; 9 | char dns[MAX_NAME_LEN] = {0}; 10 | struct sockaddr_storage sendaddr; 11 | socklen_t addrlen; 12 | uint8_t sendbuf[MAX_PACKET_LEN]; 13 | 14 | void on_close(coios_t *ss, coudp_t* udp) { 15 | printf("on_close\n"); 16 | udpclient = NULL; 17 | } 18 | 19 | void on_error(coios_t *ss, coudp_t* udp, const char *msg) { 20 | fprintf(stderr, "%s\n", msg); 21 | udpclient = NULL; 22 | } 23 | 24 | void on_recv(coios_t *ss, coudp_t* udp, const void *buff, int size, struct sockaddr *addr, socklen_t addrlen) { 25 | // 解析回应包 26 | ipaddr_t *ipaddrs; 27 | int addrnum; 28 | int code = codns_parse_response(buff, size, &ipaddrs, &addrnum); 29 | if (code != 0) { 30 | switch (code) { 31 | case 1: 32 | fprintf(stderr, "Format error\n"); return; 33 | case 2: 34 | fprintf(stderr, "Server failure\n"); return; 35 | case 3: 36 | fprintf(stderr, "Name Error\n"); return; 37 | case 4: 38 | fprintf(stderr, "Not Implemented\n"); return; 39 | case 5: 40 | fprintf(stderr, "Refused\n"); return; 41 | default: 42 | return; 43 | } 44 | } 45 | // IP列表 46 | char sip[40]; 47 | int i; 48 | for (i = 0; i < addrnum; ++i) { 49 | ipaddr_t *addr = &ipaddrs[i]; 50 | if (inet_ntop(addr->af, &addr->addr, sip, 40)) { 51 | printf("%s\n", sip); 52 | } 53 | } 54 | 55 | CO_FREE(ipaddrs); 56 | } 57 | 58 | coudp_t *get_udp(coios_t *ss) { 59 | if (!udpclient) { 60 | udpclient = coudp_new(ss, dns, DEFAULT_PORT, NULL, false, (struct sockaddr*)&sendaddr, &addrlen); 61 | coudp_on_recv(ss, udpclient, on_recv); 62 | coudp_on_error(ss, udpclient, on_error); 63 | coudp_on_close(ss, udpclient, on_close); 64 | } 65 | return udpclient; 66 | } 67 | 68 | void on_stdin_input(coios_t *ss, cofd_t *fd, const void *buf, int size) { 69 | // 生成请求包 70 | int sz = MAX_PACKET_LEN; 71 | char name[MAX_NAME_LEN] = {0}; 72 | strncpy(name, buf, CO_MIN(MAX_NAME_LEN, size-1)); 73 | if (codns_pack_request(sendbuf, &sz, name)) { 74 | fprintf(stderr, "request error: %s\n", name); 75 | return; 76 | } 77 | coudp_t *udp = get_udp(ss); 78 | coudp_send(ss, udp, sendbuf, sz, (struct sockaddr*)&sendaddr, addrlen); 79 | } 80 | 81 | void run_client(coloop_t *loop) { 82 | codns_get_server(dns, MAX_NAME_LEN); 83 | 84 | // 绑定stdin到异步IO 85 | cofd_t *fd = cofd_bind(loop->ioserivce, STDIN_FILENO, NULL); 86 | cofd_on_recv(loop->ioserivce, fd, on_stdin_input); 87 | 88 | printf("input domain name: \n"); 89 | } 90 | 91 | 92 | int main(int argc, char const *argv[]) 93 | { 94 | coios_ignsigpipe(); 95 | coloop_t *loop = coloop_new(10); 96 | run_client(loop); 97 | coloop_run(loop); 98 | coloop_free(loop); 99 | return 0; 100 | } 101 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # colinlib 2 | 3 | 由C语言实现的基础库,提供的功能有: 4 | 5 | ## 基础库 6 | - co_vec 向量数组 7 | - co_dict 字典(哈希表),内部有一个链表用于遍历,使用它可以实现lrucache 8 | - co_set 集合,内部由红黑树实现。 9 | - co_list 双向链表 10 | - co_queue 循环队列 11 | - co_pqueue 优先队列 12 | - co_buffer 可读写bufer,环形buffer 13 | - co_utf8 utf8解码 14 | - ca_falloc 固定长度的分配器 15 | - co_endian 大小端字节序的转换 16 | 17 | ## 网络库 18 | - co_timingwheel 基于时间轮的高效定时器 19 | - co_timerservice 定时器服务 20 | - co_routine 高效协程库,基于少量汇编的快速执行环境切换 21 | - co_loop/co_poll/co_ioservice 封装epoll/kqueue的高并发异步IO框架:支持tcp, udp和其他fd的异步IO。 22 | - co_routineex 整合上面的协程库以及异步IO框架,实现“同步”的读写。 23 | - co_dnsutils DNS解析函数 24 | 25 | ## 其他 26 | - co_wordfilter 关键字过滤 27 | 28 | 该库没有使用全局变量,函数也是可重入的,理论上可以安全的跑在独立线程上。 29 | 30 | # 编译以及测试 31 | 32 | 该库仅支持linux/*bsd/macos等操作系统 ,不支持windows。 33 | 34 | Make文件提供测试程序的编译: 35 | 36 | ```bash 37 | git clone https://github.com/colinsusie/colinlib.git 38 | cd colinlib 39 | make 40 | ``` 41 | 42 | 测试程序用于验证代码的正确性,同时也是了解代码用法的途径,比如下面几个测试程序: 43 | 44 | - test_echo_server/test_echo_client echo服务器和客户端,基于事件回调的方式,用少量代码即可实现功能。 45 | - test_echo_server2/test_echo_client2 另一个echo服务器和客户端,基于协程的同步方式,与上面相比哪种更好,由自己选择。 46 | - test_udp_dns 异步DNS查询程序,基于事件回调的方式。 47 | - test_udp_dns2 另一个异步DNS查询程序,基于协程的同步方式。 48 | - test_timerservice 时间轮定时器服务,提供简单的使用接口。 49 | - test_coroutine 协程测试程序 50 | 51 | 下面是基于回调的echo客户端的代码: 52 | 53 | ```c 54 | #include "../src/co_loop.h" 55 | 56 | cotcp_t *client_tcp = NULL; 57 | 58 | void on_recv(coios_t *ss, cotcp_t* tcp, const void *buff, int size) { 59 | write(STDOUT_FILENO, buff, size); 60 | } 61 | 62 | void on_close(coios_t *ss, cotcp_t* tcp) { 63 | printf("on_close: %d\n", tcp->fd); 64 | coloop_stop(ss->loop); 65 | } 66 | 67 | void on_error(coios_t *ss, cotcp_t* tcp, const char *msg) { 68 | fprintf(stderr, "on_error: %s\n", msg); 69 | coloop_stop(ss->loop); 70 | } 71 | 72 | void on_connected(coios_t *ss, cotcp_t* tcp) { 73 | char ip[128] = {0}; 74 | char port[32] = {0}; 75 | coios_getpeername(tcp->fd, ip, 128, port, 32); 76 | printf("connected to %s:%s\n", ip, port); 77 | client_tcp = tcp; 78 | // 连接成功,监听事件 79 | cotcp_on_recv(ss, tcp, on_recv); 80 | cotcp_on_close(ss, tcp, on_close); 81 | cotcp_on_error(ss, tcp, on_error); 82 | } 83 | 84 | void on_connect_error(coios_t *ss, cotcp_t* tcp, const char *msg) { 85 | fprintf(stderr, "on_connect_error: %s\n", msg); 86 | coloop_stop(ss->loop); 87 | } 88 | 89 | void on_stdin_input(coios_t *ss, cofd_t *fd, const void *buf, int size) { 90 | // 从stdin得到数据,发送给服务器 91 | if (client_tcp) cotcp_send(ss, client_tcp, buf, size); 92 | } 93 | 94 | void run_client(coloop_t *loop) { 95 | // 绑定stdin到异步IO 96 | cofd_t *fd = cofd_bind(loop->ioserivce, STDIN_FILENO, NULL); 97 | cofd_on_recv(loop->ioserivce, fd, on_stdin_input); 98 | // 连接服务器 99 | cotcp_connect(loop->ioserivce, "127.0.0.1", "3458", NULL, 100 | on_connected, on_connect_error); 101 | } 102 | 103 | int main(int argc, char const *argv[]) { 104 | coios_ignsigpipe(); 105 | coloop_t *loop = coloop_new(10); 106 | run_client(loop); 107 | coloop_run(loop); 108 | coloop_free(loop); 109 | return 0; 110 | } 111 | ``` 112 | 113 | ## 最后 114 | 115 | 虽然写了很多测试程序,并且用valgrind检查过内存问题,但错误在所难免,如果发现问题,欢迎提Issues。 -------------------------------------------------------------------------------- /src/co_endian.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 字节序转换 3 | * by colin 4 | */ 5 | #ifndef __CO_ENDIAN__ 6 | #define __CO_ENDIAN__ 7 | 8 | #ifdef __cplusplus 9 | extern "C" { 10 | #endif 11 | 12 | // 判断是否是小端字节序 13 | static inline bool is_little_endian() { 14 | static const union { 15 | int dummy; 16 | char little; 17 | } host_endian = {1}; 18 | return host_endian.little; 19 | } 20 | 21 | #if defined(__linux__) 22 | #include 23 | #elif defined(__APPLE__) 24 | #include 25 | #define htobe16(x) OSSwapHostToBigInt16(x) 26 | #define htole16(x) OSSwapHostToLittleInt16(x) 27 | #define be16toh(x) OSSwapBigToHostInt16(x) 28 | #define le16toh(x) OSSwapLittleToHostInt16(x) 29 | 30 | #define htobe32(x) OSSwapHostToBigInt32(x) 31 | #define htole32(x) OSSwapHostToLittleInt32(x) 32 | #define be32toh(x) OSSwapBigToHostInt32(x) 33 | #define le32toh(x) OSSwapLittleToHostInt32(x) 34 | 35 | #define htobe64(x) OSSwapHostToBigInt64(x) 36 | #define htole64(x) OSSwapHostToLittleInt64(x) 37 | #define be64toh(x) OSSwapBigToHostInt64(x) 38 | #define le64toh(x) OSSwapLittleToHostInt64(x) 39 | #elif defined(__OpenBSD__) 40 | #include 41 | #elif defined(__NetBSD__) || defined(__FreeBSD__) 42 | #include 43 | #define be16toh(x) betoh16(x) 44 | #define le16toh(x) letoh16(x) 45 | #define be32toh(x) betoh32(x) 46 | #define le32toh(x) letoh32(x) 47 | #define be64toh(x) betoh64(x) 48 | #define le64toh(x) letoh64(x) 49 | #else 50 | #error platform not supported 51 | #endif 52 | 53 | typedef union floattype { 54 | float f; 55 | double d; 56 | char buff[8]; 57 | } floattype_t; 58 | 59 | static inline void _swap_float(char *dest, const char *src, int size) { 60 | dest += size - 1; 61 | while (size-- != 0) 62 | *(dest--) = *(src++); 63 | } 64 | 65 | static inline float htole32f(float v) { 66 | if (is_little_endian()) { 67 | return v; 68 | } else { 69 | floattype_t f; 70 | _swap_float(f.buff, (char*)&v, sizeof(float)); 71 | return f.f; 72 | } 73 | } 74 | 75 | static inline float htobe32f(float v) { 76 | if (!is_little_endian()) { 77 | return v; 78 | } else { 79 | floattype_t f; 80 | _swap_float(f.buff, (char*)&v, sizeof(float)); 81 | return f.f; 82 | } 83 | } 84 | 85 | static inline double htole64f(double v) { 86 | if (is_little_endian()) { 87 | return v; 88 | } else { 89 | floattype_t f; 90 | _swap_float(f.buff, (char*)&v, sizeof(double)); 91 | return f.d; 92 | } 93 | } 94 | 95 | static inline double htobe64f(double v) { 96 | if (!is_little_endian()) { 97 | return v; 98 | } else { 99 | floattype_t f; 100 | _swap_float(f.buff, (char*)&v, sizeof(double)); 101 | return f.d; 102 | } 103 | } 104 | 105 | static inline float le32tohf(float v) { 106 | return htole32f(v); 107 | } 108 | 109 | static inline double be32tohf(double v) { 110 | return htobe32f(v); 111 | } 112 | 113 | static inline float le64tohf(float v) { 114 | return htole64f(v); 115 | } 116 | 117 | static inline double be64tohf(double v) { 118 | return htobe64f(v); 119 | } 120 | 121 | 122 | #ifdef __cplusplus 123 | } 124 | #endif 125 | #endif 126 | -------------------------------------------------------------------------------- /src/co_list.c: -------------------------------------------------------------------------------- 1 | #include "co_list.h" 2 | 3 | colist_t* colist_new(uint16_t itemsize) { 4 | colist_t *list = CO_MALLOC(sizeof(*list)); 5 | list->head = NULL; 6 | list->tail = NULL; 7 | list->itemsize = itemsize; 8 | return list; 9 | } 10 | 11 | void* colist_free(colist_t *list) { 12 | colist_node_t *node = list->head; 13 | colist_node_t *temp; 14 | while (node) { 15 | temp = node->next; 16 | CO_FREE(node); 17 | node = temp; 18 | } 19 | list->head = NULL; 20 | list->tail = NULL; 21 | CO_FREE(list); 22 | return NULL; 23 | } 24 | 25 | void colist_push_head(colist_t *list, const void *data) { 26 | int size = sizeof(colist_node_t) + list->itemsize; 27 | colist_node_t *node = CO_MALLOC(size); 28 | memset(node, 0, size); 29 | memcpy((char*)node + sizeof(colist_node_t), data, list->itemsize); 30 | if (!list->head) { 31 | list->head = list->tail = node; 32 | } else { 33 | node->next = list->head; 34 | list->head->prev = node; 35 | list->head = node; 36 | } 37 | } 38 | 39 | void colist_push_tail(colist_t *list, const void *data) { 40 | int size = sizeof(colist_node_t) + list->itemsize; 41 | colist_node_t *node = CO_MALLOC(size); 42 | memset(node, 0, size); 43 | memcpy((char*)node + sizeof(colist_node_t), data, list->itemsize); 44 | if (!list->tail) { 45 | list->head = list->tail = node; 46 | } else { 47 | node->prev = list->tail; 48 | list->tail->next = node; 49 | list->tail = node; 50 | } 51 | } 52 | 53 | void colist_push_at(colist_t *list, colist_node_t *node, const void *data, bool before) { 54 | assert(node); 55 | int size = sizeof(colist_node_t) + list->itemsize; 56 | colist_node_t *newnode = CO_MALLOC(size); 57 | memset(newnode, 0, size); 58 | memcpy((char*)newnode + sizeof(colist_node_t), data, list->itemsize); 59 | if (before) { 60 | newnode->next = node; 61 | newnode->prev = node->prev; 62 | if (node->prev) 63 | node->prev->next = newnode; 64 | node->prev = newnode; 65 | if (list->head == node) 66 | list->head = newnode; 67 | } else { 68 | newnode->prev = node; 69 | newnode->next = node->next; 70 | if (node->next) 71 | node->next->prev = newnode; 72 | node->next = newnode; 73 | if (list->tail == node) 74 | list->tail = newnode; 75 | } 76 | } 77 | 78 | bool colist_pop_head(colist_t *list, void *data) { 79 | return colist_pop_at(list, list->head, data); 80 | } 81 | 82 | bool colist_pop_tail(colist_t *list, void *data) { 83 | return colist_pop_at(list, list->tail, data); 84 | } 85 | 86 | bool colist_pop_at(colist_t *list, colist_node_t *node, void *data) { 87 | if (!node) 88 | return false; 89 | if (list->head == node) { 90 | list->head = list->head->next; 91 | if (list->head) 92 | list->head->prev = NULL; 93 | } 94 | if (list->tail == node) { 95 | list->tail = list->tail->prev; 96 | if (list->tail) 97 | list->tail->next = NULL; 98 | } 99 | if (node->prev) 100 | node->prev->next = node->next; 101 | if (node->next) 102 | node->next->prev = node->prev; 103 | if (data) 104 | colist_getvalue(list, node, data); 105 | CO_FREE(node); 106 | return true; 107 | } 108 | -------------------------------------------------------------------------------- /src/co_timingwheel.c: -------------------------------------------------------------------------------- 1 | #include "co_timingwheel.h" 2 | 3 | #define FIRST_INDEX(v) ((v) & TVR_MASK) 4 | #define NTH_INDEX(v, n) (((v) >> (TVR_BITS + (n) * TVN_BITS)) & TVN_MASK) 5 | 6 | void cotw_init(cotw_t *tw, uint16_t interval, uint64_t currtime) { 7 | memset(tw, 0, sizeof(*tw)); 8 | tw->interval = interval; 9 | tw->lasttime = currtime; 10 | int i, j; 11 | for (i = 0; i < TVR_SIZE; ++i) { 12 | coclink_init(tw->tvroot.vec + i); 13 | } 14 | for (i = 0; i < 4; ++i) { 15 | for (j = 0; j < TVN_SIZE; ++j) 16 | coclink_init(tw->tv[i].vec + j); 17 | } 18 | } 19 | 20 | void cotw_node_init(cotnode_t *node, timer_cb_t cb, void *ud) { 21 | node->next = 0; 22 | node->prev = 0; 23 | node->userdata = ud; 24 | node->callback = cb; 25 | node->expire = 0; 26 | } 27 | 28 | static void _cotw_add(cotw_t *tw, cotnode_t *node) { 29 | uint32_t expire = node->expire; 30 | uint32_t idx = expire - tw->currtick; 31 | coclink_node_t *head = NULL; 32 | if (idx < TVR_SIZE) { 33 | head = tw->tvroot.vec + FIRST_INDEX(expire); 34 | } else { 35 | int i; 36 | uint64_t sz; 37 | for (i = 0; i < 4; ++i) { 38 | sz = (1ULL << (TVR_BITS + (i+1) * TVN_BITS)); 39 | if (idx < sz) { 40 | idx = NTH_INDEX(expire, i); 41 | head = tw->tv[i].vec + idx; 42 | break; 43 | } 44 | } 45 | } 46 | if (head) 47 | coclink_add_back(head, (coclink_node_t*)node); 48 | } 49 | 50 | void cotw_add(cotw_t *tw, cotnode_t *node, uint32_t ticks) { 51 | node->expire = tw->currtick + ((ticks > 0) ? ticks : 1); 52 | _cotw_add(tw, node); 53 | } 54 | 55 | int cotw_del(cotw_t *tw, cotnode_t *node) { 56 | if (!coclink_is_empty((coclink_node_t*)node)) { 57 | coclink_remote((coclink_node_t*)node); 58 | return 1; 59 | } 60 | return 0; 61 | } 62 | 63 | void _cotw_cascade(cotw_t *tw, tvnum_t *tv, int idx) { 64 | coclink_node_t head; 65 | coclink_init(&head); 66 | coclink_splice(tv->vec + idx, &head); 67 | while (!coclink_is_empty(&head)) { 68 | cotnode_t *node = (cotnode_t*)head.next; 69 | coclink_remote(head.next); 70 | _cotw_add(tw, node); 71 | } 72 | } 73 | 74 | void _cotw_tick(cotw_t *tw) { 75 | ++tw->currtick; 76 | 77 | uint32_t currtick = tw->currtick; 78 | int index = (currtick & TVR_MASK); 79 | if (index == 0) { 80 | int i = 0; 81 | int idx; 82 | do { 83 | idx = NTH_INDEX(tw->currtick, i); 84 | _cotw_cascade(tw, &(tw->tv[i]), idx); 85 | } while (idx == 0 && ++i < 4); 86 | } 87 | 88 | coclink_node_t head; 89 | coclink_init(&head); 90 | coclink_splice(tw->tvroot.vec + index, &head); 91 | while (!coclink_is_empty(&head)) { 92 | cotnode_t *node = (cotnode_t*)head.next; 93 | coclink_remote(head.next); 94 | if (node->callback) { 95 | node->callback(node->userdata); 96 | } 97 | } 98 | } 99 | 100 | void cotw_update(cotw_t *tw, uint64_t currtime) { 101 | if (currtime > tw->lasttime) { 102 | int diff = currtime - tw->lasttime + tw->remainder; 103 | int intv = tw->interval; 104 | tw->lasttime = currtime; 105 | while (diff >= intv) { 106 | diff -= intv; 107 | _cotw_tick(tw); 108 | } 109 | tw->remainder = diff; 110 | } 111 | } -------------------------------------------------------------------------------- /src/co_buffer.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 各种类型的buffer 3 | * by colin 4 | */ 5 | #ifndef __CO_BUFFER__ 6 | #define __CO_BUFFER__ 7 | #include "co_utils.h" 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | // 字节序 14 | typedef enum cb_endian { 15 | CB_EN_NATIVE, // 主机序 16 | CB_EN_LITTLE, // 小端 17 | CB_EN_BIG, // 大端 18 | } cb_endian_t; 19 | 20 | // 打印BUFF:调试用 21 | void coprintfbuffer(const void *buffer, int size, int blocksize); 22 | 23 | /////////////////////////////////////////////////////////////////////////////////// 24 | // 读写buffer 25 | 26 | typedef struct cobuffer { 27 | void *buffer; // 内存 28 | int size; // 内存大小 29 | int pos; // 当前读或写的位置 30 | cb_endian_t endian; // 字节序 31 | } cobuffer_t; 32 | 33 | // 初始化和释放 34 | cobuffer_t* cobuffer_new(const char *buffer, int bufsz, cb_endian_t endian); 35 | void* cobuffer_free(cobuffer_t *bf); 36 | // 定位: abs指定是否绝对定位 false表示相对于当前pos,绝对定位支持-1,-2表示最后,返回实际的定位 37 | int cobuffer_seek(cobuffer_t *bf, bool abs, int pos); 38 | // buff大小位置等 39 | static inline void* cobuffer_buffer(cobuffer_t *bf) { return bf->buffer; } 40 | static inline int cobuffer_size(cobuffer_t *bf) { return bf->size; } 41 | static inline int cobuffer_pos(cobuffer_t *bf) { return bf->pos; } 42 | // 通用读写 43 | bool cobuffer_read(cobuffer_t *bf, void *buffer, int size); 44 | void cobuffer_write(cobuffer_t *bf, const void *buffer, int size); 45 | // 读各种类型 46 | int8_t cobuffer_read_int8(cobuffer_t *bf, bool *succ); 47 | uint8_t cobuffer_read_uint8(cobuffer_t *bf, bool *succ); 48 | int16_t cobuffer_read_int16(cobuffer_t *bf, bool *succ); 49 | uint16_t cobuffer_read_uint16(cobuffer_t *bf, bool *succ); 50 | int32_t cobuffer_read_int32(cobuffer_t *bf, bool *succ); 51 | uint32_t cobuffer_read_uint32(cobuffer_t *bf, bool *succ); 52 | int64_t cobuffer_read_int64(cobuffer_t *bf, bool *succ); 53 | uint64_t cobuffer_read_uint64(cobuffer_t *bf, bool *succ); 54 | float cobuffer_read_float32(cobuffer_t *bf, bool *succ); 55 | double cobuffer_read_float64(cobuffer_t *bf, bool *succ); 56 | // 写各种类型 57 | void cobuffer_write_int8(cobuffer_t *bf, int8_t v); 58 | void cobuffer_write_uint8(cobuffer_t *bf, uint8_t v); 59 | void cobuffer_write_int16(cobuffer_t *bf, int16_t v); 60 | void cobuffer_write_uint16(cobuffer_t *bf, uint16_t v); 61 | void cobuffer_write_int32(cobuffer_t *bf, int32_t v); 62 | void cobuffer_write_uint32(cobuffer_t *bf, uint32_t v); 63 | void cobuffer_write_int64(cobuffer_t *bf, int64_t v); 64 | void cobuffer_write_uint64(cobuffer_t *bf, uint64_t v); 65 | void cobuffer_write_float32(cobuffer_t *bf, float v); 66 | void cobuffer_write_float64(cobuffer_t *bf, double v); 67 | 68 | 69 | /////////////////////////////////////////////////////////////////////////////////// 70 | // 圆形buffer: 用于生产者/消费者模式下的buffer,自增长 71 | 72 | typedef struct coringbuf { 73 | void *buffer; 74 | int size; 75 | int head; 76 | int tail; 77 | } coringbuf_t; 78 | 79 | // 初始化和释放circle buffer 80 | coringbuf_t* coringbuf_new(int initsize); 81 | void* coringbuf_free(coringbuf_t *rb); 82 | // 读buffer,返回实际读到的buffer大小 83 | int coringbuf_read(coringbuf_t *rb, void *buffer, int size); 84 | // 写buffer 85 | void coringbuf_write(coringbuf_t *rb, const void *buffer, int size); 86 | // 取缓冲的头 87 | void *coringbuf_head(coringbuf_t *rb); 88 | // 还剩多少可以读 89 | int coringbuf_readable_size(coringbuf_t *rb); 90 | // 可读一次连续的内存的大小 91 | int coringbuf_readonce_size(coringbuf_t *rb); 92 | // 消耗了多少内存 93 | bool coringbuf_consume_size(coringbuf_t *rb, int size); 94 | 95 | #ifdef __cplusplus 96 | } 97 | #endif 98 | 99 | #endif -------------------------------------------------------------------------------- /test/test_udp_dns2.c: -------------------------------------------------------------------------------- 1 | #include "../src/co_routineex.h" 2 | #include "../src/co_dnsutils.h" 3 | 4 | #define MAX_NAME_LEN 255 5 | #define DEFAULT_PORT "53" 6 | #define MAX_PACKET_LEN 512 7 | 8 | coudp_t *udpclient = NULL; 9 | char dns[MAX_NAME_LEN] = {0}; 10 | struct sockaddr_storage sendaddr; 11 | socklen_t addrlen; 12 | uint8_t sendbuf[MAX_PACKET_LEN]; 13 | 14 | static void parse_dns_res(cobuffer_t *buff) { 15 | ipaddr_t *ipaddrs; 16 | int addrnum; 17 | int code = codns_parse_response(buff->buffer, buff->pos, &ipaddrs, &addrnum); 18 | if (code != 0) { 19 | switch (code) { 20 | case 1: 21 | fprintf(stderr, "Format error\n"); return; 22 | case 2: 23 | fprintf(stderr, "Server failure\n"); return; 24 | case 3: 25 | fprintf(stderr, "Name Error\n"); return; 26 | case 4: 27 | fprintf(stderr, "Not Implemented\n"); return; 28 | case 5: 29 | fprintf(stderr, "Refused\n"); return; 30 | default: 31 | return; 32 | } 33 | } 34 | // IP列表 35 | char sip[40]; 36 | int i; 37 | for (i = 0; i < addrnum; ++i) { 38 | ipaddr_t *addr = &ipaddrs[i]; 39 | if (inet_ntop(addr->af, &addr->addr, sip, 40)) { 40 | printf("%s\n", sip); 41 | } 42 | } 43 | CO_FREE(ipaddrs); 44 | } 45 | 46 | static void udp_rountine(cosched_t *sch, void *ud) { 47 | cortenv_t *env = ud; 48 | codns_get_server(dns, MAX_NAME_LEN); 49 | udpclient = coudp_new(env->loop->ioserivce, dns, DEFAULT_PORT, NULL, false, 50 | (struct sockaddr*)&sendaddr, &addrlen); 51 | if (!udpclient) { 52 | fprintf(stderr, "coudp_new failed\n"); 53 | return; 54 | } 55 | cort_udp_bind(env, udpclient); 56 | cobuffer_t *buff = cobuffer_new(NULL, 256, 0); 57 | while (true) { 58 | if (cort_udp_read(env, udpclient, buff)) { 59 | parse_dns_res(buff); 60 | } else { 61 | break; 62 | } 63 | } 64 | cobuffer_free(buff); 65 | } 66 | 67 | static void io_rountine(cosched_t *sch, void *ud) { 68 | printf("input domain name: \n"); 69 | 70 | cortenv_t *env = ud; 71 | cofd_t *fd = cofd_bind(env->loop->ioserivce, STDIN_FILENO, NULL); 72 | cort_fd_bind(env, fd); 73 | 74 | cobuffer_t *buff = cobuffer_new(NULL, 256, 0); 75 | while (true) { 76 | if (cort_fd_read(env, fd, buff)) { 77 | int sz = MAX_PACKET_LEN; 78 | char name[MAX_NAME_LEN] = {0}; 79 | strncpy(name, cobuffer_buffer(buff), CO_MIN(MAX_NAME_LEN, cobuffer_pos(buff)-1)); 80 | if (codns_pack_request(sendbuf, &sz, name)) { 81 | fprintf(stderr, "request error: %s\n", name); 82 | break; 83 | } 84 | if (udpclient) { 85 | coudp_send(env->loop->ioserivce, udpclient, sendbuf, sz, (struct sockaddr*)&sendaddr, addrlen); 86 | } 87 | } else { 88 | break; 89 | } 90 | } 91 | cobuffer_free(buff); 92 | } 93 | 94 | static void test_client(cortenv_t *env) { 95 | int co = cort_new(env->sch, udp_rountine, env); 96 | cort_resume(env->sch, co); 97 | co = cort_new(env->sch, io_rountine, env); 98 | cort_resume(env->sch, co); 99 | } 100 | 101 | int main(int argc, char const *argv[]) 102 | { 103 | coloop_t *loop = coloop_new(1); 104 | cortenv_t *env = cortenv_new(loop, 0); 105 | 106 | test_client(env); 107 | coloop_run(loop); 108 | 109 | cortenv_free(env); 110 | coloop_free(loop); 111 | return 0; 112 | } 113 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: test 2 | 3 | test: test_falloc test_dict test_vec test_queue test_list test_buffer \ 4 | test_utf8 test_timingwheel test_timerservice test_coroutine \ 5 | test_echo_server test_echo_client test_udp_dns test_echo_tps \ 6 | test_echo_server2 test_echo_client2 test_udp_dns2 test_pqueue \ 7 | test_set test_misc test_wordfilter 8 | 9 | test_misc: test/test_misc.c 10 | gcc -g -Wall -o test_misc test/test_misc.c 11 | 12 | test_falloc: test/test_falloc.c src/co_utils.h src/co_falloc.h src/co_falloc.c 13 | gcc -g -Wall -o test_falloc test/test_falloc.c src/co_falloc.c 14 | 15 | test_dict: test/test_dict.c src/co_utils.h src/co_dict.h src/co_dict.c 16 | gcc -g -Wall -o test_dict test/test_dict.c src/co_dict.c 17 | 18 | test_vec: test/test_vec.c src/co_utils.h src/co_vec.h src/co_vec.c 19 | gcc -g -Wall -o test_vec test/test_vec.c src/co_vec.c 20 | 21 | test_queue: test/test_queue.c src/co_queue.c src/co_utils.h src/co_queue.h src/co_vec.c src/co_vec.h 22 | gcc -g -Wall -o test_queue test/test_queue.c src/co_queue.c src/co_vec.c 23 | 24 | test_pqueue: test/test_pqueue.c src/co_pqueue.c src/co_utils.h src/co_pqueue.h src/co_vec.c src/co_vec.h 25 | gcc -g -Wall -o test_pqueue test/test_pqueue.c src/co_pqueue.c src/co_vec.c 26 | 27 | test_list: test/test_list.c src/co_list.c src/co_list.h src/co_utils.h 28 | gcc -g -Wall -o test_list test/test_list.c src/co_list.c 29 | 30 | test_set: test/test_set.c src/co_set.c src/co_set.h src/co_utils.h 31 | gcc -g -Wall -o test_set test/test_set.c src/co_set.c 32 | 33 | test_buffer: test/test_buffer.c src/co_buffer.c src/co_buffer.h src/co_utils.h src/co_endian.h 34 | gcc -g -Wall -o test_buffer test/test_buffer.c src/co_buffer.c 35 | 36 | test_utf8: test/test_utf8.c src/co_utf8.c src/co_utf8.h src/co_utils.h 37 | gcc -g -Wall -o test_utf8 test/test_utf8.c src/co_utf8.c 38 | 39 | test_timingwheel: test/test_timingwheel.c src/co_timingwheel.c src/co_timingwheel.h src/co_utils.h src/co_clink.h 40 | gcc -g -Wall -o test_timingwheel test/test_timingwheel.c src/co_timingwheel.c 41 | 42 | test_timerservice: test/test_timerservice.c src/co_timerservice.c src/co_timerservice.h src/co_timingwheel.c \ 43 | src/co_timingwheel.h src/co_utils.h src/co_clink.h src/co_falloc.c src/co_falloc.h 44 | gcc -g -Wall -o test_timerservice test/test_timerservice.c src/co_timerservice.c src/co_timingwheel.c src/co_falloc.c 45 | 46 | test_coroutine: test/test_coroutine.c src/co_routine.c src/co_routine.h src/co_ctx.c src/co_ctx.h src/coctx_swap.S src/co_utils.h 47 | gcc -g -Wall -o test_coroutine test/test_coroutine.c src/co_routine.c src/co_ctx.c src/coctx_swap.S 48 | 49 | test_wordfilter: test/test_wordfilter.c misc/co_wordfilter.c src/co_utils.h src/co_vec.h src/co_vec.c src/co_utf8.c src/co_utf8.h 50 | gcc -g -Wall -o test_wordfilter test/test_wordfilter.c misc/co_wordfilter.c src/co_vec.c src/co_utf8.c 51 | 52 | csrc = $(wildcard src/*.[cS]) 53 | cinc = $(wildcard src/*.h) 54 | 55 | test_echo_server: test/test_echo_server.c $(csrc) $(cinc) 56 | gcc -g -Wall -o test_echo_server test/test_echo_server.c $(csrc) 57 | test_echo_client: test/test_echo_client.c $(csrc) $(cinc) 58 | gcc -g -Wall -o test_echo_client test/test_echo_client.c $(csrc) 59 | test_udp_dns: test/test_udp_dns.c $(csrc) $(cinc) 60 | gcc -g -Wall -o test_udp_dns test/test_udp_dns.c $(csrc) 61 | test_echo_tps: test/test_echo_tps.c $(csrc) $(cinc) 62 | gcc -g -Wall -o test_echo_tps test/test_echo_tps.c $(csrc) 63 | test_echo_server2: test/test_echo_server2.c $(csrc) $(cinc) 64 | gcc -g -Wall -o test_echo_server2 test/test_echo_server2.c $(csrc) 65 | test_echo_client2: test/test_echo_client2.c $(csrc) $(cinc) 66 | gcc -g -Wall -o test_echo_client2 test/test_echo_client2.c $(csrc) 67 | test_udp_dns2: test/test_udp_dns2.c $(csrc) $(cinc) 68 | gcc -g -Wall -o test_udp_dns2 test/test_udp_dns2.c $(csrc) 69 | 70 | 71 | .PHONY: clean 72 | clean: 73 | rm -f test_* -------------------------------------------------------------------------------- /test/test_buffer.c: -------------------------------------------------------------------------------- 1 | #include "../src/co_buffer.h" 2 | 3 | void test_endian() { 4 | cobuffer_t *wb = cobuffer_new(NULL, 16, CB_EN_BIG); 5 | cobuffer_write_int8(wb, 0x10); 6 | cobuffer_write_int8(wb, 0x11); 7 | cobuffer_write_int8(wb, 0x12); 8 | cobuffer_write_int8(wb, 0x13); 9 | coprintfbuffer(wb->buffer, wb->pos, 1); 10 | 11 | cobuffer_seek(wb, true, 0); 12 | cobuffer_write_int16(wb, 0xFE01); 13 | cobuffer_write_uint16(wb, 0xFE02); 14 | cobuffer_write_int32(wb, 0xFE03); 15 | cobuffer_write_uint32(wb, 0xFE04); 16 | cobuffer_write_int64(wb, 0xFE05); 17 | cobuffer_write_uint64(wb, 0xFE06); 18 | cobuffer_write_float32(wb, 1.2345f); 19 | cobuffer_write_float64(wb, 1.2345); 20 | coprintfbuffer(wb->buffer, wb->pos, 2); 21 | cobuffer_free(wb); 22 | 23 | wb = cobuffer_new(NULL, 16, CB_EN_LITTLE); 24 | cobuffer_write_int16(wb, 0xFE01); 25 | cobuffer_write_uint16(wb, 0xFE02); 26 | cobuffer_write_int32(wb, 0xFE03); 27 | cobuffer_write_uint32(wb, 0xFE04); 28 | cobuffer_write_int64(wb, 0xFE05); 29 | cobuffer_write_uint64(wb, 0xFE06); 30 | cobuffer_write_float32(wb, 1.2345f); 31 | cobuffer_write_float64(wb, 1.2345); 32 | coprintfbuffer(wb->buffer, wb->pos, 2); 33 | cobuffer_free(wb); 34 | 35 | wb = cobuffer_new(NULL, 16, CB_EN_NATIVE); 36 | cobuffer_write_int16(wb, 0xFE01); 37 | cobuffer_write_uint16(wb, 0xFE02); 38 | cobuffer_write_int32(wb, 0xFE03); 39 | cobuffer_write_uint32(wb, 0xFE04); 40 | cobuffer_write_int64(wb, 0xFE05); 41 | cobuffer_write_uint64(wb, 0xFE06); 42 | cobuffer_write_float32(wb, 1.2345f); 43 | cobuffer_write_float64(wb, 1.2345); 44 | coprintfbuffer(wb->buffer, wb->pos, 2); 45 | cobuffer_free(wb); 46 | } 47 | 48 | void test_read_write() { 49 | struct mydata { 50 | int d1; 51 | float f1; 52 | int64_t d2; 53 | }; 54 | struct mydata md = {0x11FE, 1.2211, 0x32EDD1112}; 55 | 56 | cobuffer_t *wb = cobuffer_new(NULL, 16, CB_EN_BIG); 57 | cobuffer_write_int64(wb, 0xFE05); 58 | cobuffer_write_uint64(wb, 0xFE06); 59 | cobuffer_write_float32(wb, 1.2345f); 60 | cobuffer_write_float64(wb, 1.2345); 61 | cobuffer_write(wb, &md, sizeof(md)); 62 | coprintfbuffer(wb->buffer, wb->pos, 2); 63 | 64 | bool succ; 65 | cobuffer_seek(wb, true, 0); 66 | printf("%jX\n", cobuffer_read_int64(wb, &succ)); 67 | printf("%jX\n", cobuffer_read_uint64(wb, &succ)); 68 | printf("%f\n", cobuffer_read_float32(wb, &succ)); 69 | printf("%f\n", cobuffer_read_float64(wb, &succ)); 70 | struct mydata md2; 71 | cobuffer_read(wb, &md2, sizeof(md2)); 72 | printf("d1=%X\n", md2.d1); 73 | printf("f1=%f\n", md2.f1); 74 | printf("d2=%jX\n", md2.d2); 75 | 76 | cobuffer_free(wb); 77 | } 78 | 79 | void test_circle_buffer() { 80 | coringbuf_t *rb = coringbuf_new(64); 81 | 82 | char *str = "helloworldhelloworldhelloworldhelloworldhelloworld"; 83 | int len = strlen(str); 84 | coringbuf_write(rb, str, len); 85 | coringbuf_write(rb, str, len); 86 | coringbuf_write(rb, str, len); 87 | 88 | char str2[19] = {0}; 89 | while (1) { 90 | int n = coringbuf_read(rb, str2, 18); 91 | printf(">>>>>>%s\n", str2); 92 | if (n < 18) break; 93 | } 94 | 95 | coringbuf_free(rb); 96 | } 97 | 98 | void test_circle_buffer2() { 99 | coringbuf_t *rb = coringbuf_new(64); 100 | char *str = "helloworldhelloworldhelloworldhelloworldhelloworld"; 101 | int len = strlen(str); 102 | char str2[50] = {0}; 103 | coringbuf_write(rb, str, len); 104 | coringbuf_write(rb, str, len); 105 | coringbuf_read(rb, str2, 50); 106 | coringbuf_read(rb, str2, 50); 107 | coringbuf_write(rb, str, len); 108 | 109 | printf("readable=%d, head=%d, tail=%d\n", coringbuf_readable_size(rb), rb->head, rb->tail); 110 | 111 | while (coringbuf_readable_size(rb)) { 112 | int readonce = coringbuf_readonce_size(rb); 113 | void *buffer = coringbuf_head(rb); 114 | // 比如用于socket write 115 | (void)buffer; 116 | // comsume buffer ... 117 | printf("comsume buffer: %d\n", readonce); 118 | coringbuf_consume_size(rb, readonce); 119 | } 120 | 121 | coringbuf_free(rb); 122 | } 123 | 124 | int main(int argc, char const *argv[]) 125 | { 126 | test_endian(); 127 | test_read_write(); 128 | test_circle_buffer(); 129 | test_circle_buffer2(); 130 | return 0; 131 | } 132 | -------------------------------------------------------------------------------- /test/test_coroutine.c: -------------------------------------------------------------------------------- 1 | #include "../src/co_routine.h" 2 | #include 3 | #include 4 | 5 | struct args { 6 | int n; 7 | }; 8 | 9 | double timediff(struct timeval *begin, struct timeval *end) { 10 | return (end->tv_sec + end->tv_usec * 1.0 / 1000000) - 11 | (begin->tv_sec + begin->tv_usec * 1.0 / 1000000); 12 | } 13 | 14 | /////////////////////////////////////////////////////////////////////////////////// 15 | // 简单测试 16 | static void foo(cosched_t * S, void *ud) { 17 | struct args * arg = ud; 18 | int start = arg->n; 19 | int i; 20 | for (i=0;i<5;i++) { 21 | printf("coroutine %d : %d\n", cort_running(S) , start + i); 22 | cort_yield(S); 23 | } 24 | } 25 | 26 | static void test(cosched_t *S) { 27 | struct args arg1 = { 0 }; 28 | struct args arg2 = { 100 }; 29 | 30 | int co1 = cort_new(S, foo, &arg1); 31 | int co2 = cort_new(S, foo, &arg2); 32 | printf("test start===============\n"); 33 | while (cort_status(S,co1) && cort_status(S,co2)) { 34 | cort_resume(S,co1); 35 | cort_resume(S,co2); 36 | } 37 | printf("test end==============\n"); 38 | } 39 | 40 | /////////////////////////////////////////////////////////////////////////////////// 41 | // 递归创建1000个协程 42 | static void foo2(cosched_t * S, void *ud) { 43 | struct args * arg = ud; 44 | if (arg->n < 1000) { 45 | arg->n++; 46 | int co = cort_new(S, foo2, arg); 47 | printf("coroutine: %d, n=%d\n", co, arg->n); 48 | cort_resume(S, co); 49 | } 50 | } 51 | 52 | static void test2(cosched_t *S) { 53 | printf("test2 start===============\n"); 54 | struct args arg = { 0 }; 55 | int co = cort_new(S, foo2, &arg); 56 | printf("coroutine: %d, n=%d\n", co, arg.n); 57 | cort_resume(S, co); 58 | printf("test2 end==============\n"); 59 | } 60 | 61 | /////////////////////////////////////////////////////////////////////////////////// 62 | // 主协程测试 63 | static void test3(cosched_t *S) { 64 | printf("test3 start===============\n"); 65 | int mainco = cort_running(S); 66 | printf("main co: %d\n", mainco); 67 | printf("yield mainco: %d\n", cort_yield(S)); 68 | printf("test3 end==============\n"); 69 | } 70 | 71 | /////////////////////////////////////////////////////////////////////////////////// 72 | // 协程相互resume 73 | static int co1, co2, co3; 74 | 75 | static void foo4_3(cosched_t *S, void *ud) { 76 | printf("[%d] run\n", cort_running(S)); 77 | cort_resume(S, co2); 78 | printf("[%d] run done\n", cort_running(S)); 79 | } 80 | 81 | static void foo4_2(cosched_t *S, void *ud) { 82 | printf("[%d] run\n", cort_running(S)); 83 | cort_yield(S); 84 | printf("[%d] run done\n", cort_running(S)); 85 | } 86 | 87 | static void foo4_1(cosched_t *S, void *ud) { 88 | printf("[%d] run\n", cort_running(S)); 89 | cort_resume(S, co2); 90 | co3 = cort_new(S, foo4_3, NULL); 91 | cort_resume(S, co3); 92 | printf("[%d] run done\n", cort_running(S)); 93 | } 94 | 95 | static void test4(cosched_t *S) { 96 | printf("test4 start===============\n"); 97 | co1 = cort_new(S, foo4_1, NULL); 98 | co2 = cort_new(S, foo4_2, NULL); 99 | cort_resume(S, co1); 100 | printf("test4 end===============\n"); 101 | } 102 | 103 | /////////////////////////////////////////////////////////////////////////////////// 104 | // 协程的创建和切换消耗 105 | int stop = 0; 106 | static void foo_5(cosched_t *S, void *ud) { 107 | while (!stop) { 108 | cort_yield(S); 109 | } 110 | } 111 | 112 | static void test5(cosched_t *S) { 113 | printf("test5 start===============\n"); 114 | struct timeval begin; 115 | struct timeval end; 116 | int i; 117 | int count = 1000; 118 | 119 | gettimeofday(&begin, NULL); 120 | for (i = 0; i < count; ++i) { 121 | cort_new(S, foo_5, NULL); 122 | } 123 | gettimeofday(&end, NULL); 124 | printf("create time=%f\n", timediff(&begin, &end)); 125 | 126 | gettimeofday(&begin, NULL); 127 | for (i =0; i < 5000000; ++i) { 128 | int co = (i % count) + 1; 129 | cort_resume(S, co); 130 | } 131 | gettimeofday(&end, NULL); 132 | printf("swap time=%f\n", timediff(&begin, &end)); 133 | 134 | // 先释放掉原来的 135 | stop = 1; 136 | for (i = 0; i < count; ++i) { 137 | int co = (i % count) + 1; 138 | cort_resume(S, co); 139 | } 140 | gettimeofday(&begin, NULL); 141 | for (i = 0; i < count; ++i) { 142 | cort_new(S, foo_5, NULL); 143 | } 144 | gettimeofday(&end, NULL); 145 | printf("create time2=%f\n", timediff(&begin, &end)); 146 | printf("test5 end===============\n"); 147 | } 148 | 149 | int main() { 150 | cosched_t * S = cort_open(0); 151 | test(S); 152 | test2(S); 153 | test3(S); 154 | test4(S); 155 | test5(S); 156 | cort_close(S); 157 | return 0; 158 | } 159 | 160 | -------------------------------------------------------------------------------- /src/co_vec.c: -------------------------------------------------------------------------------- 1 | #include "co_vec.h" 2 | 3 | #define INIT_CAP 8 4 | 5 | static inline void _check_and_grow(covec_t *vec) { 6 | if (vec->size + 1 >= vec->cap) { 7 | int cap = CO_MAX(INIT_CAP, vec->cap*2); 8 | covec_growcap(vec, cap); 9 | } 10 | } 11 | 12 | covec_t* covec_new(uint16_t itemsize) { 13 | covec_t *vec = CO_MALLOC(sizeof(*vec)); 14 | vec->itemsize = itemsize; 15 | vec->size = 0; 16 | vec->cap = 0; 17 | vec->data = NULL; 18 | return vec; 19 | } 20 | 21 | void* covec_free(covec_t *vec) { 22 | covec_clear(vec); 23 | CO_FREE(vec); 24 | return NULL; 25 | } 26 | 27 | void covec_clear(covec_t *vec) { 28 | CO_FREE(vec->data); 29 | vec->data = NULL; 30 | vec->cap = 0; 31 | vec->size = 0; 32 | } 33 | 34 | void covec_resize(covec_t *vec, int size) { 35 | if (vec->size == size) 36 | return; 37 | if (vec->cap >= size) { 38 | vec->size = size; 39 | } else { 40 | vec->data = CO_REALLOC(vec->data, size*vec->itemsize); 41 | vec->cap = size; 42 | vec->size = size; 43 | } 44 | } 45 | 46 | void covec_growcap(covec_t *vec, int cap) { 47 | if (cap > vec->cap) { 48 | vec->data = CO_REALLOC(vec->data, cap*vec->itemsize); 49 | vec->cap = cap; 50 | } 51 | } 52 | 53 | bool covec_push(covec_t *vec, int index, const void *data) { 54 | if (index < 0) 55 | index = vec->size + index; 56 | if (index < 0 || index > vec->size) 57 | return false; 58 | _check_and_grow(vec); 59 | 60 | if (index != vec->size) { 61 | covec_move(vec, index, index + 1, vec->size - index); 62 | } 63 | memcpy((char*)vec->data + index * vec->itemsize, data, vec->itemsize); 64 | vec->size++; 65 | return true; 66 | } 67 | 68 | bool covec_push_head(covec_t *vec, const void *data) { 69 | return covec_push(vec, 0, data); 70 | } 71 | 72 | bool covec_push_tail(covec_t *vec, const void *data) { 73 | return covec_push(vec, vec->size, data); 74 | } 75 | 76 | bool covec_get(covec_t *vec, int index, void *data) { 77 | if (index < 0) 78 | index = vec->size + index; 79 | if (index < 0 || index >= vec->size) 80 | return false; 81 | memcpy(data, (char*)vec->data + index * vec->itemsize, vec->itemsize); 82 | return true; 83 | } 84 | 85 | void *covec_get_ptr(covec_t *vec, int index) { 86 | if (index < 0) 87 | index = vec->size + index; 88 | if (index < 0 || index >= vec->size) 89 | return NULL; 90 | return (char*)vec->data + index * vec->itemsize; 91 | } 92 | 93 | bool covec_get_head(covec_t *vec, void *data) { 94 | return covec_get(vec, 0, data); 95 | } 96 | 97 | bool covec_get_tail(covec_t *vec, void *data) { 98 | return covec_get(vec, vec->size-1, data); 99 | } 100 | 101 | bool covec_set(covec_t *vec, int index, const void *data) { 102 | if (index < 0) 103 | index = vec->size + index; 104 | if (index < 0 || index >= vec->size) 105 | return false; 106 | memcpy((char*)vec->data + index * vec->itemsize, data, vec->itemsize); 107 | return true; 108 | } 109 | 110 | bool covec_set_head(covec_t *vec, const void *data) { 111 | return covec_set(vec, 0, data); 112 | } 113 | 114 | bool covec_set_tail(covec_t *vec, const void *data) { 115 | return covec_set(vec, vec->size-1, data); 116 | } 117 | 118 | bool covec_del(covec_t *vec, int index, void *data) { 119 | if (index < 0) 120 | index = vec->size + index; 121 | if (index < 0 || index >= vec->size) 122 | return false; 123 | if (data) { 124 | covec_get(vec, index, data); 125 | } 126 | if (index != vec->size-1) { 127 | covec_move(vec, index + 1, index, vec->size - index - 1); 128 | } 129 | vec->size--; 130 | return true; 131 | } 132 | 133 | bool covec_del_head(covec_t *vec, void *data) { 134 | return covec_del(vec, 0, data); 135 | } 136 | 137 | bool covec_del_tail(covec_t *vec, void *data) { 138 | return covec_del(vec, vec->size-1, data); 139 | } 140 | 141 | void covec_copy(covec_t *vfrom, covec_t *vto) { 142 | covec_clear(vto); 143 | covec_resize(vto, vfrom->size); 144 | memcpy(vto->data, vfrom->data, vfrom->size * vfrom->itemsize); 145 | } 146 | 147 | void covec_move(covec_t *vec, int from, int to, int count) { 148 | char *dst = (char*)vec->data; 149 | memmove(dst + to * vec->itemsize, dst + from * vec->itemsize, count * vec->itemsize); 150 | } 151 | 152 | void covec_swap(covec_t *vec, int idx1, int idx2) { 153 | const int stsize = 128; 154 | uint8_t data1[stsize], data2[stsize]; 155 | uint8_t *ptr1 = vec->itemsize <= stsize ? data1 : CO_MALLOC(vec->itemsize); 156 | uint8_t *ptr2 = vec->itemsize <= stsize ? data2 : CO_MALLOC(vec->itemsize); 157 | if (covec_get(vec, idx1, ptr1) && covec_get(vec, idx2, ptr2)) { 158 | covec_set(vec, idx1, ptr2); 159 | covec_set(vec, idx2, ptr1); 160 | } 161 | if (ptr1 != data1) CO_FREE(ptr1); 162 | if (ptr2 != data2) CO_FREE(ptr2); 163 | } -------------------------------------------------------------------------------- /src/co_dnsutils.c: -------------------------------------------------------------------------------- 1 | #include "co_dnsutils.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #pragma pack(push) 10 | #pragma pack(1) 11 | typedef struct dns_header { 12 | uint16_t tid ; 13 | uint16_t flags ; 14 | uint16_t qdcount ; 15 | uint16_t ancount ; 16 | uint16_t nscount ; 17 | uint16_t arcount ; 18 | } dns_header_t; 19 | #pragma pack(pop) 20 | 21 | #define DNS_TYPE_A 1 22 | #define DNS_TYPE_AAAA 28 23 | #define DNS_CLASS_IN 1 24 | 25 | int codns_get_server(char *dnssvr, int n) { 26 | FILE * f = fopen("/etc/resolv.conf", "r"); 27 | if (f == NULL) return 1; 28 | int ret = 1; 29 | char line[512]; 30 | const char *sch = "nameserver"; 31 | while (fgets(line, 512, f)) { 32 | char* ss = strstr(line, sch); 33 | if (!ss) continue; 34 | ss = strrchr(ss, 0x20); 35 | if (!ss) continue; 36 | ss++; 37 | char *es = strchr(ss, '\n'); 38 | if (!es) continue; 39 | if (es-ss >= n) continue; 40 | strncpy(dnssvr, ss, es-ss); 41 | ret = 0; 42 | break; 43 | } 44 | fclose(f); 45 | return ret; 46 | } 47 | 48 | static uint16_t gtid = 1234; 49 | inline static uint16_t gen_tid() { 50 | return gtid++; 51 | } 52 | 53 | int codns_pack_request(uint8_t *buf, int *size, const char *name) { 54 | int maxsize = *size; 55 | if (maxsize < sizeof(dns_header_t)) return 1; 56 | int pos = 0; 57 | 58 | dns_header_t header; 59 | memset(&header, 0, sizeof(dns_header_t)); 60 | header.tid = htons(gen_tid()); 61 | header.flags = htons(0x0100); // Query, Standard Mode, Recursion Desired 62 | header.qdcount = htons(1); 63 | memcpy(buf+pos, &header, sizeof(dns_header_t)); 64 | pos += sizeof(header); 65 | 66 | const char *pname = name; 67 | const char *ppos; 68 | int len; 69 | for (;;) { 70 | ppos = strchr(pname, '.'); 71 | len = ppos ? ppos - pname : strlen(pname); 72 | if (maxsize < pos+1+len) return 1; 73 | buf[pos++] = len; 74 | memcpy(buf+pos, pname, len); 75 | pos += len; 76 | if (ppos) 77 | pname = ppos+1; 78 | else 79 | break; 80 | } 81 | if (maxsize < pos+1) return 1; 82 | buf[pos++] = '\0'; 83 | 84 | uint16_t qtype = htons(DNS_TYPE_A); // A 85 | if (maxsize < pos+2) return 1; 86 | memcpy(buf+pos, &qtype, 2); 87 | pos += 2; 88 | 89 | uint16_t qclass = htons(DNS_CLASS_IN); // IN 90 | if (maxsize < pos+2) return 1; 91 | memcpy(buf+pos, &qclass, 2); 92 | pos += 2; 93 | 94 | *size = pos; 95 | return 0; 96 | } 97 | 98 | int codns_parse_response(const uint8_t *buf, int size, ipaddr_t **addrs, int *addrnum) { 99 | if (size < sizeof(dns_header_t)) return 1; 100 | int pos = 0; 101 | 102 | dns_header_t *header = (dns_header_t *)(buf + pos); 103 | pos += sizeof(dns_header_t); 104 | 105 | // rcode 106 | int rcode = ntohs(header->flags) & 0x000F; 107 | if (rcode != 0) 108 | return rcode; 109 | 110 | // query 111 | uint16_t qdcount = ntohs(header->qdcount); 112 | if (qdcount != 1) return 1; 113 | uint8_t len; 114 | // 这里要处理名字指针的情况 115 | while (buf[pos] != '\0') { 116 | if (size < pos+1) return 1; 117 | len = *((uint8_t*)(buf+pos)); 118 | if ((len & 0xC0) == 0xC0) { // name pointer 119 | pos++; 120 | break; 121 | } else { 122 | pos++; 123 | if (size < pos+len) return 1; 124 | pos += len; 125 | } 126 | } 127 | if (size < pos+1) return 1; 128 | pos++; 129 | if (size < pos+4) return 1; 130 | pos += 4; 131 | 132 | // answer 133 | uint16_t ancount = ntohs(header->ancount); 134 | if (ancount < 1) return 1; 135 | ipaddr_t *retads = CO_CALLOC(ancount, sizeof(ipaddr_t)); 136 | #define CHECK_BUF(n) if (size < pos+(n)) { free(retads); return 1;} 137 | 138 | int i; 139 | int num = 0; 140 | for (i = 0; i < ancount; ++i) { 141 | // 这里要处理名字指针的情况 142 | while (buf[pos] != '\0') { 143 | CHECK_BUF(1); 144 | len = *((uint8_t*)(buf+pos)); 145 | if ((len & 0xC0) == 0xC0) { // name pointer 146 | pos++; 147 | break; 148 | } else { 149 | pos++; 150 | CHECK_BUF(len); 151 | pos += len; 152 | } 153 | } 154 | CHECK_BUF(1); 155 | pos++; 156 | // atype 157 | CHECK_BUF(2); 158 | uint16_t atype = ntohs(*((uint16_t*)(buf+pos))); 159 | pos += 2; 160 | // skip class, ttl 161 | CHECK_BUF(6); 162 | pos += 6; 163 | // rdlen 164 | CHECK_BUF(2); 165 | uint16_t rdlen = ntohs(*((uint16_t*)(buf+pos))); 166 | pos += 2; 167 | // rddata 168 | CHECK_BUF(rdlen); 169 | if (atype == DNS_TYPE_A) { 170 | retads[num].af = AF_INET; 171 | memcpy(&retads[num].addr.a4, buf+pos, 4); 172 | num++; 173 | } else if (atype == DNS_TYPE_AAAA) { 174 | retads[num].af = AF_INET6; 175 | memcpy(&retads[num].addr.a6, buf+pos, 16); 176 | num++; 177 | } 178 | pos += rdlen; 179 | } 180 | 181 | *addrs = retads; 182 | *addrnum = num; 183 | return 0; 184 | } -------------------------------------------------------------------------------- /src/co_routine.c: -------------------------------------------------------------------------------- 1 | #include "co_routine.h" 2 | 3 | #if __APPLE__ && __MACH__ 4 | #include 5 | #else 6 | #include 7 | #endif 8 | 9 | // 如果是x64,替代为自己的实现 10 | #if defined(__x86_64__) 11 | #define USE_COCTX 12 | #include "co_ctx.h" 13 | #endif 14 | 15 | #define MIN_STACK_SIZE (128*1024) 16 | #define MAX_STACK_SIZE (1024*1024) 17 | #define DEFAULT_COROUTINE 128 18 | #define MAIN_CO_ID 0 19 | 20 | struct cort; 21 | 22 | // 每个线程的调度器 23 | typedef struct cosched { 24 | int stsize; // 栈大小 25 | int nco; // 当前有几个协程 26 | int cap; // 协程数组容量 27 | int running; // 当前正在运行的协程ID 28 | struct cort **co; // 协程数组 29 | } cosched_t; 30 | 31 | // 协程数据 32 | typedef struct cort { 33 | cort_func_t func; // 协程回调函数 34 | void *ud; // 用户数据 35 | int pco; // 前一个协程,即resume这个协程的那个协程 36 | #ifdef USE_COCTX 37 | coctx_t ctx; // 协程的执行环境 38 | #else 39 | ucontext_t ctx; // 协程的执行环境 40 | #endif 41 | cosched_t * sch; // 调度器 42 | int status; // 当前状态:CO_STATUS_RUNNING... 43 | char *stack; // 栈内存 44 | } cort_t; 45 | 46 | cosched_t* cort_open(int stsize) { 47 | cosched_t *S = CO_MALLOC(sizeof(*S)); 48 | S->nco = 0; 49 | S->stsize = CO_MIN(CO_MAX(stsize, MIN_STACK_SIZE), MAX_STACK_SIZE); 50 | S->cap = DEFAULT_COROUTINE; 51 | S->co = CO_MALLOC(sizeof(cort_t *) * S->cap); 52 | memset(S->co, 0, sizeof(cort_t *) * S->cap); 53 | 54 | // 创建主协程 55 | int id = cort_new(S, NULL, NULL); 56 | assert(id == MAIN_CO_ID); 57 | // 主协程为运行状态 58 | cort_t *co = S->co[MAIN_CO_ID]; 59 | co->status = CO_STATUS_RUNNING; 60 | S->running = id; 61 | return S; 62 | } 63 | 64 | void cort_close(cosched_t *S) { 65 | assert(S->running == MAIN_CO_ID); 66 | int i; 67 | for (i=0;icap;i++) { 68 | cort_t * co = S->co[i]; 69 | if (co) { 70 | CO_FREE(co->stack); 71 | CO_FREE(co); 72 | } 73 | } 74 | CO_FREE(S->co); 75 | S->co = NULL; 76 | CO_FREE(S); 77 | } 78 | 79 | static void cofunc(uint32_t low32, uint32_t hi32) { 80 | uintptr_t ptr = (uintptr_t)low32 | ((uintptr_t)hi32 << 32); 81 | cosched_t *S = (cosched_t *)ptr; 82 | int id = S->running; 83 | cort_t *co = S->co[id]; 84 | co->func(S, co->ud); 85 | // 标记协程为死亡 86 | co->status = CO_STATUS_DEAD; 87 | --S->nco; 88 | // 恢复前一个协程 89 | cort_t *pco = S->co[co->pco]; 90 | pco->status = CO_STATUS_RUNNING; 91 | S->running = co->pco; 92 | #ifdef USE_COCTX 93 | coctx_t dummy; 94 | coctx_swap(&dummy, &pco->ctx); 95 | #else 96 | ucontext_t dummy; 97 | swapcontext(&dummy, &pco->ctx); 98 | #endif 99 | } 100 | 101 | int cort_new(cosched_t *S, cort_func_t func, void *ud) { 102 | int cid = -1; 103 | if (S->nco >= S->cap) { 104 | cid = S->cap; 105 | S->co = CO_REALLOC(S->co, S->cap * 2 * sizeof(cort_t *)); 106 | memset(S->co + S->cap , 0 , sizeof(cort_t *) * S->cap); 107 | S->cap *= 2; 108 | } else { 109 | int i; 110 | for (i=0;icap;i++) { 111 | int id = (i+S->nco) % S->cap; 112 | if (S->co[id] == NULL) { 113 | cid = id; 114 | break; 115 | } 116 | else if (S->co[id]->status == CO_STATUS_DEAD) { 117 | // printf("reuse dead cort: %d\n", id); 118 | cid = id; 119 | break; 120 | } 121 | } 122 | } 123 | 124 | if (cid >= 0) { 125 | cort_t *co; 126 | if (S->co[cid]) 127 | co = S->co[cid]; 128 | else { 129 | co = CO_MALLOC(sizeof(*co)); 130 | co->pco = 0; 131 | co->stack = cid != MAIN_CO_ID ? CO_MALLOC(S->stsize) : 0; 132 | S->co[cid] = co; 133 | } 134 | ++S->nco; 135 | 136 | co->func = func; 137 | co->ud = ud; 138 | co->sch = S; 139 | co->status = CO_STATUS_SUSPEND; 140 | 141 | if (func) { 142 | cort_t *curco = S->co[S->running]; 143 | assert(curco); 144 | #ifdef USE_COCTX 145 | co->ctx.ss_sp = co->stack; 146 | co->ctx.ss_size = S->stsize; 147 | uintptr_t ptr = (uintptr_t)S; 148 | coctx_make(&co->ctx, cofunc, (uint32_t)ptr, (uint32_t)(ptr>>32)); 149 | #else 150 | getcontext(&co->ctx); 151 | co->ctx.uc_stack.ss_sp = co->stack; 152 | co->ctx.uc_stack.ss_size = S->stsize; 153 | co->ctx.uc_link = &curco->ctx; 154 | uintptr_t ptr = (uintptr_t)S; 155 | makecontext(&co->ctx, (void (*)(void))cofunc, 2, (uint32_t)ptr, (uint32_t)(ptr>>32)); 156 | #endif 157 | } 158 | } 159 | 160 | return cid; 161 | } 162 | 163 | int cort_resume(cosched_t * S, int id) { 164 | assert(id >=0 && id < S->cap); 165 | cort_t *co = S->co[id]; 166 | cort_t *curco = S->co[S->running]; 167 | if (co == NULL || curco == NULL) 168 | return -1; 169 | int status = co->status; 170 | switch(status) { 171 | case CO_STATUS_SUSPEND: 172 | curco->status = CO_STATUS_NORMAL; 173 | co->pco = S->running; 174 | co->status = CO_STATUS_RUNNING; 175 | S->running = id; 176 | #ifdef USE_COCTX 177 | coctx_swap(&curco->ctx, &co->ctx); 178 | #else 179 | swapcontext(&curco->ctx, &co->ctx); 180 | #endif 181 | return 0; 182 | default: 183 | return -1; 184 | } 185 | } 186 | 187 | int cort_yield(cosched_t * S) { 188 | int id = S->running; 189 | // 主协程不能yield 190 | if (id == MAIN_CO_ID) 191 | return -1; 192 | // 恢复当前协程环境 193 | assert(id >= 0); 194 | cort_t * co = S->co[id]; 195 | cort_t *pco = S->co[co->pco]; 196 | co->status = CO_STATUS_SUSPEND; 197 | pco->status = CO_STATUS_RUNNING; 198 | S->running = co->pco; 199 | #ifdef USE_COCTX 200 | coctx_swap(&co->ctx ,&pco->ctx); 201 | #else 202 | swapcontext(&co->ctx ,&pco->ctx); 203 | #endif 204 | return 0; 205 | } 206 | 207 | int cort_status(cosched_t * S, int id) { 208 | assert(id>=0 && id < S->cap); 209 | if (S->co[id] == NULL) { 210 | return CO_STATUS_DEAD; 211 | } 212 | return S->co[id]->status; 213 | } 214 | 215 | int cort_running(cosched_t * S) { 216 | return S->running; 217 | } 218 | 219 | bool cort_ismain(int co) { 220 | return co == MAIN_CO_ID; 221 | } 222 | -------------------------------------------------------------------------------- /misc/co_wordfilter.c: -------------------------------------------------------------------------------- 1 | #include "co_wordfilter.h" 2 | #include "../src/co_vec.h" 3 | #include "../src/co_utf8.h" 4 | 5 | typedef struct cowf_node { 6 | covec_t *chvec; // 子结点数组 7 | int code; // 字符码 8 | bool isend; // 是否结束,从根到结束作为一个单词 9 | } cowf_node_t; 10 | 11 | typedef struct cowf { 12 | cowf_node_t *root; 13 | } cowf_t; 14 | 15 | static cowf_node_t* _cowf_new_node() { 16 | cowf_node_t *node = CO_MALLOC(sizeof(*node)); 17 | node->code = 0; 18 | node->isend = false; 19 | node->chvec = NULL; 20 | return node; 21 | } 22 | 23 | static void _cowf_free_node(cowf_node_t *node) { 24 | if (node->chvec) { 25 | int i; 26 | int len = covec_size(node->chvec); 27 | for (i = 0; i < len; ++i) { 28 | cowf_node_t *child = covec_get_tp(node->chvec, i, cowf_node_t*); 29 | _cowf_free_node(child); 30 | } 31 | node->chvec = covec_free(node->chvec); 32 | } 33 | CO_FREE(node); 34 | } 35 | 36 | void* cowf_new() { 37 | cowf_t *wf = CO_MALLOC(sizeof(*wf)); 38 | memset(wf, 0, sizeof(*wf)); 39 | return wf; 40 | } 41 | 42 | void* cowf_free(void *handle) { 43 | cowf_clear(handle); 44 | CO_FREE(handle); 45 | return NULL; 46 | } 47 | 48 | void cowf_clear(void *handle) { 49 | cowf_t *wf = handle; 50 | if (wf->root) { 51 | _cowf_free_node(wf->root); 52 | wf->root = NULL; 53 | } 54 | } 55 | 56 | bool cowf_loadwords(void *handle, const char *path) { 57 | FILE * f = fopen(path, "r"); 58 | if (f == NULL) return false; 59 | 60 | char word[256]; // 关键字最多支持这么长 61 | while (fgets(word, 256, f)) { 62 | int len = strlen(word) - 1; 63 | if (word[len] == '\n') 64 | word[len] = '\0'; 65 | if (len > 0) 66 | cowf_addword(handle, word); 67 | } 68 | fclose(f); 69 | return true; 70 | } 71 | 72 | static cowf_node_t* _cowf_find_child(cowf_node_t *parent, int code, int *index) { 73 | if (!parent->chvec) 74 | parent->chvec = covec_new(sizeof(cowf_node_t*)); 75 | // 先查找,如果找到直接返回 76 | int n = covec_size(parent->chvec); 77 | int mid = 0; 78 | int low = 0; 79 | int high = n-1; 80 | cowf_node_t *node = NULL; 81 | while (low <= high) { 82 | mid = (high + low) / 2; 83 | node = covec_get_tp(parent->chvec, mid, cowf_node_t*); 84 | if (code == node->code) { 85 | *index = mid; 86 | return node; 87 | } 88 | else if (code > node->code) 89 | low = mid + 1; 90 | else 91 | high = mid - 1; 92 | } 93 | // 找不到,返回可插入的位置 94 | *index = (!node || code < node->code) ? mid : mid + 1; 95 | return NULL; 96 | } 97 | 98 | 99 | static cowf_node_t* _cowf_insert_child(cowf_node_t *parent, int code) { 100 | int index; 101 | cowf_node_t*node = _cowf_find_child(parent, code, &index); 102 | // 如果找不到就插入到合适的位置 103 | if (!node) { 104 | node = _cowf_new_node(); 105 | node->code = code; 106 | covec_push(parent->chvec, index, &node); 107 | } 108 | return node; 109 | } 110 | 111 | void cowf_addword(void *handle, const char *word) { 112 | cowf_t *wf = handle; 113 | if (!wf->root) 114 | wf->root = _cowf_new_node(); 115 | 116 | cowf_node_t *parent = wf->root; 117 | cowf_node_t *child = NULL; 118 | int code; 119 | const char *p = word; 120 | while (*p) { 121 | p = coutf8_decode(p, &code); 122 | if (!p) { 123 | printf("cowf_addword: utf8 decode error: %s\n", p); 124 | break; 125 | } 126 | child = _cowf_insert_child(parent, code); 127 | parent = child; 128 | } 129 | if (child) 130 | child->isend = true; 131 | } 132 | 133 | // 取一个词word的最后子结点,如果取不到返回空 134 | static cowf_node_t* _cowf_get_lastchild(cowf_node_t *parent, const char *word) { 135 | cowf_node_t *child = NULL; 136 | int code, index; 137 | const char *p = word; 138 | while (*p) { 139 | p = coutf8_decode(p, &code); 140 | if (!p) return NULL; 141 | 142 | child = _cowf_find_child(parent, code, &index); 143 | if (!child) return NULL; 144 | 145 | parent = child; 146 | } 147 | return child; 148 | } 149 | 150 | bool cowf_exist(void *handle, const char *word) { 151 | cowf_t *wf = handle; 152 | if (!wf->root) return false; 153 | 154 | cowf_node_t *child = _cowf_get_lastchild(wf->root, word); 155 | return child && child->isend; 156 | } 157 | 158 | void cowf_delword(void *handle, const char *word) { 159 | // 只将词尾结点的isend设为false 160 | cowf_t *wf = handle; 161 | if (!wf->root) return; 162 | 163 | cowf_node_t *child = _cowf_get_lastchild(wf->root, word); 164 | if (child) 165 | child->isend = false; 166 | } 167 | 168 | // 检查是否匹配到关键字,如果没匹配到,返回NULL,如果匹配到,返回结尾指针 169 | static const char* _cowf_check_word(cowf_node_t *parent, const char *text) { 170 | cowf_node_t *child = NULL; 171 | int code, index; 172 | const char *p = text; 173 | while (*p) { 174 | p = coutf8_decode(p, &code); 175 | if (!p) return NULL; 176 | 177 | child = _cowf_find_child(parent, code, &index); 178 | if (!child) 179 | return NULL; 180 | else if (child->isend) 181 | return p; 182 | parent = child; 183 | } 184 | return NULL; 185 | } 186 | 187 | bool cowf_fitler(void *handle, char *text, char ch) { 188 | cowf_t *wf = handle; 189 | if (!wf->root) return false; 190 | 191 | bool result = false; 192 | int code; 193 | char *p = text; 194 | const char *e = NULL; 195 | while (*p) { 196 | e = _cowf_check_word(wf->root, p); 197 | if (e) { 198 | while (p != e) *p++ = ch; 199 | result = true; 200 | } else { 201 | p = (char*)coutf8_decode(p, &code); 202 | if (!p) break; 203 | } 204 | } 205 | return result; 206 | } 207 | 208 | bool cowf_check(void *handle, const char *text) { 209 | cowf_t *wf = handle; 210 | if (!wf->root) return false; 211 | 212 | int code; 213 | const char *p = text; 214 | const char *e = NULL; 215 | while (*p) { 216 | e = _cowf_check_word(wf->root, p); 217 | if (e) { 218 | return true; 219 | } 220 | p = coutf8_decode(p, &code); 221 | if (!p) break; 222 | } 223 | return false; 224 | } -------------------------------------------------------------------------------- /src/co_poll.h: -------------------------------------------------------------------------------- 1 | /** 2 | * epoll/kqueue 封装 3 | * by colin 4 | */ 5 | #ifndef __CO_EPOLL__ 6 | #define __CO_EPOLL__ 7 | 8 | #include "co_utils.h" 9 | #include 10 | #ifdef __linux__ 11 | # include 12 | #elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined (__NetBSD__) 13 | # include 14 | #else 15 | # error "platform not support" 16 | #endif 17 | 18 | #ifdef __cplusplus 19 | extern "C" { 20 | #endif 21 | //////////////////////////////////////////////////////////////////////////////////////////////////////// 22 | // 公共定义 23 | 24 | typedef struct copollevent { 25 | void *ud; 26 | bool read; 27 | bool write; 28 | bool error; 29 | } copollevent_t; 30 | 31 | typedef void (*fn_poll_t)(void *copoll, copollevent_t *ev, void *ud); 32 | 33 | //////////////////////////////////////////////////////////////////////////////////////////////////////// 34 | // linux 下使用epoll 35 | #ifdef __linux__ 36 | 37 | typedef struct copoll { 38 | int efd; 39 | int evnum; 40 | struct epoll_event *events; 41 | void *ud; 42 | } coepoll_t; 43 | 44 | static inline char* copoll_name() { 45 | return "epoll"; 46 | } 47 | 48 | static inline void* copoll_new() { 49 | coepoll_t *ep = (coepoll_t*)CO_MALLOC(sizeof(coepoll_t)); 50 | ep->efd = epoll_create(1024); 51 | ep->evnum = 512; 52 | ep->events = (struct epoll_event*)CO_CALLOC(ep->evnum, sizeof(struct epoll_event)); 53 | return ep; 54 | } 55 | 56 | static inline void* copoll_free(void *copoll) { 57 | coepoll_t *ep = (coepoll_t*)copoll; 58 | close(ep->efd); 59 | CO_FREE(ep->events); 60 | CO_FREE(ep); 61 | return NULL; 62 | } 63 | 64 | static inline void* copoll_userdata(void *copoll) { 65 | return ((coepoll_t*)copoll)->ud; 66 | } 67 | 68 | // 启动监听:默认开启读监听 69 | static inline int copoll_add(void *copoll, int fd, void *ud) { 70 | coepoll_t *ep = (coepoll_t*)copoll; 71 | struct epoll_event ev; 72 | ev.events = EPOLLIN; 73 | ev.data.ptr = ud; 74 | int ret = epoll_ctl(ep->efd, EPOLL_CTL_ADD, fd, &ev); 75 | return ret; 76 | } 77 | 78 | // 启动写监听 79 | static inline int copoll_request_write(void *copoll, int fd, void *ud, bool enable) { 80 | coepoll_t *ep = (coepoll_t*)copoll; 81 | struct epoll_event ev; 82 | ev.events = EPOLLIN | (enable ? EPOLLOUT : 0); 83 | ev.data.ptr = ud; 84 | return epoll_ctl(ep->efd, EPOLL_CTL_MOD, fd, &ev); 85 | } 86 | 87 | // 删除监听 88 | static inline int copoll_del(void *copoll, int fd) { 89 | coepoll_t *ep = (coepoll_t*)copoll; 90 | return epoll_ctl(ep->efd, EPOLL_CTL_DEL, fd , NULL); 91 | } 92 | 93 | // 等待事件到达 94 | static inline void copoll_wait(void *copoll, int timeout, fn_poll_t fn, void *ud) { 95 | assert(fn); 96 | coepoll_t *ep = (coepoll_t*)copoll; 97 | int n = epoll_wait(ep->efd , ep->events, ep->evnum, timeout); 98 | if (n > 0) { 99 | int i; 100 | copollevent_t cpev; 101 | struct epoll_event *ev; 102 | for (i = 0; i < n; ++i) { 103 | ev = ep->events + i; 104 | cpev.ud = ev->data.ptr; 105 | cpev.read = (ev->events & (EPOLLIN | EPOLLHUP)) != 0; 106 | cpev.write = (ev->events & EPOLLOUT) != 0; 107 | cpev.error = (ev->events & EPOLLERR) != 0; 108 | fn(copoll, &cpev, ud); 109 | } 110 | } 111 | } 112 | 113 | //////////////////////////////////////////////////////////////////////////////////////////////////////// 114 | // BSD 下使用kqueue 115 | #elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined (__NetBSD__) 116 | 117 | typedef struct cokqueue { 118 | int efd; 119 | int evnum; 120 | struct kevent *events; 121 | void *ud; 122 | } cokqueue_t; 123 | 124 | static inline char* copoll_name() { 125 | return "kqueue"; 126 | } 127 | 128 | static inline void* copoll_new() { 129 | cokqueue_t *ep = (cokqueue_t*)CO_MALLOC(sizeof(cokqueue_t)); 130 | ep->efd = kqueue(); 131 | ep->evnum = 512; 132 | ep->events = CO_CALLOC(ep->evnum, sizeof(struct kevent)); 133 | return ep; 134 | } 135 | 136 | static inline void* copoll_free(void *copoll) { 137 | cokqueue_t *ep = (cokqueue_t*)copoll; 138 | close(ep->efd); 139 | CO_FREE(ep->events); 140 | CO_FREE(ep); 141 | return NULL; 142 | } 143 | 144 | static inline void* copoll_userdata(void *copoll) { 145 | return ((cokqueue_t*)copoll)->ud; 146 | } 147 | 148 | // 删除监听 149 | static inline int copoll_del(void *copoll, int fd) { 150 | cokqueue_t *ep = (cokqueue_t*)copoll; 151 | struct kevent ke; 152 | EV_SET(&ke, fd, EVFILT_READ, EV_DELETE, 0, 0, NULL); 153 | kevent(ep->efd, &ke, 1, NULL, 0, NULL); 154 | EV_SET(&ke, fd, EVFILT_WRITE, EV_DELETE, 0, 0, NULL); 155 | kevent(ep->efd, &ke, 1, NULL, 0, NULL); 156 | return 0; 157 | } 158 | 159 | // 启动读监听 160 | static inline int copoll_add(void *copoll, int fd, void *ud) { 161 | cokqueue_t *ep = (cokqueue_t*)copoll; 162 | struct kevent ke; 163 | EV_SET(&ke, fd, EVFILT_READ, EV_ADD, 0, 0, ud); 164 | if (kevent(ep->efd, &ke, 1, NULL, 0, NULL) == -1 || ke.flags & EV_ERROR) { 165 | return -1; 166 | } 167 | EV_SET(&ke, fd, EVFILT_WRITE, EV_ADD, 0, 0, ud); 168 | if (kevent(ep->efd, &ke, 1, NULL, 0, NULL) == -1 || ke.flags & EV_ERROR) { 169 | EV_SET(&ke, fd, EVFILT_READ, EV_DELETE, 0, 0, NULL); 170 | kevent(ep->efd, &ke, 1, NULL, 0, NULL); 171 | return -1; 172 | } 173 | EV_SET(&ke, fd, EVFILT_WRITE, EV_DISABLE, 0, 0, ud); 174 | if (kevent(ep->efd, &ke, 1, NULL, 0, NULL) == -1 || ke.flags & EV_ERROR) { 175 | copoll_del(copoll, fd); 176 | return -1; 177 | } 178 | return 0; 179 | } 180 | 181 | // 启动写监听:默认开启读监听 182 | static inline int copoll_request_write(void *copoll, int fd, void *ud, bool enable) { 183 | cokqueue_t *ep = (cokqueue_t*)copoll; 184 | struct kevent ke; 185 | EV_SET(&ke, fd, EVFILT_WRITE, enable ? EV_ENABLE : EV_DISABLE, 0, 0, ud); 186 | if (kevent(ep->efd, &ke, 1, NULL, 0, NULL) == -1 || ke.flags & EV_ERROR) 187 | return -1; 188 | return 0; 189 | } 190 | 191 | // 等待事件到达 192 | static inline void copoll_wait(void *copoll, int timeout, fn_poll_t fn, void *ud) { 193 | assert(fn); 194 | cokqueue_t *ep = (cokqueue_t*)copoll; 195 | struct timespec to; 196 | struct timespec *pto; 197 | if (timeout < 0) { 198 | pto = NULL; 199 | } else { 200 | pto = &to; 201 | to.tv_sec = timeout / 1000; 202 | to.tv_nsec = (timeout % 1000) * 1000 * 1000; 203 | } 204 | int n = kevent(ep->efd, NULL, 0, ep->events, ep->evnum, pto); 205 | int i; 206 | copollevent_t cpev; 207 | struct kevent *ev; 208 | for (i = 0; i < n; ++i) { 209 | ev = ep->events + i; 210 | cpev.ud = ev->udata; 211 | cpev.read = (ev->filter & EVFILT_READ) != 0; 212 | cpev.write = (ev->filter & EVFILT_WRITE) != 0; 213 | cpev.error = (ev->flags & EV_ERROR) != 0; 214 | fn(copoll, &cpev, ud); 215 | } 216 | } 217 | 218 | #endif 219 | 220 | #ifdef __cplusplus 221 | } 222 | #endif 223 | #endif -------------------------------------------------------------------------------- /src/co_dict.c: -------------------------------------------------------------------------------- 1 | #include "co_dict.h" 2 | 3 | #define CODICT_INIT_SIZE 61 4 | #define CODICT_RESIZE_RADIO 0.75 5 | 6 | static void _check_and_resize(codict_t *dict) { 7 | static size_t s_bucketsizes[] = { 8 | 61, 113, 251, 509, 1021, 2039, 4093, 8191, 16381, 9 | 32749, 65521, 126727, 262063, 522713, 1046429, 10 | 2090867, 4186067, 8363639, 16777207, 33489353, 11 | }; 12 | static size_t s_bucketcount = sizeof(s_bucketsizes) / sizeof(s_bucketsizes[0]); 13 | if (dict->count >= dict->cap * CODICT_RESIZE_RADIO) { 14 | int i; 15 | int cap = s_bucketsizes[s_bucketcount-1]; 16 | for (i = 0; i < s_bucketcount; ++i) { 17 | if (s_bucketsizes[i] > dict->cap) { 18 | cap = s_bucketsizes[i]; 19 | break; 20 | } 21 | } 22 | dict->cap = cap; 23 | CO_FREE(dict->buckets); 24 | dict->buckets = CO_CALLOC(cap, sizeof(codict_node_t*)); 25 | codict_node_t *curr = dict->listhead; 26 | while (curr) { 27 | size_t idx = curr->hash % cap; 28 | curr->next = dict->buckets[idx]; 29 | dict->buckets[idx] = curr; 30 | curr = curr->listnext; 31 | } 32 | } 33 | } 34 | 35 | codict_t* codict_new(copfn_hash fn_hash, copfn_equal fn_equal, uint16_t keysz, uint16_t valsz) { 36 | assert(fn_hash); 37 | assert(fn_equal); 38 | codict_t *dict = CO_MALLOC(sizeof(*dict)); 39 | dict->cap = 0; 40 | dict->buckets = NULL; 41 | dict->count = 0; 42 | dict->fn_equal = fn_equal; 43 | dict->fn_hash = fn_hash; 44 | dict->listhead = NULL; 45 | dict->listtail = NULL; 46 | dict->keysz = keysz; 47 | dict->valsz = valsz; 48 | _check_and_resize(dict); 49 | return dict; 50 | } 51 | 52 | codict_node_t * codict_get(codict_t *dict, const void *key) { 53 | uint64_t hash = dict->fn_hash(key); 54 | size_t idx = hash % dict->cap; 55 | codict_node_t *node = dict->buckets[idx]; 56 | for (; node != NULL; node = node->next) 57 | if (node->hash == hash && dict->fn_equal(node->key, key)) 58 | break; 59 | return node; 60 | } 61 | 62 | codict_node_t* codict_set(codict_t *dict, const void *key, const void *val) { 63 | codict_node_t *node = codict_get(dict, key); 64 | if (node) { 65 | memcpy(node->value, val, dict->valsz); 66 | return node; 67 | } 68 | 69 | _check_and_resize(dict); 70 | 71 | uint64_t hash = dict->fn_hash(key); 72 | size_t idx = hash % dict->cap; 73 | node = CO_MALLOC(sizeof(codict_node_t) + dict->keysz + dict->valsz); 74 | node->next = dict->buckets[idx]; 75 | dict->buckets[idx] = node; 76 | node->hash = hash; 77 | node->key = ((char*)node + sizeof(codict_node_t)); 78 | memcpy(node->key, key, dict->keysz); 79 | node->value = ((char*)node + sizeof(codict_node_t) + dict->keysz); 80 | memcpy(node->value, val, dict->valsz); 81 | 82 | if (!dict->listhead) { 83 | dict->listhead = dict->listtail = node; 84 | node->listprev = node->listnext = NULL; 85 | } else { 86 | dict->listtail->listnext = node; 87 | node->listprev = dict->listtail; 88 | node->listnext = NULL; 89 | dict->listtail = node; 90 | } 91 | 92 | dict->count++; 93 | return node; 94 | } 95 | 96 | bool codict_del(codict_t *dict, const void *key) { 97 | uint64_t hash = dict->fn_hash(key); 98 | size_t idx = hash % dict->cap; 99 | codict_node_t *node = dict->buckets[idx]; 100 | codict_node_t *curr, *prev; 101 | for (curr = node; curr != NULL; prev = curr, curr = curr->next) { 102 | if (curr->hash == hash && dict->fn_equal(curr->key, key)) 103 | break; 104 | } 105 | if (!curr) 106 | return false; 107 | 108 | if (curr == node) 109 | dict->buckets[idx] = curr->next; 110 | else 111 | prev->next = curr->next; 112 | 113 | if (dict->listhead == curr) dict->listhead = curr->listnext; 114 | if (dict->listtail == curr) dict->listtail = curr->listprev; 115 | if (curr->listprev) 116 | curr->listprev->listnext = curr->listnext; 117 | if (curr->listnext) 118 | curr->listnext->listprev = curr->listprev; 119 | 120 | CO_FREE(curr); 121 | dict->count--; 122 | return true; 123 | } 124 | 125 | void codict_clear(codict_t *dict) { 126 | size_t i; 127 | codict_node_t *e, *t; 128 | for (i = 0; i < dict->cap; ++i) { 129 | e = dict->buckets[i]; 130 | while (e) { 131 | t = e->next; 132 | CO_FREE(e); 133 | e = t; 134 | } 135 | dict->buckets[i] = NULL; 136 | } 137 | dict->listhead = dict->listtail = NULL; 138 | dict->count = 0; 139 | } 140 | 141 | void* codict_free(codict_t *dict) { 142 | codict_clear(dict); 143 | CO_FREE(dict->buckets); 144 | CO_FREE(dict); 145 | return NULL; 146 | } 147 | 148 | void codict_move(codict_t *dict, codict_node_t *node, bool head) { 149 | if (head) { 150 | if (dict->listhead != node) { 151 | if (dict->listtail == node) 152 | dict->listtail = node->listprev; 153 | if (node->listprev) 154 | node->listprev->listnext = node->listnext; 155 | if (node->listnext) 156 | node->listnext->listprev = node->listprev; 157 | node->listprev = NULL; 158 | node->listnext = dict->listhead; 159 | dict->listhead->listprev = node; 160 | dict->listhead = node; 161 | } 162 | } else { 163 | if (dict->listtail != node) { 164 | if (dict->listhead == node) 165 | dict->listhead = node->listnext; 166 | if (node->listprev) 167 | node->listprev->listnext = node->listnext; 168 | if (node->listnext) 169 | node->listnext->listprev = node->listprev; 170 | node->listnext = NULL; 171 | node->listprev = dict->listtail; 172 | dict->listtail->listnext = node; 173 | dict->listtail = node; 174 | } 175 | } 176 | } 177 | 178 | //////////////////////////////////////////////////////////////////////////////// 179 | // 哈希函数: fnv1a64:https://github.com/devries/fnv1a 180 | static const uint64_t fnv64_prime = UINT64_C(1099511628211); 181 | static const uint64_t fnv64_offset = UINT64_C(14695981039346656037); 182 | static uint64_t codict_fnv1a64_hash(const void *key, size_t len) { 183 | uint8_t *pointer = (uint8_t *)key; 184 | uint8_t *buf_end = pointer + len; 185 | uint64_t hash = fnv64_offset; 186 | while(pointer < buf_end) { 187 | hash ^= (uint64_t)*pointer++; 188 | hash *= fnv64_prime; 189 | } 190 | return hash; 191 | } 192 | 193 | bool codict_str_equal(const void *key1, const void *key2) { 194 | const char *str1 = *(const char **)(key1); 195 | const char *str2 = *(const char **)(key2); 196 | return strcmp(str1, str2) == 0; 197 | } 198 | 199 | bool codict_int_equal(const void *key1, const void *key2) { 200 | return *(int*)key1 == *(int*)key2; 201 | } 202 | 203 | bool codict_ptr_equal(const void *key1, const void *key2) { 204 | return *(intptr_t*)key1 == *(intptr_t*)key2; 205 | } 206 | 207 | uint64_t codict_str_hash(const void *key) { 208 | const char *str = *(const char **)(key); 209 | int len = strlen(str); 210 | return codict_fnv1a64_hash(str, len); 211 | } 212 | 213 | uint64_t codict_int_hash(const void *key) { 214 | return *(int*)key; 215 | } 216 | 217 | uint64_t codict_ptr_hash(const void *key) { 218 | return *(uintptr_t*)key; 219 | } -------------------------------------------------------------------------------- /src/co_ioservice.h: -------------------------------------------------------------------------------- 1 | /** 2 | * io服务框架 3 | * by colin 4 | */ 5 | #ifndef __CO_IOSERVICE__ 6 | #define __CO_IOSERVICE__ 7 | #include "co_utils.h" 8 | #include "co_buffer.h" 9 | #include "co_vec.h" 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #ifdef __cplusplus 19 | extern "C" { 20 | #endif 21 | 22 | // 声明 23 | struct coloop; 24 | typedef struct coloop coloop_t; 25 | struct cotcp; 26 | typedef struct cotcp cotcp_t; 27 | struct coudp; 28 | typedef struct coudp coudp_t; 29 | struct cofd; 30 | typedef struct cofd cofd_t; 31 | struct coios; 32 | typedef struct coios coios_t; 33 | 34 | // 预留大小 35 | #define COTCP_SIZE 8192 36 | #define COUDP_SIZE 4096 37 | #define COFD_SIZE 1024 38 | 39 | // socket类型 40 | #define COIO_TCP 0 41 | #define COIO_UDP 1 42 | #define COIO_FD 2 43 | 44 | // IO基类 45 | typedef struct coio { 46 | int fd; // 文件fd 47 | uint8_t type; // 类型: COIO_TCP... 48 | uint8_t state; // 当前状态 49 | uint16_t recvsize; // 接受buff大小 50 | void *recvbuf; // 接受buff 51 | coios_t *ioservice; // IO service 52 | void *ud; // 用户数据 53 | } coio_t; 54 | 55 | ///////////////////////////////////////////////////////////////////////////////////////////////// 56 | // tcp 57 | // 连接事件,监听socket和连接socket都会触发 58 | // 如果是监听socket: tcp为新进来的socket 59 | // 如果是连接socket: tcp为连接成功的socket 60 | typedef void (*fn_tcp_connect_t)(coios_t *ss, cotcp_t* tcp); 61 | // 收到数据的事件 62 | typedef void (*fn_tcp_recv_t)(coios_t *ss, cotcp_t* tcp, const void *buff, int size); 63 | // 发生错误的事件 64 | typedef void (*fn_tcp_error_t)(coios_t *ss, cotcp_t* tcp, const char *msg); 65 | // 关闭事件 66 | typedef void (*fn_tcp_close_t)(coios_t *ss, cotcp_t* tcp); 67 | 68 | // tcp状态 69 | #define COTCP_INVALID 0 70 | #define COTCP_NEW 1 71 | #define COTCP_LISTEN 2 72 | #define COTCP_CONNECTING 3 73 | #define COTCP_CONNECTED 4 74 | #define COTCP_CLOSING 5 75 | 76 | // tcp对象 77 | typedef struct cotcp { 78 | int fd; // 文件fd 79 | uint8_t type; // 类型 80 | uint8_t state; // 当前状态 81 | uint16_t recvsize; // 接受buff大小 82 | void *recvbuf; // 接受buff 83 | coios_t *ioservice; // IO service 84 | void *ud; // 用户数据 85 | coringbuf_t *sendbuf; // 发送buff 86 | fn_tcp_connect_t fn_connect;// 各种事件 87 | fn_tcp_recv_t fn_recv; 88 | fn_tcp_error_t fn_error; 89 | fn_tcp_close_t fn_close; 90 | } cotcp_t; 91 | 92 | // 创建TCP监听socket,返回cotcp_t* 93 | cotcp_t* cotcp_listen(coios_t *ss, 94 | const char *ip, const char *port, void *ud, // ip, port, ud 95 | fn_tcp_connect_t fn_connect // 有新连接进来会回调 96 | ); 97 | // 连接远程服务器 98 | bool cotcp_connect(coios_t *ss, 99 | const char *ip, const char *port, void *ud, 100 | fn_tcp_connect_t fn_connect, // 连接成功会回调 101 | fn_tcp_error_t fn_error // 连接失败会回调 102 | ); 103 | // 发送数据 104 | bool cotcp_send(coios_t *ss, cotcp_t* tcp, const void *buff, int size); 105 | // 关闭socket, force为false表示等发送数据完了再关闭,为true则马上关闭 106 | bool cotcp_close(coios_t *ss, cotcp_t* tcp, bool force); 107 | // 注册错误事件 108 | bool cotcp_on_error(coios_t *ss, cotcp_t* tcp, fn_tcp_error_t fn); 109 | // 注册接收事件 110 | bool cotcp_on_recv(coios_t *ss, cotcp_t* tcp, fn_tcp_recv_t fn); 111 | // 注册关闭事件 112 | bool cotcp_on_close(coios_t *ss, cotcp_t* tcp, fn_tcp_close_t fn); 113 | 114 | 115 | ///////////////////////////////////////////////////////////////////////////////////////////////// 116 | // udp 117 | // 收到数据的事件: 118 | typedef void (*fn_udp_recv_t)(coios_t *ss, coudp_t* udp, const void *buff, int size, struct sockaddr *addr, socklen_t addrlen); 119 | // 发生错误的事件 120 | typedef void (*fn_udp_error_t)(coios_t *ss, coudp_t* udp, const char *msg); 121 | // 关闭事件 122 | typedef void (*fn_udp_close_t)(coios_t *ss, coudp_t* udp); 123 | 124 | // UDP缓存结点 125 | typedef struct udpbuffer { 126 | struct udpbuffer *next; // 下一个缓存 127 | struct sockaddr *addr; // 地址信息 128 | socklen_t addrlen; // 地址长度 129 | void *buffer; // 缓存 130 | char *ptr; // 当前未发送的缓存,buffer != ptr表示只发送了一部分 131 | int size; // 当前未发送的缓存大小 132 | } udpbuffer_t; 133 | 134 | // UDP缓存列表 135 | typedef struct udpsendlist { 136 | struct udpbuffer *head; 137 | struct udpbuffer *tail; 138 | } udpsendlist_t; 139 | 140 | // udp状态 141 | #define COUDP_INVALID 0 142 | #define COUDP_NEW 1 143 | #define COUDP_CLOSING 2 144 | 145 | // udp对象 146 | typedef struct coudp { 147 | int fd; // 文件fd 148 | uint8_t type; // 类型 149 | uint8_t state; // 当前状态 150 | uint16_t recvsize; // 接受buff大小 151 | void *recvbuf; // 接受buff 152 | coios_t *ioservice; // IO service 153 | void *ud; // 用户数据 154 | udpsendlist_t sendlist; // 发送列表 155 | fn_udp_recv_t fn_recv; 156 | fn_udp_error_t fn_error; 157 | fn_udp_close_t fn_close; 158 | } coudp_t; 159 | 160 | // 新建UDP对象, bindaddr指定是否绑定到一个地址上 161 | coudp_t* coudp_new(coios_t *ss, const char *ip, const char *port, void *ud, 162 | bool bindaddr, struct sockaddr *addr, socklen_t *addrlen); 163 | // 发送数据到一个地址 164 | bool coudp_send(coios_t *ss, coudp_t *udp, const void *buff, int size, struct sockaddr *addr, socklen_t addrlen); 165 | // 关闭UDP 166 | bool coudp_close(coios_t *ss, coudp_t *udp, bool force); 167 | // 注册错误事件 168 | bool coudp_on_error(coios_t *ss, coudp_t* udp, fn_udp_error_t fn); 169 | // 注册接收事件 170 | bool coudp_on_recv(coios_t *ss, coudp_t* udp, fn_udp_recv_t fn); 171 | // 注册关闭事件 172 | bool coudp_on_close(coios_t *ss, coudp_t* udp, fn_udp_close_t fn); 173 | 174 | 175 | ///////////////////////////////////////////////////////////////////////////////////////////////// 176 | // fd:用于绑定已有的FD对象 177 | // FD收到数据的事件 178 | typedef void (*fn_fd_recv_t)(coios_t *ss, cofd_t* fd, const void *buff, int size); 179 | typedef void (*fn_fd_error_t)(coios_t *ss, cofd_t* fd, const char *msg); 180 | typedef void (*fn_fd_close_t)(coios_t *ss, cofd_t* fd); 181 | 182 | // fd状态 183 | #define COFD_INVALID 0 184 | #define COFD_NEW 1 185 | #define COFD_BIND 2 186 | 187 | // 其他通用fd对象 188 | typedef struct cofd { 189 | int fd; // 文件fd 190 | uint8_t type; // 类型 191 | uint8_t state; // 当前状态 192 | uint16_t recvsize; // 接受buff大小 193 | void *recvbuf; // 接受buff 194 | coios_t *ioservice; // IO service 195 | void *ud; // 用户数据 196 | coringbuf_t *sendbuf; // 发送buff 197 | fn_fd_recv_t fn_recv; // 事件 198 | fn_fd_error_t fn_error; 199 | fn_fd_close_t fn_close; 200 | } cofd_t; 201 | 202 | // 绑定FD 203 | cofd_t* cofd_bind(coios_t *ss, int fd, void *ud); 204 | // 反绑FD 205 | bool cofd_unbind(coios_t *ss, cofd_t *fd); 206 | // 发送数据 207 | bool cofd_send(coios_t *ss, cofd_t *fd, void *buf, int size); 208 | // 注册错误事件 209 | bool cofd_on_error(coios_t *ss, cofd_t* fd, fn_fd_error_t fn); 210 | // 注册接收事件 211 | bool cofd_on_recv(coios_t *ss, cofd_t* fd, fn_fd_recv_t fn); 212 | // 注册关闭事件 213 | bool cofd_on_close(coios_t *ss, cofd_t* fd, fn_fd_close_t fn); 214 | 215 | 216 | ///////////////////////////////////////////////////////////////////////////////////////////////// 217 | // 异步IO服务 218 | typedef struct coios { 219 | coloop_t *loop; // 事件循环 220 | cotcp_t tcps[COTCP_SIZE]; // 预留的各种对象 221 | coudp_t udps[COUDP_SIZE]; 222 | cofd_t fds[COFD_SIZE]; 223 | uint32_t tcpid; // 当前分配的索引 224 | uint32_t udpid; 225 | uint32_t fdid; 226 | } coios_t; 227 | 228 | // socket服务初始化和释放 229 | coios_t* coios_new(coloop_t *loop); 230 | void* coios_free(coios_t *ss); 231 | // socket选项:无阻塞 232 | void coios_nonblocking(int fd); 233 | // 忽略信号 234 | int coios_ignsigpipe(); 235 | // 通过fd取地址字符串 236 | bool coios_getpeername(int fd, char *ip, int iplen, char *port, int portlen); 237 | // 通过addr取地址字符串,表现形式为:ip:port或[ipv6]:port 238 | bool coios_getaddrname(struct sockaddr *addr, socklen_t addrlen, char *ip, int iplen, char *port, int portlen); 239 | // 通过ip和port获得地址结构 240 | bool coios_getaddr(const char *ip, const char *port, socklen_t *addrlen, socklen_t *socklen); 241 | // TCP无迟延 242 | void cotcp_nodelay(int fd); 243 | 244 | #ifdef __cplusplus 245 | } 246 | #endif 247 | #endif -------------------------------------------------------------------------------- /src/co_routineex.c: -------------------------------------------------------------------------------- 1 | #include "co_routineex.h" 2 | 3 | cortenv_t* cortenv_new(coloop_t *loop, int stsize) { 4 | cortenv_t *env = CO_MALLOC(sizeof(cortenv_t)); 5 | env->loop = loop; 6 | env->sch = cort_open(stsize); 7 | return env; 8 | } 9 | 10 | void* cortenv_free(cortenv_t *env) { 11 | cort_close(env->sch); 12 | CO_FREE(env); 13 | return NULL; 14 | } 15 | 16 | static void _on_sleep_timer(cots_t *ts, void *th, void *ud1, void *ud2) { 17 | cortenv_t *env = (cortenv_t*)ud1; 18 | int co = (int)(intptr_t)ud2; 19 | cort_resume(env->sch, co); 20 | } 21 | 22 | ////////////////////////////////////////////////////////////////////////// 23 | // tcp 24 | 25 | void cort_sleep(cortenv_t *env, uint32_t ms) { 26 | int co = cort_running(env->sch); 27 | if (cort_ismain(co)) { 28 | fprintf(stderr, "The main coroutine can't sleep\n"); 29 | return; 30 | } 31 | cots_add_timer(env->loop->timeservice, ms, 0, _on_sleep_timer, env, (void*)(intptr_t)co); 32 | cort_yield(env->sch); 33 | } 34 | 35 | typedef struct tcpreaddata { 36 | bool error; 37 | bool close; 38 | int co; 39 | cobuffer_t *buff; 40 | cortenv_t *env; 41 | } tcpreaddata_t; 42 | 43 | void on_tcp_close(coios_t *ss, cotcp_t* tcp) { 44 | printf("on_tcp_close: %d\n", tcp->fd); 45 | tcpreaddata_t *data = (tcpreaddata_t*)tcp->ud; 46 | data->close = true; 47 | data->error = false; 48 | cort_resume(data->env->sch, data->co); 49 | } 50 | 51 | void on_tcp_error(coios_t *ss, cotcp_t* tcp, const char *msg) { 52 | fprintf(stderr, "on_tcp_error: %s\n", msg); 53 | tcpreaddata_t *data = (tcpreaddata_t*)tcp->ud; 54 | data->close = false; 55 | data->error = true; 56 | cort_resume(data->env->sch, data->co); 57 | } 58 | 59 | void on_tcp_recv(coios_t *ss, cotcp_t* tcp, const void *buff, int size) { 60 | tcpreaddata_t *data = (tcpreaddata_t*)tcp->ud; 61 | data->close = false; 62 | data->error = false; 63 | cobuffer_write(data->buff, buff, size); 64 | cort_resume(data->env->sch, data->co); 65 | } 66 | 67 | void cort_tcp_bind(cortenv_t *env, cotcp_t *tcp) { 68 | int co = cort_running(env->sch); 69 | if (cort_ismain(co)) { 70 | fprintf(stderr, "The main coroutine can't call cort_tcp_bind\n"); 71 | return; 72 | } 73 | cotcp_on_error(env->loop->ioserivce, tcp, on_tcp_error); 74 | cotcp_on_close(env->loop->ioserivce, tcp, on_tcp_close); 75 | cotcp_on_recv(env->loop->ioserivce, tcp, on_tcp_recv); 76 | } 77 | 78 | bool cort_tcp_read(cortenv_t *env, cotcp_t *tcp, cobuffer_t *buff) { 79 | int co = cort_running(env->sch); 80 | if (cort_ismain(co)) { 81 | fprintf(stderr, "The main coroutine can't call cort_tcp_read\n"); 82 | return false; 83 | } 84 | 85 | cobuffer_seek(buff, true, 0); 86 | tcpreaddata_t data = {false, false, co, buff, env}; 87 | tcp->ud = &data; 88 | cort_yield(env->sch); 89 | 90 | if (data.close || data.error) 91 | return false; 92 | else 93 | return true; 94 | } 95 | 96 | typedef struct tcpconndata { 97 | int co; 98 | cotcp_t *tcp; 99 | cortenv_t *env; 100 | } tcpconndata_t; 101 | 102 | static void on_tcp_connected(coios_t *ss, cotcp_t* tcp) { 103 | printf("connected succed\n"); 104 | tcpconndata_t *data = tcp->ud; 105 | data->tcp = tcp; 106 | cort_resume(data->env->sch, data->co); 107 | } 108 | 109 | static void on_tcp_connect_error(coios_t *ss, cotcp_t* tcp, const char *msg) { 110 | fprintf(stderr, "on_connect_error: %s\n", msg); 111 | tcpconndata_t *data = tcp->ud; 112 | cort_resume(data->env->sch, data->co); 113 | } 114 | 115 | cotcp_t* cort_tcp_connect(cortenv_t *env, const char *ip, const char *port) { 116 | int co = cort_running(env->sch); 117 | if (cort_ismain(co)) { 118 | fprintf(stderr, "The main coroutine can't call cort_tcp_read\n"); 119 | return false; 120 | } 121 | 122 | tcpconndata_t data = {co, NULL, env}; 123 | cotcp_connect(env->loop->ioserivce, ip, port, &data, on_tcp_connected, on_tcp_connect_error); 124 | cort_yield(env->sch); 125 | return data.tcp; 126 | } 127 | 128 | ////////////////////////////////////////////////////////////////////////// 129 | // udp 130 | 131 | typedef struct udpreaddata { 132 | bool error; 133 | bool close; 134 | int co; 135 | cobuffer_t *buff; 136 | cortenv_t *env; 137 | } udpreaddata_t; 138 | 139 | void on_udp_close(coios_t *ss, coudp_t* udp) { 140 | printf("on_udp_close: %d\n", udp->fd); 141 | udpreaddata_t *data = (udpreaddata_t*)udp->ud; 142 | data->close = true; 143 | data->error = false; 144 | cort_resume(data->env->sch, data->co); 145 | } 146 | 147 | void on_udp_error(coios_t *ss, coudp_t* udp, const char *msg) { 148 | fprintf(stderr, "on_udp_error: %s\n", msg); 149 | udpreaddata_t *data = (udpreaddata_t*)udp->ud; 150 | data->close = false; 151 | data->error = true; 152 | cort_resume(data->env->sch, data->co); 153 | } 154 | 155 | void on_udp_recv(coios_t *ss, coudp_t* udp, const void *buff, int size, struct sockaddr *addr, socklen_t addrlen) { 156 | udpreaddata_t *data = (udpreaddata_t*)udp->ud; 157 | data->close = false; 158 | data->error = false; 159 | cobuffer_write(data->buff, buff, size); 160 | cort_resume(data->env->sch, data->co); 161 | } 162 | 163 | void cort_udp_bind(cortenv_t *env, coudp_t *udp) { 164 | int co = cort_running(env->sch); 165 | if (cort_ismain(co)) { 166 | fprintf(stderr, "The main coroutine can't call cort_tcp_bind\n"); 167 | return; 168 | } 169 | coudp_on_error(env->loop->ioserivce, udp, on_udp_error); 170 | coudp_on_close(env->loop->ioserivce, udp, on_udp_close); 171 | coudp_on_recv(env->loop->ioserivce, udp, on_udp_recv); 172 | } 173 | 174 | bool cort_udp_read(cortenv_t *env, coudp_t *udp, cobuffer_t *buff) { 175 | int co = cort_running(env->sch); 176 | if (cort_ismain(co)) { 177 | fprintf(stderr, "The main coroutine can't call cort_fd_read\n"); 178 | return false; 179 | } 180 | 181 | cobuffer_seek(buff, true, 0); 182 | udpreaddata_t data = {false, false, co, buff, env}; 183 | udp->ud = &data; 184 | cort_yield(env->sch); 185 | 186 | if (data.close || data.error) 187 | return false; 188 | else 189 | return true; 190 | } 191 | 192 | ////////////////////////////////////////////////////////////////////////// 193 | // fd 194 | 195 | typedef struct fdreaddata { 196 | bool error; 197 | bool close; 198 | int co; 199 | cobuffer_t *buff; 200 | cortenv_t *env; 201 | } fdreaddata_t; 202 | 203 | void on_fd_close(coios_t *ss, cofd_t* fd) { 204 | printf("on_fd_close: %d\n", fd->fd); 205 | fdreaddata_t *data = (fdreaddata_t*)fd->ud; 206 | data->close = true; 207 | data->error = false; 208 | cort_resume(data->env->sch, data->co); 209 | } 210 | 211 | void on_fd_error(coios_t *ss, cofd_t* fd, const char *msg) { 212 | fprintf(stderr, "on_fd_error: %s\n", msg); 213 | fdreaddata_t *data = (fdreaddata_t*)fd->ud; 214 | data->close = false; 215 | data->error = true; 216 | cort_resume(data->env->sch, data->co); 217 | } 218 | 219 | void on_fd_recv(coios_t *ss, cofd_t* fd, const void *buff, int size) { 220 | fdreaddata_t *data = (fdreaddata_t*)fd->ud; 221 | data->close = false; 222 | data->error = false; 223 | cobuffer_write(data->buff, buff, size); 224 | cort_resume(data->env->sch, data->co); 225 | } 226 | 227 | 228 | void cort_fd_bind(cortenv_t *env, cofd_t *fd) { 229 | int co = cort_running(env->sch); 230 | if (cort_ismain(co)) { 231 | fprintf(stderr, "The main coroutine can't call cort_tcp_bind\n"); 232 | return; 233 | } 234 | cofd_on_error(env->loop->ioserivce, fd, on_fd_error); 235 | cofd_on_close(env->loop->ioserivce, fd, on_fd_close); 236 | cofd_on_recv(env->loop->ioserivce, fd, on_fd_recv); 237 | } 238 | 239 | bool cort_fd_read(cortenv_t *env, cofd_t *fd, cobuffer_t *buff) { 240 | int co = cort_running(env->sch); 241 | if (cort_ismain(co)) { 242 | fprintf(stderr, "The main coroutine can't call cort_fd_read\n"); 243 | return false; 244 | } 245 | 246 | cobuffer_seek(buff, true, 0); 247 | fdreaddata_t data = {false, false, co, buff, env}; 248 | fd->ud = &data; 249 | cort_yield(env->sch); 250 | 251 | if (data.close || data.error) 252 | return false; 253 | else 254 | return true; 255 | } 256 | -------------------------------------------------------------------------------- /src/co_buffer.c: -------------------------------------------------------------------------------- 1 | #include "co_buffer.h" 2 | #include "co_endian.h" 3 | 4 | #define MIN_BUFF_SIZE 32 5 | 6 | void coprintfbuffer(const void *buffer, int size, int blocksize) { 7 | int i, j; 8 | int p = 0; 9 | const uint8_t *s = (const uint8_t*)buffer; 10 | while (1) { 11 | for (i = 0; i < 80; ++i) { 12 | for (j = 0; j < blocksize; ++j) { 13 | if (p >= size) { 14 | printf("\n"); 15 | return; 16 | } 17 | printf("%.2X", s[p++]); 18 | } 19 | printf(" "); 20 | } 21 | printf("\n"); 22 | } 23 | } 24 | 25 | cobuffer_t* cobuffer_new(const char *buffer, int bufsz, cb_endian_t endian) { 26 | cobuffer_t* bf = CO_MALLOC(sizeof(*bf)); 27 | int size = CO_MAX(bufsz, MIN_BUFF_SIZE); 28 | bf->buffer = CO_MALLOC(size); 29 | bf->size = size; 30 | bf->pos = 0; 31 | bf->endian = endian; 32 | if (buffer && bufsz) 33 | cobuffer_write(bf, buffer, bufsz); 34 | return bf; 35 | } 36 | 37 | void* cobuffer_free(cobuffer_t *bf) { 38 | CO_FREE(bf->buffer); 39 | CO_FREE(bf); 40 | return NULL; 41 | } 42 | 43 | int cobuffer_seek(cobuffer_t *bf, bool abs, int pos) { 44 | if (!abs) 45 | pos += bf->pos; 46 | else if (pos < 0) 47 | pos = bf->size - pos; 48 | bf->pos = CO_CLAMP(pos, 0, bf->size-1); 49 | return bf->pos; 50 | } 51 | 52 | int8_t cobuffer_read_int8(cobuffer_t *bf, bool *succ) { 53 | int8_t v; 54 | *succ = cobuffer_read(bf, &v, sizeof(int8_t)); 55 | return v; 56 | } 57 | 58 | uint8_t cobuffer_read_uint8(cobuffer_t *bf, bool *succ) { 59 | uint8_t v; 60 | *succ = cobuffer_read(bf, &v, sizeof(uint8_t)); 61 | return v; 62 | } 63 | 64 | int16_t cobuffer_read_int16(cobuffer_t *bf, bool *succ) { 65 | int16_t v; 66 | *succ = cobuffer_read(bf, &v, sizeof(int16_t)); 67 | if (*succ) { 68 | if (bf->endian == CB_EN_LITTLE) 69 | v = le16toh(v); 70 | else if (bf->endian == CB_EN_BIG) 71 | v = be16toh(v); 72 | } 73 | return v; 74 | } 75 | 76 | uint16_t cobuffer_read_uint16(cobuffer_t *bf, bool *succ) { 77 | uint16_t v; 78 | *succ = cobuffer_read(bf, &v, sizeof(uint16_t)); 79 | if (*succ) { 80 | if (bf->endian == CB_EN_LITTLE) 81 | v = le16toh(v); 82 | else if (bf->endian == CB_EN_BIG) 83 | v = be16toh(v); 84 | } 85 | return v; 86 | } 87 | 88 | int32_t cobuffer_read_int32(cobuffer_t *bf, bool *succ) { 89 | int32_t v; 90 | *succ = cobuffer_read(bf, &v, sizeof(int32_t)); 91 | if (*succ) { 92 | if (bf->endian == CB_EN_LITTLE) 93 | v = le32toh(v); 94 | else if (bf->endian == CB_EN_BIG) 95 | v = be32toh(v); 96 | } 97 | return v; 98 | } 99 | 100 | uint32_t cobuffer_read_uint32(cobuffer_t *bf, bool *succ) { 101 | uint32_t v; 102 | *succ = cobuffer_read(bf, &v, sizeof(uint32_t)); 103 | if (*succ) { 104 | if (bf->endian == CB_EN_LITTLE) 105 | v = le32toh(v); 106 | else if (bf->endian == CB_EN_BIG) 107 | v = be32toh(v); 108 | } 109 | return v; 110 | } 111 | 112 | int64_t cobuffer_read_int64(cobuffer_t *bf, bool *succ) { 113 | int64_t v; 114 | *succ = cobuffer_read(bf, &v, sizeof(int64_t)); 115 | if (*succ) { 116 | if (bf->endian == CB_EN_LITTLE) 117 | v = le64toh(v); 118 | else if (bf->endian == CB_EN_BIG) 119 | v = be64toh(v); 120 | } 121 | return v; 122 | 123 | } 124 | 125 | uint64_t cobuffer_read_uint64(cobuffer_t *bf, bool *succ) { 126 | uint64_t v; 127 | *succ = cobuffer_read(bf, &v, sizeof(uint64_t)); 128 | if (*succ) { 129 | if (bf->endian == CB_EN_LITTLE) 130 | v = le64toh(v); 131 | else if (bf->endian == CB_EN_BIG) 132 | v = be64toh(v); 133 | } 134 | return v; 135 | } 136 | 137 | float cobuffer_read_float32(cobuffer_t *bf, bool *succ) { 138 | float v; 139 | *succ = cobuffer_read(bf, &v, sizeof(float)); 140 | if (*succ) { 141 | if (bf->endian == CB_EN_LITTLE) 142 | v = le32tohf(v); 143 | else if (bf->endian == CB_EN_BIG) 144 | v = be32tohf(v); 145 | } 146 | return v; 147 | } 148 | 149 | double cobuffer_read_float64(cobuffer_t *bf, bool *succ) { 150 | double v; 151 | *succ = cobuffer_read(bf, &v, sizeof(double)); 152 | if (*succ) { 153 | if (bf->endian == CB_EN_LITTLE) 154 | v = le64tohf(v); 155 | else if (bf->endian == CB_EN_BIG) 156 | v = be64tohf(v); 157 | } 158 | return v; 159 | } 160 | 161 | bool cobuffer_read(cobuffer_t *bf, void *buffer, int size) { 162 | if (bf->pos + size <= bf->size) { 163 | memcpy(buffer, (char*)bf->buffer+bf->pos, size); 164 | bf->pos += size; 165 | return true; 166 | } 167 | return false; 168 | } 169 | 170 | static inline void _wb_check_and_grow(cobuffer_t *bf, int size) { 171 | if (bf->pos + size > bf->size) { 172 | int newsize = CO_MAX(bf->pos + size, bf->size * 2); 173 | bf->buffer = CO_REALLOC(bf->buffer, newsize); 174 | bf->size = newsize; 175 | } 176 | } 177 | 178 | void cobuffer_write_int8(cobuffer_t *bf, int8_t v) { 179 | cobuffer_write(bf, &v, sizeof(int8_t)); 180 | } 181 | 182 | void cobuffer_write_uint8(cobuffer_t *bf, uint8_t v) { 183 | cobuffer_write(bf, &v, sizeof(uint8_t)); 184 | } 185 | 186 | void cobuffer_write_int16(cobuffer_t *bf, int16_t v) { 187 | if (bf->endian == CB_EN_LITTLE) 188 | v = htole16(v); 189 | else if (bf->endian == CB_EN_BIG) 190 | v = htobe16(v); 191 | cobuffer_write(bf, &v, sizeof(int16_t)); 192 | } 193 | 194 | void cobuffer_write_uint16(cobuffer_t *bf, uint16_t v) { 195 | if (bf->endian == CB_EN_LITTLE) 196 | v = htole16(v); 197 | else if (bf->endian == CB_EN_BIG) 198 | v = htobe16(v); 199 | cobuffer_write(bf, &v, sizeof(uint16_t)); 200 | } 201 | 202 | void cobuffer_write_int32(cobuffer_t *bf, int32_t v) { 203 | if (bf->endian == CB_EN_LITTLE) 204 | v = htole32(v); 205 | else if (bf->endian == CB_EN_BIG) 206 | v = htobe32(v); 207 | cobuffer_write(bf, &v, sizeof(int32_t)); 208 | } 209 | 210 | void cobuffer_write_uint32(cobuffer_t *bf, uint32_t v) { 211 | if (bf->endian == CB_EN_LITTLE) 212 | v = htole32(v); 213 | else if (bf->endian == CB_EN_BIG) 214 | v = htobe32(v); 215 | cobuffer_write(bf, &v, sizeof(uint32_t)); 216 | } 217 | 218 | void cobuffer_write_int64(cobuffer_t *bf, int64_t v) { 219 | if (bf->endian == CB_EN_LITTLE) 220 | v = htole64(v); 221 | else if (bf->endian == CB_EN_BIG) 222 | v = htobe64(v); 223 | cobuffer_write(bf, &v, sizeof(int64_t)); 224 | } 225 | 226 | void cobuffer_write_uint64(cobuffer_t *bf, uint64_t v) { 227 | if (bf->endian == CB_EN_LITTLE) 228 | v = htole64(v); 229 | else if (bf->endian == CB_EN_BIG) 230 | v = htobe64(v); 231 | cobuffer_write(bf, &v, sizeof(uint64_t)); 232 | } 233 | 234 | void cobuffer_write_float32(cobuffer_t *bf, float v) { 235 | if (bf->endian == CB_EN_LITTLE) 236 | v = htole32f(v); 237 | else if (bf->endian == CB_EN_BIG) 238 | v = htobe32f(v); 239 | cobuffer_write(bf, &v, sizeof(float)); 240 | } 241 | 242 | void cobuffer_write_float64(cobuffer_t *bf, double v) { 243 | if (bf->endian == CB_EN_LITTLE) 244 | v = htole64f(v); 245 | else if (bf->endian == CB_EN_BIG) 246 | v = htobe64f(v); 247 | cobuffer_write(bf, &v, sizeof(double)); 248 | } 249 | 250 | void cobuffer_write(cobuffer_t *bf, const void *buffer, int size) { 251 | _wb_check_and_grow(bf, size); 252 | if (buffer) 253 | memcpy((char*)bf->buffer+bf->pos, buffer, size); 254 | bf->pos += size; 255 | } 256 | 257 | coringbuf_t* coringbuf_new(int initsize) { 258 | coringbuf_t *rb = CO_MALLOC(sizeof(*rb)); 259 | rb->size = initsize; 260 | rb->head = 0; 261 | rb->tail = 0; 262 | rb->buffer = CO_MALLOC(initsize); 263 | return rb; 264 | } 265 | 266 | void* coringbuf_free(coringbuf_t *rb) { 267 | CO_FREE(rb->buffer); 268 | CO_FREE(rb); 269 | return NULL; 270 | } 271 | 272 | int coringbuf_read(coringbuf_t *rb, void *buffer, int size) { 273 | int readable = coringbuf_readable_size(rb); 274 | size = readable >= size ? size : readable; 275 | int readonce = coringbuf_readonce_size(rb); 276 | int len = CO_MIN(size, readonce); 277 | memcpy(buffer, (uint8_t*)rb->buffer + rb->head, len); 278 | if (size > len) 279 | memcpy((uint8_t*)buffer + len, rb->buffer, size-len); 280 | rb->head = (rb->head + size) % rb->size; 281 | return size; 282 | } 283 | 284 | static inline void _cb_check_and_grow(coringbuf_t *rb, int size) { 285 | int readable = coringbuf_readable_size(rb); 286 | int writable = rb->size - readable; 287 | if (writable <= size) { 288 | int newsize = CO_MAX(rb->size * 2, readable + size + 1); 289 | rb->buffer = CO_REALLOC(rb->buffer, newsize); 290 | if (rb->tail < rb->head) { 291 | int readonce = coringbuf_readonce_size(rb); 292 | memmove((uint8_t*)rb->buffer + newsize - readonce, (uint8_t*)rb->buffer + rb->head, readonce); 293 | rb->head = newsize - readonce; 294 | } 295 | rb->size = newsize; 296 | } 297 | } 298 | 299 | void coringbuf_write(coringbuf_t *rb, const void *buffer, int size) { 300 | _cb_check_and_grow(rb, size); 301 | int len = CO_MIN(size, rb->size - rb->tail); 302 | memcpy((uint8_t*)rb->buffer + rb->tail, buffer, len); 303 | if (size > len) 304 | memcpy((uint8_t*)rb->buffer, (uint8_t*)buffer + len, size - len); 305 | rb->tail = (rb->tail + size) % rb->size; 306 | } 307 | 308 | void *coringbuf_head(coringbuf_t *rb) { 309 | return (uint8_t*)rb->buffer + rb->head; 310 | } 311 | 312 | int coringbuf_readable_size(coringbuf_t *rb) { 313 | if (rb->tail >= rb->head) 314 | return rb->tail - rb->head; 315 | else 316 | return rb->size - (rb->head - rb->tail); 317 | } 318 | 319 | int coringbuf_readonce_size(coringbuf_t *rb) { 320 | if (rb->tail >= rb->head) 321 | return rb->tail - rb->head; 322 | else 323 | return rb->size - rb->head; 324 | } 325 | 326 | bool coringbuf_consume_size(coringbuf_t *rb, int size) { 327 | int readable = coringbuf_readable_size(rb); 328 | if (readable >= size) { 329 | rb->head = (rb->head + size) % rb->size; 330 | return true; 331 | } 332 | return false; 333 | } -------------------------------------------------------------------------------- /test/test_set.c: -------------------------------------------------------------------------------- 1 | #include "../src/co_set.h" 2 | 3 | ///////////////////////////////////////////////////////////////////////////////////////////////// 4 | // 绘制二叉树 5 | // printing tree in ascii 6 | 7 | typedef struct asciinode_struct asciinode; 8 | 9 | struct asciinode_struct { 10 | asciinode *left, *right; 11 | 12 | // length of the edge from this node to its children 13 | int edge_length; 14 | 15 | int height; 16 | 17 | int lablen; 18 | 19 | //-1=I am left, 0=I am root, 1=right 20 | int parent_dir; 21 | 22 | // max supported unit32 in dec, 10 digits max 23 | char label[11]; 24 | }; 25 | 26 | #define MAX_HEIGHT 1000 27 | int lprofile[MAX_HEIGHT]; 28 | int rprofile[MAX_HEIGHT]; 29 | #define INFINITY (1 << 20) 30 | 31 | // adjust gap between left and right nodes 32 | int gap = 3; 33 | 34 | // used for printing next node in the same level, 35 | // this is the x coordinate of the next char printed 36 | int print_next; 37 | 38 | int MIN(int X, int Y) { return ((X) < (Y)) ? (X) : (Y); } 39 | 40 | int MAX(int X, int Y) { return ((X) > (Y)) ? (X) : (Y); } 41 | 42 | asciinode *build_ascii_tree_recursive(coset_t *tree, coset_node_t *t) { 43 | asciinode *node; 44 | 45 | if (t == coset_nil(tree)) return NULL; 46 | 47 | node = malloc(sizeof(asciinode)); 48 | node->left = build_ascii_tree_recursive(tree, t->left); 49 | node->right = build_ascii_tree_recursive(tree, t->right); 50 | 51 | if (node->left != NULL) { 52 | node->left->parent_dir = -1; 53 | } 54 | 55 | if (node->right != NULL) { 56 | node->right->parent_dir = 1; 57 | } 58 | 59 | sprintf(node->label, "%d(%d)", coset_data(t, int), t->color); 60 | node->lablen = strlen(node->label); 61 | 62 | return node; 63 | } 64 | 65 | // Copy the tree into the ascii node structre 66 | asciinode *build_ascii_tree(coset_t *tree, coset_node_t *t) { 67 | asciinode *node; 68 | if (t == NULL) return NULL; 69 | node = build_ascii_tree_recursive(tree, t); 70 | node->parent_dir = 0; 71 | return node; 72 | } 73 | 74 | // Free all the nodes of the given tree 75 | void free_ascii_tree(asciinode *node) { 76 | if (node == NULL) return; 77 | free_ascii_tree(node->left); 78 | free_ascii_tree(node->right); 79 | free(node); 80 | } 81 | 82 | // The following function fills in the lprofile array for the given tree. 83 | // It assumes that the center of the label of the root of this tree 84 | // is located at a position (x,y). It assumes that the edge_length 85 | // fields have been computed for this tree. 86 | void compute_lprofile(asciinode *node, int x, int y) { 87 | int i, isleft; 88 | if (node == NULL) return; 89 | isleft = (node->parent_dir == -1); 90 | lprofile[y] = MIN(lprofile[y], x - ((node->lablen - isleft) / 2)); 91 | if (node->left != NULL) { 92 | for (i = 1; i <= node->edge_length && y + i < MAX_HEIGHT; i++) { 93 | lprofile[y + i] = MIN(lprofile[y + i], x - i); 94 | } 95 | } 96 | compute_lprofile(node->left, x - node->edge_length - 1, 97 | y + node->edge_length + 1); 98 | compute_lprofile(node->right, x + node->edge_length + 1, 99 | y + node->edge_length + 1); 100 | } 101 | 102 | void compute_rprofile(asciinode *node, int x, int y) { 103 | int i, notleft; 104 | if (node == NULL) return; 105 | notleft = (node->parent_dir != -1); 106 | rprofile[y] = MAX(rprofile[y], x + ((node->lablen - notleft) / 2)); 107 | if (node->right != NULL) { 108 | for (i = 1; i <= node->edge_length && y + i < MAX_HEIGHT; i++) { 109 | rprofile[y + i] = MAX(rprofile[y + i], x + i); 110 | } 111 | } 112 | compute_rprofile(node->left, x - node->edge_length - 1, 113 | y + node->edge_length + 1); 114 | compute_rprofile(node->right, x + node->edge_length + 1, 115 | y + node->edge_length + 1); 116 | } 117 | 118 | // This function fills in the edge_length and 119 | // height fields of the specified tree 120 | void compute_edge_lengths(asciinode *node) { 121 | int h, hmin, i, delta; 122 | if (node == NULL) return; 123 | compute_edge_lengths(node->left); 124 | compute_edge_lengths(node->right); 125 | 126 | /* first fill in the edge_length of node */ 127 | if (node->right == NULL && node->left == NULL) { 128 | node->edge_length = 0; 129 | } else { 130 | if (node->left != NULL) { 131 | for (i = 0; i < node->left->height && i < MAX_HEIGHT; i++) { 132 | rprofile[i] = -INFINITY; 133 | } 134 | compute_rprofile(node->left, 0, 0); 135 | hmin = node->left->height; 136 | } else { 137 | hmin = 0; 138 | } 139 | if (node->right != NULL) { 140 | for (i = 0; i < node->right->height && i < MAX_HEIGHT; i++) { 141 | lprofile[i] = INFINITY; 142 | } 143 | compute_lprofile(node->right, 0, 0); 144 | hmin = MIN(node->right->height, hmin); 145 | } else { 146 | hmin = 0; 147 | } 148 | delta = 4; 149 | for (i = 0; i < hmin; i++) { 150 | delta = MAX(delta, gap + 1 + rprofile[i] - lprofile[i]); 151 | } 152 | 153 | // If the node has two children of height 1, then we allow the 154 | // two leaves to be within 1, instead of 2 155 | if (((node->left != NULL && node->left->height == 1) || 156 | (node->right != NULL && node->right->height == 1)) && 157 | delta > 4) { 158 | delta--; 159 | } 160 | 161 | node->edge_length = ((delta + 1) / 2) - 1; 162 | } 163 | 164 | // now fill in the height of node 165 | h = 1; 166 | if (node->left != NULL) { 167 | h = MAX(node->left->height + node->edge_length + 1, h); 168 | } 169 | if (node->right != NULL) { 170 | h = MAX(node->right->height + node->edge_length + 1, h); 171 | } 172 | node->height = h; 173 | } 174 | 175 | // This function prints the given level of the given tree, assuming 176 | // that the node has the given x cordinate. 177 | void print_level(asciinode *node, int x, int level) { 178 | int i, isleft; 179 | if (node == NULL) return; 180 | isleft = (node->parent_dir == -1); 181 | if (level == 0) { 182 | for (i = 0; i < (x - print_next - ((node->lablen - isleft) / 2)); i++) { 183 | printf(" "); 184 | } 185 | print_next += i; 186 | printf("%s", node->label); 187 | print_next += node->lablen; 188 | } else if (node->edge_length >= level) { 189 | if (node->left != NULL) { 190 | for (i = 0; i < (x - print_next - (level)); i++) { 191 | printf(" "); 192 | } 193 | print_next += i; 194 | printf("/"); 195 | print_next++; 196 | } 197 | if (node->right != NULL) { 198 | for (i = 0; i < (x - print_next + (level)); i++) { 199 | printf(" "); 200 | } 201 | print_next += i; 202 | printf("\\"); 203 | print_next++; 204 | } 205 | } else { 206 | print_level(node->left, x - node->edge_length - 1, 207 | level - node->edge_length - 1); 208 | print_level(node->right, x + node->edge_length + 1, 209 | level - node->edge_length - 1); 210 | } 211 | } 212 | 213 | // prints ascii tree for given coset_node_t structure 214 | void print_ascii_tree(coset_t *tree, coset_node_t *t) { 215 | asciinode *proot; 216 | int xmin, i; 217 | if (t == coset_nil(tree)) return; 218 | proot = build_ascii_tree(tree, t); 219 | compute_edge_lengths(proot); 220 | for (i = 0; i < proot->height && i < MAX_HEIGHT; i++) { 221 | lprofile[i] = INFINITY; 222 | } 223 | compute_lprofile(proot, 0, 0); 224 | xmin = 0; 225 | for (i = 0; i < proot->height && i < MAX_HEIGHT; i++) { 226 | xmin = MIN(xmin, lprofile[i]); 227 | } 228 | for (i = 0; i < proot->height; i++) { 229 | print_next = 0; 230 | print_level(proot, -xmin, i); 231 | printf("\n"); 232 | } 233 | if (proot->height >= MAX_HEIGHT) { 234 | printf("(This tree is taller than %d, and may be drawn incorrectly.)\n", 235 | MAX_HEIGHT); 236 | } 237 | free_ascii_tree(proot); 238 | } 239 | 240 | // 绘制二叉树 241 | void draw_set(coset_t *tree) { 242 | print_ascii_tree(tree, tree->root); 243 | printf("\n"); 244 | } 245 | ///////////////////////////////////////////////////////////////////////////////////////////////// 246 | 247 | static int compare1(void *ud, const void *item1, const void *item2) { 248 | int v1 = *((int*)item1); 249 | int v2 = *((int*)item2); 250 | return v1 - v2; 251 | } 252 | 253 | void print_set(coset_t *set) { 254 | coset_node_t *node = coset_end(set); 255 | while (node) { 256 | printf("%d ", coset_data(node, int)); 257 | node = coset_prev(set, node); 258 | } 259 | printf("\n"); 260 | } 261 | 262 | void test1() { 263 | // 随机增加,和随机删除 264 | coset_t *set = coset_new(sizeof(int), compare1, NULL); 265 | int i; 266 | for (i = 0; i < 20; ++i) { 267 | int v = co_randrange(0, 100); 268 | coset_add(set, &v); 269 | } 270 | 271 | 272 | for (i = 0; i < 20; ++i) { 273 | int v = co_randrange(0, 100); 274 | coset_delete(set, &v); 275 | } 276 | draw_set(set); 277 | print_set(set); 278 | printf("set size=%d\n", coset_size(set)); 279 | coset_free(set); 280 | } 281 | 282 | void test2() { 283 | // 集合操作 284 | coset_t *set = coset_new(sizeof(int), compare1, NULL); 285 | coset_t *set2 = coset_new(sizeof(int), compare1, NULL); 286 | 287 | coset_add_tp(set, 35, int); 288 | coset_add_tp(set, 48, int); 289 | coset_add_tp(set, 21, int); 290 | coset_add_tp(set, 17, int); 291 | coset_add_tp(set, 89, int); 292 | coset_add_tp(set, 50, int); 293 | draw_set(set); 294 | coset_add_tp(set2, 35, int); 295 | coset_add_tp(set2, 49, int); 296 | coset_add_tp(set2, 20, int); 297 | coset_add_tp(set2, 17, int); 298 | coset_add_tp(set2, 56, int); 299 | coset_add_tp(set2, 52, int); 300 | draw_set(set2); 301 | 302 | coset_intersect(set, set2); 303 | draw_set(set); 304 | 305 | coset_union(set, set2); 306 | draw_set(set); 307 | 308 | coset_minus(set, set2); 309 | draw_set(set); 310 | 311 | coset_add_tp(set, 35, int); 312 | coset_add_tp(set, 48, int); 313 | coset_add_tp(set, 21, int); 314 | coset_add_tp(set, 17, int); 315 | coset_add_tp(set, 89, int); 316 | coset_add_tp(set, 50, int); 317 | draw_set(set); 318 | 319 | printf("set size=%d\n", coset_size(set)); 320 | int v = 20; 321 | printf("data=%d, exist=%d\n", v, coset_exist(set, &v)); 322 | v = 21; 323 | printf("data=%d, exist=%d\n", v, coset_exist(set, &v)); 324 | v = 50; 325 | printf("data=%d, exist=%d\n", v, coset_exist(set, &v)); 326 | v = 30; 327 | printf("data=%d, exist=%d\n", v, coset_exist(set, &v)); 328 | 329 | coset_free(set); 330 | coset_free(set2); 331 | } 332 | 333 | int main(int argc, char const *argv[]) 334 | { 335 | srand(time(NULL)); 336 | test1(); 337 | test2(); 338 | return 0; 339 | } 340 | -------------------------------------------------------------------------------- /src/co_set.c: -------------------------------------------------------------------------------- 1 | #include "co_set.h" 2 | 3 | // 空结点 4 | coset_node_t* coset_nil(coset_t *set) { 5 | return set->nil; 6 | } 7 | 8 | coset_t* coset_new(uint16_t datasize, coset_comp_t fn, void *ud) { 9 | assert(fn); 10 | coset_t *set = CO_MALLOC(sizeof(*set)); 11 | memset(set, 0, sizeof(coset_t)); 12 | set->nilnode.color = 1; // 空结点是黑色的 13 | set->nil = &set->nilnode; // 指向空结点 14 | set->root = set->nil; 15 | set->root->parent = set->nil; 16 | set->fn_comp = fn; 17 | set->ud = ud; 18 | set->datasize = datasize; 19 | set->size = 0; 20 | return set; 21 | } 22 | 23 | void* coset_free(coset_t *set) { 24 | coset_clear(set); 25 | CO_FREE(set); 26 | return NULL; 27 | } 28 | 29 | void coset_clear(coset_t *set) { 30 | coset_node_t *curr = coset_begin(set); 31 | while (curr) { 32 | coset_node_t *next = coset_next(set, curr); 33 | coset_delete(set, curr->data); 34 | curr = next; 35 | } 36 | } 37 | 38 | // 查找结点 39 | static coset_node_t* _coset_search(coset_t *set, void *data) { 40 | coset_node_t *curr = set->root; 41 | while (curr != set->nil) { 42 | int ret = set->fn_comp(set->ud, data, curr->data); 43 | if (ret < 0) 44 | curr = curr->left; 45 | else if (ret > 0) 46 | curr = curr->right; 47 | else 48 | break; 49 | } 50 | return curr; 51 | } 52 | 53 | // 取最小结点 54 | static coset_node_t* _coset_smallest(coset_t *set, coset_node_t *curr) { 55 | while (curr->left != set->nil) 56 | curr = curr->left; 57 | return curr; 58 | } 59 | 60 | // 取最大结点 61 | static coset_node_t* _coset_largest(coset_t *set, coset_node_t *curr) { 62 | while (curr->right != set->nil) 63 | curr = curr->right; 64 | return curr; 65 | } 66 | 67 | // 后继 68 | static coset_node_t* _coset_successor(coset_t *set, coset_node_t *curr) { 69 | // 如果右孩子存在,则找右孩子树的最小结点 70 | if (curr->right != set->nil) 71 | return _coset_smallest(set, curr->right); 72 | // 否则往父查找 73 | coset_node_t *successor = curr->parent; 74 | while (successor != set->nil && curr == successor->right) { 75 | curr = successor; 76 | successor = successor->parent; 77 | } 78 | return successor; 79 | } 80 | 81 | // 前继 82 | static coset_node_t* _coset_predecessor(coset_t *set, coset_node_t *curr) { 83 | // 如果右孩子存在,则找右孩子树的最小结点 84 | if (curr->left != set->nil) 85 | return _coset_largest(set, curr->left); 86 | // 否则往父查找 87 | coset_node_t *predecessor = curr->parent; 88 | while (predecessor != set->nil && curr == predecessor->left) { 89 | curr = predecessor; 90 | predecessor = predecessor->parent; 91 | } 92 | return predecessor; 93 | } 94 | 95 | static void _coset_leftrot(coset_t *set, coset_node_t *x) { 96 | coset_node_t *y = x->right; // 把y指向x的右孩子 97 | x->right = y->left; // y的左孩子变成x的右孩子 98 | if (y->left != set->nil) // 如果y的左孩子不为空,则设它的父为x 99 | y->left->parent = x; 100 | 101 | y->parent = x->parent; // 更新y的父为x的父 102 | if (x->parent == set->nil) // x的父为空,说明x原本是根节点,重置set->root 103 | set->root = y; 104 | else if (x == x->parent->left) // 若原先x是其父的左孩子 105 | x->parent->left = y; // 则更新后y也是其父的左孩子 106 | else // 若原先x是其父的右孩子 107 | x->parent->right = y; // 则更新后y也是其父的右孩子 108 | 109 | y->left = x; // 设置y的左孩子为x 110 | x->parent = y; // 设置x的父为y,到此完成左旋 111 | } 112 | 113 | static void _coset_rightrot(coset_t *set, coset_node_t *y){ 114 | coset_node_t *x = y->left; // 把x指向y的左孩子 115 | y->left = x->right; // x的右孩子变成y的左孩子 116 | if (x->right != set->nil) // 如果x的右孩子不为空,则设它为父为y 117 | x->right->parent = y; 118 | 119 | x->parent = y->parent; // 更新x的父为y的父 120 | if (y->parent == set->nil) // y的父为空,说明y原本是根节点,重置set->root 121 | set->root = x; 122 | else if (y == y->parent->left) // 若原先y是其父的左孩子 123 | y->parent->left = x; // 则更新后x也是其父的左孩子 124 | else // 若原先y是其父的右孩子 125 | y->parent->right = x; // 则更新后x也是其父的右孩子 126 | 127 | x->right = y; // 设置x的右孩子为y 128 | y->parent = x; // 设置y的父为x,到此完成右旋 129 | } 130 | 131 | static void _coset_insert_fixedup(coset_t *set, coset_node_t *node) { 132 | // parent是红色才进循环 133 | coset_node_t *curr = node; 134 | while (curr->parent->color == 0) { 135 | if (curr->parent == curr->parent->parent->left) { // 父是祖父的左孩子 136 | coset_node_t *uncle = curr->parent->parent->right; 137 | // case1: 若uncle是红色 138 | if (uncle->color == 0) { 139 | curr->parent->color = 1; // 把父改成黑色 140 | uncle->color = 1; // 把叔改成黑色 141 | curr->parent->parent->color = 0; // 把祖父改成红色 142 | curr = curr->parent->parent; // 把祖父设成当前结点,继续循环 143 | } 144 | // case2 & 3: uncle是黑色 145 | else { 146 | // case2:我是父的右孩子 147 | if (curr == curr->parent->right){ 148 | curr = curr->parent; // 把父设成当前结点 149 | _coset_leftrot(set, curr); // 进行左旋,左旋后就变成case3 150 | } 151 | // case3:我是父的左孩子 152 | curr->parent->color = 1; // 把父设成黑色 153 | curr->parent->parent->color = 0; // 把祖父设成红色 154 | _coset_rightrot(set, curr->parent->parent); // 对祖父进行右旋 155 | } 156 | } 157 | else { // 父是祖父的右孩子:与上面处理相反 158 | coset_node_t *uncle = curr->parent->parent->left; 159 | // case1: 若uncle是红色 160 | if (uncle->color == 0) { 161 | curr->parent->color = 1; 162 | uncle->color = 1; 163 | curr->parent->parent->color = 0; 164 | curr = curr->parent->parent; 165 | } 166 | // case2 & 3: uncle是黑色 167 | else { 168 | // case2 169 | if (curr == curr->parent->left) { 170 | curr = curr->parent; 171 | _coset_rightrot(set, curr); 172 | } 173 | // case3 174 | curr->parent->color = 1; 175 | curr->parent->parent->color = 0; 176 | _coset_leftrot(set, curr->parent->parent); 177 | } 178 | } 179 | } 180 | // 确保父结点为黑色 181 | set->root->color = 1; 182 | } 183 | 184 | 185 | void coset_add(coset_t *set, void *data) { 186 | coset_node_t *parent = set->nil; 187 | coset_node_t *curr = set->root; 188 | int ret = 0; 189 | // 找到插入的位置 190 | while (curr != set->nil) { 191 | parent = curr; 192 | ret = set->fn_comp(set->ud, data, curr->data); 193 | if (ret < 0) 194 | curr = curr->left; 195 | else if (ret > 0) 196 | curr = curr->right; 197 | else 198 | return; // 值相关不用插入,直接退出 199 | } 200 | // 创建结点 201 | coset_node_t *node = CO_MALLOC(sizeof(coset_node_t) + set->datasize); 202 | node->parent = parent; 203 | node->left = set->nil; 204 | node->right = set->nil; 205 | node->color = 0; 206 | node->data = (void*)(node + 1); 207 | memcpy(node->data, data, set->datasize); 208 | set->size++; 209 | 210 | // 加入父结点的树 211 | if (parent == set->nil) 212 | set->root = node; 213 | else if (ret < 0) 214 | parent->left = node; 215 | else 216 | parent->right = node; 217 | // 向上修正 218 | _coset_insert_fixedup(set, node); 219 | } 220 | 221 | static void _coset_delete_fixedup(coset_t *set, coset_node_t *curr) { 222 | while (curr != set->root && curr->color == 1) { 223 | if (curr == curr->parent->left) { 224 | coset_node_t *sibling = curr->parent->right; 225 | if (sibling->color == 0) { 226 | sibling->color = 1; 227 | curr->parent->color = 0; 228 | _coset_leftrot(set, curr->parent); 229 | sibling = curr->parent->right; 230 | } 231 | if (sibling->left->color == 1 && sibling->right->color == 1) { 232 | sibling->color = 0; 233 | curr = curr->parent; 234 | } 235 | else { 236 | if (sibling->right->color == 1){ 237 | sibling->left->color = 1; 238 | sibling->color = 0; 239 | _coset_rightrot(set, sibling); 240 | sibling = curr->parent->right; 241 | } 242 | sibling->color = curr->parent->color; 243 | curr->parent->color = 1; 244 | sibling->right->color = 1; 245 | _coset_leftrot(set, curr->parent); 246 | curr = set->root; 247 | } 248 | } 249 | else { 250 | coset_node_t *sibling = curr->parent->left; 251 | if (sibling->color == 0) { 252 | sibling->color = 1; 253 | curr->parent->color = 0; 254 | _coset_rightrot(set, curr->parent); 255 | sibling = curr->parent->left; 256 | } 257 | if (sibling->left->color == 1 && sibling->right->color == 1) { 258 | sibling->color = 0; 259 | curr = curr->parent; 260 | } 261 | else { 262 | if (sibling->left->color == 1){ 263 | sibling->right->color = 1; 264 | sibling->color = 0; 265 | _coset_leftrot(set, sibling); 266 | sibling = curr->parent->left; 267 | } 268 | sibling->color = curr->parent->color; 269 | curr->parent->color = 1; 270 | sibling->left->color = 1; 271 | _coset_rightrot(set, curr->parent); 272 | curr = set->root; 273 | } 274 | } 275 | } 276 | curr->color = 1; 277 | } 278 | 279 | void coset_delete(coset_t *set, void *data) { 280 | // 先查找结点 281 | coset_node_t *curr = _coset_search(set, data); 282 | if (curr == set->nil) 283 | return; 284 | 285 | coset_node_t *dnode = NULL; // 要被删除的结点 286 | coset_node_t *child = NULL; // 要被刪除的结点的孩子 287 | 288 | if (curr->left == set->nil || curr->right == set->nil) 289 | dnode = curr; // 如果最多只有一个孩子,则当前结点是删除结点 290 | else 291 | dnode = _coset_smallest(set, curr->right); // 否则找到后继结点,作为删除结点,因为right一定存在,所以简化为找right的最小结点 292 | 293 | // 经过上面简化后,dnode最多只有一个孩子,将删除结点的孩子,和删除结点的父关联起来,这样删除结点就可以安全删除 294 | child = dnode->left != set->nil ? dnode->left : dnode->right; 295 | child->parent = dnode->parent; // child有可能为NIL 296 | if (dnode->parent == set->nil) 297 | set->root = child; 298 | else if (dnode == dnode->parent->left) 299 | dnode->parent->left = child; 300 | else 301 | dnode->parent->right = child; 302 | 303 | // 如果删除结点不是当前结点,就要更新当前结点的值 304 | if (dnode != curr) 305 | memcpy(curr->data, dnode->data, set->datasize); 306 | 307 | // 释放内存 308 | set->size--; 309 | 310 | // 如果删除结点是黑色,就可能破坏红黑树的规则,要进行修正 311 | if (dnode->color == 1) 312 | _coset_delete_fixedup(set, child); 313 | 314 | CO_FREE(dnode); 315 | } 316 | 317 | bool coset_exist(coset_t *set, void *data) { 318 | return _coset_search(set, data) != set->nil; 319 | } 320 | 321 | void coset_union(coset_t *set, coset_t *set2) { 322 | assert(set->datasize == set2->datasize); 323 | coset_node_t *curr = coset_begin(set2); 324 | while (curr) { 325 | coset_add(set, curr->data); 326 | curr = coset_next(set2, curr); 327 | } 328 | } 329 | 330 | void coset_intersect(coset_t *set, coset_t *set2) { 331 | assert(set->datasize == set2->datasize); 332 | coset_node_t *curr = coset_begin(set); 333 | while (curr) { 334 | coset_node_t *next = coset_next(set, curr); 335 | if (!coset_exist(set2, curr->data)) 336 | coset_delete(set, curr->data); 337 | curr = next; 338 | } 339 | } 340 | 341 | void coset_minus(coset_t *set, coset_t *set2) { 342 | assert(set->datasize == set2->datasize); 343 | coset_node_t *curr = coset_begin(set2); 344 | while (curr) { 345 | coset_delete(set, curr->data); 346 | curr = coset_next(set2, curr); 347 | } 348 | } 349 | 350 | coset_node_t* coset_begin(coset_t *set) { 351 | if (set->root != set->nil) { 352 | coset_node_t *curr = _coset_smallest(set, set->root); 353 | return curr == set->nil ? NULL : curr; 354 | } 355 | return NULL; 356 | } 357 | 358 | coset_node_t* coset_next(coset_t *set, coset_node_t *curr) { 359 | curr = _coset_successor(set, curr); 360 | return curr == set->nil ? NULL : curr; 361 | } 362 | 363 | coset_node_t* coset_prev(coset_t *set, coset_node_t *curr) { 364 | curr = _coset_predecessor(set, curr); 365 | return curr == set->nil ? NULL : curr; 366 | } 367 | 368 | coset_node_t* coset_end(coset_t *set) { 369 | if (set->root != set->nil) { 370 | coset_node_t *curr = _coset_largest(set, set->root); 371 | return curr == set->nil ? NULL : curr; 372 | } 373 | return NULL; 374 | } 375 | -------------------------------------------------------------------------------- /src/co_ioservice.c: -------------------------------------------------------------------------------- 1 | #include "co_ioservice.h" 2 | #include "co_loop.h" 3 | #include "co_poll.h" 4 | #include 5 | 6 | #define BACKLOG 128 7 | #define INIT_READ_BUF 512 8 | #define MAX_READ_BUF (uint16_t)65536 9 | 10 | int coios_ignsigpipe() { 11 | struct sigaction sa; 12 | sa.sa_handler = SIG_IGN; 13 | sa.sa_flags = 0; 14 | sigemptyset(&sa.sa_mask); 15 | return sigaction(SIGPIPE, &sa, 0); 16 | } 17 | 18 | bool coios_getpeername(int fd, char *ip, int iplen, char *port, int portlen) { 19 | struct sockaddr_storage addr; 20 | socklen_t addrlen = sizeof(struct sockaddr_storage); 21 | if (getpeername(fd, (struct sockaddr*)&addr, &addrlen) == 0) { 22 | return coios_getaddrname((struct sockaddr*)&addr, addrlen, ip, iplen, port, portlen); 23 | } 24 | return false; 25 | } 26 | 27 | bool coios_getaddrname(struct sockaddr *addr, socklen_t addrlen, char *ip, int iplen, char *port, int portlen) { 28 | if (getnameinfo(addr, addrlen, ip, iplen, port, portlen, NI_NUMERICHOST|NI_NUMERICSERV) == 0) { 29 | return true; 30 | } 31 | return false; 32 | } 33 | 34 | bool coios_getaddr(const char *ip, const char *port, socklen_t *addrlen, socklen_t *socklen) { 35 | struct addrinfo hints; 36 | memset(&hints, 0, sizeof(struct addrinfo)); 37 | hints.ai_family = AF_UNSPEC; 38 | hints.ai_socktype = SOCK_STREAM; 39 | 40 | struct addrinfo *result; 41 | if (getaddrinfo(ip, port, &hints, &result) == 0) { 42 | *socklen = result->ai_addrlen; 43 | memcpy(addrlen, result->ai_addr, result->ai_addrlen); 44 | freeaddrinfo(result); 45 | return true; 46 | } else { 47 | freeaddrinfo(result); 48 | return false; 49 | } 50 | } 51 | 52 | void coios_nonblocking(int fd) { 53 | int flag = fcntl(fd, F_GETFL, 0); 54 | if ( -1 != flag ) 55 | fcntl(fd, F_SETFL, flag | O_NONBLOCK); 56 | } 57 | 58 | void cotcp_nodelay(int fd) { 59 | int value = 1; 60 | setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &value, sizeof(value)); 61 | } 62 | 63 | // 向前声明 64 | void _udpbuffer_free(udpsendlist_t *list); 65 | static void _cotcp_handle_write(coloop_t *loop, cotcp_t *tcp); 66 | static void _cotcp_handle_read(coloop_t *loop, cotcp_t *tcp); 67 | static void _cotcp_handle_error(coloop_t *loop, cotcp_t *tcp); 68 | static void _cotcp_handle_connect(coloop_t *loop, cotcp_t *tcp); 69 | static void _cotcp_handle_accept(coloop_t *loop, cotcp_t *tcp); 70 | static void _cofd_handle_write(coloop_t *loop, cofd_t *fd); 71 | static void _cofd_handle_read(coloop_t *loop, cofd_t *fd); 72 | static void _cofd_handle_error(coloop_t *loop, cofd_t *fd); 73 | static void _coudp_handle_write(coloop_t *loop, coudp_t *udp); 74 | static void _coudp_handle_read(coloop_t *loop, coudp_t *udp); 75 | static void _coudp_handle_error(coloop_t *loop, coudp_t *udp); 76 | 77 | 78 | 79 | // 处理poll事件 80 | static void _coios_process_event(coloop_t *loop, copollevent_t *ev) { 81 | coio_t *so = (coio_t*)ev->ud; 82 | if (so->type == COIO_TCP) { 83 | cotcp_t *tcp = (cotcp_t*)so; 84 | switch (tcp->state) { 85 | case COTCP_LISTEN: 86 | _cotcp_handle_accept(loop, tcp); 87 | break; 88 | case COTCP_CONNECTING: 89 | _cotcp_handle_connect(loop, tcp); 90 | break; 91 | case COTCP_INVALID: 92 | fprintf(stderr, "invalid socket -tcp\n"); 93 | break; 94 | default: 95 | if (ev->read) { // read 96 | _cotcp_handle_read(loop, tcp); 97 | } 98 | if (ev->write) { // write 99 | _cotcp_handle_write(loop, tcp); 100 | } 101 | if (ev->error) { // error 102 | _cotcp_handle_error(loop, tcp); 103 | } 104 | } 105 | } else if (so->type == COIO_UDP) { 106 | coudp_t *udp = (coudp_t*)so; 107 | if (udp->state == COFD_BIND || udp->state == COFD_NEW) { 108 | if (ev->read) { // read 109 | _coudp_handle_read(loop, udp); 110 | } 111 | if (ev->write) { // write 112 | _coudp_handle_write(loop, udp); 113 | } 114 | if (ev->error) { // error 115 | _coudp_handle_error(loop, udp); 116 | } 117 | } else if (udp->state == COUDP_INVALID) { 118 | fprintf(stderr, "invalid socket - udp\n"); 119 | } 120 | 121 | } else if (so->type == COIO_FD) { 122 | cofd_t *fd = (cofd_t*)so; 123 | if (fd->state == COFD_BIND) { 124 | if (ev->read) { // read 125 | _cofd_handle_read(loop, fd); 126 | } 127 | if (ev->write) { // write 128 | _cofd_handle_write(loop, fd); 129 | } 130 | if (ev->error) { // error 131 | _cofd_handle_error(loop, fd); 132 | } 133 | } else if (fd->state == COFD_INVALID) { 134 | fprintf(stderr, "invalid socket - fd\n"); 135 | } 136 | } 137 | } 138 | 139 | coios_t* coios_new(coloop_t *loop) { 140 | coios_t *ss = CO_MALLOC(sizeof(coios_t)); 141 | memset(ss, 0, sizeof(*ss)); 142 | int i; 143 | for (i = 0; i < COTCP_SIZE; ++i) { 144 | cotcp_t *tcp = &ss->tcps[i]; 145 | tcp->type = COIO_TCP; 146 | tcp->ioservice = ss; 147 | } 148 | for (i = 0; i < COUDP_SIZE; ++i) { 149 | coudp_t *udp = &ss->udps[i]; 150 | udp->type = COIO_UDP; 151 | udp->ioservice = ss; 152 | } 153 | for (i = 0; i < COFD_SIZE; ++i) { 154 | cofd_t *cofd = &ss->fds[i]; 155 | cofd->type = COIO_FD; 156 | cofd->ioservice = ss; 157 | } 158 | ss->loop = loop; 159 | coloop_processcb(loop, _coios_process_event); 160 | return ss; 161 | } 162 | 163 | void* coios_free(coios_t *ss) { 164 | int i; 165 | for (i = 0; i < COTCP_SIZE; ++i) { 166 | cotcp_t *tcp = &ss->tcps[i]; 167 | if (tcp->sendbuf) 168 | coringbuf_free(tcp->sendbuf); 169 | if (tcp->recvbuf) 170 | CO_FREE(tcp->recvbuf); 171 | } 172 | for (i = 0; i < COUDP_SIZE; ++i) { 173 | coudp_t *udp = &ss->udps[i]; 174 | if (udp->recvbuf) 175 | CO_FREE(udp->recvbuf); 176 | _udpbuffer_free(&udp->sendlist); 177 | } 178 | for (i = 0; i < COFD_SIZE; ++i) { 179 | cofd_t *fd = &ss->fds[i]; 180 | if (fd->sendbuf) 181 | coringbuf_free(fd->sendbuf); 182 | if (fd->recvbuf) 183 | CO_FREE(fd->recvbuf); 184 | } 185 | CO_FREE(ss); 186 | return NULL; 187 | } 188 | 189 | ///////////////////////////////////////////////////////////////////////////////////////////////// 190 | static cotcp_t* _cotcp_alloc(coios_t *ss) { 191 | int i, index; 192 | for (i = 0; i < COTCP_SIZE; ++i) { 193 | index = (ss->tcpid++) % COTCP_SIZE; 194 | cotcp_t *tcp = &ss->tcps[index]; 195 | if (tcp->state == COTCP_INVALID) { 196 | tcp->state = COTCP_NEW; 197 | return tcp; 198 | } 199 | } 200 | return NULL; 201 | } 202 | 203 | static void _cotcp_free(coios_t *ss, cotcp_t *tcp) { 204 | if (tcp->state == COTCP_INVALID) 205 | return; 206 | if (tcp->sendbuf) 207 | coringbuf_free(tcp->sendbuf); 208 | if (tcp->recvbuf) 209 | CO_FREE(tcp->recvbuf); 210 | memset(tcp, 0, sizeof(*tcp)); 211 | tcp->type = COIO_TCP; 212 | tcp->ioservice = ss; 213 | } 214 | 215 | static bool _cotcp_has_senddata(cotcp_t *tcp) { 216 | return tcp->sendbuf && coringbuf_readable_size(tcp->sendbuf); 217 | } 218 | 219 | static void _cotcp_close(coios_t *ss, cotcp_t *tcp) { 220 | if (tcp->state == COTCP_INVALID) 221 | return; 222 | copoll_del(ss->loop->poll, tcp->fd); 223 | if (close(tcp->fd) < 0) 224 | perror("_cotcp_close - close"); 225 | _cotcp_free(ss, tcp); 226 | } 227 | 228 | static void _cotcp_handle_error(coloop_t *loop, cotcp_t *tcp) { 229 | if (tcp->state == COTCP_INVALID) 230 | return; 231 | const char * err = NULL; 232 | int eno = errno; 233 | if (eno) 234 | err = strerror(eno); 235 | else { 236 | int error; 237 | socklen_t len = sizeof(error); 238 | int code = getsockopt(tcp->fd, SOL_SOCKET, SO_ERROR, &error, &len); 239 | if (code) 240 | err = strerror(error); 241 | else 242 | err = "Unknown error"; 243 | } 244 | if (tcp->fn_error) { 245 | tcp->fn_error(loop->ioserivce, tcp, err); 246 | } 247 | _cotcp_close(loop->ioserivce, tcp); 248 | } 249 | 250 | static void _cotcp_handle_accept(coloop_t *loop, cotcp_t *tcp) { 251 | struct sockaddr_storage claddr; 252 | socklen_t addrlen = sizeof(struct sockaddr_storage); 253 | for (;;) { 254 | int fd = accept(tcp->fd, (struct sockaddr*)&claddr, &addrlen); 255 | if (fd < 0) { 256 | int no = errno; 257 | if (no == EINTR) 258 | continue; 259 | perror("_cotcp_handle_accept - accept"); 260 | return; 261 | } 262 | cotcp_t *ctcp = _cotcp_alloc(loop->ioserivce); 263 | if (!ctcp) { 264 | fprintf(stderr, "too many tcp\n"); 265 | close(fd); 266 | return; 267 | } 268 | coios_nonblocking(fd); 269 | ctcp->fd = fd; 270 | ctcp->ud = tcp->ud; 271 | ctcp->state = COTCP_CONNECTED; 272 | copoll_add(loop->poll, fd, ctcp); 273 | if (tcp->fn_connect) 274 | tcp->fn_connect(loop->ioserivce, ctcp); 275 | return; 276 | } 277 | } 278 | 279 | static void _cotcp_handle_connect(coloop_t *loop, cotcp_t *tcp) { 280 | int error; 281 | socklen_t len = sizeof(error); 282 | int code = getsockopt(tcp->fd, SOL_SOCKET, SO_ERROR, &error, &len); 283 | if (code < 0 || error) { 284 | int eno = code >= 0 ? error : errno; 285 | if (tcp->fn_error) 286 | tcp->fn_error(loop->ioserivce, tcp, strerror(eno)); 287 | _cotcp_close(loop->ioserivce, tcp); 288 | } else { 289 | tcp->state = COTCP_CONNECTED; 290 | // 连接成功后,会将错误事件重置,需要再手动设置一次 291 | tcp->fn_error = NULL; 292 | if (tcp->fn_connect) 293 | tcp->fn_connect(loop->ioserivce, tcp); 294 | } 295 | } 296 | 297 | static void _cotcp_handle_read(coloop_t *loop, cotcp_t *tcp) { 298 | if (tcp->state == COTCP_INVALID) 299 | return; 300 | if (!tcp->recvbuf) { 301 | tcp->recvsize = INIT_READ_BUF; 302 | tcp->recvbuf = CO_MALLOC(tcp->recvsize); 303 | } 304 | while (1) { 305 | ssize_t n = read(tcp->fd, tcp->recvbuf, tcp->recvsize); 306 | if (n < 0) { 307 | int no = errno; 308 | if (no == EINTR) 309 | continue; 310 | else if (no == EAGAIN || no == EWOULDBLOCK) // 缓冲满了,下次再来 311 | return; 312 | else { // 其他错误 313 | _cotcp_handle_error(loop, tcp); 314 | return; 315 | } 316 | } else if (n == 0) { // socket关闭 317 | if (tcp->fn_close) 318 | tcp->fn_close(loop->ioserivce, tcp); 319 | _cotcp_close(loop->ioserivce, tcp); 320 | return; 321 | } else { 322 | // 连接状态下才触发事件 323 | if (tcp->state == COTCP_CONNECTED) { 324 | if (tcp->fn_recv) 325 | tcp->fn_recv(loop->ioserivce, tcp, tcp->recvbuf, n); 326 | if (tcp->state != COTCP_INVALID && n == tcp->recvsize) { 327 | tcp->recvsize = CO_MIN(MAX_READ_BUF, tcp->recvsize*2); 328 | tcp->recvbuf = CO_REALLOC(tcp->recvbuf, tcp->recvsize); 329 | } 330 | } 331 | return; 332 | } 333 | } 334 | } 335 | 336 | static void _cotcp_check_closing(coloop_t *loop, cotcp_t *tcp) { 337 | if (tcp->state == COTCP_CLOSING) { // 关闭socket 338 | _cotcp_close(loop->ioserivce, tcp); 339 | } else { 340 | copoll_request_write(loop->poll, tcp->fd, tcp, false); 341 | } 342 | } 343 | 344 | static void _cotcp_handle_write(coloop_t *loop, cotcp_t *tcp) { 345 | if (tcp->state == COTCP_INVALID) 346 | return; 347 | int maxsz = 2048; 348 | int size; 349 | while (_cotcp_has_senddata(tcp)) { 350 | size = CO_MIN(maxsz, coringbuf_readonce_size(tcp->sendbuf)); 351 | if (!size) 352 | break; 353 | void *buff = coringbuf_head(tcp->sendbuf); 354 | int nwrite = write(tcp->fd, buff, size); 355 | if (nwrite < 0) { 356 | int no = errno; 357 | if (no == EINTR) // 信号中断,继续 358 | continue; 359 | else if (no == EAGAIN || no == EWOULDBLOCK) // 缓冲满了,下次再来 360 | return; 361 | else { // 其他错误 362 | _cotcp_handle_error(loop, tcp); 363 | return; 364 | } 365 | } 366 | coringbuf_consume_size(tcp->sendbuf, nwrite); 367 | if (nwrite != size) 368 | return; 369 | } 370 | 371 | // 已经写完,关闭监听 372 | _cotcp_check_closing(loop, tcp); 373 | } 374 | 375 | cotcp_t* cotcp_listen(coios_t *ss, const char *ip, const char *port, void *ud, fn_tcp_connect_t fn_connect) { 376 | cotcp_t *tcp = _cotcp_alloc(ss); 377 | if (!tcp) return NULL; 378 | 379 | struct addrinfo hints; 380 | memset(&hints, 0, sizeof(struct addrinfo)); 381 | hints.ai_family = AF_UNSPEC; 382 | hints.ai_socktype = SOCK_STREAM; 383 | hints.ai_flags = AI_PASSIVE; 384 | 385 | struct addrinfo *result; 386 | int s = getaddrinfo(ip, port, &hints, &result); 387 | if (s != 0) { 388 | _cotcp_free(ss, tcp); 389 | errno = ENOSYS; 390 | return NULL; 391 | } 392 | 393 | int optval = 1; 394 | int fd = 0; 395 | struct addrinfo *rp; 396 | for (rp = result; rp != NULL; rp = rp->ai_next) { 397 | fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); 398 | if (fd == -1) 399 | continue; 400 | if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) == -1) { 401 | perror("cotcp_listen - setsockopt"); 402 | close(fd); 403 | freeaddrinfo(result); 404 | _cotcp_free(ss, tcp); 405 | return NULL; 406 | } 407 | if (bind(fd, rp->ai_addr, rp->ai_addrlen) == 0) 408 | break; 409 | close(fd); 410 | } 411 | 412 | if (rp == NULL) { 413 | freeaddrinfo(result); 414 | _cotcp_free(ss, tcp); 415 | return NULL; 416 | } 417 | 418 | if (listen(fd, BACKLOG) == -1) { 419 | perror("cotcp_listen - listen"); 420 | close(fd); 421 | freeaddrinfo(result); 422 | _cotcp_free(ss, tcp); 423 | return NULL; 424 | } 425 | 426 | freeaddrinfo(result); 427 | tcp->fd = fd; 428 | tcp->ud = ud; 429 | tcp->fn_connect = fn_connect; 430 | tcp->state = COTCP_LISTEN; 431 | copoll_add(ss->loop->poll, fd, tcp); 432 | return tcp; 433 | } 434 | 435 | bool cotcp_connect(coios_t *ss, const char *ip, const char *port, void *ud, fn_tcp_connect_t fn_connect, 436 | fn_tcp_error_t fn_error) { 437 | cotcp_t *tcp = _cotcp_alloc(ss); 438 | if (!tcp) return false; 439 | 440 | struct addrinfo hints; 441 | memset(&hints, 0, sizeof(struct addrinfo)); 442 | hints.ai_family = AF_UNSPEC; 443 | hints.ai_socktype = SOCK_STREAM; 444 | 445 | struct addrinfo *result; 446 | int s = getaddrinfo(ip, port, &hints, &result); 447 | if (s != 0) { 448 | _cotcp_free(ss, tcp); 449 | errno = ENOSYS; 450 | return false; 451 | } 452 | 453 | int fd = 0; 454 | struct addrinfo *rp; 455 | int ret; 456 | for (rp = result; rp != NULL; rp = rp->ai_next) { 457 | fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); 458 | if (fd == -1) 459 | continue; 460 | coios_nonblocking(fd); 461 | ret = connect(fd, rp->ai_addr, rp->ai_addrlen); 462 | if (ret != 0 && errno != EINPROGRESS) { 463 | close(fd); 464 | continue; 465 | } 466 | break; 467 | } 468 | 469 | if (rp == NULL) { 470 | perror("cotcp_connect - connect"); 471 | freeaddrinfo(result); 472 | _cotcp_free(ss, tcp); 473 | return false; 474 | } 475 | 476 | freeaddrinfo(result); 477 | tcp->fd = fd; 478 | tcp->ud = ud; 479 | tcp->fn_connect = fn_connect; 480 | tcp->fn_error = fn_error; 481 | copoll_add(ss->loop->poll, fd, tcp); 482 | if (ret == 0) { 483 | tcp->state = COTCP_CONNECTED; 484 | if (tcp->fn_connect) 485 | tcp->fn_connect(ss, tcp); 486 | } else { 487 | tcp->state = COTCP_CONNECTING; // 正在连接,等待连接事件到来 488 | copoll_request_write(ss->loop->poll, fd, tcp, true); 489 | } 490 | return true; 491 | } 492 | 493 | bool cotcp_send(coios_t *ss, cotcp_t *tcp, const void *buff, int size) { 494 | if (tcp->state != COTCP_CONNECTED || !size) 495 | return false; 496 | if (!tcp->sendbuf) 497 | tcp->sendbuf = coringbuf_new(size*2); 498 | coringbuf_write(tcp->sendbuf, buff, size); 499 | copoll_request_write(ss->loop->poll, tcp->fd, tcp, true); 500 | // 先尝试直接发送,发送不成功再进入监听队列 501 | _cotcp_handle_write(ss->loop, tcp); 502 | return true; 503 | } 504 | 505 | bool cotcp_close(coios_t *ss, cotcp_t *tcp, bool force) { 506 | if (tcp->state > COTCP_NEW && tcp->state < COTCP_CLOSING) { 507 | // 如果有数据,尝试发送一次 508 | if (_cotcp_has_senddata(tcp)) 509 | _cotcp_handle_write(ss->loop, tcp); 510 | if (force || !_cotcp_has_senddata(tcp)) { 511 | if (tcp->fn_close) 512 | tcp->fn_close(ss, tcp); 513 | _cotcp_close(ss, tcp); 514 | } else { 515 | tcp->state = COTCP_CLOSING; 516 | } 517 | return true; 518 | } 519 | return false; 520 | } 521 | 522 | bool cotcp_on_error(coios_t *ss, cotcp_t *tcp, fn_tcp_error_t fn) { 523 | if (tcp->state > COTCP_NEW && tcp->state < COTCP_CLOSING) { 524 | tcp->fn_error = fn; 525 | return true; 526 | } 527 | return false; 528 | } 529 | 530 | bool cotcp_on_recv(coios_t *ss, cotcp_t *tcp, fn_tcp_recv_t fn) { 531 | if (tcp->state > COTCP_LISTEN && tcp->state < COTCP_CLOSING) { 532 | tcp->fn_recv = fn; 533 | return true; 534 | } 535 | return false; 536 | } 537 | 538 | bool cotcp_on_close(coios_t *ss, cotcp_t* tcp, fn_tcp_close_t fn) { 539 | if (tcp->state > COTCP_NEW && tcp->state < COTCP_CLOSING) { 540 | tcp->fn_close = fn; 541 | return true; 542 | } 543 | return false; 544 | } 545 | 546 | ///////////////////////////////////////////////////////////////////////////////////////////////// 547 | // fd 548 | 549 | static cofd_t* _cofd_alloc(coios_t *ss) { 550 | int i, index; 551 | for (i = 0; i < COFD_SIZE; ++i) { 552 | index = (ss->fdid++) % COFD_SIZE; 553 | cofd_t *fd = &ss->fds[index]; 554 | if (fd->state == COFD_INVALID) { 555 | fd->state = COFD_NEW; 556 | return fd; 557 | } 558 | } 559 | return NULL; 560 | } 561 | 562 | static void _cofd_free(coios_t *ss, cofd_t *fd) { 563 | if (fd->state == COFD_INVALID) 564 | return; 565 | if (fd->sendbuf) 566 | coringbuf_free(fd->sendbuf); 567 | if (fd->recvbuf) 568 | CO_FREE(fd->recvbuf); 569 | memset(fd, 0, sizeof(*fd)); 570 | fd->type = COIO_FD; 571 | fd->ioservice = ss; 572 | } 573 | 574 | static bool _cofd_has_senddata(cofd_t *fd) { 575 | return fd->sendbuf && coringbuf_readable_size(fd->sendbuf); 576 | } 577 | 578 | cofd_t* cofd_bind(coios_t *ss, int fd, void *ud) { 579 | cofd_t *cofd = _cofd_alloc(ss); 580 | if (!cofd) return NULL; 581 | 582 | coios_nonblocking(fd); 583 | cofd->fd = fd; 584 | cofd->ud = ud; 585 | cofd->state = COFD_BIND; 586 | copoll_add(ss->loop->poll, fd, cofd); 587 | return cofd; 588 | } 589 | 590 | // 反绑FD 591 | bool cofd_unbind(coios_t *ss, cofd_t *fd) { 592 | // 马上解除 593 | if (fd->state == COFD_BIND) { 594 | copoll_del(ss->loop->poll, fd->fd); 595 | _cofd_free(ss, fd); 596 | return true; 597 | } 598 | return false; 599 | } 600 | 601 | // 发送数据 602 | bool cofd_send(coios_t *ss, cofd_t *fd, void *buf, int size) { 603 | if (fd->state != COFD_BIND || !size) 604 | return false; 605 | if (!fd->sendbuf) 606 | fd->sendbuf = coringbuf_new(size*2); 607 | coringbuf_write(fd->sendbuf, buf, size); 608 | copoll_request_write(ss->loop->poll, fd->fd, fd->ud, true); 609 | // 先尝试直接发送,发送不成功再进入监听队列 610 | _cofd_handle_write(ss->loop, fd); 611 | return true; 612 | } 613 | 614 | // 注册错误事件 615 | bool cofd_on_error(coios_t *ss, cofd_t* fd, fn_fd_error_t fn) { 616 | if (fd->state == COFD_BIND) { 617 | fd->fn_error = fn; 618 | return true; 619 | } 620 | return false; 621 | } 622 | 623 | // 注册接收事件 624 | bool cofd_on_recv(coios_t *ss, cofd_t* fd, fn_fd_recv_t fn) { 625 | if (fd->state == COFD_BIND) { 626 | fd->fn_recv = fn; 627 | return true; 628 | } 629 | return false; 630 | } 631 | 632 | // 注册关闭事件 633 | bool cofd_on_close(coios_t *ss, cofd_t* fd, fn_fd_close_t fn) { 634 | if (fd->state == COFD_BIND) { 635 | fd->fn_close = fn; 636 | return true; 637 | } 638 | return false; 639 | } 640 | 641 | static void _cofd_handle_read(coloop_t *loop, cofd_t *fd) { 642 | if (fd->state == COFD_INVALID) 643 | return; 644 | if (!fd->recvbuf) { 645 | fd->recvsize = INIT_READ_BUF; 646 | fd->recvbuf = CO_MALLOC(fd->recvsize); 647 | } 648 | while (1) { 649 | ssize_t n = read(fd->fd, fd->recvbuf, fd->recvsize); 650 | if (n < 0) { 651 | int no = errno; 652 | if (no == EINTR) 653 | continue; 654 | else if (no == EAGAIN || no == EWOULDBLOCK) // 缓冲满了,下次再来 655 | return; 656 | else { // 其他错误 657 | _cofd_handle_error(loop, fd); 658 | return; 659 | } 660 | } else if (n == 0) { // socket关闭 661 | if (fd->fn_close) 662 | fd->fn_close(loop->ioserivce, fd); 663 | cofd_unbind(loop->ioserivce, fd); 664 | return; 665 | } else { 666 | if (fd->fn_recv) 667 | fd->fn_recv(loop->ioserivce, fd, fd->recvbuf, n); 668 | if (fd->state != COFD_INVALID &&n == fd->recvsize) { 669 | fd->recvsize = CO_MIN(MAX_READ_BUF, fd->recvsize*2); 670 | fd->recvbuf = CO_REALLOC(fd->recvbuf, fd->recvsize); 671 | } 672 | return; 673 | } 674 | } 675 | } 676 | 677 | static void _cofd_handle_write(coloop_t *loop, cofd_t *fd) { 678 | if (fd->state == COFD_INVALID) 679 | return; 680 | int maxsz = 2048; 681 | int size; 682 | while (_cofd_has_senddata(fd)) { 683 | size = CO_MIN(maxsz, coringbuf_readonce_size(fd->sendbuf)); 684 | if (!size) 685 | break; 686 | void *buff = coringbuf_head(fd->sendbuf); 687 | int nwrite = write(fd->fd, buff, size); 688 | if (nwrite < 0) { 689 | int no = errno; 690 | if (no == EINTR) // 信号中断,继续 691 | continue; 692 | else if (no == EAGAIN || no == EWOULDBLOCK) // 缓冲满了,下次再来 693 | return; 694 | else { // 其他错误 695 | _cofd_handle_error(loop, fd); 696 | return; 697 | } 698 | } 699 | coringbuf_consume_size(fd->sendbuf, nwrite); 700 | if (nwrite != size) 701 | return; 702 | } 703 | 704 | // 已经写完,关闭监听 705 | copoll_request_write(loop->poll, fd->fd, fd->ud, false); 706 | } 707 | 708 | static void _cofd_handle_error(coloop_t *loop, cofd_t *fd) { 709 | if (fd->state == COFD_INVALID) 710 | return; 711 | const char * err = NULL; 712 | int eno = errno; 713 | if (eno) 714 | err = strerror(eno); 715 | else { 716 | int error; 717 | socklen_t len = sizeof(error); 718 | int code = getsockopt(fd->fd, SOL_SOCKET, SO_ERROR, &error, &len); 719 | if (code) 720 | err = strerror(error); 721 | else 722 | err = "Unknown error"; 723 | } 724 | if (fd->fn_error) { 725 | fd->fn_error(loop->ioserivce, fd, err); 726 | } 727 | cofd_unbind(loop->ioserivce, fd); 728 | } 729 | 730 | ///////////////////////////////////////////////////////////////////////////////////////////////// 731 | // udp 732 | static coudp_t* _coudp_alloc(coios_t *ss) { 733 | int i, index; 734 | for (i = 0; i < COUDP_SIZE; ++i) { 735 | index = (ss->udpid++) % COUDP_SIZE; 736 | coudp_t *udp = &ss->udps[index]; 737 | if (udp->state == COUDP_INVALID) { 738 | udp->state = COUDP_NEW; 739 | return udp; 740 | } 741 | } 742 | return NULL; 743 | } 744 | 745 | static void _coudp_free(coios_t *ss, coudp_t *udp) { 746 | if (udp->state == COUDP_INVALID) 747 | return; 748 | if (udp->recvbuf) 749 | CO_FREE(udp->recvbuf); 750 | _udpbuffer_free(&udp->sendlist); 751 | memset(udp, 0, sizeof(*udp)); 752 | udp->type = COIO_UDP; 753 | udp->ioservice = ss; 754 | } 755 | 756 | void _udpbuffer_add(udpsendlist_t *list, const void *buff, int size, struct sockaddr *addr, socklen_t addrlen) { 757 | udpbuffer_t *wb = CO_MALLOC(sizeof(*wb)); 758 | wb->buffer = CO_MALLOC(size); 759 | memcpy(wb->buffer, buff, size); 760 | wb->ptr = wb->buffer; 761 | wb->size = size; 762 | wb->addr = CO_MALLOC(addrlen); 763 | wb->addrlen = addrlen; 764 | memcpy(wb->addr, addr, addrlen); 765 | wb->next = NULL; 766 | if (!list->head) { 767 | list->head = list->tail = wb; 768 | } else { 769 | list->tail->next = wb; 770 | list->tail = wb; 771 | } 772 | } 773 | 774 | void _udpbuffer_free(udpsendlist_t *list) { 775 | udpbuffer_t *wb = list->head; 776 | while (wb) { 777 | udpbuffer_t *tmp = wb; 778 | wb = wb->next; 779 | CO_FREE(tmp->addr); 780 | CO_FREE(tmp->buffer); 781 | CO_FREE(tmp); 782 | } 783 | list->head = NULL; 784 | list->tail = NULL; 785 | } 786 | 787 | static void _coudp_close(coios_t *ss, coudp_t *udp) { 788 | if (udp->state == COUDP_INVALID) 789 | return; 790 | copoll_del(ss->loop->poll, udp->fd); 791 | if (close(udp->fd) < 0) 792 | perror("_coudp_close - close"); 793 | _coudp_free(ss, udp); 794 | } 795 | 796 | // 新建UDP对象并绑定到一个地址上 797 | coudp_t* coudp_new(coios_t *ss, const char *ip, const char *port, void *ud, bool bindaddr, 798 | struct sockaddr *addr, socklen_t *addrlen) { 799 | coudp_t *udp = _coudp_alloc(ss); 800 | if (!udp) return NULL; 801 | 802 | struct addrinfo hints; 803 | memset(&hints, 0, sizeof(struct addrinfo)); 804 | hints.ai_family = AF_UNSPEC; 805 | hints.ai_socktype = SOCK_DGRAM; 806 | hints.ai_flags = AI_PASSIVE; 807 | 808 | struct addrinfo *result; 809 | int s = getaddrinfo(ip, port, &hints, &result); 810 | if (s != 0) { 811 | errno = ENOSYS; 812 | _coudp_free(ss, udp); 813 | return NULL; 814 | } 815 | 816 | int optval = 1; 817 | int fd = 0; 818 | struct addrinfo *rp; 819 | for (rp = result; rp != NULL; rp = rp->ai_next) { 820 | fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); 821 | if (fd == -1) 822 | continue; 823 | if (bindaddr && setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) == -1) { 824 | perror("coudp_new - setsockopt"); 825 | close(fd); 826 | freeaddrinfo(result); 827 | _coudp_free(ss, udp); 828 | return NULL; 829 | } 830 | if (!bindaddr || bind(fd, rp->ai_addr, rp->ai_addrlen) == 0) 831 | break; 832 | close(fd); 833 | } 834 | 835 | if (rp == NULL) { 836 | perror("coudp_new - bind"); 837 | freeaddrinfo(result); 838 | _coudp_free(ss, udp); 839 | return NULL; 840 | } 841 | 842 | if (addr && addrlen) { 843 | *addrlen = rp->ai_addrlen; 844 | memcpy(addr, rp->ai_addr, rp->ai_addrlen); 845 | } 846 | freeaddrinfo(result); 847 | coios_nonblocking(fd); 848 | udp->fd = fd; 849 | udp->ud = ud; 850 | udp->state = COUDP_NEW; 851 | copoll_add(ss->loop->poll, fd, udp); 852 | return udp; 853 | } 854 | 855 | // 发送数据到一个地址 856 | bool coudp_send(coios_t *ss, coudp_t *udp, const void *buff, int size, struct sockaddr *addr, socklen_t addrlen) { 857 | if (udp->state != COUDP_NEW || !size) 858 | return false; 859 | // 加入缓存 860 | _udpbuffer_add(&udp->sendlist, buff, size, addr, addrlen); 861 | copoll_request_write(ss->loop->poll, udp->fd, udp, true); 862 | // 先尝试直接发送,发送不成功再进入监听队列 863 | _coudp_handle_write(ss->loop, udp); 864 | return true; 865 | } 866 | 867 | static bool _coudp_has_senddata(coudp_t *udp) { 868 | return udp->sendlist.head != NULL; 869 | } 870 | 871 | // 关闭UDP 872 | bool coudp_close(coios_t *ss, coudp_t *udp, bool force) { 873 | if (udp->state >= COUDP_NEW && udp->state < COUDP_CLOSING) { 874 | // 如果有数据,尝试发送一次 875 | if (_coudp_has_senddata(udp)) 876 | _coudp_handle_write(ss->loop, udp); 877 | if (force || !_coudp_has_senddata(udp)) { 878 | if (udp->fn_close) 879 | udp->fn_close(ss, udp); 880 | _coudp_close(ss, udp); 881 | } else { 882 | udp->state = COUDP_CLOSING; 883 | } 884 | return true; 885 | } 886 | return false; 887 | } 888 | 889 | // 注册错误事件 890 | bool coudp_on_error(coios_t *ss, coudp_t* udp, fn_udp_error_t fn) { 891 | if (udp->state == COUDP_NEW) { 892 | udp->fn_error = fn; 893 | return true; 894 | } 895 | return false; 896 | } 897 | 898 | // 注册接收事件 899 | bool coudp_on_recv(coios_t *ss, coudp_t* udp, fn_udp_recv_t fn) { 900 | if (udp->state == COUDP_NEW) { 901 | udp->fn_recv = fn; 902 | return true; 903 | } 904 | return false; 905 | } 906 | 907 | // 注册关闭事件 908 | bool coudp_on_close(coios_t *ss, coudp_t* udp, fn_udp_close_t fn) { 909 | if (udp->state == COUDP_NEW) { 910 | udp->fn_close = fn; 911 | return true; 912 | } 913 | return false; 914 | } 915 | 916 | static void _coudp_check_closing(coloop_t *loop, coudp_t *udp) { 917 | if (udp->state == COUDP_CLOSING) { // 关闭socket 918 | _coudp_close(loop->ioserivce, udp); 919 | } else { 920 | copoll_request_write(loop->poll, udp->fd, udp, false); 921 | } 922 | } 923 | 924 | static void _coudp_handle_write(coloop_t *loop, coudp_t *udp) { 925 | if (udp->state == COUDP_INVALID) 926 | return; 927 | udpsendlist_t *list = &udp->sendlist; 928 | while (list->head) { 929 | udpbuffer_t *wb = list->head; 930 | for (;;) { 931 | ssize_t sz = sendto(udp->fd, wb->ptr, wb->size, 0, wb->addr, wb->addrlen); 932 | if (sz < 0) { 933 | int no = errno; 934 | if (no == EINTR) // 信号中断,继续 935 | continue; 936 | else if (no == EAGAIN || no == EWOULDBLOCK) // 内核缓冲满了,下次再来 937 | return; 938 | else { // 其他错误 939 | _coudp_handle_error(loop, udp); 940 | return; 941 | } 942 | } 943 | if (sz != wb->size) { // 未完全发送出去,下次再来 944 | wb->ptr += sz; 945 | wb->size -= sz; 946 | return; 947 | } 948 | break; 949 | } 950 | list->head = wb->next; 951 | CO_FREE(wb->buffer); 952 | CO_FREE(wb->addr); 953 | CO_FREE(wb); 954 | } 955 | list->tail = NULL; 956 | // 到这里写全部完成,关闭写事件 957 | _coudp_check_closing(loop, udp); 958 | } 959 | 960 | static void _coudp_handle_read(coloop_t *loop, coudp_t *udp) { 961 | if (udp->state == COUDP_INVALID) 962 | return; 963 | if (!udp->recvbuf) { 964 | udp->recvsize = INIT_READ_BUF; 965 | udp->recvbuf = CO_MALLOC(udp->recvsize); 966 | } 967 | while (1) { 968 | struct sockaddr_storage claddr; 969 | socklen_t addrlen = sizeof(struct sockaddr_storage); 970 | ssize_t n = recvfrom(udp->fd, udp->recvbuf, udp->recvsize, 0, (struct sockaddr*) &claddr, &addrlen); 971 | if (n < 0) { 972 | int no = errno; 973 | if (no == EINTR) 974 | continue; 975 | else if (no == EAGAIN || no == EWOULDBLOCK) // 缓冲满了,下次再来 976 | return; 977 | else { // 其他错误 978 | _coudp_handle_error(loop, udp); 979 | return; 980 | } 981 | } else if (n == 0) { // socket关闭 982 | if (udp->fn_close) 983 | udp->fn_close(loop->ioserivce, udp); 984 | _coudp_close(loop->ioserivce, udp); 985 | return; 986 | } else { 987 | if (udp->fn_recv) 988 | udp->fn_recv(loop->ioserivce, udp, udp->recvbuf, n, (struct sockaddr*) &claddr, addrlen); 989 | if (udp->state != COUDP_INVALID &&n == udp->recvsize) { 990 | udp->recvsize = CO_MIN(MAX_READ_BUF, udp->recvsize*2); 991 | udp->recvbuf = CO_REALLOC(udp->recvbuf, udp->recvsize); 992 | } 993 | return; 994 | } 995 | } 996 | } 997 | 998 | static void _coudp_handle_error(coloop_t *loop, coudp_t *udp) { 999 | if (udp->state == COUDP_INVALID) 1000 | return; 1001 | const char * err = NULL; 1002 | int eno = errno; 1003 | if (eno) 1004 | err = strerror(eno); 1005 | else { 1006 | int error; 1007 | socklen_t len = sizeof(error); 1008 | int code = getsockopt(udp->fd, SOL_SOCKET, SO_ERROR, &error, &len); 1009 | if (code) 1010 | err = strerror(error); 1011 | else 1012 | err = "Unknown error"; 1013 | } 1014 | if (udp->fn_error) { 1015 | udp->fn_error(loop->ioserivce, udp, err); 1016 | } 1017 | _coudp_close(loop->ioserivce, udp); 1018 | } --------------------------------------------------------------------------------