├── README.md ├── common ├── actionmoni-client.c ├── actionmoni-client.h ├── base64.c ├── base64.h ├── hash.c ├── hash.h ├── is-binary.c ├── is-binary.h ├── log.c ├── log.h ├── md5.c ├── md5.h ├── mime.c ├── mime.h ├── network.c ├── network.h ├── process.c ├── process.h ├── rbtree.c ├── rbtree.h ├── sha1.c ├── sha1.h ├── sha256.c ├── sha256.h ├── shm.c ├── shm.h ├── smp.c ├── smp.h ├── strings.c ├── strings.h ├── timeouts.c ├── timeouts.h ├── times.c ├── times.h ├── urlcoder.c └── urlcoder.h ├── merry.c ├── merry.h └── se ├── libeio ├── config.h ├── ecb.h ├── eio.c ├── eio.h └── xthread.h ├── se-kqueue.c ├── se-util.c ├── se-util.h ├── se.c └── se.h /README.md: -------------------------------------------------------------------------------- 1 | Merry 2 | === 3 | 网络服务层开发框架 4 | 5 | 特性 6 | --- 7 | * 多进程 epoll 驱动模型(兼容 kqueue) 8 | * 高性能 timeout 事件管理器 9 | * 进程管理、自我维护 10 | * 高性能日志接口 11 | * 共享内存接口 12 | * 精简的内存池实现 13 | * 常用字符串方法(urlcoder / base64) 14 | 15 | 文件列表 16 | --- 17 | 18 | . 19 | ├── README.md 20 | ├── merry.c 21 | ├── [merry.h](#merryh) --框架总入口 22 | ├── se --epoll/kqueue 封装 23 | │ ├── se-kqueue.c 24 | │ ├── se-util.c --常用TCP接口封装 25 | │ ├── [se-util.h](#se-utilh) 26 | │ ├── se.c 27 | │ └── [se.h](#seh) 28 | └── common 29 |    ├── actionmoni-client.c --ActionMoni 监控服务(UDP)客户端 30 |    ├── [actionmoni-client.h](#actionmoni-clienth) 31 |    ├── base64.c 32 |    ├── [base64.h](#base64h) 33 |    ├── hash.c 34 |    ├── [hash.h](#hashh) 35 |    ├── is-binary.c --判断某个文件内容是否为二进制文件 36 |    ├── [is-binary.h](#is-binaryh) 37 |    ├── log.c --日志系统 38 |    ├── [log.h](#logh) 39 |    ├── md5.c 40 |    ├── [md5.h](#md5h) 41 |    ├── mime.c 42 |    ├── [mime.h](#mimeh) 43 |    ├── network.c --常用网络函数 44 |    ├── [network.h](#networkh) 45 |    ├── process.c --常用进程管理函数 46 |    ├── [process.h](#processh) 47 |    ├── sha1.c 48 |    ├── [sha1.h](#sha1h) 49 |    ├── sha256.c 50 |    ├── [sha256.h](#sha256h) 51 |    ├── shm.c --共享内存的常用函数封装 52 |    ├── [shm.h](#shmh) 53 |    ├── smp.c --简单的内存分配器(支持跟踪) 54 |    ├── [smp.h](#smph) 55 |    ├── strings.c 56 |    ├── [strings.h](#stringsh) 57 |    ├── timeouts.c --定时器 58 |    ├── [timeouts.h](#timeoutsh) 59 |    ├── times.c 60 |    ├── [times.h](#timesh) 61 |    ├── urlcoder.c 62 |    └── [urlcoder.h](#urlcoderh) 63 | 64 | ------ 65 | 66 | 函数接口 67 | -- 68 | 69 | merry.h 70 | --- 71 | 72 | 框架总入口,如只使用框架里面的一些方法,可不使用 73 | 74 | #### merry_start 75 | int merry\_start(int argc, const char \*\*argv, void (\*help)(), void (\*master)(), void (\*onexit)(), void (\*worker)(), int worker_count); 76 | 77 | 启动方法 78 | 79 | int argc --命令行参数数量,从 int main() 方法中传递 80 | const char **argv, --命令行参数 81 | void (*help)*(), --输出Help信息的方法,框架自动判断命令行参数并调用该方法 82 | void (*master)(), --主进程方法 83 | void (*worker)(), --任务方法 84 | void (*onexit)(), --如捕捉到进程关闭信号会调用该方法,再执行退出 85 | int worker_count --最多开启多少个worker,默认0,指无限制,让框架自动按CPU核心数量进行设置 86 | 87 | 88 | se.h 89 | --- 90 | 91 | 网络IO事件驱动方法的封装,支持 Linux epoll 和 BSD kqueue 92 | 93 | typedef int (*se_rw_proc_t)(se_ptr_t *ptr); 94 | typedef int (*se_waitout_proc_t)(); 95 | 96 | #### se\_create 97 | `int se_create(int event_size);` 98 | 99 | 创建IO事件驱动的文件描述符 100 | 101 | int event_size --事件循环的数组大小,一般为 4096 102 | 103 | #### se\_loop 104 | 105 | IO事件驱动的主体循环 106 | 107 | `int se_loop(int loop_fd, int waitout, se_waitout_proc_t waitout_proc);` 108 | 109 | int loop_fd, --IO事件驱动的文件描述符 110 | int waitout, --主体循环过程中的超时设置,超时后可执行 waitout_proc 方法,再进入循环。以获取CPU处理的时间片段 111 | se_waitout_proc_t waitout_proc --主体循环中的子方法,用于处理些IO事件以外的小任务(注意不能长时间堵塞,子任务应该能在10毫秒内完成,否则请开线程处理) 112 | 113 | 114 | #### se\_add 115 | 116 | 绑定IO事件 117 | 118 | `se_ptr_t *se_add(int loop_fd, int fd, void *data);` 119 | 120 | int loop_fd, --IO事件驱动的文件描述符 121 | int fd, --IO事件的文件描述符,如某个 client fd 122 | void *data --针对该事件的额外数据 123 | 124 | 返回 se_ptr_t * 类型的结构体 125 | 126 | #### se\_delete 127 | 128 | 删除IO事件 129 | 130 | `int se_delete(se_ptr_t *ptr);` 131 | 132 | se_ptr_t *ptr --IO事件的结构体 133 | 134 | 返回值 1 或 0 135 | 136 | #### se\_be\_read 137 | 138 | 设置IO事件将可读取 139 | 140 | `int se_be_read(se_ptr_t *ptr, se_rw_proc_t func);` 141 | 142 | se_ptr_t *ptr --IO事件的结构体 143 | se_rw_proc_t func --触发事件后对应执行的方法 144 | 145 | 返回值 1 或 0 146 | 147 | #### se\_be\_write 148 | 149 | 设置IO事件将可写入 150 | 151 | `int se_be_write(se_ptr_t *ptr, se_rw_proc_t func);` 152 | 153 | se_ptr_t *ptr --IO事件的结构体 154 | se_rw_proc_t func --触发事件后对应执行的方法 155 | 156 | 返回值 1 或 0 157 | 158 | #### se\_be\_pri 159 | 160 | 设置IO事件将等待(暂不处理读写事件) 161 | 162 | `int se_be_pri(se_ptr_t *ptr, se_rw_proc_t func);` 163 | 164 | se_ptr_t *ptr --IO事件的结构体 165 | se_rw_proc_t func --触发事件后对应执行的方法,一般为 NULL 166 | 167 | 返回值 1 或 0 168 | 169 | #### se\_be\_rw 170 | 171 | 设置IO事件将可读取或写入 172 | 173 | `int se_be_rw(se_ptr_t *ptr, se_rw_proc_t rfunc, se_rw_proc_t wfunc);` 174 | 175 | se_ptr_t *ptr --IO事件的结构体 176 | se_rw_proc_t rfunc --触发事件后对应执行的读取方法 177 | se_rw_proc_t wfunc --触发事件后对应执行的写入方法 178 | 179 | 返回值 1 或 0 180 | 181 | se-util.h 182 | --- 183 | 184 | typedef void (*se_be_accept_cb)(int fd, struct in_addr client_addr); 185 | typedef void (*se_be_dns_query_cb)(void *data, struct sockaddr_in addr); 186 | typedef void (*se_be_connect_cb)(void *data, int fd); 187 | 188 | #### se\_accept 189 | 190 | 设置IO事件将可收到网络连接请求 191 | 192 | `int se_accept(int loop_fd, int server_fd, se_be_accept_cb _be_accept);` 193 | 194 | int loop_fd, --IO事件驱动的文件描述符 195 | int server_fd, --服务端的IO事件文件描述符 196 | se_be_accept_cb _be_accept --触发事件后对应执行的 accept 方法 197 | 198 | 返回结果 1 或 0 199 | 200 | //typedef void (*se_be_accept_cb)(int fd, struct in_addr client_addr); 201 | _be_accept 接收方法中, 202 | int fd 为该次连接新建的文件描述符, 203 | client_addr 为客户端IP 204 | 205 | #### se\_dns\_query 206 | 207 | 发起一个异步 DNS 查询 208 | 209 | `int se_dns_query(int loop_fd, const char *name, int timeout, se_be_dns_query_cb cb, void *data);` 210 | 211 | int loop_fd, --IO事件驱动的文件描述符 212 | const char *name, --需查询的域名 213 | int timeout, --查询超时时间(秒) 214 | se_be_dns_query_cb cb, --接收查询结果的方法 215 | void *data --该次查询所带的额外数据 216 | 217 | 返回值 1 或 0 218 | 219 | //typedef void (*se_be_dns_query_cb)(void *data, struct sockaddr_in addr); 220 | cb 接收方法中, 221 | void *data 为该次查询所带的额外数据, 222 | addr 为查询结果,如 addr == {0} 表示查询失败(查询超时也返回 {0}) 223 | 224 | 另外可通过全局变量 se_errno 判断错误类型,如 se_errno == SE_DNS_QUERY_TIMEOUT 225 | 226 | #### se\_connect 227 | 228 | 发起一个异步网络连接请求 229 | 230 | `int se_connect(int loop_fd, const char *host, int port, int timeout, se_be_connect_cb _be_connect, void *data);` 231 | 232 | int loop_fd, --IO事件驱动的文件描述符 233 | const char *host, --服务端IP或域名(自动发起异步DNS查询) 234 | int port, --服务端端口 235 | int timeout, --连接超时时间(秒) 236 | se_be_connect_cb _be_connect, --接收连接结果的方法 237 | void *data --该次连接所带的额外数据 238 | 239 | 返回值 1 或 0 240 | 241 | //typedef void (*se_be_connect_cb)(void *data, int fd); 242 | _be_connect 接收方法中, 243 | void *data 为该次连接所带的额外数据, 244 | int fd 为连接的文件描述符 245 | 246 | 如 fd < 0 即连接失败(连接超时也为 -1) 247 | 另外可通过全局变量 se_errno 判断错误类型,如 se_errno == SE_CONNECT_TIMEOUT 248 | 249 | actionmoni-client.h 250 | --- 251 | 252 | ActionMoni 监控服务客户端(UDP协议) 253 | 254 | #### actionmoni\_open 255 | 256 | 连接到 ActionMoni 服务器 257 | 258 | `int actionmoni_open(const char *host, int port);` 259 | 260 | const char *host, --服务器IP 261 | int port --服务器端口 262 | 263 | 返回连接的文件描述符 264 | 265 | #### actionmoni\_count 266 | 267 | 计数器加一操作 268 | 269 | `int actionmoni_count(const char *_key);` 270 | 271 | const char *_key --KEY 272 | 273 | #### actionmoni\_counts 274 | 275 | 计数器加n操作 276 | 277 | `int actionmoni_counts(const char *_key, uint32_t cs);` 278 | 279 | const char *_key, --KEY 280 | uint32_t cs --加n,n>=0 281 | 282 | #### actionmoni\_ts 283 | 284 | 耗时|频率的计数操作 285 | 286 | `int actionmoni_ts(const char *_key, int ts);` 287 | 288 | const char *_key, --KEY 289 | int ts --耗时|频率 290 | 291 | #### actionmoni\_multi 292 | 293 | 批量操作 294 | 295 | `int actionmoni_multi(int cnt, ...);` 296 | 297 | int cnt, --该次批量操作的总操作数量(<= 10) 298 | ... --具体的操作内容 299 | 300 | #### actionmoni\_set\_keys 301 | 302 | 在ActionMoni服务器上标记KEYS 303 | 304 | `int actionmoni_set_keys(const char *_keys, int _len);` 305 | 306 | const char *_keys, --KEYS,以逗号间隔 307 | int _len --字符串长度(<= 4080) 308 | 309 | base64.h 310 | --- 311 | 312 | base64 编解码方法 313 | 314 | #### base64\_encoded\_length 315 | 316 | 计算字符串进行base64编码的可能长度 317 | 318 | `#define base64_encoded_length(len) (((len + 2) / 3) * 4)` 319 | 320 | #### base64\_decoded\_length 321 | 322 | 计算base64字符串进行解码后的可能长度 323 | 324 | `#define base64_decoded_length(len) (((len + 3) / 4) * 3)` 325 | 326 | #### base64_encode 327 | 328 | base64 编码方法 329 | 330 | `int base64_encode(unsigned char *dst, const unsigned char *src, int len);` 331 | 332 | #### base64_decode 333 | 334 | base64 解码方法 335 | 336 | `int base64_decode(unsigned char *dst, const unsigned char *src, size_t slen);` 337 | 338 | #### base64\_decode\_url 339 | 340 | base64 解码方法(URL) 341 | 342 | `int base64_decode_url(unsigned char *dst, const unsigned char *src, size_t slen);` 343 | 344 | hash.h 345 | --- 346 | 347 | 常用哈希方法 348 | 349 | #### fnv1a_32 350 | 351 | `uint32_t fnv1a_32(const unsigned char *data, uint32_t len);` 352 | 353 | #### fnv1a_64 354 | `uint32_t fnv1a_64(const unsigned char *data, uint32_t len);` 355 | 356 | #### MurmurHash64A 357 | `uint64_t MurmurHash64A(const void *key, int len, unsigned int seed);` 358 | 359 | #### MurmurHash2 360 | `unsigned int MurmurHash2(const void *key, int len, unsigned int seed);` 361 | 362 | #### XXH32 363 | `unsigned int XXH32(const void *input, int len, unsigned int seed);` 364 | 365 | #### XXH32_init 366 | `void *XXH32_init(unsigned int seed);` 367 | 368 | #### XXH32_update 369 | `XXH_errorcode XXH32_update(void *state, const void *input, int len);` 370 | 371 | #### XXH32_digest 372 | `unsigned int XXH32_digest(void *state);` 373 | 374 | 375 | is-binary.h 376 | --- 377 | 378 | 判断内容是否二进制格式 379 | 380 | #### is_binary 381 | 382 | `int is_binary(const char *buf, int buf_len);` 383 | 384 | log.h 385 | --- 386 | 387 | #define DEBUG 1 388 | #define INFO 2 389 | #define NOTICE 3 390 | #define WARN 4 391 | #define ALERT 5 392 | #define ERR 6 393 | 394 | 日志系统,框架会自动判断程序执行的命令行参数,默认不写入 log 文件,如以 daemon 模式启动,也不会在屏幕输出 log,如非 daemon 模式启动会输出到屏幕。 395 | 执行程序的命令参数为:log=/path/filename,level 396 | 如指定 log 文件名,会同时写入log文件(支持多进程模式) 397 | 398 | #### LOGF 399 | 400 | 记录日志 401 | 402 | `#define LOGF(l,a,...)` 403 | 404 | l --Level,(DEBUG|INFO|NOTICE|WARN|ALERT|ERR) 405 | a --Format,%s%d (兼容 printf 所支持的格式) 406 | ... --日志数据 407 | 408 | #### open_log 409 | 410 | 打开日志文件 411 | 412 | `logf_t *open_log(const char *fn, int sz);` 413 | 414 | const char *fn, --日志文件名 415 | int sz --共享内存中的缓存大小(建议 40KB) 416 | 417 | 返回日志文件的结构体 418 | 419 | #### log_destory 420 | 421 | 关闭并销毁日志文件结构体 422 | 423 | `void log_destory(logf_t *logf);` 424 | 425 | logf_t *logf --日志文件结构体 426 | 427 | #### log_writef 428 | 429 | 写入日志 430 | 431 | `int log_writef(logf_t *logf, const char *fmt, ...);` 432 | 433 | logf_t *logf, --日志文件结构体 434 | const char *fmt,--格式,%s%d (兼容 printf 所支持的格式) 435 | ... --日志数据 436 | 437 | #### sync_logs 438 | 439 | 日志文件写入磁盘 440 | 441 | `int sync_logs(logf_t *logf);` 442 | 443 | logf_t *logf --日志文件结构体 444 | 445 | md5.h 446 | --- 447 | 448 | md5 方法 449 | 450 | #### MD5Init 451 | 452 | 初始化MD5结构体 453 | 454 | `void MD5Init(MD5_CTX *);` 455 | 456 | MD5_CTX * --MD5结构体 457 | 458 | #### MD5Update 459 | 460 | 输入内容 461 | 462 | `void MD5Update(MD5_CTX *, const unsigned char *, unsigned int);` 463 | 464 | MD5_CTX *, --MD5结构体 465 | const unsigned char *, --内容 466 | unsigned int --内容长度 467 | 468 | #### MD5Final 469 | 470 | 获取结果 471 | 472 | `void MD5Final(unsigned char [16], MD5_CTX *);` 473 | 474 | unsigned char [16], --接收结果的char数组 475 | MD5_CTX * --MD5结构体 476 | 477 | #### md5 478 | 479 | md5 方法(对以上3个方法的简化封装) 480 | 481 | `void md5(const unsigned char *data, size_t len, char *hex);` 482 | 483 | const unsigned char *data, --内容 484 | size_t len, --内容长度 485 | char *hex --接收结果的char数组(size >= 32) 486 | 487 | mime.h 488 | --- 489 | 490 | 根据文件扩展名判断 MIME 类型 491 | 492 | #### get\_mime\_type 493 | 494 | 获取 MIME 类型 495 | 496 | `const char *get_mime_type(const char *filename);` 497 | 498 | const char *filename --文件名 499 | 500 | 返回值为 “text/plain” 类字符串 501 | 502 | network.h 503 | --- 504 | 505 | 常用网络IO操作方法 506 | 507 | #### set_nonblocking 508 | 509 | 设置文件描述符为非堵塞或堵塞 510 | 511 | `int set_nonblocking(int fd, int blocking);` 512 | 513 | int fd, --文件描述符 514 | int blocking --是否堵塞 515 | 516 | #### network_bind 517 | 518 | 绑定端口 519 | 520 | `int network_bind(const char *addr, int port);` 521 | 522 | const char *addr, --需绑定的IP 523 | int port --需绑定的端口 524 | 525 | #### network\_raw\_send 526 | 527 | 发送数据(堵塞模式) 528 | 529 | `int network_raw_send(int client_fd, const char *contents, int length);` 530 | 531 | int client_fd, --文件描述符 532 | const char* contents, --内容 533 | int length --内容长度 534 | 535 | #### network\_raw\_read 536 | 537 | 读取数据(堵塞模式) 538 | 539 | `char *network_raw_read(int cfd, int *datas_len);` 540 | 541 | int cfd, --文件描述符 542 | int *datas_len --读取到的长度 543 | 544 | 返回值为 char* 类型 545 | 546 | #### network\_raw\_sendfile 547 | 548 | 发送文件(堵塞模式) 549 | 550 | `int network_raw_sendfile(int out_fd, int in_fd, off_t *offset, size_t count);` 551 | 552 | int out_fd, --文件描述符 553 | int in_fd, --待发送的文件描述符 554 | off_t *offset, -- 555 | size_t count -- 556 | 557 | process.h 558 | --- 559 | 560 | 常用进程管理方法 561 | 562 | #### get\_cpu\_num 563 | 564 | 获取CPU数量 565 | 566 | `int get_cpu_num();` 567 | 568 | #### set\_cpu\_affinity 569 | 570 | 设置当前进程的CPU亲和性 571 | 572 | `int set_cpu_affinity(uint32_t active_cpu);` 573 | 574 | #### set\_process\_title 575 | 576 | 设置当前进程的命令行标题(如top列表上的显示内容) 577 | 578 | `void set_process_title(const char *title, int is_master);` 579 | 580 | #### init\_process\_title 581 | 582 | 初始化当前进程的命令行标题(仅主进程启动时调用) 583 | 584 | `char *init_process_title(int argc, const char **argv);` 585 | 586 | #### start\_master\_main 587 | 588 | 执行主进行任务方法 589 | 590 | `void start_master_main(void (*func)(), void (*onexit)());` 591 | 592 | #### daemonize 593 | 594 | 进入daemon后台守护进程模式 595 | 596 | `void daemonize();` 597 | 598 | #### attach\_on\_exit 599 | 600 | 捕获程序退出信号 601 | 602 | `void attach_on_exit(void *fun);` 603 | 604 | #### set\_process\_user 605 | 606 | 设置当前进程的用户、用户组 607 | 608 | `void set_process_user(const char *user, const char *group);` 609 | 610 | #### getarg 611 | 612 | 获取命令行参数 613 | 614 | `char *getarg(const char *key);` 615 | 616 | #### fork_process 617 | 618 | fork子进程 619 | 620 | `int fork_process(void (*func)(int i));` 621 | 622 | #### new\_thread\_p 623 | 624 | 创建线程 625 | 626 | `int new_thread_p(void *func, void *i);` 627 | 628 | sha1.h 629 | --- 630 | 631 | `void sha1(const unsigned char *input, size_t ilen, unsigned char output[20]);` 632 | 633 | `int sha1_file(const char *path, unsigned char output[20]);` 634 | 635 | `void sha1_hmac(const unsigned char *key, size_t keylen, const unsigned char *input, size_t ilen, unsigned char output[20]);` 636 | 637 | sha256.h 638 | --- 639 | 640 | shm.h 641 | --- 642 | 643 | 共享内存操作方法 644 | 645 | `shm_t *shm_malloc(size_t size);` 646 | `void shm_free(shm_t *shm);` 647 | `int shm_lock(shm_t *shm);` 648 | `int shm_unlock(shm_t *shm);` 649 | 650 | smp.h 651 | --- 652 | 653 | 简单的内存分配器,引入merry.h或smp.h后,宏定义替换系统的malloc/realloc/free函数(需注意多个c文件之间是否一致,否则混合使用会导致内存错误) 654 | (带调试支持)默认禁用调试,如需开启请在编译代码时加入 -D SMPDEBUG 参数(所有c代码) 655 | 656 | #### dump\_smp\_link 657 | 658 | 输出当前内存分配器中的内存块列表(需打开SMPDEBUG模式) 659 | 660 | `void dump_smp_link();` 661 | 662 | `void *smp_malloc(unsigned int size);` 663 | 664 | `void *smp_realloc(void *p, unsigned int _size);` 665 | 666 | `int smp_free(void *p);` 667 | 668 | strings.h 669 | --- 670 | 671 | 常用字符串方法 672 | 673 | #### stricmp 674 | 675 | 字符串匹配(大小写不敏感) 676 | 677 | `int stricmp(const char *str1, const char *str2);` 678 | 679 | #### stristr 680 | 681 | 字符串搜索(大小写不敏感) 682 | 683 | `char *stristr(const char *str, const char *pat, int length);` 684 | 685 | #### random_string 686 | 687 | 产生随机字符串(性能不好,不建议频密使用) 688 | 689 | `void random_string(char *string, size_t length, int s);` 690 | 691 | #### _strtoul 692 | 693 | 字符串转换为unsigned long数字(支持 2~64 进制) 694 | 695 | `unsigned long _strtol(char *str64, int base);` 696 | 697 | #### _ultostr 698 | 699 | 把unsigned long数字转换为字符串(支持 2~64 进制) 700 | 701 | `char *_ltostr(char *str, long val, unsigned base);` 702 | 703 | #### strsplit 704 | 705 | 字符串切分方法(不会对原字符串进行任何修改) 706 | 707 | `char *strsplit(const void *string_org, int org_len, const char *demial, char **last, int *len);` 708 | 709 | char *str = "abc,,ee,dd"; 710 | int str_len = strlen(str); 711 | 712 | char *tok = NULL; 713 | char *last = NULL; 714 | int len = 0; 715 | 716 | tok = strsplit(str, str_len, ",", &last, &len); 717 | while(tok){ 718 | //... 719 | tok = strsplit(str, str_len, ",", &last, &len); 720 | } 721 | 722 | timeouts.h 723 | --- 724 | 725 | 定时器方法 726 | 727 | #### add_timeout 728 | 729 | 创建一个定时任务 730 | 731 | `timeout_t *add_timeout(void *ptr, int timeout, timeout_handle_cb handle);` 732 | 733 | #### update_timeout 734 | 735 | 更新定时任务的到期时间 736 | 737 | `void update_timeout(timeout_t *n, int timeout);` 738 | 739 | #### delete_timeout 740 | 741 | 删除一个定时任务,注意:传入的timeout_t结构体会被 free 742 | 743 | `void delete_timeout(timeout_t *n);` 744 | 745 | #### check_timeouts 746 | 747 | 处理到期任务,一般在 epoll loop 内定期执行 748 | 749 | `int check_timeouts();` 750 | 751 | times.h 752 | --- 753 | 754 | 常用时间方法 755 | 756 | #### longtime 757 | 758 | 获取当前时间(毫秒) 759 | `long longtime();` 760 | 761 | #### update_time 762 | 763 | 更新时间记录 764 | 765 | `time_t update_time();` 766 | 767 | #### 全局变量 768 | 769 | time_t now = 0; --当前时间 770 | char now_gmt[32] = {0}; --当前时间GMT格式字符串 771 | char now_lc[32] = {0}; --当前本地时间字符串 772 | 773 | 使用以上全局变量,请注意定期执行 update_time 更新时间记录 774 | 775 | urlcoder.h 776 | --- 777 | 778 | `uintptr_t urlencode(u_char *dst, u_char *src, size_t size, unsigned int type);` 779 | 780 | `void urldecode(u_char **dst, u_char **src, size_t size, unsigned int type);` -------------------------------------------------------------------------------- /common/actionmoni-client.c: -------------------------------------------------------------------------------- 1 | #include "actionmoni-client.h" 2 | 3 | /* 4 | printf("%d\n", actionmoni_open("192.168.0.69", 1234)); 5 | actionmoni_set_keys("aaa,bbb", 7); 6 | actionmoni_count("aaa"); //aaa+1 7 | actionmoni_counts("aaa", 10); //aaa+ 10 8 | actionmoni_ts("bbb", 10); // 10ms 9 | actionmoni_multi(3, // n of actions 10 | AC_NODE_ADD, "aaa", 11 | AC_NODE_ADD_CS, "aaa", 10, 12 | 100+10, "bbb" 13 | ); 14 | exit(0); 15 | */ 16 | static int actionmoni_fd = -1; 17 | static struct sockaddr_in servaddr = {0}; 18 | static char buf_4096[4096] = {0}; 19 | 20 | static uint32_t fnv1_32(const char *data, uint32_t len) 21 | { 22 | uint32_t rv = 2166136261; 23 | uint32_t i; 24 | 25 | for(i = 0; i < len; i++) { 26 | rv += (rv << 1) + (rv << 4) + (rv << 7) + (rv << 8) + (rv << 24); 27 | rv = rv ^ data[i]; 28 | } 29 | 30 | return rv; 31 | } 32 | 33 | int actionmoni_open(const char *host, int port) 34 | { 35 | actionmoni_fd = socket(AF_INET, SOCK_DGRAM, 0); 36 | 37 | bzero(&servaddr, sizeof(servaddr)); 38 | servaddr.sin_family = AF_INET; 39 | servaddr.sin_addr.s_addr = inet_addr(host); 40 | servaddr.sin_port = htons(port); 41 | 42 | buf_4096[0] = '#'; 43 | 44 | return actionmoni_fd; 45 | } 46 | 47 | int actionmoni_count(const char *_key) 48 | { 49 | int len = 1; 50 | uint32_t ac = AC_NODE_ADD; 51 | memcpy(buf_4096 + len, &ac, sizeof(uint32_t)); 52 | len += sizeof(uint32_t); 53 | 54 | uint32_t key = fnv1_32(_key, strlen(_key)); 55 | memcpy(buf_4096 + len, &key, sizeof(uint32_t)); 56 | len += sizeof(uint32_t); 57 | 58 | return actionmoni_fd > -1 59 | && sendto(actionmoni_fd, buf_4096, len, 0, (struct sockaddr *)&servaddr, sizeof(servaddr)); 60 | } 61 | 62 | int actionmoni_counts(const char *_key, uint32_t cs) 63 | { 64 | int len = 1; 65 | uint32_t ac = AC_NODE_ADD_CS; 66 | memcpy(buf_4096 + len, &ac, sizeof(uint32_t)); 67 | len += sizeof(uint32_t); 68 | 69 | uint32_t key = fnv1_32(_key, strlen(_key)); 70 | memcpy(buf_4096 + len, &key, sizeof(uint32_t)); 71 | len += sizeof(uint32_t); 72 | 73 | memcpy(buf_4096 + len, &cs, sizeof(uint32_t)); 74 | len += sizeof(uint32_t); 75 | 76 | return actionmoni_fd > -1 77 | && sendto(actionmoni_fd, buf_4096, len, 0, (struct sockaddr *)&servaddr, sizeof(servaddr)); 78 | } 79 | 80 | int actionmoni_ts(const char *_key, int ts) 81 | { 82 | int len = 1; 83 | uint32_t ac = 100 + ts; 84 | memcpy(buf_4096 + len, &ac, sizeof(uint32_t)); 85 | len += sizeof(uint32_t); 86 | 87 | uint32_t key = fnv1_32(_key, strlen(_key)); 88 | memcpy(buf_4096 + len, &key, sizeof(uint32_t)); 89 | len += sizeof(uint32_t); 90 | 91 | return actionmoni_fd > -1 92 | && sendto(actionmoni_fd, buf_4096, len, 0, (struct sockaddr *)&servaddr, sizeof(servaddr)); 93 | } 94 | 95 | int actionmoni_multi(int cnt, ...) 96 | { 97 | if(actionmoni_fd == -1) { 98 | return 0; 99 | } 100 | 101 | buf_4096[0] = '@'; 102 | int len = 5; 103 | 104 | va_list v1; 105 | uint32_t i = 0, k = 0; 106 | uint32_t ac = 0, v = 0; 107 | char *_key = NULL; 108 | va_start(v1, cnt); 109 | 110 | while(i < cnt) { 111 | k++; 112 | 113 | if(k == 1) { 114 | ac = va_arg(v1, uint32_t); 115 | 116 | } else if(k == 2) { 117 | _key = va_arg(v1, char *); 118 | 119 | if(!_key) { 120 | break; 121 | } 122 | 123 | if(ac != AC_NODE_ADD_CS) { 124 | k = 0; 125 | memcpy(buf_4096 + len, "#", 1); 126 | len += 1; 127 | memcpy(buf_4096 + len, &ac, sizeof(uint32_t)); 128 | len += sizeof(uint32_t); 129 | 130 | uint32_t key = fnv1_32(_key, strlen(_key)); 131 | memcpy(buf_4096 + len, &key, sizeof(uint32_t)); 132 | len += sizeof(uint32_t); 133 | 134 | i++; 135 | } 136 | 137 | } else if(k++ >= 3) { 138 | v = va_arg(v1, uint32_t); 139 | k = 0; 140 | 141 | memcpy(buf_4096 + len, "#", 1); 142 | len += 1; 143 | 144 | memcpy(buf_4096 + len, &ac, sizeof(uint32_t)); 145 | len += sizeof(uint32_t); 146 | 147 | uint32_t key = fnv1_32(_key, strlen(_key)); 148 | memcpy(buf_4096 + len, &key, sizeof(uint32_t)); 149 | len += sizeof(uint32_t); 150 | 151 | memcpy(buf_4096 + len, &v, sizeof(uint32_t)); 152 | len += sizeof(uint32_t); 153 | 154 | i++; 155 | } 156 | } 157 | 158 | va_end(v1); 159 | 160 | memcpy(buf_4096 + 1, &i, sizeof(uint32_t)); 161 | 162 | int n = sendto(actionmoni_fd, buf_4096, len, 0, (struct sockaddr *)&servaddr, 163 | sizeof(servaddr)); 164 | 165 | buf_4096[0] = '#'; 166 | 167 | return n; 168 | } 169 | 170 | int actionmoni_set_keys(const char *_keys, int _len) 171 | { 172 | if(_len > 4080) { 173 | return 0; 174 | } 175 | 176 | int len = 1; 177 | uint32_t ac = AC_SET_KEY_LIST; 178 | memcpy(buf_4096 + len, &ac, sizeof(uint32_t)); 179 | len += sizeof(uint32_t); 180 | 181 | uint32_t key = _len; 182 | memcpy(buf_4096 + len, &key, sizeof(uint32_t)); 183 | len += sizeof(uint32_t); 184 | 185 | memcpy(buf_4096 + len, _keys, _len); 186 | len += _len; 187 | printf("%d %s\n", actionmoni_fd, buf_4096 + 9); 188 | return actionmoni_fd > -1 189 | && sendto(actionmoni_fd, buf_4096, len, 0, (struct sockaddr *)&servaddr, sizeof(servaddr)); 190 | } 191 | -------------------------------------------------------------------------------- /common/actionmoni-client.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #ifndef _ACTIONMONI_CLIENT 10 | #define _ACTIONMONI_CLIENT 11 | 12 | #define AC_NODE_ADD 5 13 | #define AC_NODE_ADD_CS 11 14 | #define AC_SET_KEY_LIST 98 15 | 16 | int actionmoni_open(const char *host, int port); 17 | int actionmoni_count(const char *_key); 18 | int actionmoni_counts(const char *_key, uint32_t cs); 19 | int actionmoni_ts(const char *_key, int ts); 20 | int actionmoni_multi(int cnt, ...); 21 | int actionmoni_set_keys(const char *_keys, int _len); 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /common/base64.c: -------------------------------------------------------------------------------- 1 | #include "base64.h" 2 | 3 | static int base64_encode_internal(unsigned char *dst, const unsigned char *src, int len, const unsigned char *basis, 4 | int padding) 5 | { 6 | unsigned char *d; 7 | const unsigned char *s; 8 | s = src; 9 | d = dst; 10 | 11 | while(len > 2) { 12 | *d++ = basis[(s[0] >> 2) & 0x3f]; 13 | *d++ = basis[((s[0] & 3) << 4) | (s[1] >> 4)]; 14 | *d++ = basis[((s[1] & 0x0f) << 2) | (s[2] >> 6)]; 15 | *d++ = basis[s[2] & 0x3f]; 16 | s += 3; 17 | len -= 3; 18 | } 19 | 20 | if(len) { 21 | *d++ = basis[(s[0] >> 2) & 0x3f]; 22 | 23 | if(len == 1) { 24 | *d++ = basis[(s[0] & 3) << 4]; 25 | *d++ = '='; 26 | 27 | } else { 28 | *d++ = basis[((s[0] & 3) << 4) | (s[1] >> 4)]; 29 | *d++ = basis[(s[1] & 0x0f) << 2]; 30 | } 31 | 32 | if(padding) { 33 | *d++ = '='; 34 | } 35 | } 36 | 37 | return d - dst; 38 | } 39 | 40 | int base64_encode(unsigned char *dst, const unsigned char *src, int len) 41 | { 42 | static unsigned char basis64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 43 | 44 | return base64_encode_internal(dst, src, len, basis64, 1); 45 | } 46 | 47 | int base64_encode_url(unsigned char *dst, const unsigned char *src, int len) 48 | { 49 | static unsigned char basis64_url[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; 50 | 51 | return base64_encode_internal(dst, src, len, basis64_url, 0); 52 | } 53 | 54 | static int base64_decode_internal(unsigned char *dst, const unsigned char *src, size_t slen, const unsigned char *basis) 55 | { 56 | size_t len; 57 | unsigned char *d; 58 | const unsigned char *s; 59 | 60 | for(len = 0; len < slen; len++) { 61 | if(src[len] == '=') { 62 | break; 63 | } 64 | 65 | if(basis[src[len]] == 77) { 66 | return 0; 67 | } 68 | } 69 | 70 | if(len % 4 == 1) { 71 | return 0; 72 | } 73 | 74 | s = src; 75 | d = dst; 76 | 77 | while(len > 3) { 78 | *d++ = (char)(basis[s[0]] << 2 | basis[s[1]] >> 4); 79 | *d++ = (char)(basis[s[1]] << 4 | basis[s[2]] >> 2); 80 | *d++ = (char)(basis[s[2]] << 6 | basis[s[3]]); 81 | s += 4; 82 | len -= 4; 83 | } 84 | 85 | if(len > 1) { 86 | *d++ = (char)(basis[s[0]] << 2 | basis[s[1]] >> 4); 87 | } 88 | 89 | if(len > 2) { 90 | *d++ = (char)(basis[s[1]] << 4 | basis[s[2]] >> 2); 91 | } 92 | 93 | return d - dst; 94 | } 95 | 96 | int base64_decode(unsigned char *dst, const unsigned char *src, size_t slen) 97 | { 98 | static unsigned char basis64[] = { 99 | 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 100 | 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 101 | 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 62, 77, 77, 77, 63, 102 | 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 77, 77, 77, 77, 77, 77, 103 | 77, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 104 | 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 77, 77, 77, 77, 77, 105 | 77, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 106 | 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 77, 77, 77, 77, 77, 107 | 108 | 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 109 | 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 110 | 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 111 | 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 112 | 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 113 | 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 114 | 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 115 | 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77 116 | }; 117 | return base64_decode_internal(dst, src, slen, basis64); 118 | } 119 | 120 | int base64_decode_url(unsigned char *dst, const unsigned char *src, size_t slen) 121 | { 122 | static unsigned char basis64[] = { 123 | 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 124 | 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 125 | 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 62, 77, 77, 126 | 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 77, 77, 77, 77, 77, 77, 127 | 77, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 128 | 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 77, 77, 77, 77, 63, 129 | 77, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 130 | 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 77, 77, 77, 77, 77, 131 | 132 | 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 133 | 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 134 | 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 135 | 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 136 | 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 137 | 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 138 | 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 139 | 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77 140 | }; 141 | return base64_decode_internal(dst, src, slen, basis64); 142 | } 143 | -------------------------------------------------------------------------------- /common/base64.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #ifndef _BASE64_H 7 | #define _BASE64_H 8 | 9 | #define base64_encoded_length(len) (((len + 2) / 3) * 4) 10 | #define base64_decoded_length(len) (((len + 3) / 4) * 3) 11 | int base64_encode(unsigned char *dst, const unsigned char *src, int len); 12 | int base64_encode_url(unsigned char *dst, const unsigned char *src, int len); 13 | int base64_decode(unsigned char *dst, const unsigned char *src, size_t slen); 14 | int base64_decode_url(unsigned char *dst, const unsigned char *src, size_t slen); 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /common/hash.h: -------------------------------------------------------------------------------- 1 | #include "smp.h" 2 | 3 | #ifndef _MERRY_HASH_H 4 | #define _MERRY_HASH_H 5 | 6 | #include 7 | 8 | uint32_t fnv1a_32(const void *key, uint32_t len); 9 | uint32_t fnv1a_64(const void *key, uint32_t len); 10 | 11 | #if defined(__x86_64__) 12 | #define MURMUR_HASH MurmurHash64A 13 | uint64_t MurmurHash64A(const void *key, int len, unsigned int seed); 14 | #define MurmurHash MurmurHash64A 15 | typedef uint64_t murmur_t; 16 | 17 | #elif defined(__i386__) 18 | #define MURMUR_HASH MurmurHash2 19 | unsigned int MurmurHash2(const void *key, int len, unsigned int seed); 20 | #define MurmurHash MurmurHash2 21 | typedef unsigned int murmur_t; 22 | 23 | #else 24 | #define MURMUR_HASH MurmurHashNeutral2 25 | unsigned int MurmurHashNeutral2(const void *key, int len, unsigned int seed); 26 | #define MurmurHash MurmurHashNeutral2 27 | typedef unsigned int murmur_t; 28 | 29 | #endif 30 | 31 | #endif /// _MERRY_HASH_H 32 | 33 | /* Notice extracted from xxHash homepage : 34 | 35 | xxHash is an extremely fast Hash algorithm, running at RAM speed limits. 36 | It also successfully passes all tests from the SMHasher suite. 37 | 38 | Comparison (single thread, Windows Seven 32 bits, using SMHasher on a Core 2 Duo @3GHz) 39 | 40 | Name Speed Q.Score Author 41 | xxHash 5.4 GB/s 10 42 | CrapWow 3.2 GB/s 2 Andrew 43 | MumurHash 3a 2.7 GB/s 10 Austin Appleby 44 | SpookyHash 2.0 GB/s 10 Bob Jenkins 45 | SBox 1.4 GB/s 9 Bret Mulvey 46 | Lookup3 1.2 GB/s 9 Bob Jenkins 47 | SuperFastHash 1.2 GB/s 1 Paul Hsieh 48 | CityHash64 1.05 GB/s 10 Pike & Alakuijala 49 | FNV 0.55 GB/s 5 Fowler, Noll, Vo 50 | CRC32 0.43 GB/s 9 51 | MD5-32 0.33 GB/s 10 Ronald L. Rivest 52 | SHA1-32 0.28 GB/s 10 53 | 54 | Q.Score is a measure of quality of the hash function. 55 | It depends on successfully passing SMHasher test set. 56 | 10 is a perfect score. 57 | */ 58 | 59 | #pragma once 60 | 61 | #if defined (__cplusplus) 62 | extern "C" { 63 | #endif 64 | 65 | 66 | //**************************** 67 | // Type 68 | //**************************** 69 | typedef enum { 70 | XXH_OK = 0, XXH_ERROR 71 | } 72 | XXH_errorcode; 73 | 74 | 75 | 76 | //**************************** 77 | // Simple Hash Functions 78 | //**************************** 79 | 80 | unsigned int XXH32(const void *input, int len, unsigned int seed); 81 | 82 | /* 83 | XXH32() : 84 | Calculate the 32-bits hash of sequence of length "len" stored at memory address "input". 85 | The memory between input & input+len must be valid (allocated and read-accessible). 86 | "seed" can be used to alter the result predictably. 87 | This function successfully passes all SMHasher tests. 88 | Speed on Core 2 Duo @ 3 GHz (single thread, SMHasher benchmark) : 5.4 GB/s 89 | Note that "len" is type "int", which means it is limited to 2^31-1. 90 | If your data is larger, use the advanced functions below. 91 | */ 92 | 93 | 94 | 95 | //**************************** 96 | // Advanced Hash Functions 97 | //**************************** 98 | 99 | void *XXH32_init(unsigned int seed); 100 | XXH_errorcode XXH32_update(void *state, const void *input, int len); 101 | unsigned int XXH32_digest(void *state); 102 | 103 | /* 104 | These functions calculate the xxhash of an input provided in several small packets, 105 | as opposed to an input provided as a single block. 106 | 107 | It must be started with : 108 | void* XXH32_init() 109 | The function returns a pointer which holds the state of calculation. 110 | 111 | This pointer must be provided as "void* state" parameter for XXH32_update(). 112 | XXH32_update() can be called as many times as necessary. 113 | The user must provide a valid (allocated) input. 114 | The function returns an error code, with 0 meaning OK, and any other value meaning there is an error. 115 | Note that "len" is type "int", which means it is limited to 2^31-1. 116 | If your data is larger, it is recommended to chunk your data into blocks 117 | of size for example 2^30 (1GB) to avoid any "int" overflow issue. 118 | 119 | Finally, you can end the calculation anytime, by using XXH32_digest(). 120 | This function returns the final 32-bits hash. 121 | You must provide the same "void* state" parameter created by XXH32_init(). 122 | Memory will be freed by XXH32_digest(). 123 | */ 124 | 125 | 126 | int XXH32_sizeofState(); 127 | XXH_errorcode XXH32_resetState(void *state, unsigned int seed); 128 | 129 | #define XXH32_SIZEOFSTATE 48 130 | typedef struct { 131 | long long ll[(XXH32_SIZEOFSTATE + (sizeof(long long) - 1)) / sizeof(long long)]; 132 | } XXH32_stateSpace_t; 133 | /* 134 | These functions allow user application to make its own allocation for state. 135 | 136 | XXH32_sizeofState() is used to know how much space must be allocated for the xxHash 32-bits state. 137 | Note that the state must be aligned to access 'long long' fields. Memory must be allocated and referenced by a pointer. 138 | This pointer must then be provided as 'state' into XXH32_resetState(), which initializes the state. 139 | 140 | For static allocation purposes (such as allocation on stack, or freestanding systems without malloc()), 141 | use the structure XXH32_stateSpace_t, which will ensure that memory space is large enough and correctly aligned to access 'long long' fields. 142 | */ 143 | 144 | 145 | unsigned int XXH32_intermediateDigest(void *state); 146 | /* 147 | This function does the same as XXH32_digest(), generating a 32-bit hash, 148 | but preserve memory context. 149 | This way, it becomes possible to generate intermediate hashes, and then continue feeding data with XXH32_update(). 150 | To free memory context, use XXH32_digest(), or free(). 151 | */ 152 | 153 | 154 | 155 | //**************************** 156 | // Deprecated function names 157 | //**************************** 158 | // The following translations are provided to ease code transition 159 | // You are encouraged to no longer this function names 160 | #define XXH32_feed XXH32_update 161 | #define XXH32_result XXH32_digest 162 | #define XXH32_getIntermediateResult XXH32_intermediateDigest 163 | 164 | 165 | 166 | #if defined (__cplusplus) 167 | } 168 | #endif 169 | -------------------------------------------------------------------------------- /common/is-binary.c: -------------------------------------------------------------------------------- 1 | #include "is-binary.h" 2 | 3 | int is_binary(const char *buf, int buf_len) 4 | { 5 | if(!buf || buf_len < 1) { 6 | return 0; 7 | } 8 | 9 | int suspicious_bytes = 0; 10 | int total_bytes = buf_len > 1024 ? 1024 : buf_len; 11 | const unsigned char *buf_c = (const unsigned char *)buf; 12 | int i; 13 | 14 | if(buf_len == 0) { 15 | return 0; 16 | } 17 | 18 | if(buf_len >= 3 && buf_c[0] == 0xEF && buf_c[1] == 0xBB && buf_c[2] == 0xBF) { 19 | /* UTF-8 BOM. This isn't binary. */ 20 | return 0; 21 | } 22 | 23 | for(i = 0; i < total_bytes; i++) { 24 | /* Disk IO is so slow that it's worthwhile to do this calculation after every suspicious byte. */ 25 | /* This is true even on a 1.6Ghz Atom with an Intel 320 SSD. */ 26 | /* Read at least 32 bytes before making a decision */ 27 | if(i >= 32 && (suspicious_bytes * 100) / total_bytes > 10) { 28 | return 1; 29 | } 30 | 31 | if(buf_c[i] == '\0') { 32 | /* NULL char. It's binary */ 33 | return 1; 34 | 35 | } else if((buf_c[i] < 7 || buf_c[i] > 14) && (buf_c[i] < 32 36 | || buf_c[i] > 127)) { 37 | /* UTF-8 detection */ 38 | if(buf_c[i] > 191 && buf_c[i] < 224 && i + 1 < total_bytes) { 39 | i++; 40 | 41 | if(buf_c[i] < 192) { 42 | continue; 43 | } 44 | 45 | } else if(buf_c[i] > 223 && buf_c[i] < 239 && i + 2 < total_bytes) { 46 | i++; 47 | 48 | if(buf_c[i] < 192 && buf_c[i + 1] < 192) { 49 | i++; 50 | continue; 51 | } 52 | } 53 | 54 | suspicious_bytes++; 55 | } 56 | } 57 | 58 | if((suspicious_bytes * 100) / total_bytes > 10) { 59 | return 1; 60 | } 61 | 62 | return 0; 63 | } 64 | -------------------------------------------------------------------------------- /common/is-binary.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #ifndef _IS_BINARY_H 4 | #define _IS_BINARY_H 5 | 6 | int is_binary(const char *buf, int buf_len); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /common/log.c: -------------------------------------------------------------------------------- 1 | #include "log.h" 2 | #include "times.h" 3 | #include 4 | #include 5 | logf_t *LOGF_T = NULL; 6 | int LOG_LEVEL = NOTICE; 7 | 8 | extern time_t now; 9 | extern struct tm _now_gtm; 10 | extern struct tm _now_lc; 11 | extern char now_gmt[32]; 12 | extern char now_lc[32]; 13 | 14 | extern int is_daemon; 15 | extern int pid; 16 | 17 | static char buf_4096[4096] = {0}; 18 | 19 | logf_t *open_log(const char *fn, int sz) 20 | { 21 | if(!fn) { 22 | return NULL; 23 | } 24 | 25 | char *p = strstr(fn, ","); 26 | char oldc = 0; 27 | char split_by = 0; 28 | short auto_delete = 0; 29 | 30 | if(p) { 31 | if(strstr(p, "DEBUG")) { 32 | LOG_LEVEL = 1; 33 | 34 | } else if(strstr(p, "INFO")) { 35 | LOG_LEVEL = 2; 36 | 37 | } else if(strstr(p, "NOTICE")) { 38 | LOG_LEVEL = 3; 39 | 40 | } else if(strstr(p, "WARN")) { 41 | LOG_LEVEL = 4; 42 | 43 | } else if(strstr(p, "ALERT")) { 44 | LOG_LEVEL = 5; 45 | 46 | } else if(strstr(p, "ERR")) { 47 | LOG_LEVEL = 6; 48 | 49 | } else if(strstr(p, "NO")) { 50 | LOG_LEVEL = 7; 51 | 52 | } else { 53 | int i = atoi(p + 1); 54 | 55 | if(i > 0 && i < 8) { 56 | LOG_LEVEL = i; 57 | } 58 | } 59 | 60 | if(strstr(p, ",h")) { 61 | split_by = 'h'; 62 | 63 | } else if(strstr(p, ",d")) { 64 | split_by = 'd'; 65 | 66 | } else if(strstr(p, ",w")) { 67 | split_by = 'w'; 68 | 69 | } else if(strstr(p, ",m")) { 70 | split_by = 'm'; 71 | } 72 | 73 | if(split_by != 0 && strstr(p + 1, ",")) { 74 | auto_delete = atoi(strstr(p + 1, ",") + 2); 75 | } 76 | 77 | oldc = p[0]; 78 | p[0] = '\0'; 79 | } 80 | 81 | if(!fn || strlen(fn) < 1) { 82 | p[0] = oldc; 83 | return NULL; 84 | } 85 | 86 | int fd = open(fn, O_APPEND | O_CREAT | O_WRONLY, 0644); 87 | 88 | logf_t *_logf = NULL; 89 | 90 | if(fd > -1) { 91 | _logf = malloc(sizeof(logf_t)); 92 | 93 | if(_logf) { 94 | bzero(_logf, sizeof(logf_t)); 95 | _logf->file = malloc(strlen(fn)); 96 | 97 | if(_logf->file) { 98 | memcpy(_logf->file, fn, strlen(fn)); 99 | _logf->file[strlen(fn)] = '\0'; 100 | } 101 | 102 | _logf->split_by = split_by; 103 | _logf->auto_delete = auto_delete; 104 | localtime_r(&now, &_logf->last_split_tm); 105 | _logf->LOG_FD = fd; 106 | _logf->_shm_log_buf = shm_malloc(sz + sizeof(long)); 107 | 108 | if(_logf->_shm_log_buf) { 109 | _logf->log_buf_len = (long *)((char *)_logf->_shm_log_buf->p + sz); 110 | *(_logf->log_buf_len) = 0; 111 | _logf->log_buf = _logf->_shm_log_buf->p; 112 | _logf->log_buf_size = sz > LOG_BUF_SIZE * 2 ? sz : LOG_BUF_SIZE * 2; 113 | 114 | } else { 115 | free(_logf); 116 | _logf = NULL; 117 | } 118 | } 119 | } 120 | 121 | if(p) { 122 | p[0] = oldc; 123 | } 124 | 125 | return _logf; 126 | } 127 | 128 | void log_destory(logf_t *_logf) 129 | { 130 | if(!_logf) { 131 | return; 132 | } 133 | 134 | sync_logs(_logf); 135 | free(_logf->file); 136 | _logf->file = NULL; 137 | shm_free(_logf->_shm_log_buf); 138 | _logf->_shm_log_buf = NULL; 139 | 140 | if(_logf->LOG_FD != -1) { 141 | close(_logf->LOG_FD); 142 | _logf->LOG_FD = -1; 143 | } 144 | } 145 | 146 | void copy_buf_to_shm_log_buf(logf_t *_logf) 147 | { 148 | if(!_logf || _logf->_inner_log_buf_len < 1) { 149 | return; 150 | } 151 | 152 | shm_lock(_logf->_shm_log_buf); 153 | 154 | if(*(_logf->log_buf_len) + _logf->_inner_log_buf_len > _logf->log_buf_size) { 155 | write(_logf->LOG_FD, _logf->log_buf, *(_logf->log_buf_len)); 156 | *(_logf->log_buf_len) = 0; 157 | } 158 | 159 | memcpy(_logf->log_buf + (*_logf->log_buf_len), _logf->_inner_log_buf, _logf->_inner_log_buf_len); 160 | *(_logf->log_buf_len) += _logf->_inner_log_buf_len; 161 | 162 | shm_unlock(_logf->_shm_log_buf); 163 | 164 | _logf->_inner_log_buf_len = 0; 165 | } 166 | 167 | int log_writef(logf_t *_logf, const char *fmt, ...) 168 | { 169 | if(!_logf || _logf->LOG_FD == -1) { 170 | return 0; 171 | } 172 | 173 | va_list args; 174 | va_start(args, fmt); 175 | int n = vsnprintf(buf_4096, 4096, fmt, args); 176 | va_end(args); 177 | 178 | update_time(); 179 | 180 | if(now > _logf->last_wtime || _logf->_inner_log_buf_len + n >= LOG_BUF_SIZE) { 181 | _logf->last_wtime = now; 182 | copy_buf_to_shm_log_buf(_logf); 183 | } 184 | 185 | memcpy(_logf->_inner_log_buf + _logf->_inner_log_buf_len, buf_4096, n); 186 | _logf->_inner_log_buf_len += n; 187 | 188 | return n; 189 | } 190 | 191 | int sync_logs(logf_t *_logf) 192 | { 193 | if(!_logf || _logf->LOG_FD == -1) { 194 | return 0; 195 | } 196 | 197 | if(_logf->split_by) { 198 | int dosplit = 0; 199 | time_t old = now; 200 | 201 | if(_logf->split_by == 'h' && _logf->last_split_tm.tm_hour != _now_lc.tm_hour) { 202 | dosplit = 1; 203 | old -= _logf->auto_delete * 3600; 204 | 205 | } else if(_logf->split_by == 'd' && _logf->last_split_tm.tm_mday != _now_lc.tm_mday) { 206 | dosplit = 1; 207 | old -= _logf->auto_delete * 86400; 208 | 209 | } else if(_logf->split_by == 'w' && _logf->last_split_tm.tm_wday != _now_lc.tm_wday) { 210 | dosplit = 1; 211 | old -= _logf->auto_delete * 604800; 212 | 213 | } else if(_logf->split_by == 'm' && _logf->last_split_tm.tm_mon != _now_lc.tm_mon) { 214 | dosplit = 1; 215 | old -= _logf->auto_delete * 2592000; 216 | 217 | } 218 | 219 | if(dosplit && _logf->file) { 220 | sprintf(buf_4096, "%s-%04d-%02d-%02d-%02d", _logf->file, _now_lc.tm_year + 1900, _now_lc.tm_mon + 1, _now_lc.tm_mday, 221 | _now_lc.tm_hour); 222 | 223 | if(rename(_logf->file, buf_4096) == 0) { 224 | close(_logf->LOG_FD); 225 | localtime_r(&now, &_logf->last_split_tm); 226 | _logf->LOG_FD = open(_logf->file, O_APPEND | O_CREAT | O_WRONLY, 0644); 227 | } 228 | 229 | if(_logf->auto_delete > 0) { 230 | struct tm _old_lc = {0}; 231 | localtime_r(&old, &_old_lc); 232 | 233 | if(_logf->split_by == 'h') { 234 | sprintf(buf_4096, "rm -f %s-%04d-%02d-%02d-%02d &", _logf->file, _old_lc.tm_year + 1900, _old_lc.tm_mon + 1, 235 | _old_lc.tm_mday, _old_lc.tm_hour); 236 | 237 | } else { 238 | sprintf(buf_4096, "rm -f %s-%04d-%02d-%02d-* &", _logf->file, _old_lc.tm_year + 1900, _old_lc.tm_mon + 1, 239 | _old_lc.tm_mday); 240 | } 241 | 242 | FILE *fp = popen(buf_4096, "r"); 243 | pclose(fp); 244 | } 245 | } 246 | } 247 | 248 | copy_buf_to_shm_log_buf(_logf); 249 | int n = 0; 250 | 251 | if(*_logf->log_buf_len > 0) { 252 | n = write(_logf->LOG_FD, _logf->log_buf, *_logf->log_buf_len); 253 | *_logf->log_buf_len = 0; 254 | } 255 | 256 | return n; 257 | } 258 | -------------------------------------------------------------------------------- /common/log.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "shm.h" 9 | #include "smp.h" 10 | 11 | #ifndef _LOG_H 12 | #define _LOG_H 13 | 14 | #define DEBUG 1 15 | #define INFO 2 16 | #define NOTICE 3 17 | #define WARN 4 18 | #define ALERT 5 19 | #define ERR 6 20 | 21 | #define LOG_BUF_SIZE 8192 22 | typedef struct { 23 | int LOG_FD; 24 | 25 | shm_t *_shm_log_buf; 26 | char *file; 27 | char split_by; 28 | short auto_delete; 29 | struct tm last_split_tm; 30 | char *log_buf; 31 | long *log_buf_len; 32 | char _inner_log_buf[LOG_BUF_SIZE]; 33 | int _inner_log_buf_len; 34 | int log_buf_size; 35 | long last_wtime; 36 | } logf_t; 37 | 38 | #define LOGF(l,a,...) if(l>=LOG_LEVEL&&(((is_daemon==1&&LOGF_T)||printf("%s%s %s [%d-%s:%s:%d] " a "%s", \ 39 | (l==DEBUG?"\x1b[0m":(l==INFO?"\x1b[32m":(l==NOTICE?"\x1b[34m":(l==WARN?"\x1b[33m":(l==ALERT?"\x1b[35m":"\x1b[31m"))))), now_lc, \ 40 | (l==DEBUG?"DEBUG ":(l==INFO?"INFO ":(l==NOTICE?"NOTICE":(l==WARN?"WARN ":(l==ALERT?"ALERT ":"ERR "))))), \ 41 | pid, __FILE__, __FUNCTION__, __LINE__, ##__VA_ARGS__, "\x1b[0m\n") ))&&LOGF_T) \ 42 | log_writef(LOGF_T, "%s [%d-%s:%s:%d] %s "a"\n", now_lc, pid, __FILE__, __FUNCTION__, __LINE__, \ 43 | (l==DEBUG?"DEBUG":(l==INFO?"INFO":(l==NOTICE?"NOTICE":(l==WARN?"WARN":(l==ALERT?"ALERT":"ERR"))))), \ 44 | ##__VA_ARGS__) 45 | 46 | #define _LOGF(l,f,a,...) if(l>=LOG_LEVEL&&(((is_daemon==1&&LOGF_T)||printf("%s%s %s [%d-%s] " a "%s", \ 47 | (l==DEBUG?"\x1b[0m":(l==INFO?"\x1b[32m":(l==NOTICE?"\x1b[34m":(l==WARN?"\x1b[33m":(l==ALERT?"\x1b[35m":"\x1b[31m"))))), now_lc, \ 48 | (l==DEBUG?"DEBUG ":(l==INFO?"INFO ":(l==NOTICE?"NOTICE":(l==WARN?"WARN ":(l==ALERT?"ALERT ":"ERR "))))), \ 49 | pid, f, ##__VA_ARGS__, "\x1b[0m\n") ))&&LOGF_T) \ 50 | log_writef(LOGF_T, "%s [%d-%s] %s "a"\n", now_lc, pid, f, \ 51 | (l==DEBUG?"DEBUG":(l==INFO?"INFO":(l==NOTICE?"NOTICE":(l==WARN?"WARN":(l==ALERT?"ALERT":"ERR"))))), \ 52 | ##__VA_ARGS__) 53 | 54 | logf_t *open_log(const char *fn, int sz); 55 | void log_destory(logf_t *logf); 56 | int log_writef(logf_t *logf, const char *fmt, ...); 57 | void copy_buf_to_shm_log_buf(logf_t *logf); 58 | int sync_logs(logf_t *logf); 59 | 60 | #endif 61 | -------------------------------------------------------------------------------- /common/md5.c: -------------------------------------------------------------------------------- 1 | /* 2 | * MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm 3 | * 4 | * Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All 5 | * rights reserved. 6 | * 7 | * License to copy and use this software is granted provided that it 8 | * is identified as the "RSA Data Security, Inc. MD5 Message-Digest 9 | * Algorithm" in all material mentioning or referencing this software 10 | * or this function. 11 | * 12 | * License is also granted to make and use derivative works provided 13 | * that such works are identified as "derived from the RSA Data 14 | * Security, Inc. MD5 Message-Digest Algorithm" in all material 15 | * mentioning or referencing the derived work. 16 | * 17 | * RSA Data Security, Inc. makes no representations concerning either 18 | * the merchantability of this software or the suitability of this 19 | * software for any particular purpose. It is provided "as is" 20 | * without express or implied warranty of any kind. 21 | * 22 | * These notices must be retained in any copies of any part of this 23 | * documentation and/or software. 24 | * 25 | * This code is the same as the code published by RSA Inc. It has been 26 | * edited for clarity and style only. 27 | */ 28 | 29 | #include "md5.h" 30 | 31 | static void MD5Transform(u_int32_t [4], const unsigned char [64]); 32 | 33 | #if (BYTE_ORDER == LITTLE_ENDIAN) 34 | #define Encode memcpy 35 | #define Decode memcpy 36 | #else 37 | 38 | /* 39 | * Encodes input (u_int32_t) into output (unsigned char). Assumes len is 40 | * a multiple of 4. 41 | */ 42 | 43 | static void 44 | Encode(unsigned char *output, u_int32_t *input, unsigned int len) 45 | { 46 | unsigned int i; 47 | u_int32_t *op = (u_int32_t *)output; 48 | 49 | for(i = 0; i < len / 4; i++) { 50 | op[i] = htole32(input[i]); 51 | } 52 | } 53 | 54 | /* 55 | * Decodes input (unsigned char) into output (u_int32_t). Assumes len is 56 | * a multiple of 4. 57 | */ 58 | 59 | static void 60 | Decode(u_int32_t *output, const unsigned char *input, unsigned int len) 61 | { 62 | unsigned int i; 63 | const u_int32_t *ip = (const u_int32_t *)input; 64 | 65 | for(i = 0; i < len / 4; i++) { 66 | output[i] = le32toh(ip[i]); 67 | } 68 | } 69 | #endif 70 | 71 | static unsigned char PADDING[64] = { 72 | 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 73 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 74 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 75 | }; 76 | 77 | /* F, G, H and I are basic MD5 functions. */ 78 | #define F(x, y, z) (((x) & (y)) | ((~x) & (z))) 79 | #define G(x, y, z) (((x) & (z)) | ((y) & (~z))) 80 | #define H(x, y, z) ((x) ^ (y) ^ (z)) 81 | #define I(x, y, z) ((y) ^ ((x) | (~z))) 82 | 83 | /* ROTATE_LEFT rotates x left n bits. */ 84 | #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) 85 | 86 | /* 87 | * FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. 88 | * Rotation is separate from addition to prevent recomputation. 89 | */ 90 | #define FF(a, b, c, d, x, s, ac) { \ 91 | (a) += F ((b), (c), (d)) + (x) + (u_int32_t)(ac); \ 92 | (a) = ROTATE_LEFT ((a), (s)); \ 93 | (a) += (b); \ 94 | } 95 | #define GG(a, b, c, d, x, s, ac) { \ 96 | (a) += G ((b), (c), (d)) + (x) + (u_int32_t)(ac); \ 97 | (a) = ROTATE_LEFT ((a), (s)); \ 98 | (a) += (b); \ 99 | } 100 | #define HH(a, b, c, d, x, s, ac) { \ 101 | (a) += H ((b), (c), (d)) + (x) + (u_int32_t)(ac); \ 102 | (a) = ROTATE_LEFT ((a), (s)); \ 103 | (a) += (b); \ 104 | } 105 | #define II(a, b, c, d, x, s, ac) { \ 106 | (a) += I ((b), (c), (d)) + (x) + (u_int32_t)(ac); \ 107 | (a) = ROTATE_LEFT ((a), (s)); \ 108 | (a) += (b); \ 109 | } 110 | 111 | /* MD5 initialization. Begins an MD5 operation, writing a new context. */ 112 | 113 | void MD5Init(context) 114 | MD5_CTX *context; 115 | { 116 | 117 | context->count[0] = context->count[1] = 0; 118 | 119 | /* Load magic initialization constants. */ 120 | context->state[0] = 0x67452301; 121 | context->state[1] = 0xefcdab89; 122 | context->state[2] = 0x98badcfe; 123 | context->state[3] = 0x10325476; 124 | } 125 | 126 | /* 127 | * MD5 block update operation. Continues an MD5 message-digest 128 | * operation, processing another message block, and updating the 129 | * context. 130 | */ 131 | 132 | void 133 | MD5Update(context, in, inputLen) 134 | MD5_CTX *context; 135 | const unsigned char *in; 136 | unsigned int inputLen; 137 | { 138 | unsigned int i, idx, partLen; 139 | const unsigned char *input = in; 140 | 141 | /* Compute number of bytes mod 64 */ 142 | idx = (unsigned int)((context->count[0] >> 3) & 0x3F); 143 | 144 | /* Update number of bits */ 145 | if((context->count[0] += ((u_int32_t)inputLen << 3)) 146 | < ((u_int32_t)inputLen << 3)) { 147 | context->count[1]++; 148 | } 149 | 150 | context->count[1] += ((u_int32_t)inputLen >> 29); 151 | 152 | partLen = 64 - idx; 153 | 154 | /* Transform as many times as possible. */ 155 | if(inputLen >= partLen) { 156 | memcpy((void *)&context->buffer[idx], (const void *)input, 157 | partLen); 158 | MD5Transform(context->state, context->buffer); 159 | 160 | for(i = partLen; i + 63 < inputLen; i += 64) { 161 | MD5Transform(context->state, &input[i]); 162 | } 163 | 164 | idx = 0; 165 | 166 | } else { 167 | i = 0; 168 | } 169 | 170 | /* Buffer remaining input */ 171 | /* memcpy ((void *)&context->buffer[idx], (const void *)&input[i], 172 | inputLen-i);*/ 173 | memcpy(&context->buffer[idx], &input[i], 174 | inputLen - i); 175 | } 176 | 177 | /* 178 | * MD5 padding. Adds padding followed by original length. 179 | */ 180 | 181 | void 182 | MD5Pad(context) 183 | MD5_CTX *context; 184 | { 185 | unsigned char bits[8]; 186 | unsigned int idx, padLen; 187 | 188 | /* Save number of bits */ 189 | Encode(bits, context->count, 8); 190 | 191 | /* Pad out to 56 mod 64. */ 192 | idx = (unsigned int)((context->count[0] >> 3) & 0x3f); 193 | padLen = (idx < 56) ? (56 - idx) : (120 - idx); 194 | MD5Update(context, PADDING, padLen); 195 | 196 | /* Append length (before padding) */ 197 | MD5Update(context, bits, 8); 198 | } 199 | 200 | /* 201 | * MD5 finalization. Ends an MD5 message-digest operation, writing the 202 | * the message digest and zeroizing the context. 203 | */ 204 | 205 | void 206 | MD5Final(digest, context) 207 | unsigned char digest[16]; 208 | MD5_CTX *context; 209 | { 210 | /* Do padding. */ 211 | MD5Pad(context); 212 | 213 | /* Store state in digest */ 214 | Encode(digest, context->state, 16); 215 | 216 | /* Zeroize sensitive information. */ 217 | bzero(context, sizeof(*context)); 218 | } 219 | 220 | /* MD5 basic transformation. Transforms state based on block. */ 221 | 222 | static void 223 | MD5Transform(state, block) 224 | u_int32_t state[4]; 225 | const unsigned char block[64]; 226 | { 227 | u_int32_t a = state[0], b = state[1], c = state[2], d = state[3], x[16]; 228 | 229 | Decode(x, block, 64); 230 | 231 | /* Round 1 */ 232 | #define S11 7 233 | #define S12 12 234 | #define S13 17 235 | #define S14 22 236 | FF(a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ 237 | FF(d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ 238 | FF(c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ 239 | FF(b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ 240 | FF(a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ 241 | FF(d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ 242 | FF(c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ 243 | FF(b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ 244 | FF(a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ 245 | FF(d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ 246 | FF(c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ 247 | FF(b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ 248 | FF(a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ 249 | FF(d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ 250 | FF(c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ 251 | FF(b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ 252 | 253 | /* Round 2 */ 254 | #define S21 5 255 | #define S22 9 256 | #define S23 14 257 | #define S24 20 258 | GG(a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ 259 | GG(d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ 260 | GG(c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ 261 | GG(b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ 262 | GG(a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ 263 | GG(d, a, b, c, x[10], S22, 0x2441453); /* 22 */ 264 | GG(c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ 265 | GG(b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ 266 | GG(a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ 267 | GG(d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ 268 | GG(c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ 269 | GG(b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ 270 | GG(a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ 271 | GG(d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ 272 | GG(c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ 273 | GG(b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ 274 | 275 | /* Round 3 */ 276 | #define S31 4 277 | #define S32 11 278 | #define S33 16 279 | #define S34 23 280 | HH(a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ 281 | HH(d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ 282 | HH(c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ 283 | HH(b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ 284 | HH(a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ 285 | HH(d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ 286 | HH(c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ 287 | HH(b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ 288 | HH(a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ 289 | HH(d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ 290 | HH(c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ 291 | HH(b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */ 292 | HH(a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ 293 | HH(d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ 294 | HH(c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ 295 | HH(b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ 296 | 297 | /* Round 4 */ 298 | #define S41 6 299 | #define S42 10 300 | #define S43 15 301 | #define S44 21 302 | II(a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ 303 | II(d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ 304 | II(c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ 305 | II(b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ 306 | II(a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ 307 | II(d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ 308 | II(c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ 309 | II(b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ 310 | II(a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ 311 | II(d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ 312 | II(c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ 313 | II(b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ 314 | II(a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ 315 | II(d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ 316 | II(c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ 317 | II(b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ 318 | 319 | state[0] += a; 320 | state[1] += b; 321 | state[2] += c; 322 | state[3] += d; 323 | 324 | /* Zeroize sensitive information. */ 325 | bzero(x, sizeof(x)); 326 | } 327 | 328 | void md5(const unsigned char *data, size_t len, char *hex) 329 | { 330 | MD5_CTX md5context; 331 | unsigned char digest[16] = {0}; 332 | 333 | MD5Init(&md5context); 334 | MD5Update(&md5context, data, len); 335 | MD5Final(digest, &md5context); 336 | 337 | int i = 0; 338 | char u[3] = {0}; 339 | 340 | for(i = 0; i < 16; i++) { 341 | sprintf(u, "%.2x", (unsigned int) digest[i]); 342 | memcpy(hex + (i * 2), u, 2); 343 | } 344 | } 345 | -------------------------------------------------------------------------------- /common/md5.h: -------------------------------------------------------------------------------- 1 | /* MD5.H - header file for MD5C.C 2 | * $FreeBSD: src/sys/sys/md5.h,v 1.20.10.1.2.1 2009/10/25 01:10:29 kensmith Exp $ 3 | */ 4 | 5 | /*- 6 | Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All 7 | rights reserved. 8 | 9 | License to copy and use this software is granted provided that it 10 | is identified as the "RSA Data Security, Inc. MD5 Message-Digest 11 | Algorithm" in all material mentioning or referencing this software 12 | or this function. 13 | 14 | License is also granted to make and use derivative works provided 15 | that such works are identified as "derived from the RSA Data 16 | Security, Inc. MD5 Message-Digest Algorithm" in all material 17 | mentioning or referencing the derived work. 18 | 19 | RSA Data Security, Inc. makes no representations concerning either 20 | the merchantability of this software or the suitability of this 21 | software for any particular purpose. It is provided "as is" 22 | without express or implied warranty of any kind. 23 | 24 | These notices must be retained in any copies of any part of this 25 | documentation and/or software. 26 | */ 27 | 28 | #ifndef _MD5_H_ 29 | #define _MD5_H_ 30 | 31 | #include 32 | #include 33 | 34 | typedef unsigned int u_int32_t; 35 | 36 | #define MD5_BLOCK_LENGTH 64 37 | #define MD5_DIGEST_LENGTH 16 38 | #define MD5_DIGEST_STRING_LENGTH (MD5_DIGEST_LENGTH * 2 + 1) 39 | 40 | /* MD5 context. */ 41 | typedef struct MD5Context { 42 | u_int32_t state[4]; /* state (ABCD) */ 43 | u_int32_t count[2]; /* number of bits, modulo 2^64 (lsb first) */ 44 | unsigned char buffer[64]; /* input buffer */ 45 | } MD5_CTX; 46 | 47 | void MD5Init(MD5_CTX *); 48 | void MD5Update(MD5_CTX *, const unsigned char *, unsigned int); 49 | void MD5Final(unsigned char [16], MD5_CTX *); 50 | void md5(const unsigned char *data, size_t len, char *hex); 51 | 52 | #endif /* _MD5_H_ */ 53 | -------------------------------------------------------------------------------- /common/mime.c: -------------------------------------------------------------------------------- 1 | #include "mime.h" 2 | 3 | static mime_t *mime_types[26]; 4 | static int inited = 0; 5 | 6 | static void add_mime_type(char *ext, char *type) 7 | { 8 | int ext_len = strlen(ext); 9 | int type_len = strlen(type); 10 | mime_t *n = malloc(sizeof(mime_t) + ext_len + 2 + type_len); 11 | 12 | n->next = NULL; 13 | n->ext = (char *) n + sizeof(mime_t); 14 | n->type = n->ext + ext_len + 1; 15 | 16 | memcpy(n->ext, ext, ext_len); 17 | memcpy(n->type, type, type_len); 18 | 19 | n->ext[ext_len] = '\0'; 20 | n->type[type_len] = '\0'; 21 | 22 | int k = (tolower(ext[0]) - 'a') % 26; 23 | 24 | if(mime_types[k] == NULL) { 25 | mime_types[k] = n; 26 | 27 | } else { 28 | n->next = mime_types[k]; 29 | mime_types[k] = n; 30 | } 31 | } 32 | 33 | void init_mime_types() 34 | { 35 | inited = 1; 36 | int i = 0; 37 | 38 | for(i = 0; i < 26; i++) { 39 | mime_types[i] = NULL; 40 | } 41 | 42 | add_mime_type("txt", "text/plain"); 43 | add_mime_type("htm", "text/html"); 44 | add_mime_type("html", "text/html"); 45 | add_mime_type("shtml", "text/html"); 46 | add_mime_type("xhtml", "application/xhtml+xml"); 47 | add_mime_type("js", "text/javascript"); 48 | add_mime_type("json", "application/json"); 49 | add_mime_type("atom", "application/atom+xml"); 50 | add_mime_type("css", "text/css"); 51 | add_mime_type("rss", "text/xml"); 52 | add_mime_type("xml", "text/xml"); 53 | 54 | add_mime_type("jpg", "image/jpeg"); 55 | add_mime_type("jpeg", "image/jpeg"); 56 | add_mime_type("gif", "image/gif"); 57 | add_mime_type("png", "image/png"); 58 | add_mime_type("ico", "image/x-icon"); 59 | add_mime_type("jng", "image/x-jng"); 60 | add_mime_type("bmp", "image/bmp"); 61 | add_mime_type("webp", "image/webp"); 62 | add_mime_type("wbmp", "image/vnd.wap.wbmp"); 63 | add_mime_type("tif", "image/tiff"); 64 | add_mime_type("tiff", "image/tiff"); 65 | 66 | add_mime_type("mid", "audio/mid"); 67 | add_mime_type("midi", "audio/mid"); 68 | add_mime_type("kar", "audio/mid"); 69 | add_mime_type("mp3", "audio/mpeg"); 70 | add_mime_type("oga", "audio/ogg"); 71 | add_mime_type("ogg", "audio/ogg"); 72 | add_mime_type("m4a", "audio/x-m4a"); 73 | add_mime_type("ra", "audio/x-realaudio"); 74 | add_mime_type("wav", "audio/x-wav"); 75 | add_mime_type("mp4a", "audio/mp4"); 76 | 77 | add_mime_type("3gp", "video/3gpp"); 78 | add_mime_type("3gpp", "video/3gpp"); 79 | add_mime_type("mpeg", "video/mpeg"); 80 | add_mime_type("mpg", "video/mpeg"); 81 | add_mime_type("ogv", "video/ogg"); 82 | add_mime_type("mov", "video/quicktime"); 83 | add_mime_type("webm", "video/webm"); 84 | add_mime_type("flv", "video/x-flv"); 85 | add_mime_type("m4v", "video/x-m4v"); 86 | add_mime_type("mng", "video/x-mng"); 87 | add_mime_type("asx", "video/x-ms-asf"); 88 | add_mime_type("asf", "video/x-ms-asf"); 89 | add_mime_type("wmv", "video/x-ms-wmv"); 90 | add_mime_type("avi", "video/x-msvideo"); 91 | add_mime_type("mp4", "application/mp4"); 92 | 93 | add_mime_type("manifest", "text/cache-manifest"); 94 | add_mime_type("mml", "text/mathml"); 95 | add_mime_type("jad", "text/vnd.sun.j2me.app-descriptor"); 96 | add_mime_type("wml", "text/vnd.wap.wml"); 97 | add_mime_type("htc", "text/x-component"); 98 | 99 | add_mime_type("jar", "application/java-archive"); 100 | add_mime_type("war", "application/java-archive"); 101 | add_mime_type("ear", "application/java-archive"); 102 | add_mime_type("7z", "application/x-7z-compressed"); 103 | add_mime_type("zip", "application/zip"); 104 | add_mime_type("tar", "application/x-tar"); 105 | add_mime_type("gz", "application/x-gzip"); 106 | add_mime_type("bz2", "application/x-bzip"); 107 | add_mime_type("tbz", "application/x-bzip-compressed-tar"); 108 | add_mime_type("rar", "application/x-rar-compressed"); 109 | add_mime_type("xpi", "application/x-xpinstall"); 110 | add_mime_type("rpm", "application/x-redhat-package-manager"); 111 | add_mime_type("crx", "application/x-chrome-extension"); 112 | add_mime_type("deb", "application/application/x-debian-package"); 113 | add_mime_type("rtf", "application/rtf"); 114 | add_mime_type("ps", "application/postscript"); 115 | add_mime_type("eps", "application/postscript"); 116 | add_mime_type("ai", "application/postscript"); 117 | add_mime_type("pdf", "application/pdf"); 118 | add_mime_type("swf", "application/x-shockwave-flash"); 119 | add_mime_type("der", "application/x-x509-ca-cert"); 120 | add_mime_type("pem", "application/x-x509-ca-cert"); 121 | add_mime_type("crt", "application/x-x509-ca-cert"); 122 | 123 | 124 | add_mime_type("woff", "application/x-woff"); 125 | add_mime_type("ttc", "font/truetype"); 126 | add_mime_type("ttf", "font/truetype"); 127 | add_mime_type("otf", "font/opentype"); 128 | add_mime_type("svg", "image/svg+xml"); 129 | add_mime_type("svgz", "image/svg+xml"); 130 | 131 | add_mime_type("lua", "text/plain"); 132 | add_mime_type("php", "text/plain"); 133 | add_mime_type("py", "text/plain"); 134 | add_mime_type("rb", "text/plain"); 135 | add_mime_type("java", "text/plain"); 136 | add_mime_type("log", "text/plain"); 137 | 138 | add_mime_type("doc", "application/msword"); 139 | add_mime_type("xls", "application/vnd.ms-excel"); 140 | add_mime_type("ppt", "application/vnd.ms-powerpoint"); 141 | add_mime_type("docx", 142 | "application/vnd.openxmlformats-officedocument.wordprocessingml.document"); 143 | add_mime_type("pptx", 144 | "application/vnd.openxmlformats-officedocument.presentationml.presentation"); 145 | add_mime_type("xlsx", 146 | "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); 147 | } 148 | 149 | const char *get_mime_type(const char *filename) 150 | { 151 | if(inited == 0) { 152 | init_mime_types(); 153 | } 154 | 155 | int i = 0; 156 | const char *ext = filename; 157 | int l = strlen(filename); 158 | 159 | for(i = l; i--;) { 160 | if(ext[i] == '.') { 161 | ext = &ext[i + 1]; 162 | 163 | break; 164 | } 165 | } 166 | 167 | char *t = "application/octet-stream"; 168 | mime_t *u = mime_types[(tolower(ext[0]) - 'a') % 26]; 169 | 170 | while(u) { 171 | if(stricmp(u->ext, ext) == 0) { 172 | return u->type; 173 | } 174 | 175 | u = u->next; 176 | } 177 | 178 | return t; 179 | } 180 | -------------------------------------------------------------------------------- /common/mime.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "strings.h" 6 | #include "smp.h" 7 | 8 | #ifndef _MIME_H 9 | #define _MIME_H 10 | 11 | typedef struct { 12 | char *ext; 13 | char *type; 14 | void *next; 15 | } mime_t; 16 | 17 | void init_mime_types(); 18 | const char *get_mime_type(const char *filename); 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /common/network.c: -------------------------------------------------------------------------------- 1 | #include "network.h" 2 | 3 | extern time_t now; 4 | extern struct tm _now_gtm; 5 | extern struct tm _now_lc; 6 | extern char now_gmt[32]; 7 | extern char now_lc[32]; 8 | 9 | int set_nonblocking(int fd, int nonblocking) 10 | { 11 | int flags = fcntl(fd, F_GETFL, 0); 12 | 13 | if(flags == -1) { 14 | return 0; 15 | } 16 | 17 | if(nonblocking) { 18 | flags |= O_NONBLOCK; 19 | 20 | } else { 21 | flags &= ~O_NONBLOCK; 22 | } 23 | 24 | return fcntl(fd, F_SETFL, flags) != -1; 25 | } 26 | 27 | int network_bind(const char *addr, int port) 28 | { 29 | int fd = -1; 30 | struct sockaddr_in sin; 31 | 32 | if((fd = socket(AF_INET, SOCK_STREAM, 0)) <= 0) { 33 | perror("Socket failed"); 34 | signal(SIGHUP, SIG_IGN); 35 | exit(1); 36 | } 37 | 38 | int reuseaddr = 1, nodelay = 1; 39 | setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const void *) &reuseaddr, 40 | sizeof(int)); 41 | setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (const void *) &nodelay, sizeof(int)); 42 | 43 | bzero(&sin, sizeof(struct sockaddr_in)); 44 | sin.sin_family = AF_INET; 45 | sin.sin_port = htons((short)(port)); 46 | 47 | if(strlen(addr) > 6) { 48 | inet_aton(addr, & (sin.sin_addr)); 49 | 50 | } else { 51 | sin.sin_addr.s_addr = INADDR_ANY; 52 | } 53 | 54 | if(bind(fd, (struct sockaddr *) &sin, sizeof(sin)) != 0) { 55 | sleep(1); 56 | 57 | if(bind(fd, (struct sockaddr *) &sin, sizeof(sin)) != 0) { 58 | perror("bind failed\n"); 59 | signal(SIGHUP, SIG_IGN); 60 | exit(1); 61 | } 62 | } 63 | 64 | if(!set_nonblocking(fd , 1)) { 65 | perror("set nonblocking failed\n"); 66 | exit(1); 67 | } 68 | 69 | if(listen(fd, 1024) != 0) { 70 | perror("listen failed\n"); 71 | signal(SIGHUP, SIG_IGN); 72 | exit(1); 73 | } 74 | 75 | return fd; 76 | } 77 | 78 | int network_raw_send(int client_fd, const char *contents, int length) 79 | { 80 | int len = 0, n; 81 | int a = 0; 82 | int max = length; 83 | 84 | while(1) { 85 | if(len >= length || length < 1) { 86 | break; 87 | } 88 | 89 | n = send(client_fd, contents + len, length - len, MSG_DONTWAIT); 90 | 91 | if(n < 0) { 92 | if(errno == EAGAIN || errno == EWOULDBLOCK) { 93 | if(a++ > max) { 94 | return 0; 95 | } 96 | 97 | continue; 98 | 99 | } else { 100 | return -1; 101 | break; 102 | } 103 | } 104 | 105 | len += n; 106 | } 107 | 108 | return len; 109 | } 110 | 111 | char *network_raw_read(int cfd, int *datas_len) 112 | { 113 | char *datas = NULL; 114 | int len = 0; 115 | int n = 0; 116 | 117 | while(1) { 118 | if(datas == NULL) { 119 | datas = (char *) malloc(sizeof(char) * EP_D_BUF_SIZE); 120 | bzero(datas, EP_D_BUF_SIZE); 121 | 122 | } else { 123 | datas = (char *) realloc(datas, sizeof(char) * (len + EP_D_BUF_SIZE)); 124 | bzero(datas + len, EP_D_BUF_SIZE); 125 | } 126 | 127 | if((n = read(cfd, datas + len, EP_D_BUF_SIZE)) <= 0) { 128 | if(n < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) { 129 | continue; 130 | } 131 | 132 | break; 133 | } 134 | 135 | len += n; 136 | 137 | if(datas[len - 3] == '\n' && datas[len - 1] == '\n') { 138 | break; 139 | } 140 | } 141 | 142 | if(datas[len - 3] == '\n' && datas[len - 1] == '\n') { 143 | datas[len - 4] = '\0'; 144 | 145 | } else { 146 | free(datas); 147 | datas = NULL; 148 | len = 0; 149 | } 150 | 151 | if(*datas_len) { 152 | *datas_len = len; 153 | } 154 | 155 | return datas; 156 | } 157 | 158 | int network_raw_sendfile(int out_fd, int in_fd, off_t *offset, size_t count) 159 | { 160 | #if defined(__APPLE__) || defined(__FreeBSD__) 161 | off_t my_count = count; 162 | int rc; 163 | 164 | // We have to do this loop nastiness, because mac os x fails with resource 165 | // temporarily unavailable (per bug e8eddb51a8) 166 | do { 167 | #if defined(__APPLE__) 168 | rc = sendfile(in_fd, out_fd, *offset, &my_count, NULL, 0); 169 | #elif defined(__FreeBSD__) 170 | rc = sendfile(in_fd, out_fd, *offset, count, NULL, &my_count, 0); 171 | #endif 172 | *offset += my_count; 173 | } while(rc != 0 && errno == 35); 174 | 175 | return my_count; 176 | #else 177 | return sendfile(out_fd, in_fd, offset, count); 178 | #endif 179 | } 180 | -------------------------------------------------------------------------------- /common/network.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #ifdef linux 5 | #include 6 | #endif 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include "smp.h" 20 | #include "times.h" 21 | 22 | #define close(fd) do { if (fd >= 0) { close(fd); fd = -1; } } while (0) 23 | #define NOAGAIN (errno != EAGAIN && errno != EWOULDBLOCK) 24 | 25 | #ifndef _NETWORK_H 26 | #define _NETWORK_H 27 | 28 | #define EP_D_BUF_SIZE 1024*32 29 | 30 | int set_nonblocking(int fd, int blocking); 31 | int network_bind(const char *addr, int port); 32 | int network_raw_send(int client_fd, const char *contents, int length); 33 | char *network_raw_read(int cfd, int *datas_len); 34 | int network_raw_sendfile(int out_fd, int in_fd, off_t *offset, size_t count); 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /common/process.c: -------------------------------------------------------------------------------- 1 | #include "process.h" 2 | #include "times.h" 3 | #include "log.h" 4 | 5 | char hostname[1024]; 6 | char process_chdir[924]; 7 | char process_name[100]; 8 | int is_daemon = 0; 9 | int is_master = 1; 10 | int process_count = 1; 11 | int pid = -1; 12 | 13 | int server_fd = 0; 14 | int ssl_server_fd = 0; 15 | int loop_fd = 0; 16 | 17 | extern logf_t *LOGF_T; 18 | 19 | static const char *process_char_last; 20 | 21 | static char buf_4096[4096] = {0}; 22 | 23 | int get_cpu_num() 24 | { 25 | FILE *f = fopen("/proc/cpuinfo", "r"); 26 | 27 | if(f == NULL) { 28 | return sysconf(_SC_NPROCESSORS_ONLN); 29 | } 30 | 31 | int cpu_cores = 0; 32 | int phisical_id = 0; 33 | 34 | while(fgets(buf_4096, 4096, f)) { 35 | if(strstr(buf_4096, "cpu cores")) { 36 | char *x = strchr(buf_4096, ':'); 37 | 38 | if(x) { 39 | x += 1; 40 | cpu_cores = atoi(x); 41 | } 42 | 43 | } else if(strstr(buf_4096, "physical id")) { 44 | char *x = strchr(buf_4096, ':'); 45 | 46 | if(x) { 47 | x += 1; 48 | int temp = atoi(x); 49 | 50 | if(temp > phisical_id) { 51 | phisical_id = temp; 52 | } 53 | } 54 | } 55 | } 56 | 57 | fclose(f); 58 | 59 | return cpu_cores * (phisical_id + 1); 60 | } 61 | 62 | int set_cpu_affinity(uint32_t n) 63 | { 64 | #ifdef linux 65 | int m = 0; 66 | cpu_set_t cpu_mask; 67 | 68 | m = sysconf(_SC_NPROCESSORS_ONLN); 69 | n = n % m; 70 | 71 | if(sched_getaffinity(0, sizeof(cpu_set_t), &cpu_mask) == -1) { 72 | return 0; 73 | } 74 | 75 | CPU_ZERO(&cpu_mask); 76 | CPU_SET(n, &cpu_mask); 77 | 78 | if(sched_setaffinity(0, sizeof(cpu_set_t), &cpu_mask) == -1) { 79 | return 0; 80 | } 81 | 82 | return 1; 83 | #else 84 | return 0; 85 | #endif 86 | } 87 | 88 | void set_process_title(const char *title, int is_master) 89 | { 90 | pid = getpid(); 91 | _argv[1] = 0; 92 | char *p = (char *)_argv[0]; 93 | bzero(p, process_char_last - p); 94 | 95 | if(is_master) { 96 | snprintf(p, process_char_last - p, "%s: %s %s%s", process_name, title, 97 | process_chdir, process_name); 98 | int i = 1; 99 | 100 | for(i = 1; i < _argc; i++) { 101 | sprintf(p, "%s %s", p, environ[i]); 102 | } 103 | 104 | } else if(is_daemon) { 105 | snprintf(p, process_char_last - p, "%s: %s", process_name, title); 106 | } 107 | } 108 | 109 | char *init_process_title(int argc, const char **argv) 110 | { 111 | pid = getpid(); 112 | _argc = argc; 113 | _argv = argv; 114 | size_t n = 0; 115 | int i = 0; 116 | #ifdef linux 117 | n = readlink("/proc/self/exe" , process_chdir , sizeof(process_chdir)); 118 | #else 119 | uint32_t new_argv0_s = sizeof(process_chdir); 120 | 121 | if(_NSGetExecutablePath(process_chdir, &new_argv0_s) == 0) { 122 | n = strlen(process_chdir); 123 | } 124 | 125 | #endif 126 | i = n; 127 | 128 | int cped = 0; 129 | 130 | while(n > 1) { 131 | if(process_chdir[n--] == '/') { 132 | if(cped++ == 0) { 133 | strncpy(process_name, ((char *) process_chdir) + n + 2, i - n); 134 | } 135 | 136 | if(process_chdir[n] == '.') { 137 | n--; 138 | continue; 139 | } 140 | 141 | process_chdir[n + 2] = '\0'; 142 | break; 143 | } 144 | } 145 | 146 | n = chdir(process_chdir); 147 | 148 | n = 0; 149 | 150 | for(i = 0; argv[i]; ++i) { 151 | n += strlen(argv[i]) + 1; 152 | } 153 | 154 | static char *raw_environ = NULL; 155 | 156 | if(raw_environ) { 157 | free(raw_environ); 158 | } 159 | 160 | raw_environ = malloc(n); 161 | 162 | char *raw = raw_environ; 163 | 164 | for(i = 0; argv[i]; ++i) { 165 | memcpy(raw, argv[i], strlen(argv[i]) + 1); 166 | environ[i] = raw; 167 | raw += strlen(argv[i]) + 1; 168 | } 169 | 170 | process_char_last = argv[0]; 171 | /* 172 | for(i = 0; i < argc; ++i) { 173 | process_char_last += strlen(argv[i]) + 1; 174 | }*/ 175 | 176 | for(i = 0; environ[i]; i++) { 177 | process_char_last += strlen(environ[i]) + 1; 178 | } 179 | 180 | return process_chdir; 181 | } 182 | 183 | static int _signal_handler = 0; 184 | int check_process_for_exit() 185 | { 186 | return _signal_handler == 1; 187 | } 188 | 189 | int signal_handler(int sig, siginfo_t *info, void *secret) 190 | { 191 | switch(sig) { 192 | case SIGHUP: 193 | kill(0, SIGWINCH); // 优雅关闭子进程 194 | break; 195 | 196 | case SIGTERM: 197 | _signal_handler = 1; 198 | break; 199 | 200 | case SIGWINCH: 201 | if(is_master == 0) { 202 | _signal_handler = 1; 203 | } 204 | 205 | break; 206 | } 207 | 208 | return 0; 209 | } 210 | 211 | void daemonize() 212 | { 213 | int i = 0; 214 | 215 | if(getppid() == 1) { 216 | return; 217 | } 218 | 219 | i = fork(); 220 | 221 | if(i < 0) { 222 | kill(getppid(), SIGINT); 223 | exit(1); 224 | } 225 | 226 | if(i > 0) { 227 | kill(getppid(), SIGINT); 228 | exit(0); 229 | } 230 | 231 | setsid(); 232 | 233 | struct sigaction mc; 234 | mc.sa_handler = (void *)signal_handler; 235 | sigemptyset(&mc.sa_mask); 236 | mc.sa_flags = SA_RESTART | SA_SIGINFO; 237 | 238 | sigaction(SIGHUP, &mc, NULL); // 终端挂起 239 | sigaction(SIGTERM, &mc, NULL); // 终止信号 240 | 241 | // 忽略以下信号 242 | mc.sa_handler = SIG_IGN; 243 | 244 | sigaction(SIGCHLD, &mc, 0); 245 | sigaction(SIGTSTP, &mc, 0); 246 | sigaction(SIGTTOU, &mc, 0); 247 | sigaction(SIGTTIN, &mc, 0); 248 | sigaction(SIGPIPE, &mc, 0); 249 | 250 | is_daemon = 1; 251 | } 252 | 253 | static void (*on_master_exit_func)() = NULL; 254 | static void (*on_worker_exit_func)() = NULL; 255 | void on_process_exit_handler(int sig, siginfo_t *info, void *secret) 256 | { 257 | if(on_worker_exit_func) { 258 | copy_buf_to_shm_log_buf(LOGF_T); 259 | on_worker_exit_func(); 260 | copy_buf_to_shm_log_buf(LOGF_T); 261 | smp_free_all(); 262 | } 263 | 264 | if(on_master_exit_func) { 265 | on_master_exit_func(); 266 | log_destory(LOGF_T); 267 | smp_free_all(); 268 | } 269 | 270 | exit(0); 271 | } 272 | 273 | void attach_on_exit(void *fun) 274 | { 275 | struct sigaction mc; 276 | mc.sa_handler = (void *)on_process_exit_handler; 277 | on_worker_exit_func = fun; 278 | sigemptyset(&mc.sa_mask); 279 | mc.sa_flags = SA_RESTART | SA_SIGINFO; 280 | 281 | sigaction(SIGHUP, &mc, NULL); // 终端挂起 282 | sigaction(SIGINT, &mc, NULL); // CTRL+C 283 | //sigaction(SIGCHLD, &mc, NULL); // 子进程退出 284 | 285 | sigaction(SIGQUIT, &mc, NULL); // 键盘的退出键 286 | sigaction(SIGILL, &mc, NULL); // 非法指令 287 | sigaction(SIGABRT, &mc, NULL); // 由 abort(3) 发出的退出指令 288 | sigaction(SIGFPE, &mc, NULL); // 浮点异常 289 | 290 | sigaction(SIGSEGV, &mc, NULL); // 无效的内存引用 291 | sigaction(SIGALRM, &mc, NULL); // 由 alarm(2) 发出的信号 292 | sigaction(SIGTERM, &mc, NULL); // 终止信号 293 | sigaction(SIGUSR1, &mc, NULL); // 用户自定义 294 | sigaction(SIGUSR2, &mc, NULL); // 用户自定义 295 | 296 | sigaction(SIGBUS, &mc, NULL); // 总线错误(内存访问错误) 297 | sigaction(SIGSYS, &mc, NULL); // 非法的系统调用 298 | 299 | sigaction(SIGTRAP, &mc, NULL); // 跟踪/断点自陷 300 | sigaction(SIGXCPU, &mc, NULL); // 超过CPU时限 301 | sigaction(SIGXFSZ, &mc, NULL); // 超过文件长度限制 302 | sigaction(SIGIOT, &mc, NULL); // IOT自陷 303 | 304 | // 忽略以下信号 305 | mc.sa_handler = SIG_IGN; 306 | sigaction(SIGPIPE, &mc, 0); 307 | sigaction(SIGTSTP, &mc, 0); // 控制终端(tty)上按下停止键 308 | sigaction(SIGTTIN, &mc, 0); // 后台进程企图从控制终端读 309 | sigaction(SIGTTOU, &mc, 0); // 后台进程企图从控制终端写 310 | 311 | mc.sa_handler = (void *)signal_handler; 312 | sigemptyset(&mc.sa_mask); 313 | mc.sa_flags = SA_SIGINFO; 314 | 315 | sigaction(SIGWINCH, &mc, NULL); // 优雅关闭 316 | } 317 | 318 | static int _workerprocess[200] = {0}; 319 | static int _workerprocess_count = 0; 320 | static void (*_workerprocess_func[200])(); 321 | int fork_process(void (*func)()) 322 | { 323 | int ret = fork(); 324 | 325 | if(ret == 0) { 326 | is_master = 0; 327 | set_process_title("worker process", 0); 328 | set_cpu_affinity(_workerprocess_count); 329 | func(_workerprocess_count); 330 | } 331 | 332 | if(ret > 0) { 333 | _workerprocess[_workerprocess_count] = ret; 334 | _workerprocess_func[_workerprocess_count] = func; 335 | _workerprocess_count++; 336 | } 337 | 338 | return ret; 339 | } 340 | 341 | void safe_process() 342 | { 343 | int i; 344 | 345 | for(i = 0; i < _workerprocess_count; i++) { 346 | if(waitpid(_workerprocess[i], NULL, WNOHANG) == -1) { 347 | int ret = fork(); 348 | 349 | if(ret == 0) { 350 | is_master = 0; 351 | set_process_title("worker process", 0); 352 | set_cpu_affinity(i); 353 | _workerprocess_func[i](i); 354 | } 355 | 356 | _workerprocess[i] = ret; 357 | } 358 | } 359 | } 360 | 361 | void start_master_main(void (*func)(), void (*onexit)()) 362 | { 363 | set_process_title("master process", 1); 364 | 365 | if(is_daemon == 0) { 366 | on_master_exit_func = onexit; 367 | } 368 | 369 | while(1) { 370 | // master 的主要工作是维护子进程的状态,如退出了会自动重启 371 | if(check_process_for_exit()) { 372 | // 检查是否收到 kill 退出信号,如果是则关闭所有子进程后,再退出 master 373 | kill(0, SIGWINCH); // 优雅关闭子进程 374 | 375 | wait_for_child_process_exit(); 376 | 377 | if(onexit) { 378 | onexit(); 379 | } 380 | 381 | log_destory(LOGF_T); 382 | smp_free_all(); 383 | 384 | exit(0); 385 | 386 | } else { 387 | // 维护子进程的状态,如退出了会自动重启 388 | safe_process(); 389 | } 390 | 391 | update_time(); 392 | func(); 393 | sleep(1); 394 | } 395 | } 396 | 397 | void wait_for_child_process_exit() 398 | { 399 | int i = 0, k = 0; 400 | 401 | while(1) { 402 | k = 0; 403 | 404 | for(i = 0; i < _workerprocess_count; i++) { 405 | if(_workerprocess[i] == 0 || waitpid(_workerprocess[i], NULL, WNOHANG) == -1) { 406 | _workerprocess[i] = 0; 407 | k++; 408 | } 409 | } 410 | 411 | if(k == _workerprocess_count) { 412 | break; 413 | } 414 | 415 | sleep(1); 416 | } 417 | 418 | log_destory(LOGF_T); 419 | } 420 | 421 | void set_process_user(const char *user, const char *group) 422 | { 423 | struct passwd *pw; 424 | const char *username = "nobody"; 425 | const char *groupname = "nobody"; 426 | 427 | if(user) { 428 | username = user; 429 | } 430 | 431 | if(group) { 432 | groupname = group; 433 | } 434 | 435 | pw = getpwnam(username); 436 | 437 | if(!pw) { 438 | printf("user %s is not exist\n", username); 439 | exit(1); 440 | } 441 | 442 | if(setuid(pw->pw_uid)) { 443 | setgid(pw->pw_gid); 444 | return; 445 | } 446 | 447 | struct group *grp = getgrnam(groupname); 448 | 449 | if(grp) { 450 | setgid(grp->gr_gid); 451 | 452 | } else { 453 | grp = getgrnam(groupname); 454 | 455 | if(grp) { 456 | setgid(grp->gr_gid); 457 | } 458 | } 459 | } 460 | 461 | char *getarg(const char *key) 462 | { 463 | int i = 0; 464 | int addp; 465 | 466 | while(i < _argc) { 467 | addp = environ[i][0] == '-' 468 | && environ[i][1] == '-' ? 2 : (environ[i][0] == '-' ? 1 : 0); 469 | 470 | if(strncmp(environ[i] + addp, key, strlen(key)) == 0 471 | && (environ[i][strlen(key) + addp] == '=' 472 | || environ[i][strlen(key) + addp] == '\0')) { 473 | return environ[i] + strlen(key) + addp + 1; 474 | } 475 | 476 | i++; 477 | } 478 | 479 | return NULL; 480 | } 481 | 482 | int new_thread(void *func) 483 | { 484 | pthread_t thread; 485 | pthread_attr_t attr; 486 | pthread_attr_init(&attr); 487 | pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); 488 | 489 | pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 490 | 491 | int i = 0; 492 | 493 | if(pthread_create(&thread, &attr, func, (void *)&i)) { 494 | return 0; 495 | } 496 | 497 | return 1; 498 | } 499 | 500 | int new_thread_p(void *func, void *i) 501 | { 502 | pthread_t thread; 503 | pthread_attr_t attr; 504 | pthread_attr_init(&attr); 505 | pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); 506 | 507 | pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 508 | 509 | if(pthread_create(&thread, &attr, func, i)) { 510 | return 0; 511 | } 512 | 513 | return 1; 514 | } 515 | -------------------------------------------------------------------------------- /common/process.h: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 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 | #ifdef __APPLE__ 22 | #include 23 | #endif 24 | 25 | #include "smp.h" 26 | 27 | #ifndef PROCESS_H 28 | #define PROCESS_H 29 | 30 | extern char **environ; 31 | const char **_argv; 32 | int _argc; 33 | 34 | int get_cpu_num(); 35 | int set_cpu_affinity(uint32_t active_cpu); 36 | void set_process_title(const char *title, int is_master); 37 | char *init_process_title(int argc, const char **argv); 38 | void start_master_main(void (*func)(), void (*onexit)()); 39 | int check_process_for_exit(); 40 | void daemonize(); 41 | void attach_on_exit(void *fun); 42 | void on_process_exit_handler(int sig, siginfo_t *info, void *secret); 43 | void set_process_user(const char *user, const char *group); 44 | char *getarg(const char *key); 45 | int fork_process(void (*func)(int i)); 46 | void safe_process(); 47 | void wait_for_child_process_exit(); 48 | int new_thread_p(void *func, void *i); 49 | #endif 50 | -------------------------------------------------------------------------------- /common/rbtree.h: -------------------------------------------------------------------------------- 1 | #ifndef __INCLUDED_RBTREE_H__ 2 | #define __INCLUDED_RBTREE_H__ 3 | 4 | /** \file rbtree.h 5 | * Declaration of associated structures and functions for a simple, intrusive 6 | * red-black tree implementation. 7 | */ 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif /* __cplusplus */ 12 | 13 | #include 14 | 15 | /** \defgroup rb_tree_state State Structures 16 | * Structures that are used to represent state of a red-black tree, including the 17 | * state of the tree itself, comparison functions used to determine how the tree 18 | * is to be traversed, and representations of red-black tree nodes themselves. 19 | * @{ 20 | */ 21 | 22 | /** 23 | * Structure that represents a node in a red-black tree. Embed this in your own 24 | * structure in order to add your structure to the given red-black tree. 25 | * Users of the rb_tree_node would embed it something like 26 | * \code{.c} 27 | struct my_sample_struct { 28 | char *name; 29 | int data; 30 | struct rb_tree_node rnode; 31 | }; 32 | * \endcode 33 | * 34 | * \note No user of `struct rb_tree_node` should ever modify or inspect any 35 | * members of the structure. 36 | */ 37 | typedef struct rb_tree_node { 38 | /** 39 | * The left child (`NULL` if empty) 40 | */ 41 | struct rb_tree_node *left; 42 | 43 | /** 44 | * The right child (`NULL` if empty) 45 | */ 46 | struct rb_tree_node *right; 47 | 48 | /** 49 | * The parent of this node (`NULL` if at root) 50 | */ 51 | struct rb_tree_node *parent; 52 | 53 | /** 54 | * The key for this node 55 | */ 56 | const void *key; 57 | 58 | /** 59 | * The color of the node 60 | */ 61 | int color; 62 | } rb_tree_node_t; 63 | 64 | /** 65 | * Pointer to a function to compare two keys, and returns as follows: 66 | * - (0, +inf] if lhs > rhs 67 | * - 0 if lhs == rhs 68 | * - [-inf, 0) if lhs < rhs 69 | */ 70 | typedef int (*rb_cmp_func_t)(const void *lhs, const void *rhs); 71 | 72 | /** 73 | * Structure representing an RB tree's associated state. Contains all 74 | * the information needed to manage the lifecycle of a RB tree. 75 | * \note Typically users should not directly manipulate the structure, 76 | * but rather use the provided accessor functions. 77 | */ 78 | typedef struct rb_tree { 79 | /** 80 | * The root of the tree 81 | */ 82 | struct rb_tree_node *root; 83 | 84 | /** 85 | * Predicate used for traversing the tree 86 | */ 87 | rb_cmp_func_t compare; 88 | 89 | /** 90 | * Left-most node of the red-black tree 91 | */ 92 | struct rb_tree_node *leftmost; 93 | } rb_tree_t; 94 | 95 | /**@} rb_tree_state */ 96 | 97 | /** \defgroup rb_result Function Results and Error Handling 98 | * @{ 99 | */ 100 | /** \typedef rb_result_t 101 | * Value of a returned result code from a red-black tree function. 102 | */ 103 | typedef int rb_result_t; 104 | 105 | /** \defgroup rb_result_code Result Codes 106 | * Error codes that can be returned from any function that returns an rb_result_t. 107 | * @{ 108 | */ 109 | 110 | /** 111 | * Function was successful 112 | */ 113 | #define RB_OK 0x0 114 | /** 115 | * Element was not found 116 | */ 117 | #define RB_NOT_FOUND 0x1 118 | /** 119 | * Bad argument provided to function (typically unexpected NULL) 120 | */ 121 | #define RB_BAD_ARG 0x2 122 | /** 123 | * Node is a duplicate of an existing node 124 | */ 125 | #define RB_DUPLICATE 0x3 126 | 127 | /**@} rb_result_code */ 128 | /**@} rb_result */ 129 | 130 | /** \brief Helper to get a pointer to a containing structure. 131 | * Given a pointer to an rb_tree_node, a target type and a member name, 132 | * return a pointer to the structure containing the `struct rb_tree_node`. 133 | * \code{.c} 134 | struct sample { 135 | const char *name; 136 | struct rb_tree_node node; 137 | }; 138 | 139 | void test(void) 140 | { 141 | struct sample samp = { .name = "Test 123" }; 142 | struct rb_tree_node *samp_node = &(samp.node); 143 | struct sample *samp2 = RB_CONTAINER_OF(samp_node, struct sample, node); 144 | 145 | assert(&samp == samp2); 146 | } 147 | * \endcode 148 | * \param x The pointer to the node 149 | * \param type The type of the containing structure 150 | * \param memb The name of the `struct rb_tree_node` in the containing structure 151 | * \return Pointer to the containing structure of the specified type 152 | */ 153 | #define RB_CONTAINER_OF(x, type, memb) \ 154 | ({ \ 155 | const __typeof__( ((type *)0)->memb ) *__member = (x); \ 156 | (type *)( (char *)__member - __offsetof__(type, memb) ); \ 157 | }) 158 | 159 | 160 | /** \defgroup rb_functions Functions for Manipulating Red-Black Trees 161 | * All functions associated with manipulating Red-Black trees using `struct rb_tree`, 162 | * inluding lifecycle functions and member manipulation and state checking functions. 163 | * @{ 164 | */ 165 | /** 166 | * \brief Construct a new, empty red-black tree. 167 | * Given a region of memory at least the size of a struct rb_tree to 168 | * store the red-black tree metadata, update it to contain an initialized, empty 169 | * red-black tree. 170 | * \param tree Pointer to the new tree. 171 | * \param compare Function used to traverse the tree. 172 | * \return RB_OK on success, an error code otherwise 173 | */ 174 | rb_result_t rb_tree_new(struct rb_tree *tree, 175 | rb_cmp_func_t compare); 176 | 177 | /** 178 | * \brief Destroy a Red-Black tree. 179 | * Clean up the state structure, clearing out the state of the tree 180 | * so that it no longer can be used. 181 | * \note Assumes that external callers will deallocate all nodes through 182 | * some application-specific mechanism. 183 | * \param tree The reference to the pointer to the tree itself. 184 | * \return RB_OK on success, an error code otherwise 185 | */ 186 | rb_result_t rb_tree_destroy(struct rb_tree *tree); 187 | 188 | /** 189 | * \brief Check if an red-black tree is empty (has no nodes). 190 | * If no nodes are present, returns a non-zero value in `is_empty` -- returns 191 | * 0 if there are nodes present. 192 | * \param tree The tree to check 193 | * \param is_empty nonzero on true, 0 otherwise 194 | * \return RB_OK on success, an error code otherwise 195 | */ 196 | rb_result_t rb_tree_empty(struct rb_tree *tree, int *is_empty); 197 | 198 | /** 199 | * \brief Find a node in the Red-Black tree given the specified key. 200 | * Given a key, search the RB-tree iteratively until the specified key is found. 201 | * This traversal is in O(log n) time, per the properties of a binary search tree. 202 | * \param tree The RB-tree to search 203 | * \param key The key to search for 204 | * \param value a reference to a pointer to receive the pointer to the rb_tree_node if key is found 205 | * \return RB_OK on success, an error code otherwise 206 | */ 207 | rb_result_t rb_tree_find(struct rb_tree *tree, 208 | const void *key, 209 | struct rb_tree_node **value); 210 | 211 | /** 212 | * \brief Insert a node into the tree. 213 | * Given a node and key, insert the node into the red-black tree and rebalance 214 | * the tree if appropriate. Insertion is O(log n) time, with two tree traversals 215 | * possible -- one for insertion (guaranteed) and one for rebalancing. 216 | * \param tree the RB tree to insert the node into 217 | * \param key The key for the node (must live as long as the node itself is in the tree) 218 | * \param node the node to be inserted into the tree 219 | * \return RB_OK on sucess, an error code otherwise 220 | */ 221 | rb_result_t rb_tree_insert(struct rb_tree *tree, 222 | const void *key, 223 | struct rb_tree_node *node); 224 | 225 | /** 226 | * \brief Remove the specified node from the Red-Black tree. 227 | * Given a pointer to the node, splice the node out of the tree, then, if applicable 228 | * rebalance the tree so the Red-Black properties are maintained. 229 | * \param tree The tree we want to remove the node from 230 | * \param node The the node we want to remove 231 | * \return RB_OK on success, an error code otherwise 232 | */ 233 | rb_result_t rb_tree_remove(struct rb_tree *tree, 234 | struct rb_tree_node *node); 235 | 236 | /** 237 | * Get the left-most element of the current tree (tracked dynamically 238 | * during insertions and removals). This operation is constant-time. 239 | * \param tree The tree to get this data element from. 240 | * \param leftmost The left-most element, returned by reference. 241 | * \return RB_OK on success, an error code otherwise. 242 | */ 243 | static inline 244 | rb_result_t rb_tree_get_leftmost(struct rb_tree *tree, 245 | struct rb_tree_node **leftmost) 246 | { 247 | if((NULL == tree) || (NULL == leftmost)) { 248 | return RB_BAD_ARG; 249 | } 250 | 251 | *leftmost = tree->leftmost; 252 | 253 | return RB_OK; 254 | } 255 | 256 | /**@} rb_functions */ 257 | 258 | #ifdef __cplusplus 259 | } // extern "C" 260 | #endif /* __cplusplus */ 261 | 262 | #endif /* __INCLUDED_RBTREE_H__ */ 263 | -------------------------------------------------------------------------------- /common/sha1.c: -------------------------------------------------------------------------------- 1 | /* 2 | * FIPS-180-1 compliant SHA-1 implementation 3 | * 4 | * Copyright (C) 2006-2013, Brainspark B.V. 5 | * 6 | * This file is part of PolarSSL (http://www.polarssl.org) 7 | * Lead Maintainer: Paul Bakker 8 | * 9 | * All rights reserved. 10 | * 11 | * This program is free software; you can redistribute it and/or modify 12 | * it under the terms of the GNU General Public License as published by 13 | * the Free Software Foundation; either version 2 of the License, or 14 | * (at your option) any later version. 15 | * 16 | * This program is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU General Public License along 22 | * with this program; if not, write to the Free Software Foundation, Inc., 23 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 24 | */ 25 | /* 26 | * The SHA-1 standard was published by NIST in 1993. 27 | * 28 | * http://www.itl.nist.gov/fipspubs/fip180-1.htm 29 | */ 30 | 31 | #include "sha1.h" 32 | 33 | #if defined(POLARSSL_FS_IO) || defined(POLARSSL_SELF_TEST) 34 | #include 35 | #endif 36 | 37 | #if !defined(POLARSSL_SHA1_ALT) 38 | 39 | /* 40 | * 32-bit integer manipulation macros (big endian) 41 | */ 42 | #ifndef GET_UINT32_BE 43 | #define GET_UINT32_BE(n,b,i) \ 44 | { \ 45 | (n) = ( (uint32_t) (b)[(i) ] << 24 ) \ 46 | | ( (uint32_t) (b)[(i) + 1] << 16 ) \ 47 | | ( (uint32_t) (b)[(i) + 2] << 8 ) \ 48 | | ( (uint32_t) (b)[(i) + 3] ); \ 49 | } 50 | #endif 51 | 52 | #ifndef PUT_UINT32_BE 53 | #define PUT_UINT32_BE(n,b,i) \ 54 | { \ 55 | (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \ 56 | (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \ 57 | (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \ 58 | (b)[(i) + 3] = (unsigned char) ( (n) ); \ 59 | } 60 | #endif 61 | 62 | /* 63 | * SHA-1 context setup 64 | */ 65 | void sha1_starts(sha1_context *ctx) 66 | { 67 | ctx->total[0] = 0; 68 | ctx->total[1] = 0; 69 | 70 | ctx->state[0] = 0x67452301; 71 | ctx->state[1] = 0xEFCDAB89; 72 | ctx->state[2] = 0x98BADCFE; 73 | ctx->state[3] = 0x10325476; 74 | ctx->state[4] = 0xC3D2E1F0; 75 | } 76 | 77 | void sha1_process(sha1_context *ctx, const unsigned char data[64]) 78 | { 79 | uint32_t temp, W[16], A, B, C, D, E; 80 | 81 | GET_UINT32_BE(W[ 0], data, 0); 82 | GET_UINT32_BE(W[ 1], data, 4); 83 | GET_UINT32_BE(W[ 2], data, 8); 84 | GET_UINT32_BE(W[ 3], data, 12); 85 | GET_UINT32_BE(W[ 4], data, 16); 86 | GET_UINT32_BE(W[ 5], data, 20); 87 | GET_UINT32_BE(W[ 6], data, 24); 88 | GET_UINT32_BE(W[ 7], data, 28); 89 | GET_UINT32_BE(W[ 8], data, 32); 90 | GET_UINT32_BE(W[ 9], data, 36); 91 | GET_UINT32_BE(W[10], data, 40); 92 | GET_UINT32_BE(W[11], data, 44); 93 | GET_UINT32_BE(W[12], data, 48); 94 | GET_UINT32_BE(W[13], data, 52); 95 | GET_UINT32_BE(W[14], data, 56); 96 | GET_UINT32_BE(W[15], data, 60); 97 | 98 | #define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n))) 99 | 100 | #define R(t) \ 101 | ( \ 102 | temp = W[(t - 3) & 0x0F] ^ W[(t - 8) & 0x0F] ^ \ 103 | W[(t - 14) & 0x0F] ^ W[ t & 0x0F], \ 104 | ( W[t & 0x0F] = S(temp,1) ) \ 105 | ) 106 | 107 | #define P(a,b,c,d,e,x) \ 108 | { \ 109 | e += S(a,5) + F(b,c,d) + K + x; b = S(b,30); \ 110 | } 111 | 112 | A = ctx->state[0]; 113 | B = ctx->state[1]; 114 | C = ctx->state[2]; 115 | D = ctx->state[3]; 116 | E = ctx->state[4]; 117 | 118 | #define F(x,y,z) (z ^ (x & (y ^ z))) 119 | #define K 0x5A827999 120 | 121 | P(A, B, C, D, E, W[0]); 122 | P(E, A, B, C, D, W[1]); 123 | P(D, E, A, B, C, W[2]); 124 | P(C, D, E, A, B, W[3]); 125 | P(B, C, D, E, A, W[4]); 126 | P(A, B, C, D, E, W[5]); 127 | P(E, A, B, C, D, W[6]); 128 | P(D, E, A, B, C, W[7]); 129 | P(C, D, E, A, B, W[8]); 130 | P(B, C, D, E, A, W[9]); 131 | P(A, B, C, D, E, W[10]); 132 | P(E, A, B, C, D, W[11]); 133 | P(D, E, A, B, C, W[12]); 134 | P(C, D, E, A, B, W[13]); 135 | P(B, C, D, E, A, W[14]); 136 | P(A, B, C, D, E, W[15]); 137 | P(E, A, B, C, D, R(16)); 138 | P(D, E, A, B, C, R(17)); 139 | P(C, D, E, A, B, R(18)); 140 | P(B, C, D, E, A, R(19)); 141 | 142 | #undef K 143 | #undef F 144 | 145 | #define F(x,y,z) (x ^ y ^ z) 146 | #define K 0x6ED9EBA1 147 | 148 | P(A, B, C, D, E, R(20)); 149 | P(E, A, B, C, D, R(21)); 150 | P(D, E, A, B, C, R(22)); 151 | P(C, D, E, A, B, R(23)); 152 | P(B, C, D, E, A, R(24)); 153 | P(A, B, C, D, E, R(25)); 154 | P(E, A, B, C, D, R(26)); 155 | P(D, E, A, B, C, R(27)); 156 | P(C, D, E, A, B, R(28)); 157 | P(B, C, D, E, A, R(29)); 158 | P(A, B, C, D, E, R(30)); 159 | P(E, A, B, C, D, R(31)); 160 | P(D, E, A, B, C, R(32)); 161 | P(C, D, E, A, B, R(33)); 162 | P(B, C, D, E, A, R(34)); 163 | P(A, B, C, D, E, R(35)); 164 | P(E, A, B, C, D, R(36)); 165 | P(D, E, A, B, C, R(37)); 166 | P(C, D, E, A, B, R(38)); 167 | P(B, C, D, E, A, R(39)); 168 | 169 | #undef K 170 | #undef F 171 | 172 | #define F(x,y,z) ((x & y) | (z & (x | y))) 173 | #define K 0x8F1BBCDC 174 | 175 | P(A, B, C, D, E, R(40)); 176 | P(E, A, B, C, D, R(41)); 177 | P(D, E, A, B, C, R(42)); 178 | P(C, D, E, A, B, R(43)); 179 | P(B, C, D, E, A, R(44)); 180 | P(A, B, C, D, E, R(45)); 181 | P(E, A, B, C, D, R(46)); 182 | P(D, E, A, B, C, R(47)); 183 | P(C, D, E, A, B, R(48)); 184 | P(B, C, D, E, A, R(49)); 185 | P(A, B, C, D, E, R(50)); 186 | P(E, A, B, C, D, R(51)); 187 | P(D, E, A, B, C, R(52)); 188 | P(C, D, E, A, B, R(53)); 189 | P(B, C, D, E, A, R(54)); 190 | P(A, B, C, D, E, R(55)); 191 | P(E, A, B, C, D, R(56)); 192 | P(D, E, A, B, C, R(57)); 193 | P(C, D, E, A, B, R(58)); 194 | P(B, C, D, E, A, R(59)); 195 | 196 | #undef K 197 | #undef F 198 | 199 | #define F(x,y,z) (x ^ y ^ z) 200 | #define K 0xCA62C1D6 201 | 202 | P(A, B, C, D, E, R(60)); 203 | P(E, A, B, C, D, R(61)); 204 | P(D, E, A, B, C, R(62)); 205 | P(C, D, E, A, B, R(63)); 206 | P(B, C, D, E, A, R(64)); 207 | P(A, B, C, D, E, R(65)); 208 | P(E, A, B, C, D, R(66)); 209 | P(D, E, A, B, C, R(67)); 210 | P(C, D, E, A, B, R(68)); 211 | P(B, C, D, E, A, R(69)); 212 | P(A, B, C, D, E, R(70)); 213 | P(E, A, B, C, D, R(71)); 214 | P(D, E, A, B, C, R(72)); 215 | P(C, D, E, A, B, R(73)); 216 | P(B, C, D, E, A, R(74)); 217 | P(A, B, C, D, E, R(75)); 218 | P(E, A, B, C, D, R(76)); 219 | P(D, E, A, B, C, R(77)); 220 | P(C, D, E, A, B, R(78)); 221 | P(B, C, D, E, A, R(79)); 222 | 223 | #undef K 224 | #undef F 225 | 226 | ctx->state[0] += A; 227 | ctx->state[1] += B; 228 | ctx->state[2] += C; 229 | ctx->state[3] += D; 230 | ctx->state[4] += E; 231 | } 232 | 233 | /* 234 | * SHA-1 process buffer 235 | */ 236 | void sha1_update(sha1_context *ctx, const unsigned char *input, size_t ilen) 237 | { 238 | size_t fill; 239 | uint32_t left; 240 | 241 | if(ilen <= 0) { 242 | return; 243 | } 244 | 245 | left = ctx->total[0] & 0x3F; 246 | fill = 64 - left; 247 | 248 | ctx->total[0] += (uint32_t) ilen; 249 | ctx->total[0] &= 0xFFFFFFFF; 250 | 251 | if(ctx->total[0] < (uint32_t) ilen) { 252 | ctx->total[1]++; 253 | } 254 | 255 | if(left && ilen >= fill) { 256 | memcpy((void *)(ctx->buffer + left), input, fill); 257 | sha1_process(ctx, ctx->buffer); 258 | input += fill; 259 | ilen -= fill; 260 | left = 0; 261 | } 262 | 263 | while(ilen >= 64) { 264 | sha1_process(ctx, input); 265 | input += 64; 266 | ilen -= 64; 267 | } 268 | 269 | if(ilen > 0) { 270 | memcpy((void *)(ctx->buffer + left), input, ilen); 271 | } 272 | } 273 | 274 | static const unsigned char sha1_padding[64] = { 275 | 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 276 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 277 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 278 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 279 | }; 280 | 281 | /* 282 | * SHA-1 final digest 283 | */ 284 | void sha1_finish(sha1_context *ctx, unsigned char output[20]) 285 | { 286 | uint32_t last, padn; 287 | uint32_t high, low; 288 | unsigned char msglen[8]; 289 | 290 | high = (ctx->total[0] >> 29) 291 | | (ctx->total[1] << 3); 292 | low = (ctx->total[0] << 3); 293 | 294 | PUT_UINT32_BE(high, msglen, 0); 295 | PUT_UINT32_BE(low, msglen, 4); 296 | 297 | last = ctx->total[0] & 0x3F; 298 | padn = (last < 56) ? (56 - last) : (120 - last); 299 | 300 | sha1_update(ctx, sha1_padding, padn); 301 | sha1_update(ctx, msglen, 8); 302 | 303 | PUT_UINT32_BE(ctx->state[0], output, 0); 304 | PUT_UINT32_BE(ctx->state[1], output, 4); 305 | PUT_UINT32_BE(ctx->state[2], output, 8); 306 | PUT_UINT32_BE(ctx->state[3], output, 12); 307 | PUT_UINT32_BE(ctx->state[4], output, 16); 308 | } 309 | 310 | #endif /* !POLARSSL_SHA1_ALT */ 311 | 312 | /* 313 | * output = SHA-1( input buffer ) 314 | */ 315 | void sha1(const unsigned char *input, size_t ilen, unsigned char output[20]) 316 | { 317 | sha1_context ctx; 318 | 319 | sha1_starts(&ctx); 320 | sha1_update(&ctx, input, ilen); 321 | sha1_finish(&ctx, output); 322 | 323 | memset(&ctx, 0, sizeof(sha1_context)); 324 | } 325 | 326 | #if defined(POLARSSL_FS_IO) 327 | /* 328 | * output = SHA-1( file contents ) 329 | */ 330 | int sha1_file(const char *path, unsigned char output[20]) 331 | { 332 | FILE *f; 333 | size_t n; 334 | sha1_context ctx; 335 | unsigned char buf[1024]; 336 | 337 | if((f = fopen(path, "rb")) == NULL) { 338 | return(POLARSSL_ERR_SHA1_FILE_IO_ERROR); 339 | } 340 | 341 | sha1_starts(&ctx); 342 | 343 | while((n = fread(buf, 1, sizeof(buf), f)) > 0) { 344 | sha1_update(&ctx, buf, n); 345 | } 346 | 347 | sha1_finish(&ctx, output); 348 | 349 | memset(&ctx, 0, sizeof(sha1_context)); 350 | 351 | if(ferror(f) != 0) { 352 | fclose(f); 353 | return(POLARSSL_ERR_SHA1_FILE_IO_ERROR); 354 | } 355 | 356 | fclose(f); 357 | return(0); 358 | } 359 | #endif /* POLARSSL_FS_IO */ 360 | 361 | /* 362 | * SHA-1 HMAC context setup 363 | */ 364 | void sha1_hmac_starts(sha1_context *ctx, const unsigned char *key, size_t keylen) 365 | { 366 | size_t i; 367 | unsigned char sum[20]; 368 | 369 | if(keylen > 64) { 370 | sha1(key, keylen, sum); 371 | keylen = 20; 372 | key = sum; 373 | } 374 | 375 | memset(ctx->ipad, 0x36, 64); 376 | memset(ctx->opad, 0x5C, 64); 377 | 378 | for(i = 0; i < keylen; i++) { 379 | ctx->ipad[i] = (unsigned char)(ctx->ipad[i] ^ key[i]); 380 | ctx->opad[i] = (unsigned char)(ctx->opad[i] ^ key[i]); 381 | } 382 | 383 | sha1_starts(ctx); 384 | sha1_update(ctx, ctx->ipad, 64); 385 | 386 | memset(sum, 0, sizeof(sum)); 387 | } 388 | 389 | /* 390 | * SHA-1 HMAC process buffer 391 | */ 392 | void sha1_hmac_update(sha1_context *ctx, const unsigned char *input, size_t ilen) 393 | { 394 | sha1_update(ctx, input, ilen); 395 | } 396 | 397 | /* 398 | * SHA-1 HMAC final digest 399 | */ 400 | void sha1_hmac_finish(sha1_context *ctx, unsigned char output[20]) 401 | { 402 | unsigned char tmpbuf[20]; 403 | 404 | sha1_finish(ctx, tmpbuf); 405 | sha1_starts(ctx); 406 | sha1_update(ctx, ctx->opad, 64); 407 | sha1_update(ctx, tmpbuf, 20); 408 | sha1_finish(ctx, output); 409 | 410 | memset(tmpbuf, 0, sizeof(tmpbuf)); 411 | } 412 | 413 | /* 414 | * SHA1 HMAC context reset 415 | */ 416 | void sha1_hmac_reset(sha1_context *ctx) 417 | { 418 | sha1_starts(ctx); 419 | sha1_update(ctx, ctx->ipad, 64); 420 | } 421 | 422 | /* 423 | * output = HMAC-SHA-1( hmac key, input buffer ) 424 | */ 425 | void sha1_hmac(const unsigned char *key, size_t keylen, 426 | const unsigned char *input, size_t ilen, 427 | unsigned char output[20]) 428 | { 429 | sha1_context ctx; 430 | 431 | sha1_hmac_starts(&ctx, key, keylen); 432 | sha1_hmac_update(&ctx, input, ilen); 433 | sha1_hmac_finish(&ctx, output); 434 | 435 | memset(&ctx, 0, sizeof(sha1_context)); 436 | } 437 | 438 | #if defined(POLARSSL_SELF_TEST) 439 | /* 440 | * FIPS-180-1 test vectors 441 | */ 442 | static unsigned char sha1_test_buf[3][57] = { 443 | { "abc" }, 444 | { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" }, 445 | { "" } 446 | }; 447 | 448 | static const int sha1_test_buflen[3] = { 449 | 3, 56, 1000 450 | }; 451 | 452 | static const unsigned char sha1_test_sum[3][20] = { 453 | { 454 | 0xA9, 0x99, 0x3E, 0x36, 0x47, 0x06, 0x81, 0x6A, 0xBA, 0x3E, 455 | 0x25, 0x71, 0x78, 0x50, 0xC2, 0x6C, 0x9C, 0xD0, 0xD8, 0x9D 456 | }, 457 | { 458 | 0x84, 0x98, 0x3E, 0x44, 0x1C, 0x3B, 0xD2, 0x6E, 0xBA, 0xAE, 459 | 0x4A, 0xA1, 0xF9, 0x51, 0x29, 0xE5, 0xE5, 0x46, 0x70, 0xF1 460 | }, 461 | { 462 | 0x34, 0xAA, 0x97, 0x3C, 0xD4, 0xC4, 0xDA, 0xA4, 0xF6, 0x1E, 463 | 0xEB, 0x2B, 0xDB, 0xAD, 0x27, 0x31, 0x65, 0x34, 0x01, 0x6F 464 | } 465 | }; 466 | 467 | /* 468 | * RFC 2202 test vectors 469 | */ 470 | static unsigned char sha1_hmac_test_key[7][26] = { 471 | { 472 | "\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B" 473 | "\x0B\x0B\x0B\x0B" 474 | }, 475 | { "Jefe" }, 476 | { 477 | "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA" 478 | "\xAA\xAA\xAA\xAA" 479 | }, 480 | { 481 | "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10" 482 | "\x11\x12\x13\x14\x15\x16\x17\x18\x19" 483 | }, 484 | { 485 | "\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C" 486 | "\x0C\x0C\x0C\x0C" 487 | }, 488 | { "" }, /* 0xAA 80 times */ 489 | { "" } 490 | }; 491 | 492 | static const int sha1_hmac_test_keylen[7] = { 493 | 20, 4, 20, 25, 20, 80, 80 494 | }; 495 | 496 | static unsigned char sha1_hmac_test_buf[7][74] = { 497 | { "Hi There" }, 498 | { "what do ya want for nothing?" }, 499 | { 500 | "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" 501 | "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" 502 | "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" 503 | "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" 504 | "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" 505 | }, 506 | { 507 | "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" 508 | "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" 509 | "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" 510 | "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" 511 | "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" 512 | }, 513 | { "Test With Truncation" }, 514 | { "Test Using Larger Than Block-Size Key - Hash Key First" }, 515 | { 516 | "Test Using Larger Than Block-Size Key and Larger" 517 | " Than One Block-Size Data" 518 | } 519 | }; 520 | 521 | static const int sha1_hmac_test_buflen[7] = { 522 | 8, 28, 50, 50, 20, 54, 73 523 | }; 524 | 525 | static const unsigned char sha1_hmac_test_sum[7][20] = { 526 | { 527 | 0xB6, 0x17, 0x31, 0x86, 0x55, 0x05, 0x72, 0x64, 0xE2, 0x8B, 528 | 0xC0, 0xB6, 0xFB, 0x37, 0x8C, 0x8E, 0xF1, 0x46, 0xBE, 0x00 529 | }, 530 | { 531 | 0xEF, 0xFC, 0xDF, 0x6A, 0xE5, 0xEB, 0x2F, 0xA2, 0xD2, 0x74, 532 | 0x16, 0xD5, 0xF1, 0x84, 0xDF, 0x9C, 0x25, 0x9A, 0x7C, 0x79 533 | }, 534 | { 535 | 0x12, 0x5D, 0x73, 0x42, 0xB9, 0xAC, 0x11, 0xCD, 0x91, 0xA3, 536 | 0x9A, 0xF4, 0x8A, 0xA1, 0x7B, 0x4F, 0x63, 0xF1, 0x75, 0xD3 537 | }, 538 | { 539 | 0x4C, 0x90, 0x07, 0xF4, 0x02, 0x62, 0x50, 0xC6, 0xBC, 0x84, 540 | 0x14, 0xF9, 0xBF, 0x50, 0xC8, 0x6C, 0x2D, 0x72, 0x35, 0xDA 541 | }, 542 | { 543 | 0x4C, 0x1A, 0x03, 0x42, 0x4B, 0x55, 0xE0, 0x7F, 0xE7, 0xF2, 544 | 0x7B, 0xE1 545 | }, 546 | { 547 | 0xAA, 0x4A, 0xE5, 0xE1, 0x52, 0x72, 0xD0, 0x0E, 0x95, 0x70, 548 | 0x56, 0x37, 0xCE, 0x8A, 0x3B, 0x55, 0xED, 0x40, 0x21, 0x12 549 | }, 550 | { 551 | 0xE8, 0xE9, 0x9D, 0x0F, 0x45, 0x23, 0x7D, 0x78, 0x6D, 0x6B, 552 | 0xBA, 0xA7, 0x96, 0x5C, 0x78, 0x08, 0xBB, 0xFF, 0x1A, 0x91 553 | } 554 | }; 555 | 556 | /* 557 | * Checkup routine 558 | */ 559 | int sha1_self_test(int verbose) 560 | { 561 | int i, j, buflen; 562 | unsigned char buf[1024]; 563 | unsigned char sha1sum[20]; 564 | sha1_context ctx; 565 | 566 | /* 567 | * SHA-1 568 | */ 569 | for(i = 0; i < 3; i++) { 570 | if(verbose != 0) { 571 | printf(" SHA-1 test #%d: ", i + 1); 572 | } 573 | 574 | sha1_starts(&ctx); 575 | 576 | if(i == 2) { 577 | memset(buf, 'a', buflen = 1000); 578 | 579 | for(j = 0; j < 1000; j++) { 580 | sha1_update(&ctx, buf, buflen); 581 | } 582 | 583 | } else 584 | sha1_update(&ctx, sha1_test_buf[i], 585 | sha1_test_buflen[i]); 586 | 587 | sha1_finish(&ctx, sha1sum); 588 | 589 | if(memcmp(sha1sum, sha1_test_sum[i], 20) != 0) { 590 | if(verbose != 0) { 591 | printf("failed\n"); 592 | } 593 | 594 | return(1); 595 | } 596 | 597 | if(verbose != 0) { 598 | printf("passed\n"); 599 | } 600 | } 601 | 602 | if(verbose != 0) { 603 | printf("\n"); 604 | } 605 | 606 | for(i = 0; i < 7; i++) { 607 | if(verbose != 0) { 608 | printf(" HMAC-SHA-1 test #%d: ", i + 1); 609 | } 610 | 611 | if(i == 5 || i == 6) { 612 | memset(buf, '\xAA', buflen = 80); 613 | sha1_hmac_starts(&ctx, buf, buflen); 614 | 615 | } else 616 | sha1_hmac_starts(&ctx, sha1_hmac_test_key[i], 617 | sha1_hmac_test_keylen[i]); 618 | 619 | sha1_hmac_update(&ctx, sha1_hmac_test_buf[i], 620 | sha1_hmac_test_buflen[i]); 621 | 622 | sha1_hmac_finish(&ctx, sha1sum); 623 | 624 | buflen = (i == 4) ? 12 : 20; 625 | 626 | if(memcmp(sha1sum, sha1_hmac_test_sum[i], buflen) != 0) { 627 | if(verbose != 0) { 628 | printf("failed\n"); 629 | } 630 | 631 | return(1); 632 | } 633 | 634 | if(verbose != 0) { 635 | printf("passed\n"); 636 | } 637 | } 638 | 639 | if(verbose != 0) { 640 | printf("\n"); 641 | } 642 | 643 | return(0); 644 | } 645 | 646 | #endif 647 | -------------------------------------------------------------------------------- /common/sha1.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file sha1.h 3 | * 4 | * \brief SHA-1 cryptographic hash function 5 | * 6 | * Copyright (C) 2006-2013, Brainspark B.V. 7 | * 8 | * This file is part of PolarSSL (http://www.polarssl.org) 9 | * Lead Maintainer: Paul Bakker 10 | * 11 | * All rights reserved. 12 | * 13 | * This program is free software; you can redistribute it and/or modify 14 | * it under the terms of the GNU General Public License as published by 15 | * the Free Software Foundation; either version 2 of the License, or 16 | * (at your option) any later version. 17 | * 18 | * This program is distributed in the hope that it will be useful, 19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 | * GNU General Public License for more details. 22 | * 23 | * You should have received a copy of the GNU General Public License along 24 | * with this program; if not, write to the Free Software Foundation, Inc., 25 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 26 | */ 27 | #ifndef POLARSSL_SHA1_H 28 | #define POLARSSL_SHA1_H 29 | 30 | #include 31 | 32 | #if defined(_MSC_VER) && !defined(EFIX64) && !defined(EFI32) 33 | #include 34 | typedef UINT32 uint32_t; 35 | #else 36 | #include 37 | #endif 38 | 39 | #define POLARSSL_ERR_SHA1_FILE_IO_ERROR -0x0076 /**< Read/write error in file. */ 40 | 41 | // Regular implementation 42 | // 43 | 44 | #ifdef __cplusplus 45 | extern "C" { 46 | #endif 47 | 48 | /** 49 | * \brief SHA-1 context structure 50 | */ 51 | typedef struct { 52 | uint32_t total[2]; /*!< number of bytes processed */ 53 | uint32_t state[5]; /*!< intermediate digest state */ 54 | unsigned char buffer[64]; /*!< data block being processed */ 55 | 56 | unsigned char ipad[64]; /*!< HMAC: inner padding */ 57 | unsigned char opad[64]; /*!< HMAC: outer padding */ 58 | } 59 | sha1_context; 60 | 61 | /** 62 | * \brief SHA-1 context setup 63 | * 64 | * \param ctx context to be initialized 65 | */ 66 | void sha1_starts(sha1_context *ctx); 67 | 68 | /** 69 | * \brief SHA-1 process buffer 70 | * 71 | * \param ctx SHA-1 context 72 | * \param input buffer holding the data 73 | * \param ilen length of the input data 74 | */ 75 | void sha1_update(sha1_context *ctx, const unsigned char *input, size_t ilen); 76 | 77 | /** 78 | * \brief SHA-1 final digest 79 | * 80 | * \param ctx SHA-1 context 81 | * \param output SHA-1 checksum result 82 | */ 83 | void sha1_finish(sha1_context *ctx, unsigned char output[20]); 84 | 85 | /* Internal use */ 86 | void sha1_process(sha1_context *ctx, const unsigned char data[64]); 87 | 88 | #ifdef __cplusplus 89 | } 90 | #endif 91 | 92 | #ifdef __cplusplus 93 | extern "C" { 94 | #endif 95 | 96 | /** 97 | * \brief Output = SHA-1( input buffer ) 98 | * 99 | * \param input buffer holding the data 100 | * \param ilen length of the input data 101 | * \param output SHA-1 checksum result 102 | */ 103 | void sha1(const unsigned char *input, size_t ilen, unsigned char output[20]); 104 | 105 | /** 106 | * \brief Output = SHA-1( file contents ) 107 | * 108 | * \param path input file name 109 | * \param output SHA-1 checksum result 110 | * 111 | * \return 0 if successful, or POLARSSL_ERR_SHA1_FILE_IO_ERROR 112 | */ 113 | int sha1_file(const char *path, unsigned char output[20]); 114 | 115 | /** 116 | * \brief SHA-1 HMAC context setup 117 | * 118 | * \param ctx HMAC context to be initialized 119 | * \param key HMAC secret key 120 | * \param keylen length of the HMAC key 121 | */ 122 | void sha1_hmac_starts(sha1_context *ctx, const unsigned char *key, size_t keylen); 123 | 124 | /** 125 | * \brief SHA-1 HMAC process buffer 126 | * 127 | * \param ctx HMAC context 128 | * \param input buffer holding the data 129 | * \param ilen length of the input data 130 | */ 131 | void sha1_hmac_update(sha1_context *ctx, const unsigned char *input, size_t ilen); 132 | 133 | /** 134 | * \brief SHA-1 HMAC final digest 135 | * 136 | * \param ctx HMAC context 137 | * \param output SHA-1 HMAC checksum result 138 | */ 139 | void sha1_hmac_finish(sha1_context *ctx, unsigned char output[20]); 140 | 141 | /** 142 | * \brief SHA-1 HMAC context reset 143 | * 144 | * \param ctx HMAC context to be reset 145 | */ 146 | void sha1_hmac_reset(sha1_context *ctx); 147 | 148 | /** 149 | * \brief Output = HMAC-SHA-1( hmac key, input buffer ) 150 | * 151 | * \param key HMAC secret key 152 | * \param keylen length of the HMAC key 153 | * \param input buffer holding the data 154 | * \param ilen length of the input data 155 | * \param output HMAC-SHA-1 result 156 | */ 157 | void sha1_hmac(const unsigned char *key, size_t keylen, 158 | const unsigned char *input, size_t ilen, 159 | unsigned char output[20]); 160 | 161 | /** 162 | * \brief Checkup routine 163 | * 164 | * \return 0 if successful, or 1 if the test failed 165 | */ 166 | int sha1_self_test(int verbose); 167 | 168 | #ifdef __cplusplus 169 | } 170 | #endif 171 | 172 | #endif /* sha1.h */ 173 | -------------------------------------------------------------------------------- /common/sha256.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file sha256.h 3 | * 4 | * \brief SHA-224 and SHA-256 cryptographic hash function 5 | * 6 | * Copyright (C) 2006-2013, Brainspark B.V. 7 | * 8 | * This file is part of PolarSSL (http://www.polarssl.org) 9 | * Lead Maintainer: Paul Bakker 10 | * 11 | * All rights reserved. 12 | * 13 | * This program is free software; you can redistribute it and/or modify 14 | * it under the terms of the GNU General Public License as published by 15 | * the Free Software Foundation; either version 2 of the License, or 16 | * (at your option) any later version. 17 | * 18 | * This program is distributed in the hope that it will be useful, 19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 | * GNU General Public License for more details. 22 | * 23 | * You should have received a copy of the GNU General Public License along 24 | * with this program; if not, write to the Free Software Foundation, Inc., 25 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 26 | */ 27 | #ifndef POLARSSL_SHA256_H 28 | #define POLARSSL_SHA256_H 29 | 30 | #include 31 | 32 | #if defined(_MSC_VER) && !defined(EFIX64) && !defined(EFI32) 33 | #include 34 | typedef UINT32 uint32_t; 35 | #else 36 | #include 37 | #endif 38 | 39 | #define POLARSSL_ERR_SHA256_FILE_IO_ERROR -0x0078 /**< Read/write error in file. */ 40 | 41 | #if !defined(POLARSSL_SHA256_ALT) 42 | // Regular implementation 43 | // 44 | 45 | #ifdef __cplusplus 46 | extern "C" { 47 | #endif 48 | 49 | /** 50 | * \brief SHA-256 context structure 51 | */ 52 | typedef struct { 53 | uint32_t total[2]; /*!< number of bytes processed */ 54 | uint32_t state[8]; /*!< intermediate digest state */ 55 | unsigned char buffer[64]; /*!< data block being processed */ 56 | 57 | unsigned char ipad[64]; /*!< HMAC: inner padding */ 58 | unsigned char opad[64]; /*!< HMAC: outer padding */ 59 | int is224; /*!< 0 => SHA-256, else SHA-224 */ 60 | } 61 | sha256_context; 62 | 63 | /** 64 | * \brief SHA-256 context setup 65 | * 66 | * \param ctx context to be initialized 67 | * \param is224 0 = use SHA256, 1 = use SHA224 68 | */ 69 | void sha256_starts(sha256_context *ctx, int is224); 70 | 71 | /** 72 | * \brief SHA-256 process buffer 73 | * 74 | * \param ctx SHA-256 context 75 | * \param input buffer holding the data 76 | * \param ilen length of the input data 77 | */ 78 | void sha256_update(sha256_context *ctx, const unsigned char *input, size_t ilen); 79 | 80 | /** 81 | * \brief SHA-256 final digest 82 | * 83 | * \param ctx SHA-256 context 84 | * \param output SHA-224/256 checksum result 85 | */ 86 | void sha256_finish(sha256_context *ctx, unsigned char output[32]); 87 | 88 | /* Internal use */ 89 | void sha256_process(sha256_context *ctx, const unsigned char data[64]); 90 | 91 | #ifdef __cplusplus 92 | } 93 | #endif 94 | 95 | #else /* POLARSSL_SHA256_ALT */ 96 | #include "sha256_alt.h" 97 | #endif /* POLARSSL_SHA256_ALT */ 98 | 99 | #ifdef __cplusplus 100 | extern "C" { 101 | #endif 102 | 103 | /** 104 | * \brief Output = SHA-256( input buffer ) 105 | * 106 | * \param input buffer holding the data 107 | * \param ilen length of the input data 108 | * \param output SHA-224/256 checksum result 109 | * \param is224 0 = use SHA256, 1 = use SHA224 110 | */ 111 | void sha256(const unsigned char *input, size_t ilen, 112 | unsigned char output[32], int is224); 113 | 114 | /** 115 | * \brief Output = SHA-256( file contents ) 116 | * 117 | * \param path input file name 118 | * \param output SHA-224/256 checksum result 119 | * \param is224 0 = use SHA256, 1 = use SHA224 120 | * 121 | * \return 0 if successful, or POLARSSL_ERR_SHA256_FILE_IO_ERROR 122 | */ 123 | int sha256_file(const char *path, unsigned char output[32], int is224); 124 | 125 | /** 126 | * \brief SHA-256 HMAC context setup 127 | * 128 | * \param ctx HMAC context to be initialized 129 | * \param key HMAC secret key 130 | * \param keylen length of the HMAC key 131 | * \param is224 0 = use SHA256, 1 = use SHA224 132 | */ 133 | void sha256_hmac_starts(sha256_context *ctx, const unsigned char *key, 134 | size_t keylen, int is224); 135 | 136 | /** 137 | * \brief SHA-256 HMAC process buffer 138 | * 139 | * \param ctx HMAC context 140 | * \param input buffer holding the data 141 | * \param ilen length of the input data 142 | */ 143 | void sha256_hmac_update(sha256_context *ctx, const unsigned char *input, size_t ilen); 144 | 145 | /** 146 | * \brief SHA-256 HMAC final digest 147 | * 148 | * \param ctx HMAC context 149 | * \param output SHA-224/256 HMAC checksum result 150 | */ 151 | void sha256_hmac_finish(sha256_context *ctx, unsigned char output[32]); 152 | 153 | /** 154 | * \brief SHA-256 HMAC context reset 155 | * 156 | * \param ctx HMAC context to be reset 157 | */ 158 | void sha256_hmac_reset(sha256_context *ctx); 159 | 160 | /** 161 | * \brief Output = HMAC-SHA-256( hmac key, input buffer ) 162 | * 163 | * \param key HMAC secret key 164 | * \param keylen length of the HMAC key 165 | * \param input buffer holding the data 166 | * \param ilen length of the input data 167 | * \param output HMAC-SHA-224/256 result 168 | * \param is224 0 = use SHA256, 1 = use SHA224 169 | */ 170 | void sha256_hmac(const unsigned char *key, size_t keylen, 171 | const unsigned char *input, size_t ilen, 172 | unsigned char output[32], int is224); 173 | 174 | /** 175 | * \brief Checkup routine 176 | * 177 | * \return 0 if successful, or 1 if the test failed 178 | */ 179 | int sha256_self_test(int verbose); 180 | 181 | #ifdef __cplusplus 182 | } 183 | #endif 184 | 185 | #endif /* sha256.h */ 186 | -------------------------------------------------------------------------------- /common/shm.c: -------------------------------------------------------------------------------- 1 | #include "shm.h" 2 | #include 3 | #include 4 | 5 | extern char process_chdir[924]; 6 | extern int is_daemon; 7 | static int shm_ftok_id = 1; 8 | 9 | shm_t *shm_malloc(size_t size) 10 | { 11 | int oflag, shm_id; 12 | 13 | /* create and init a shared memory segment for the counter */ 14 | oflag = IPC_CREAT | SHM_R | SHM_W | IPC_EXCL; 15 | 16 | //ftok(process_chdir, shm_ftok_id) 17 | if((shm_id = shmget(IPC_PRIVATE, size + sizeof(int), oflag)) < 0) { 18 | perror("shmget error\n"); 19 | return NULL; 20 | } 21 | 22 | void *p = NULL; 23 | 24 | if((p = shmat(shm_id, NULL, 0)) < 0) { 25 | return NULL; 26 | } 27 | 28 | memset(p, 0, size + sizeof(int)); 29 | 30 | shm_t *o = malloc(sizeof(shm_t)); 31 | o->shm_id = shm_id; 32 | o->p = p + sizeof(int); 33 | 34 | shm_ftok_id++; 35 | 36 | return o; 37 | } 38 | 39 | void shm_free(shm_t *shm) 40 | { 41 | if(shm == NULL) { 42 | return; 43 | } 44 | 45 | if(shmctl(shm->shm_id, IPC_RMID, NULL) == -1) { 46 | perror("shmctl del error\n"); 47 | } 48 | 49 | free(shm); 50 | shm = NULL; 51 | } 52 | 53 | int shm_lock(shm_t *shm) 54 | { 55 | if(is_daemon == 0) { 56 | return 1; 57 | } 58 | 59 | gcc_lock((int *)((char *)shm->p - sizeof(int))); 60 | return 1; 61 | } 62 | 63 | int shm_unlock(shm_t *shm) 64 | { 65 | if(is_daemon == 0) { 66 | return 1; 67 | } 68 | 69 | gcc_unlock((int *)((char *)shm->p - sizeof(int))); 70 | return 1; 71 | } 72 | -------------------------------------------------------------------------------- /common/shm.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "smp.h" 4 | 5 | #ifndef __SHM_H 6 | #define __SHM_H 7 | 8 | typedef struct _shm_t { 9 | int shm_id; 10 | void *p; 11 | } shm_t; 12 | 13 | shm_t *shm_malloc(size_t size); 14 | void shm_free(shm_t *shm); 15 | int shm_lock(shm_t *shm); 16 | int shm_unlock(shm_t *shm); 17 | 18 | #include 19 | 20 | #define gcc_lock(lkp) do{ \ 21 | while(!__sync_bool_compare_and_swap(lkp, 0, 1)){ \ 22 | sched_yield(); \ 23 | } \ 24 | }while(0) 25 | 26 | #define gcc_try_lock(lkp) ({ \ 27 | (__sync_bool_compare_and_swap(lkp, 0, 1) ? 0 : -1); \ 28 | }) 29 | 30 | #define gcc_unlock(lkp) do{ \ 31 | *(lkp) = 0; \ 32 | }while(0) 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /common/smp.c: -------------------------------------------------------------------------------- 1 | #include "smp.h" 2 | /* 3 | simple memory pool 4 | */ 5 | 6 | //#define MAX_SMP_SIZE 2048*32 // total size = 2048*2048*32 = 128MB, max block = 64KB 7 | #define MAX_SMP_SIZE 4096*32 // total size = 4096*4096*32 = 512MB, max block = 128KB 8 | 9 | /* 10 | --------------------------- 11 | | 32 | 64 | ... | 2048*32 | 12 | | 32 | 64 | ... | ------- | // count 1 13 | | .. | .. | ... | | 14 | | 32 | -- | ... | | // count (2048*32)/64 = 1024 15 | | 32 | .. | ... | | 16 | | -- | | | | // count 2048 17 | --------------------------- 18 | */ 19 | 20 | static volatile int smp_locker; 21 | static void smp_lock() 22 | { 23 | while(__sync_val_compare_and_swap(&smp_locker, 0, 1)); 24 | 25 | asm volatile("lfence" ::: "memory"); 26 | } 27 | static void smp_unlock() 28 | { 29 | smp_locker = 0; 30 | asm volatile("sfence" ::: "memory"); 31 | } 32 | 33 | static void *head[MAX_SMP_SIZE / 32] = {0}; 34 | static unsigned short link_c[MAX_SMP_SIZE / 32] = {0}; 35 | 36 | #define _SSIZE (sizeof(unsigned short)) 37 | #define _ISIZE (sizeof(unsigned int)) 38 | #define _I_SSIZE (_ISIZE + _SSIZE) 39 | #define _S_PTR(p) (*(unsigned short *)(p)) 40 | #define _I_PTR(p) (*(unsigned int *)(p)) 41 | 42 | typedef struct { 43 | void *priv; 44 | void *next; 45 | char f[64]; 46 | unsigned int l; 47 | char f2[64]; 48 | unsigned int l2; 49 | void *p; 50 | } smp_link_t; 51 | 52 | static void *smp_link[32] = {0}; 53 | static char old_f[64] = {0}; 54 | static int old_l = 0; 55 | 56 | static void add_to_smp_link(void *p, int s, char *f, int l) 57 | { 58 | if(!p) { 59 | return ; 60 | } 61 | 62 | if(s % 32 > 0) { 63 | s += 32 - (s % 32); 64 | } 65 | 66 | s = s / 32; 67 | 68 | smp_link_t *n = malloc(sizeof(smp_link_t)); 69 | n->priv = NULL; 70 | n->next = NULL; 71 | n->l = l; 72 | n->p = p; 73 | bzero(n->f, 64); 74 | bzero(n->f2, 64); 75 | 76 | int fl = strlen(f); 77 | int fs = 0; 78 | 79 | if(fl > 63) { 80 | fs = fl - 63; 81 | fl = 63; 82 | } 83 | 84 | memcpy(n->f, f + fs, fl); 85 | n->f[fl] = '\0'; 86 | 87 | if(!old_l) { 88 | memcpy(n->f2, f + fs, fl); 89 | n->f2[fl] = '\0'; 90 | n->l2 = l; 91 | 92 | } else { 93 | memcpy(n->f2, old_f, strlen(old_f)); 94 | n->f2[fl] = '\0'; 95 | n->l2 = old_l; 96 | } 97 | 98 | smp_lock(); 99 | 100 | if(!smp_link[s % 32]) { 101 | smp_link[s % 32] = n; 102 | 103 | } else { 104 | n->next = smp_link[s % 32]; 105 | ((smp_link_t *)smp_link[s % 32])->priv = n; 106 | smp_link[s % 32] = n; 107 | } 108 | 109 | smp_unlock(); 110 | } 111 | 112 | #ifdef SMPDEBUG 113 | static void delete_in_smp_link(void *p, int s) 114 | { 115 | if(!p) { 116 | return ; 117 | } 118 | 119 | if(s % 32 > 0) { 120 | s += 32 - (s % 32); 121 | } 122 | 123 | s = s / 32; 124 | smp_lock(); 125 | smp_link_t *n = smp_link[s % 32]; 126 | 127 | while(n) { 128 | if(n->p == p) { 129 | if(n->priv) { 130 | ((smp_link_t *)n->priv)->next = n->next; 131 | 132 | if(n->next) { 133 | ((smp_link_t *)n->next)->priv = n->priv; 134 | } 135 | 136 | } else { 137 | if(n->next) { 138 | ((smp_link_t *)n->next)->priv = n->priv; 139 | smp_link[s % 32] = n->next; 140 | 141 | } else { 142 | smp_link[s % 32] = NULL; 143 | } 144 | } 145 | 146 | void *m = n; 147 | n = n->next; 148 | free(m); 149 | smp_unlock(); 150 | return ; 151 | 152 | } else { 153 | n = n->next; 154 | } 155 | 156 | } 157 | 158 | smp_unlock(); 159 | printf("free error %p\n", p); 160 | exit(1); 161 | } 162 | #endif 163 | 164 | void dump_smp_link() 165 | { 166 | #ifdef SMPDEBUG 167 | smp_lock(); 168 | int i = 0; 169 | smp_link_t *n = NULL; 170 | 171 | for(i = 0; i < 32; i++) { 172 | printf("%d ========================================\n", i * 32); 173 | n = smp_link[i]; 174 | 175 | while(n) { 176 | printf("%s:%d %s:%d %p\n", n->f2, n->l2, n->f, n->l, n->p); 177 | n = n->next; 178 | } 179 | } 180 | 181 | smp_unlock(); 182 | #endif 183 | } 184 | 185 | void *smp_malloc(unsigned int size) 186 | { 187 | if(size % 32 > 0) { 188 | size += 32 - (size % 32); 189 | } 190 | 191 | if(size < 1) { 192 | return NULL; 193 | } 194 | 195 | if(size > MAX_SMP_SIZE) { 196 | void *p = malloc(size + _I_SSIZE); 197 | 198 | if(!p) { 199 | return NULL; 200 | } 201 | 202 | _I_PTR(p) = size; 203 | _S_PTR((char *)p + _ISIZE) = 0; 204 | 205 | return (char *)p + _I_SSIZE; 206 | } 207 | 208 | short k = (size / 32) % (MAX_SMP_SIZE / 32); 209 | void *p = NULL; 210 | smp_lock(); 211 | 212 | if(head[k] == NULL) { 213 | p = malloc(_SSIZE + size); 214 | 215 | if(!p) { 216 | smp_unlock(); 217 | return NULL; 218 | } 219 | 220 | _S_PTR(p) = size / 32; 221 | 222 | } else { 223 | link_c[k] --; 224 | p = head[k]; 225 | head[k] = *(void **)((char *)p + _SSIZE); 226 | 227 | } 228 | 229 | smp_unlock(); 230 | return (char *)p + _SSIZE; 231 | } 232 | 233 | void *_smp_malloc(unsigned int size, char *f, int l) 234 | { 235 | void *r = smp_malloc(size); 236 | old_l = 0; 237 | add_to_smp_link(r, size > MAX_SMP_SIZE ? 0 : size, f, l); 238 | return r; 239 | } 240 | 241 | void *smp_realloc(void *p, unsigned int _size) 242 | { 243 | if(!p) { 244 | return NULL; 245 | } 246 | 247 | if(_size % 32 > 0) { 248 | _size += 32 - (_size % 32); 249 | } 250 | 251 | unsigned int old_size = 0; 252 | 253 | if(_S_PTR((char *)p - _SSIZE) == 0) { 254 | old_size = _I_PTR((char *)p - _I_SSIZE); 255 | 256 | } else { 257 | old_size = _S_PTR((char *)p - _SSIZE) * 32; 258 | } 259 | 260 | if(_size <= old_size) { 261 | return p; 262 | } 263 | 264 | void *t = smp_malloc(_size); 265 | 266 | if(!t) { 267 | return NULL; 268 | } 269 | 270 | if(_S_PTR((char *)p - _SSIZE) == 0) { 271 | memcpy(t, p, _I_PTR((char *)p - _I_SSIZE)); 272 | 273 | } else { 274 | memcpy(t, p, _S_PTR((char *)p - _SSIZE) * 32); 275 | } 276 | 277 | smp_free(p); 278 | 279 | return t; 280 | } 281 | 282 | void *_smp_realloc(void *p, unsigned int size, char *f, int l) 283 | { 284 | old_l = 0; 285 | int old_size = 0; 286 | 287 | if(_S_PTR((char *)p - _SSIZE) == 0) { 288 | old_size = _I_PTR((char *)p - _I_SSIZE); 289 | 290 | } else { 291 | old_size = _S_PTR((char *)p - _SSIZE) * 32; 292 | } 293 | 294 | old_size = old_size / 32; 295 | 296 | smp_link_t *n = smp_link[old_size % 32]; 297 | 298 | while(n) { 299 | if(n->p == p) { 300 | memcpy(old_f, n->f2, strlen(n->f2)); 301 | old_f[strlen(n->f2)] = '\0'; 302 | old_l = n->l2; 303 | break; 304 | 305 | } else { 306 | n = n->next; 307 | } 308 | 309 | } 310 | 311 | void *r = smp_realloc(p, size); 312 | 313 | if(r != p) { 314 | add_to_smp_link(r, size > MAX_SMP_SIZE ? 0 : size, f, l); 315 | } 316 | 317 | return r; 318 | } 319 | 320 | int smp_free(void *p) 321 | { 322 | if(!p) { 323 | return 0; 324 | } 325 | 326 | if(_S_PTR((char *)p - _SSIZE) == 0) { 327 | #ifdef SMPDEBUG 328 | delete_in_smp_link(p, 0); 329 | #endif 330 | free((char *)p - _I_SSIZE); 331 | return 1; 332 | } 333 | 334 | #ifdef SMPDEBUG 335 | void *o = p; 336 | #endif 337 | p = (char *)p - _SSIZE; 338 | 339 | short k = (_S_PTR(p)) % (MAX_SMP_SIZE / 32); 340 | #ifdef SMPDEBUG 341 | delete_in_smp_link(o, (_S_PTR(p)) * 32); 342 | #endif 343 | 344 | int max = 0; 345 | 346 | if(_S_PTR(p) == 128) { // 4096 347 | max = 2000; 348 | 349 | } else if(_S_PTR(p) == 256) { // 8192 350 | max = 1000; 351 | 352 | } else { 353 | max = MAX_SMP_SIZE / (_S_PTR(p) * 32); 354 | } 355 | 356 | smp_lock(); 357 | 358 | if(link_c[k]++ >= max) { 359 | link_c[k] --; 360 | free(p); 361 | smp_unlock(); 362 | return 1; 363 | } 364 | 365 | *(void **)((char *)p + _SSIZE) = head[k]; 366 | 367 | head[k] = p; 368 | smp_unlock(); 369 | return 1; 370 | } 371 | 372 | int _smp_free(void *p, char *f, int l) 373 | { 374 | return smp_free(p); 375 | } 376 | 377 | #ifdef SMPDEBUG 378 | static int all_freed = 0; 379 | #endif 380 | void smp_free_all() 381 | { 382 | #ifdef SMPDEBUG 383 | 384 | if(all_freed++) { 385 | return; 386 | } 387 | 388 | int i = 0; 389 | smp_link_t *n = NULL, *m = NULL; 390 | void *p = NULL; 391 | smp_lock(); 392 | 393 | for(i = 0; i < 32; i++) { 394 | n = smp_link[i]; 395 | 396 | while(n) { 397 | m = n; 398 | n = n->next; 399 | p = m->p; 400 | 401 | if(_S_PTR((char *)p - _SSIZE) == 0) { 402 | free(((char *)p - _I_SSIZE)); 403 | 404 | } else { 405 | free(((char *)p - _SSIZE)); 406 | } 407 | 408 | free(m); 409 | } 410 | } 411 | 412 | void *np = NULL; 413 | 414 | for(i = 0; i < MAX_SMP_SIZE / 32; i++) { 415 | np = head[i]; 416 | 417 | while(np) { 418 | p = np; 419 | np = *(void **)((char *)np + _SSIZE); 420 | free(p); 421 | } 422 | } 423 | 424 | smp_unlock(); 425 | #endif 426 | } 427 | 428 | #ifdef SMP_DEBUG 429 | 430 | #define malloc(s) _smp_malloc(s, __FILE__, __LINE__) 431 | #define realloc(p,s) _smp_realloc(p,s, __FILE__, __LINE__) 432 | #define free(p) _smp_free(p, __FILE__, __LINE__) 433 | 434 | void main() 435 | { 436 | char *a = malloc(10240); 437 | char *b = malloc(32); 438 | free(a); 439 | free(b); 440 | a = malloc(10240); 441 | b = malloc(32); 442 | free(b); 443 | free(a); 444 | a = malloc(10240); 445 | b = malloc(32); 446 | 447 | a = realloc(a, 10340); 448 | memset(a, 'a', 10340); 449 | a[10339] = '\0'; 450 | printf("%s\n", a + 10300); 451 | 452 | b = realloc(b, 64); 453 | memset(b, 'b', 64); 454 | b[63] = '\0'; 455 | printf("%s\n", b); 456 | free(a); 457 | free(b); 458 | 459 | a = malloc(2048 * 32 + 1); 460 | free(a); 461 | a = malloc(2048 * 32 + 1); 462 | b = malloc(MAX_SMP_SIZE - 1024); 463 | b = realloc(b, MAX_SMP_SIZE + 4096); 464 | dump_smp_link(); 465 | free(a); 466 | free(b); 467 | 468 | exit(0); 469 | } 470 | 471 | #endif 472 | -------------------------------------------------------------------------------- /common/smp.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #ifndef _SMP_H 6 | #define _SMP_H 7 | 8 | void *smp_malloc(unsigned int size); 9 | void *smp_realloc(void *p, unsigned int _size); 10 | int smp_free(void *p); 11 | 12 | void *_smp_malloc(unsigned int size, char *f, int l); 13 | void *_smp_realloc(void *p, unsigned int size, char *f, int l); 14 | int _smp_free(void *p, char *f, int l); 15 | 16 | void dump_smp_link(); 17 | void smp_free_all(); 18 | 19 | #else 20 | 21 | #ifdef SMPDEBUG 22 | #define malloc(s) _smp_malloc(s, __FILE__, __LINE__) 23 | #define realloc(p,s) _smp_realloc(p,s, __FILE__, __LINE__) 24 | #define free(p) _smp_free(p, __FILE__, __LINE__) 25 | #else 26 | #define malloc(s) smp_malloc(s) 27 | #define realloc(p,s) smp_realloc(p,s) 28 | #define free(p) smp_free(p) 29 | #endif 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /common/strings.c: -------------------------------------------------------------------------------- 1 | #include "strings.h" 2 | 3 | int stricmp(const void *s1, const void *s2) 4 | { 5 | const unsigned char *p1 = (const unsigned char *) s1; 6 | const unsigned char *p2 = (const unsigned char *) s2; 7 | int result; 8 | 9 | if(p1 == p2) { 10 | return 0; 11 | } 12 | 13 | while((result = tolower(*p1) - tolower(*p2++)) == 0) { 14 | if(*p1++ == '\0') { 15 | break; 16 | } 17 | } 18 | 19 | return result; 20 | } 21 | 22 | int strincmp(const void *s1, const void *s2, size_t n) 23 | { 24 | const unsigned char *p1 = s1; 25 | const unsigned char *p2 = s2; 26 | int d = 0; 27 | 28 | for(; n != 0; n--) { 29 | int c1 = tolower(*p1++); 30 | int c2 = tolower(*p2++); 31 | 32 | if(((d = c1 - c2) != 0) || (c2 == '\0')) { 33 | break; 34 | } 35 | } 36 | 37 | return d; 38 | } 39 | 40 | const char *stristr(const void *str, const void *pat, int length) 41 | { 42 | const unsigned char *_str = str; 43 | const unsigned char *_pat = pat; 44 | int _dict[128] = {0}; 45 | 46 | if(!_str || !_pat) { 47 | return NULL; 48 | } 49 | 50 | if(length < 1) { 51 | length = strlen((char *)_str); 52 | } 53 | 54 | int pat_len = 0, i = 0, j = 0, m = 0; 55 | 56 | while(_pat[i++]) { 57 | _dict[tolower(_pat[pat_len]) % 128] = pat_len + 1; 58 | pat_len++; 59 | } 60 | 61 | for(i = pat_len - 1; i < length; i += pat_len) { 62 | j = _dict[tolower(_str[i]) % 128]; 63 | 64 | if(j) { 65 | m = i; 66 | i -= (j - 1); 67 | 68 | if(tolower(_str[i]) != tolower(_pat[0])) { 69 | continue; 70 | } 71 | 72 | for(; i < m + (pat_len - j); i++) { 73 | if((length - i) >= pat_len && tolower(_str[i + pat_len - 1]) == tolower(_pat[pat_len - 1])) { 74 | for(j = 1; j < pat_len; j++) { 75 | if(tolower(_str[i + j]) != tolower(_pat[j])) { 76 | break; 77 | } 78 | } 79 | 80 | if(j < pat_len) { 81 | continue; 82 | } 83 | 84 | return (char *)_str + i; 85 | } 86 | } 87 | } 88 | } 89 | 90 | return NULL; 91 | } 92 | 93 | void random_string(void *string, size_t length, int s) 94 | { 95 | char *_string = (char *)string; 96 | /* Seed number for rand() */ 97 | struct timeb t; 98 | ftime(&t); 99 | srand((unsigned int) 1000 * t.time + t.millitm + s); 100 | 101 | unsigned int num_chars = length; 102 | unsigned int i; 103 | unsigned int j = rand(); 104 | 105 | for(i = 0; i < num_chars; ++i) { 106 | if(j % 1000 < 500) { 107 | _string[i] = j % ('g' - 'a') + 'a'; 108 | 109 | } else { 110 | _string[i] = j % (':' - '0') + '0'; 111 | } 112 | 113 | j = rand(); 114 | } 115 | } 116 | 117 | unsigned long _strtoul(void *str64, int base) 118 | { 119 | unsigned char *_str64 = (unsigned char *)str64; 120 | unsigned long i, j, nResult = 0; 121 | char _t[32] = {0}; 122 | int m = strlen((char *)_str64); 123 | 124 | if(m > 32) { 125 | return 0; 126 | } 127 | 128 | for(i = 0; i < m; i++) { 129 | if(_str64[i] == '\r' || _str64[i] == '\n' || _str64[i] == '\t' || _str64[i] == ' ' || _str64[i] == ';' 130 | || _str64[i] == '-') { 131 | break; 132 | } 133 | 134 | _t[i] = _str64[i]; 135 | } 136 | 137 | for(i = 0; i < strlen(_t); i++) { 138 | j = _t[i] == ',' ? 62 : (_t[i] == '.' ? 63 : (_t[i] <= '9' ? _t[i] - '0' : 139 | (_t[i] <= 'Z' ? 36 + _t[i] - 'A' : 10 + _t[i] - 'a'))); 140 | nResult += pow(base, (strlen(_t) - i - 1)) * j ; 141 | } 142 | 143 | return nResult; 144 | } 145 | 146 | typedef struct { 147 | unsigned long quot; 148 | unsigned long rem; 149 | } _uldiv_t; 150 | 151 | static _uldiv_t _uldiv(unsigned long number, unsigned long denom) 152 | { 153 | _uldiv_t rv; 154 | 155 | rv.quot = number / denom; 156 | rv.rem = number % denom; 157 | return rv; 158 | } 159 | 160 | char *_ultostr(void *str, unsigned long val, unsigned base) 161 | { 162 | char *_str = (char *)str; 163 | _uldiv_t r; 164 | 165 | if(base > 64) {//36 166 | _str[0] = '\0'; 167 | return NULL; 168 | } 169 | 170 | r = _uldiv(val, base); 171 | 172 | if(r.quot > 0) { 173 | _str = _ultostr(_str, r.quot, base); 174 | } 175 | 176 | *_str++ = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ,."[(int)r.rem]; 177 | *_str = '\0'; 178 | return _str; 179 | } 180 | 181 | char *strsplit(const void *string_org, int org_len, const char *demial, char **last, int *len) 182 | { 183 | unsigned char *str; 184 | unsigned char *p; 185 | 186 | if(org_len < 1 || !string_org || !demial) { 187 | return NULL; 188 | } 189 | 190 | if(*last) { 191 | if(*last == string_org) { 192 | *last = NULL; 193 | return NULL; 194 | } 195 | 196 | str = (unsigned char *)*last; 197 | 198 | } else { 199 | str = (unsigned char *)string_org; 200 | } 201 | 202 | if(!str) { 203 | return (char *)str; 204 | } 205 | 206 | p = str; 207 | 208 | while(p < (unsigned char *)string_org + org_len && *p != demial[0]) { 209 | p++; 210 | } 211 | 212 | if(p == (unsigned char *)string_org + org_len) { 213 | *last = (char *)string_org; 214 | 215 | } else { 216 | *last = (char *)p + 1; 217 | } 218 | 219 | if(str) { 220 | if(*last != string_org) { 221 | *len = (*last - (char *)str) - 1; 222 | 223 | } else { 224 | *len = (unsigned char *)(string_org + org_len) - str; 225 | } 226 | } 227 | 228 | return (char *)str; 229 | } 230 | 231 | -------------------------------------------------------------------------------- /common/strings.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #ifndef _STRINGS_H 9 | #define _STRINGS_H 10 | 11 | int stricmp(const void *s1, const void *s2); 12 | int strincmp(const void *s1, const void *s2, size_t n); 13 | const char *stristr(const void *str, const void *pat, int length); 14 | void random_string(void *string, size_t length, int s); 15 | 16 | unsigned long _strtoul(void *str64, int base); 17 | char *_ultostr(void *str, unsigned long val, unsigned base); 18 | char *strsplit(const void *string_org, int org_len, const char *demial, char **last, int *len); 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /common/timeouts.c: -------------------------------------------------------------------------------- 1 | #include "timeouts.h" 2 | #include "smp.h" 3 | 4 | #define TIMEOUTS_LINK_RING_SIZE 6000 5 | static timeout_t *timeout_links[TIMEOUTS_LINK_RING_SIZE] = {0}; 6 | static timeout_t *timeout_link_ends[TIMEOUTS_LINK_RING_SIZE] = {0}; 7 | static unsigned long last_check_time = 0; 8 | 9 | timeout_t *add_timeout(void *ptr, int timeout, timeout_handle_cb handle) 10 | { 11 | if(timeout < 1 || !handle) { 12 | return NULL; 13 | } 14 | 15 | timeout_t *n = malloc(sizeof(timeout_t)); 16 | 17 | if(!n) { 18 | return NULL; 19 | } 20 | 21 | n->handle = handle; 22 | n->ptr = ptr; 23 | n->timeout = (longtime() + timeout) / 10; 24 | n->uper = NULL; 25 | n->next = NULL; 26 | 27 | unsigned long k = n->timeout % TIMEOUTS_LINK_RING_SIZE; 28 | 29 | if(timeout_link_ends[k] == NULL) { 30 | timeout_links[k] = n; 31 | timeout_link_ends[k] = n; 32 | 33 | } else { // add to link end 34 | timeout_link_ends[k]->next = n; 35 | n->uper = timeout_link_ends[k]; 36 | timeout_link_ends[k] = n; 37 | } 38 | 39 | return n; 40 | } 41 | 42 | int check_timeouts() 43 | { 44 | unsigned long l_now = (longtime() / 10); 45 | timeout_t *m = NULL, *n = NULL; 46 | int b = 1; 47 | 48 | if(last_check_time == 0) { 49 | last_check_time = l_now; 50 | } 51 | 52 | do { 53 | unsigned long k = last_check_time % TIMEOUTS_LINK_RING_SIZE; 54 | 55 | while(1) { 56 | b = 1; 57 | m = timeout_links[k]; 58 | n = NULL; 59 | 60 | while(m) { 61 | n = m; 62 | m = m->next; 63 | 64 | if(l_now >= n->timeout) { 65 | n->handle(n->ptr); 66 | b = 0; 67 | break; 68 | } 69 | } 70 | 71 | if(b) { 72 | break; 73 | } 74 | } 75 | 76 | if(last_check_time < l_now) { 77 | last_check_time++; 78 | continue; 79 | } 80 | } while(last_check_time < l_now); 81 | 82 | return 1; 83 | } 84 | 85 | void delete_timeout(timeout_t *n) 86 | { 87 | if(!n) { 88 | return; 89 | } 90 | 91 | unsigned long k = n->timeout % TIMEOUTS_LINK_RING_SIZE; 92 | 93 | if(n->uper) { 94 | ((timeout_t *) n->uper)->next = n->next; 95 | 96 | } else { 97 | timeout_links[k] = n->next; 98 | } 99 | 100 | if(n->next) { 101 | ((timeout_t *) n->next)->uper = n->uper; 102 | 103 | } else { 104 | timeout_link_ends[k] = n->uper; 105 | } 106 | 107 | free(n); 108 | } 109 | 110 | void update_timeout(timeout_t *n, int timeout) 111 | { 112 | if(!n) { 113 | return; 114 | } 115 | 116 | unsigned long k = n->timeout % TIMEOUTS_LINK_RING_SIZE; 117 | 118 | if(n->uper) { 119 | ((timeout_t *) n->uper)->next = n->next; 120 | 121 | } else { 122 | timeout_links[k] = n->next; 123 | } 124 | 125 | if(n->next) { 126 | ((timeout_t *) n->next)->uper = n->uper; 127 | 128 | } else { 129 | timeout_link_ends[k] = n->uper; 130 | } 131 | 132 | if(timeout < 1) { 133 | free(n); 134 | return; 135 | } 136 | 137 | n->timeout = (longtime() + timeout) / 10; 138 | n->uper = NULL; 139 | n->next = NULL; 140 | 141 | k = n->timeout % TIMEOUTS_LINK_RING_SIZE; 142 | 143 | if(timeout_link_ends[k] == NULL) { 144 | timeout_links[k] = n; 145 | timeout_link_ends[k] = n; 146 | 147 | } else { // add to link end 148 | timeout_link_ends[k]->next = n; 149 | n->uper = timeout_link_ends[k]; 150 | timeout_link_ends[k] = n; 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /common/timeouts.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "smp.h" 5 | #include "times.h" 6 | 7 | #ifndef _TIMEOUTS_H 8 | #define _TIMEOUTS_H 9 | 10 | typedef void (*timeout_handle_cb)(void *ptr); 11 | 12 | typedef struct { 13 | timeout_handle_cb handle; 14 | void *ptr; 15 | unsigned long timeout; 16 | void *uper; 17 | void *next; 18 | } timeout_t; 19 | 20 | timeout_t *add_timeout(void *ptr, int timeout, timeout_handle_cb handle); 21 | void update_timeout(timeout_t *n, int timeout); 22 | int check_timeouts(); 23 | void delete_timeout(timeout_t *n); 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /common/times.c: -------------------------------------------------------------------------------- 1 | #include "times.h" 2 | 3 | time_t now = 0; 4 | static time_t last_now = 0; 5 | struct tm _now_gtm = {0}; 6 | struct tm _now_lc = {0}; 7 | char now_gmt[32] = {0}; 8 | char now_lc[32] = {0}; 9 | 10 | static const char *DAYS_OF_WEEK[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; 11 | static const char *MONTHS_OF_YEAR[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; 12 | 13 | unsigned long longtime() 14 | { 15 | struct timeb t; 16 | ftime(&t); 17 | return 1000 * t.time + t.millitm; 18 | } 19 | 20 | time_t update_time() 21 | { 22 | time(&now); 23 | 24 | if(now <= last_now) { 25 | return now; 26 | } 27 | 28 | last_now = now; 29 | 30 | gmtime_r(&now, &_now_gtm); 31 | localtime_r(&now, &_now_lc); 32 | sprintf(now_gmt, "%s, %02d %s %04d %02d:%02d:%02d GMT", 33 | DAYS_OF_WEEK[_now_gtm.tm_wday], 34 | _now_gtm.tm_mday, 35 | MONTHS_OF_YEAR[_now_gtm.tm_mon], 36 | _now_gtm.tm_year + 1900, 37 | _now_gtm.tm_hour, 38 | _now_gtm.tm_min, 39 | _now_gtm.tm_sec); 40 | sprintf(now_lc, "%s, %02d %s %04d %02d:%02d:%02d", 41 | DAYS_OF_WEEK[_now_lc.tm_wday], 42 | _now_lc.tm_mday, 43 | MONTHS_OF_YEAR[_now_lc.tm_mon], 44 | _now_lc.tm_year + 1900, 45 | _now_lc.tm_hour, 46 | _now_lc.tm_min, 47 | _now_lc.tm_sec); 48 | 49 | return now; 50 | } 51 | -------------------------------------------------------------------------------- /common/times.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #ifndef __TIMES_H 6 | #define __TIMES_H 7 | 8 | unsigned long longtime(); 9 | time_t update_time(); 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /common/urlcoder.c: -------------------------------------------------------------------------------- 1 | #include "urlcoder.h" 2 | 3 | size_t urlencode(u_char *dst, u_char *src, size_t size, unsigned int type) 4 | { 5 | unsigned int n = 0; 6 | uint32_t *escape; 7 | u_char *d = dst; 8 | static u_char hex[] = "0123456789ABCDEF"; 9 | /* " ", "#", "%", "?", %00-%1F, %7F-%FF */ 10 | static uint32_t url[] = { 11 | 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ 12 | 13 | /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */ 14 | 0xfc009fff, /* 1111 1100 0000 0000 1001 1000 0110 1111 */ 15 | 16 | /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */ 17 | 0x78000001, /* 0111 1000 0000 0000 0000 0000 0000 0001 */ 18 | 19 | /* ~}| {zyx wvut srqp onml kjih gfed cba` */ 20 | 0xf8000001, /* 1111 1000 0000 0000 0000 0000 0000 0001 */ 21 | 22 | 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ 23 | 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ 24 | 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ 25 | 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */ 26 | }; 27 | 28 | static uint32_t uri[] = { 29 | 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ 30 | 31 | /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */ 32 | 0xf8000ff5, /* 1111 1000 0000 0000 0000 1000 0110 0101 */ 33 | 34 | /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */ 35 | 0x78000000, /* 0111 1000 0000 0000 0000 0000 0000 0000 */ 36 | 37 | /* ~}| {zyx wvut srqp onml kjih gfed cba` */ 38 | 0xf8000001, /* 1111 1000 0000 0000 0000 0000 0000 0001 */ 39 | 40 | 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ 41 | 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ 42 | 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ 43 | 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */ 44 | }; 45 | 46 | /* " ", "%", %00-%1F */ 47 | static uint32_t memcached[] = { 48 | 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ 49 | 50 | /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */ 51 | 0x00000021, /* 0000 0000 0000 0000 0000 0000 0010 0001 */ 52 | 53 | /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */ 54 | 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ 55 | 56 | /* ~}| {zyx wvut srqp onml kjih gfed cba` */ 57 | 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ 58 | 59 | 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ 60 | 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ 61 | 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ 62 | 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ 63 | }; 64 | /* mail_auth is the same as memcached */ 65 | static uint32_t *map[] = 66 | { url, memcached, url, uri }; 67 | escape = map[type]; 68 | 69 | if(d == NULL) { 70 | /* find the number of the characters to be escaped */ 71 | n = 0; 72 | 73 | while(size) { 74 | if(escape[*src >> 5] & (1 << (*src & 0x1f))) { 75 | n++; 76 | } 77 | 78 | src++; 79 | size--; 80 | } 81 | 82 | return (uintptr_t) n; 83 | } 84 | 85 | while(size) { 86 | if((type == ESCAPE_URL || type == ESCAPE_URI) && *src == ' ') { 87 | *d++ = '+'; 88 | src++; 89 | 90 | } else if(escape[*src >> 5] & (1 << (*src & 0x1f))) { 91 | *d++ = '%'; 92 | *d++ = hex[*src >> 4]; 93 | *d++ = hex[*src & 0xf]; 94 | src++; 95 | 96 | } else { 97 | *d++ = *src++; 98 | } 99 | 100 | size--; 101 | } 102 | 103 | return d - dst; 104 | } 105 | 106 | size_t urldecode(u_char **dst, u_char **src, size_t size, unsigned int type) 107 | { 108 | u_char *d, *s, ch, c, decoded; 109 | enum { 110 | sw_usual = 0, 111 | sw_quoted, 112 | sw_quoted_second 113 | } state; 114 | d = *dst; 115 | s = *src; 116 | state = 0; 117 | decoded = 0; 118 | 119 | while(size--) { 120 | ch = *s++; 121 | 122 | switch(state) { 123 | case sw_usual: 124 | if(ch == '?' 125 | && (type & (UNESCAPE_URI))) { 126 | *d++ = ch; 127 | goto done; 128 | } 129 | 130 | if(ch == '%') { 131 | state = sw_quoted; 132 | break; 133 | } 134 | 135 | if(ch == '+' && !(type & RAW_UNESCAPE_URL)) { 136 | *d++ = ' '; 137 | break; 138 | } 139 | 140 | *d++ = ch; 141 | break; 142 | 143 | case sw_quoted: 144 | if(ch >= '0' && ch <= '9') { 145 | decoded = (u_char)(ch - '0'); 146 | state = sw_quoted_second; 147 | break; 148 | } 149 | 150 | c = (u_char)(ch | 0x20); 151 | 152 | if(c >= 'a' && c <= 'f') { 153 | decoded = (u_char)(c - 'a' + 10); 154 | state = sw_quoted_second; 155 | break; 156 | } 157 | 158 | /* the invalid quoted character */ 159 | state = sw_usual; 160 | *d++ = ch; 161 | break; 162 | 163 | case sw_quoted_second: 164 | state = sw_usual; 165 | 166 | if(ch >= '0' && ch <= '9') { 167 | ch = (u_char)((decoded << 4) + ch - '0'); 168 | *d++ = ch; 169 | break; 170 | } 171 | 172 | c = (u_char)(ch | 0x20); 173 | 174 | if(c >= 'a' && c <= 'f') { 175 | ch = (u_char)((decoded << 4) + c - 'a' + 10); 176 | 177 | if(type & UNESCAPE_URI) { 178 | if(ch == '?') { 179 | *d++ = ch; 180 | goto done; 181 | } 182 | 183 | *d++ = ch; 184 | break; 185 | } 186 | 187 | *d++ = ch; 188 | break; 189 | } 190 | 191 | /* the invalid quoted character */ 192 | break; 193 | } 194 | } 195 | 196 | done: 197 | return d - *dst; 198 | } 199 | -------------------------------------------------------------------------------- /common/urlcoder.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #ifndef _URLCODER_H 7 | #define _URLCODER_H 8 | 9 | #ifndef u_char 10 | typedef unsigned char u_char; 11 | #endif 12 | 13 | #define ESCAPE_URL 0 14 | #define ESCAPE_MEMCACHED 1 15 | #define RAW_ESCAPE_URL 2 16 | #define ESCAPE_URI 3 17 | #define UNESCAPE_URL 0 18 | #define RAW_UNESCAPE_URL 1 19 | #define UNESCAPE_URI 2 20 | 21 | size_t urlencode(u_char *dst, u_char *src, size_t size, unsigned int type); 22 | size_t urldecode(u_char **dst, u_char **src, size_t size, unsigned int type); 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /merry.c: -------------------------------------------------------------------------------- 1 | #include "merry.h" 2 | 3 | char bind_addr[20] = {0}; 4 | int bind_port = 1111; 5 | char ssl_bind_addr[20] = {0}; 6 | int ssl_bind_port = 0; 7 | const char *program_name = NULL; 8 | 9 | int merry_start(int argc, const char **argv, void (*help)(), void (*master)(), void (*onexit)(), void (*worker)(), 10 | int worker_count) 11 | { 12 | update_time(); 13 | 14 | /// 初始化进程命令行信息 15 | init_process_title(argc, argv); 16 | 17 | int i = strlen(argv[0]); 18 | 19 | while(argv[0][--i] != '/'); 20 | 21 | program_name = argv[0] + i + 1; 22 | 23 | if(getarg("help")) { 24 | help(); 25 | exit(0); 26 | } 27 | 28 | if(getarg("log")) { 29 | LOGF_T = open_log(getarg("log"), 65536); // filename, bufsize 30 | } 31 | 32 | /// 把进程放入后台 33 | if(getarg("daemon")) { 34 | daemonize(); 35 | } 36 | 37 | process_count = 1; 38 | 39 | if(is_daemon == 1) { 40 | process_count = atoi(getarg("daemon")); 41 | 42 | if(process_count < 1) { 43 | process_count = get_cpu_num(); 44 | } 45 | 46 | if(process_count < 1) { 47 | process_count = 1; 48 | } 49 | } 50 | 51 | if(worker_count > 0 && process_count > worker_count) { 52 | process_count = worker_count; 53 | } 54 | 55 | sprintf(bind_addr, "0.0.0.0"); 56 | 57 | if(getarg("bind")) { 58 | if(strstr(getarg("bind"), ".")) { 59 | sprintf(bind_addr, "%s", getarg("bind")); 60 | 61 | } else { 62 | int _be_port = atoi(getarg("bind")); 63 | 64 | if(_be_port > 0) { 65 | bind_port = _be_port; 66 | } 67 | } 68 | } 69 | 70 | char *_port = strstr(bind_addr, ":"); 71 | 72 | if(_port) { 73 | bind_addr[strlen(bind_addr) - strlen(_port)] = '\0'; 74 | _port = _port + 1; 75 | 76 | if(atoi(_port) > 0 && atoi(_port) < 99999) { 77 | bind_port = atoi(_port); 78 | } 79 | } 80 | 81 | sprintf(ssl_bind_addr, "0.0.0.0"); 82 | 83 | if(getarg("ssl-bind")) { 84 | if(strstr(getarg("ssl-bind"), ".")) { 85 | sprintf(ssl_bind_addr, "%s", getarg("ssl-bind")); 86 | _port = strstr(ssl_bind_addr, ":"); 87 | 88 | if(_port) { 89 | ssl_bind_addr[strlen(ssl_bind_addr) - strlen(_port)] = '\0'; 90 | _port = _port + 1; 91 | 92 | if(atoi(_port) > 0 && atoi(_port) < 99999) { 93 | ssl_bind_port = atoi(_port); 94 | } 95 | } 96 | 97 | } else { 98 | int _be_port = atoi(getarg("ssl-bind")); 99 | 100 | if(_be_port > 0) { 101 | ssl_bind_port = _be_port; 102 | } 103 | } 104 | } 105 | 106 | server_fd = network_bind(bind_addr, bind_port); 107 | 108 | if(ssl_bind_port > 0) { 109 | ssl_server_fd = network_bind(ssl_bind_addr, ssl_bind_port); 110 | LOGF(INFO, "bind %s:%d ssl:%d", bind_addr, bind_port, ssl_bind_port); 111 | 112 | } else { 113 | LOGF(INFO, "bind %s:%d", bind_addr, bind_port); 114 | } 115 | 116 | for(i = 0; i < process_count; i++) { 117 | if(is_daemon == 1) { 118 | fork_process(worker); 119 | 120 | } else { 121 | set_cpu_affinity(0); 122 | new_thread_p(worker, 0); 123 | } 124 | } 125 | 126 | /// 进入主进程处理 127 | start_master_main(master, onexit); 128 | 129 | return 1; 130 | } 131 | -------------------------------------------------------------------------------- /merry.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "common/smp.h" 13 | #include "common/shm.h" 14 | #include "common/process.h" 15 | #include "common/network.h" 16 | #include "common/times.h" 17 | #include "common/timeouts.h" 18 | #include "common/log.h" 19 | #include "common/actionmoni-client.h" 20 | #include "common/is-binary.h" 21 | #include "common/hash.h" 22 | #include "common/base64.h" 23 | #include "common/urlcoder.h" 24 | #include "common/strings.h" 25 | #include "common/md5.h" 26 | #include "common/sha1.h" 27 | #include "common/sha256.h" 28 | #include "common/mime.h" 29 | #include "se/se.h" 30 | 31 | #ifndef _MERRY_H 32 | #define _MERRY_H 33 | 34 | extern time_t now; 35 | extern struct tm _now_gtm; 36 | extern struct tm _now_lc; 37 | extern char now_gmt[32]; 38 | extern char now_lc[32]; 39 | 40 | extern logf_t *LOGF_T; 41 | extern int LOG_LEVEL; 42 | 43 | extern char hostname[1024]; 44 | extern char process_chdir[924]; 45 | extern char process_name[100]; 46 | extern int is_daemon; 47 | extern int process_count; 48 | extern int pid; 49 | 50 | extern int server_fd; 51 | extern int ssl_server_fd; 52 | extern int loop_fd; 53 | extern int se_errno; 54 | 55 | extern char bind_addr[20]; 56 | extern int bind_port; 57 | extern const char *program_name; 58 | 59 | int merry_start(int argc, const char **argv, void (*help)(), void (*master)(), void (*onexit)(), void (*worker)(), 60 | int worker_count); 61 | 62 | #endif 63 | -------------------------------------------------------------------------------- /se/libeio/config.h: -------------------------------------------------------------------------------- 1 | /* config.h. Generated from config.h.in by configure. */ 2 | /* config.h.in. Generated from configure.ac by autoheader. */ 3 | 4 | /* Define to 1 if you have the header file. */ 5 | #define HAVE_DLFCN_H 1 6 | 7 | /* fdatasync(2) is available */ 8 | #define HAVE_FDATASYNC 1 9 | 10 | /* futimes(2) is available */ 11 | #define HAVE_FUTIMES 1 12 | 13 | /* Define to 1 if you have the header file. */ 14 | #define HAVE_INTTYPES_H 1 15 | 16 | /* fallocate(2) is available */ 17 | /* #undef HAVE_LINUX_FALLOCATE */ 18 | 19 | /* Define to 1 if you have the header file. */ 20 | /* #undef HAVE_LINUX_FIEMAP_H */ 21 | 22 | /* Define to 1 if you have the header file. */ 23 | /* #undef HAVE_LINUX_FS_H */ 24 | 25 | /* splice/vmsplice/tee(2) are available */ 26 | /* #undef HAVE_LINUX_SPLICE */ 27 | 28 | /* Define to 1 if you have the header file. */ 29 | #define HAVE_MEMORY_H 1 30 | 31 | /* posix_fadvise(2) is available */ 32 | /* #undef HAVE_POSIX_FADVISE */ 33 | 34 | /* posix_madvise(2) is available */ 35 | #define HAVE_POSIX_MADVISE 1 36 | 37 | /* prctl(PR_SET_NAME) is available */ 38 | /* #undef HAVE_PRCTL_SET_NAME */ 39 | 40 | /* readahead(2) is available (linux) */ 41 | /* #undef HAVE_READAHEAD */ 42 | 43 | /* sendfile(2) is available and supported */ 44 | #define HAVE_SENDFILE 1 45 | 46 | /* Define to 1 if you have the header file. */ 47 | #define HAVE_STDINT_H 1 48 | 49 | /* Define to 1 if you have the header file. */ 50 | #define HAVE_STDLIB_H 1 51 | 52 | /* Define to 1 if you have the header file. */ 53 | #define HAVE_STRINGS_H 1 54 | 55 | /* Define to 1 if you have the header file. */ 56 | #define HAVE_STRING_H 1 57 | 58 | /* sync_file_range(2) is available */ 59 | /* #undef HAVE_SYNC_FILE_RANGE */ 60 | 61 | /* Define to 1 if you have the header file. */ 62 | /* #undef HAVE_SYS_PRCTL_H */ 63 | 64 | /* Define to 1 if you have the header file. */ 65 | #define HAVE_SYS_STAT_H 1 66 | 67 | /* syscall(__NR_syncfs) is available */ 68 | /* #undef HAVE_SYS_SYNCFS */ 69 | 70 | /* Define to 1 if you have the header file. */ 71 | #define HAVE_SYS_SYSCALL_H 1 72 | 73 | /* Define to 1 if you have the header file. */ 74 | #define HAVE_SYS_TYPES_H 1 75 | 76 | /* Define to 1 if you have the header file. */ 77 | #define HAVE_UNISTD_H 1 78 | 79 | /* utimes(2) is available */ 80 | #define HAVE_UTIMES 1 81 | 82 | /* Define to the sub-directory in which libtool stores uninstalled libraries. 83 | */ 84 | #define LT_OBJDIR ".libs/" 85 | 86 | /* Name of package */ 87 | #define PACKAGE "libeio" 88 | 89 | /* Define to the address where bug reports for this package should be sent. */ 90 | #define PACKAGE_BUGREPORT "" 91 | 92 | /* Define to the full name of this package. */ 93 | #define PACKAGE_NAME "" 94 | 95 | /* Define to the full name and version of this package. */ 96 | #define PACKAGE_STRING "" 97 | 98 | /* Define to the one symbol short name of this package. */ 99 | #define PACKAGE_TARNAME "" 100 | 101 | /* Define to the home page for this package. */ 102 | #define PACKAGE_URL "" 103 | 104 | /* Define to the version of this package. */ 105 | #define PACKAGE_VERSION "" 106 | 107 | /* Define to 1 if you have the ANSI C header files. */ 108 | #define STDC_HEADERS 1 109 | 110 | /* Enable extensions on AIX 3, Interix. */ 111 | #ifndef _ALL_SOURCE 112 | # define _ALL_SOURCE 1 113 | #endif 114 | /* Enable GNU extensions on systems that have them. */ 115 | #ifndef _GNU_SOURCE 116 | # define _GNU_SOURCE 1 117 | #endif 118 | /* Enable threading extensions on Solaris. */ 119 | #ifndef _POSIX_PTHREAD_SEMANTICS 120 | # define _POSIX_PTHREAD_SEMANTICS 1 121 | #endif 122 | /* Enable extensions on HP NonStop. */ 123 | #ifndef _TANDEM_SOURCE 124 | # define _TANDEM_SOURCE 1 125 | #endif 126 | /* Enable general extensions on Solaris. */ 127 | #ifndef __EXTENSIONS__ 128 | # define __EXTENSIONS__ 1 129 | #endif 130 | 131 | #ifdef linux 132 | #define HAVE_LINUX_FALLOCATE 1 133 | #define HAVE_LINUX_FIEMAP_H 1 134 | #define HAVE_LINUX_FS_H 1 135 | #define HAVE_LINUX_SPLICE 1 136 | #define HAVE_POSIX_FADVISE 1 137 | #define HAVE_PRCTL_SET_NAME 1 138 | #define HAVE_READAHEAD 1 139 | #define HAVE_SYNC_FILE_RANGE 1 140 | #define HAVE_SYS_PRCTL_H 1 141 | #ifdef __NR_syncfs 142 | #define HAVE_SYS_SYNCFS 1 143 | #endif 144 | #endif 145 | 146 | /* Version number of package */ 147 | #define VERSION "1.0" 148 | 149 | /* Define to 1 if on MINIX. */ 150 | /* #undef _MINIX */ 151 | 152 | /* Define to 2 if the system does not provide POSIX.1 features except with 153 | this defined. */ 154 | /* #undef _POSIX_1_SOURCE */ 155 | 156 | /* Define to 1 if you need to in order for `stat' and other things to work. */ 157 | /* #undef _POSIX_SOURCE */ 158 | -------------------------------------------------------------------------------- /se/libeio/eio.h: -------------------------------------------------------------------------------- 1 | /* 2 | * libeio API header 3 | * 4 | * Copyright (c) 2007,2008,2009,2010,2011,2012 Marc Alexander Lehmann 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without modifica- 8 | * tion, are permitted provided that the following conditions are met: 9 | * 10 | * 1. Redistributions of source code must retain the above copyright notice, 11 | * this list of conditions and the following disclaimer. 12 | * 13 | * 2. Redistributions in binary form must reproduce the above copyright 14 | * notice, this list of conditions and the following disclaimer in the 15 | * documentation and/or other materials provided with the distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 18 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER- 19 | * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 20 | * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE- 21 | * CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 23 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 24 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH- 25 | * ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 26 | * OF THE POSSIBILITY OF SUCH DAMAGE. 27 | * 28 | * Alternatively, the contents of this file may be used under the terms of 29 | * the GNU General Public License ("GPL") version 2 or any later version, 30 | * in which case the provisions of the GPL are applicable instead of 31 | * the above. If you wish to allow the use of your version of this file 32 | * only under the terms of the GPL and not to allow others to use your 33 | * version of this file under the BSD license, indicate your decision 34 | * by deleting the provisions above and replace them with the notice 35 | * and other provisions required by the GPL. If you do not delete the 36 | * provisions above, a recipient may use your version of this file under 37 | * either the BSD or the GPL. 38 | */ 39 | #include 40 | 41 | #ifndef EIO_H_ 42 | #define EIO_H_ 43 | 44 | #ifdef __cplusplus 45 | extern "C" { 46 | #endif 47 | 48 | #include 49 | #include 50 | #include 51 | 52 | typedef struct eio_req eio_req; 53 | typedef struct eio_dirent eio_dirent; 54 | 55 | typedef int (*eio_cb)(eio_req *req); 56 | 57 | #ifndef EIO_REQ_MEMBERS 58 | # define EIO_REQ_MEMBERS 59 | #endif 60 | 61 | #ifndef EIO_STRUCT_STAT 62 | # ifdef _WIN32 63 | # define EIO_STRUCT_STAT struct _stati64 64 | # define EIO_STRUCT_STATI64 65 | # else 66 | # define EIO_STRUCT_STAT struct stat 67 | # endif 68 | #endif 69 | 70 | #ifdef _WIN32 71 | typedef int eio_uid_t; 72 | typedef int eio_gid_t; 73 | #ifdef __MINGW32__ /* no intptr_t */ 74 | typedef ssize_t eio_ssize_t; 75 | #else 76 | typedef intptr_t eio_ssize_t; /* or SSIZE_T */ 77 | #endif 78 | #if __GNUC__ 79 | typedef long long eio_ino_t; /* signed for compatibility to msvc */ 80 | #else 81 | typedef __int64 eio_ino_t; /* unsigned not supported by msvc */ 82 | #endif 83 | #else 84 | typedef uid_t eio_uid_t; 85 | typedef gid_t eio_gid_t; 86 | typedef ssize_t eio_ssize_t; 87 | typedef ino_t eio_ino_t; 88 | #endif 89 | 90 | #ifndef EIO_STRUCT_STATVFS 91 | # define EIO_STRUCT_STATVFS struct statvfs 92 | #endif 93 | 94 | /* managing working directories */ 95 | 96 | typedef struct eio_pwd *eio_wd; 97 | 98 | #define EIO_CWD 0 /* the current working directory of the process, guaranteed to be a null pointer */ 99 | #define EIO_INVALID_WD ((eio_wd)(int)-1) /* failure return for eio_wd_open */ 100 | 101 | eio_wd eio_wd_open_sync (eio_wd wd, const char *path); 102 | void eio_wd_close_sync (eio_wd wd); 103 | 104 | /* for readdir */ 105 | 106 | /* eio_readdir flags */ 107 | enum 108 | { 109 | EIO_READDIR_DENTS = 0x01, /* ptr2 contains eio_dirents, not just the (unsorted) names */ 110 | EIO_READDIR_DIRS_FIRST = 0x02, /* dirents gets sorted into a good stat() ing order to find directories first */ 111 | EIO_READDIR_STAT_ORDER = 0x04, /* dirents gets sorted into a good stat() ing order to quickly stat all files */ 112 | EIO_READDIR_FOUND_UNKNOWN = 0x80, /* set by eio_readdir when *_ARRAY was set and any TYPE=UNKNOWN's were found */ 113 | 114 | EIO_READDIR_CUSTOM1 = 0x100, /* for use by apps */ 115 | EIO_READDIR_CUSTOM2 = 0x200 /* for use by apps */ 116 | }; 117 | 118 | /* using "typical" values in the hope that the compiler will do something sensible */ 119 | enum eio_dtype 120 | { 121 | EIO_DT_UNKNOWN = 0, 122 | EIO_DT_FIFO = 1, 123 | EIO_DT_CHR = 2, 124 | EIO_DT_MPC = 3, /* multiplexed char device (v7+coherent) */ 125 | EIO_DT_DIR = 4, 126 | EIO_DT_NAM = 5, /* xenix special named file */ 127 | EIO_DT_BLK = 6, 128 | EIO_DT_MPB = 7, /* multiplexed block device (v7+coherent) */ 129 | EIO_DT_REG = 8, 130 | EIO_DT_NWK = 9, /* HP-UX network special */ 131 | EIO_DT_CMP = 9, /* VxFS compressed */ 132 | EIO_DT_LNK = 10, 133 | /* DT_SHAD = 11,*/ 134 | EIO_DT_SOCK = 12, 135 | EIO_DT_DOOR = 13, /* solaris door */ 136 | EIO_DT_WHT = 14, 137 | EIO_DT_MAX = 15 /* highest DT_VALUE ever, hopefully */ 138 | }; 139 | 140 | struct eio_dirent 141 | { 142 | int nameofs; /* offset of null-terminated name string in (char *)req->ptr2 */ 143 | unsigned short namelen; /* size of filename without trailing 0 */ 144 | unsigned char type; /* one of EIO_DT_* */ 145 | signed char score; /* internal use */ 146 | eio_ino_t inode; /* the inode number, if available, otherwise unspecified */ 147 | }; 148 | 149 | /* eio_msync flags */ 150 | enum 151 | { 152 | EIO_MS_ASYNC = 1, 153 | EIO_MS_INVALIDATE = 2, 154 | EIO_MS_SYNC = 4 155 | }; 156 | 157 | /* eio_mtouch flags */ 158 | enum 159 | { 160 | EIO_MT_MODIFY = 1 161 | }; 162 | 163 | /* eio_sync_file_range flags */ 164 | enum 165 | { 166 | EIO_SYNC_FILE_RANGE_WAIT_BEFORE = 1, 167 | EIO_SYNC_FILE_RANGE_WRITE = 2, 168 | EIO_SYNC_FILE_RANGE_WAIT_AFTER = 4 169 | }; 170 | 171 | /* eio_fallocate flags */ 172 | enum 173 | { 174 | /* these MUST match the value in linux/falloc.h */ 175 | EIO_FALLOC_FL_KEEP_SIZE = 1, 176 | EIO_FALLOC_FL_PUNCH_HOLE = 2 177 | }; 178 | 179 | /* timestamps and differences - feel free to use double in your code directly */ 180 | typedef double eio_tstamp; 181 | 182 | /* the eio request structure */ 183 | enum 184 | { 185 | EIO_CUSTOM, 186 | EIO_WD_OPEN, EIO_WD_CLOSE, 187 | 188 | EIO_CLOSE, EIO_DUP2, 189 | EIO_SEEK, EIO_READ, EIO_WRITE, 190 | EIO_READAHEAD, EIO_SENDFILE, 191 | EIO_FSTAT, EIO_FSTATVFS, 192 | EIO_FTRUNCATE, EIO_FUTIME, EIO_FCHMOD, EIO_FCHOWN, 193 | EIO_SYNC, EIO_FSYNC, EIO_FDATASYNC, EIO_SYNCFS, 194 | EIO_MSYNC, EIO_MTOUCH, EIO_SYNC_FILE_RANGE, EIO_FALLOCATE, 195 | EIO_MLOCK, EIO_MLOCKALL, 196 | EIO_GROUP, EIO_NOP, 197 | EIO_BUSY, 198 | 199 | /* these use wd + ptr1, but are emulated */ 200 | EIO_REALPATH, 201 | EIO_READDIR, 202 | 203 | /* all the following requests use wd + ptr1 as path in xxxat functions */ 204 | EIO_OPEN, 205 | EIO_STAT, EIO_LSTAT, EIO_STATVFS, 206 | EIO_TRUNCATE, 207 | EIO_UTIME, 208 | EIO_CHMOD, 209 | EIO_CHOWN, 210 | EIO_UNLINK, EIO_RMDIR, EIO_MKDIR, EIO_RENAME, 211 | EIO_MKNOD, 212 | EIO_LINK, EIO_SYMLINK, EIO_READLINK, 213 | 214 | EIO_REQ_TYPE_NUM 215 | }; 216 | 217 | /* seek whence modes */ 218 | /* these are guaranteed to hasve the traditional 0, 1, 2 values, */ 219 | /* so you might as wlel use those */ 220 | enum 221 | { 222 | EIO_SEEK_SET = 0, 223 | EIO_SEEK_CUR = 1, 224 | EIO_SEEK_END = 2 225 | }; 226 | 227 | 228 | /* mlockall constants */ 229 | enum 230 | { 231 | EIO_MCL_CURRENT = 1, 232 | EIO_MCL_FUTURE = 2 233 | }; 234 | 235 | /* request priorities */ 236 | 237 | enum { 238 | EIO_PRI_MIN = -4, 239 | EIO_PRI_MAX = 4, 240 | EIO_PRI_DEFAULT = 0 241 | }; 242 | 243 | /* eio request structure */ 244 | /* this structure is mostly read-only */ 245 | /* when initialising it, all members must be zero-initialised */ 246 | struct eio_req 247 | { 248 | eio_req volatile *next; /* private ETP */ 249 | 250 | eio_wd wd; /* all applicable requests: working directory of pathname, old name; wd_open: return wd */ 251 | 252 | eio_ssize_t result; /* result of syscall, e.g. result = read (... */ 253 | off_t offs; /* read, write, truncate, readahead, sync_file_range, fallocate: file offset, mknod: dev_t */ 254 | size_t size; /* read, write, readahead, sendfile, msync, mlock, sync_file_range, fallocate: length */ 255 | void *ptr1; /* all applicable requests: pathname, old name; readdir: optional eio_dirents */ 256 | void *ptr2; /* all applicable requests: new name or memory buffer; readdir: name strings */ 257 | eio_tstamp nv1; /* utime, futime: atime; busy: sleep time */ 258 | eio_tstamp nv2; /* utime, futime: mtime */ 259 | 260 | int int1; /* all applicable requests: file descriptor; sendfile: output fd; open, msync, mlockall, readdir: flags */ 261 | long int2; /* chown, fchown: uid; sendfile: input fd; open, chmod, mkdir, mknod: file mode, seek: whence, sync_file_range, fallocate: flags */ 262 | long int3; /* chown, fchown: gid; rename, link: working directory of new name */ 263 | int errorno; /* errno value on syscall return */ 264 | 265 | signed char type;/* EIO_xxx constant ETP */ 266 | 267 | #if __i386 || __amd64 268 | unsigned char cancelled; /* ETP */ 269 | #else 270 | sig_atomic_t cancelled; /* ETP */ 271 | #endif 272 | 273 | unsigned char flags; /* private */ 274 | signed char pri; /* the priority */ 275 | 276 | void *data; 277 | eio_cb finish; 278 | void (*destroy)(eio_req *req); /* called when request no longer needed */ 279 | void (*feed)(eio_req *req); /* only used for group requests */ 280 | 281 | EIO_REQ_MEMBERS 282 | 283 | eio_req *grp, *grp_prev, *grp_next, *grp_first; /* private ETP */ 284 | }; 285 | 286 | /* _private_ request flags */ 287 | enum { 288 | EIO_FLAG_PTR1_FREE = 0x01, /* need to free(ptr1) */ 289 | EIO_FLAG_PTR2_FREE = 0x02, /* need to free(ptr2) */ 290 | EIO_FLAG_GROUPADD = 0x04 /* some request was added to the group */ 291 | }; 292 | 293 | /* undocumented/unsupported/private helper */ 294 | /*void eio_page_align (void **addr, size_t *length);*/ 295 | 296 | /* returns < 0 on error, errno set 297 | * need_poll, if non-zero, will be called when results are available 298 | * and eio_poll_cb needs to be invoked (it MUST NOT call eio_poll_cb itself). 299 | * done_poll is called when the need to poll is gone. 300 | */ 301 | int eio_init (void (*want_poll)(void), void (*done_poll)(void)); 302 | 303 | /* must be called regularly to handle pending requests */ 304 | /* returns 0 if all requests were handled, -1 if not, or the value of EIO_FINISH if != 0 */ 305 | int eio_poll (void); 306 | 307 | /* stop polling if poll took longer than duration seconds */ 308 | void eio_set_max_poll_time (eio_tstamp nseconds); 309 | /* do not handle more then count requests in one call to eio_poll_cb */ 310 | void eio_set_max_poll_reqs (unsigned int nreqs); 311 | 312 | /* set minimum required number 313 | * maximum wanted number 314 | * or maximum idle number of threads */ 315 | void eio_set_min_parallel (unsigned int nthreads); 316 | void eio_set_max_parallel (unsigned int nthreads); 317 | void eio_set_max_idle (unsigned int nthreads); 318 | void eio_set_idle_timeout (unsigned int seconds); 319 | 320 | unsigned int eio_nreqs (void); /* number of requests in-flight */ 321 | unsigned int eio_nready (void); /* number of not-yet handled requests */ 322 | unsigned int eio_npending (void); /* number of finished but unhandled requests */ 323 | unsigned int eio_nthreads (void); /* number of worker threads in use currently */ 324 | 325 | /*****************************************************************************/ 326 | /* convenience wrappers */ 327 | 328 | #ifndef EIO_NO_WRAPPERS 329 | eio_req *eio_wd_open (const char *path, int pri, eio_cb cb, void *data); /* result=wd */ 330 | eio_req *eio_wd_close (eio_wd wd, int pri, eio_cb cb, void *data); 331 | eio_req *eio_nop (int pri, eio_cb cb, void *data); /* does nothing except go through the whole process */ 332 | eio_req *eio_busy (eio_tstamp delay, int pri, eio_cb cb, void *data); /* ties a thread for this long, simulating busyness */ 333 | eio_req *eio_sync (int pri, eio_cb cb, void *data); 334 | eio_req *eio_fsync (int fd, int pri, eio_cb cb, void *data); 335 | eio_req *eio_fdatasync (int fd, int pri, eio_cb cb, void *data); 336 | eio_req *eio_syncfs (int fd, int pri, eio_cb cb, void *data); 337 | eio_req *eio_msync (void *addr, size_t length, int flags, int pri, eio_cb cb, void *data); 338 | eio_req *eio_mtouch (void *addr, size_t length, int flags, int pri, eio_cb cb, void *data); 339 | eio_req *eio_mlock (void *addr, size_t length, int pri, eio_cb cb, void *data); 340 | eio_req *eio_mlockall (int flags, int pri, eio_cb cb, void *data); 341 | eio_req *eio_sync_file_range (int fd, off_t offset, size_t nbytes, unsigned int flags, int pri, eio_cb cb, void *data); 342 | eio_req *eio_fallocate (int fd, int mode, off_t offset, size_t len, int pri, eio_cb cb, void *data); 343 | eio_req *eio_close (int fd, int pri, eio_cb cb, void *data); 344 | eio_req *eio_readahead (int fd, off_t offset, size_t length, int pri, eio_cb cb, void *data); 345 | eio_req *eio_seek (int fd, off_t offset, int whence, int pri, eio_cb cb, void *data); 346 | eio_req *eio_read (int fd, void *buf, size_t length, off_t offset, int pri, eio_cb cb, void *data); 347 | eio_req *eio_write (int fd, void *buf, size_t length, off_t offset, int pri, eio_cb cb, void *data); 348 | eio_req *eio_fstat (int fd, int pri, eio_cb cb, void *data); /* stat buffer=ptr2 allocated dynamically */ 349 | eio_req *eio_fstatvfs (int fd, int pri, eio_cb cb, void *data); /* stat buffer=ptr2 allocated dynamically */ 350 | eio_req *eio_futime (int fd, eio_tstamp atime, eio_tstamp mtime, int pri, eio_cb cb, void *data); 351 | eio_req *eio_ftruncate (int fd, off_t offset, int pri, eio_cb cb, void *data); 352 | eio_req *eio_fchmod (int fd, mode_t mode, int pri, eio_cb cb, void *data); 353 | eio_req *eio_fchown (int fd, eio_uid_t uid, eio_gid_t gid, int pri, eio_cb cb, void *data); 354 | eio_req *eio_dup2 (int fd, int fd2, int pri, eio_cb cb, void *data); 355 | eio_req *eio_sendfile (int out_fd, int in_fd, off_t in_offset, size_t length, int pri, eio_cb cb, void *data); 356 | eio_req *eio_open (const char *path, int flags, mode_t mode, int pri, eio_cb cb, void *data); 357 | eio_req *eio_utime (const char *path, eio_tstamp atime, eio_tstamp mtime, int pri, eio_cb cb, void *data); 358 | eio_req *eio_truncate (const char *path, off_t offset, int pri, eio_cb cb, void *data); 359 | eio_req *eio_chown (const char *path, eio_uid_t uid, eio_gid_t gid, int pri, eio_cb cb, void *data); 360 | eio_req *eio_chmod (const char *path, mode_t mode, int pri, eio_cb cb, void *data); 361 | eio_req *eio_mkdir (const char *path, mode_t mode, int pri, eio_cb cb, void *data); 362 | eio_req *eio_readdir (const char *path, int flags, int pri, eio_cb cb, void *data); /* result=ptr2 allocated dynamically */ 363 | eio_req *eio_rmdir (const char *path, int pri, eio_cb cb, void *data); 364 | eio_req *eio_unlink (const char *path, int pri, eio_cb cb, void *data); 365 | eio_req *eio_readlink (const char *path, int pri, eio_cb cb, void *data); /* result=ptr2 allocated dynamically */ 366 | eio_req *eio_realpath (const char *path, int pri, eio_cb cb, void *data); /* result=ptr2 allocated dynamically */ 367 | eio_req *eio_stat (const char *path, int pri, eio_cb cb, void *data); /* stat buffer=ptr2 allocated dynamically */ 368 | eio_req *eio_lstat (const char *path, int pri, eio_cb cb, void *data); /* stat buffer=ptr2 allocated dynamically */ 369 | eio_req *eio_statvfs (const char *path, int pri, eio_cb cb, void *data); /* stat buffer=ptr2 allocated dynamically */ 370 | eio_req *eio_mknod (const char *path, mode_t mode, dev_t dev, int pri, eio_cb cb, void *data); 371 | eio_req *eio_link (const char *path, const char *new_path, int pri, eio_cb cb, void *data); 372 | eio_req *eio_symlink (const char *path, const char *new_path, int pri, eio_cb cb, void *data); 373 | eio_req *eio_rename (const char *path, const char *new_path, int pri, eio_cb cb, void *data); 374 | eio_req *eio_custom (void (*execute)(eio_req *), int pri, eio_cb cb, void *data); 375 | #endif 376 | 377 | /*****************************************************************************/ 378 | /* groups */ 379 | 380 | eio_req *eio_grp (eio_cb cb, void *data); 381 | void eio_grp_feed (eio_req *grp, void (*feed)(eio_req *req), int limit); 382 | void eio_grp_limit (eio_req *grp, int limit); 383 | void eio_grp_add (eio_req *grp, eio_req *req); 384 | void eio_grp_cancel (eio_req *grp); /* cancels all sub requests but not the group */ 385 | 386 | /*****************************************************************************/ 387 | /* request api */ 388 | 389 | /* true if the request was cancelled, useful in the invoke callback */ 390 | #define EIO_CANCELLED(req) ((req)->cancelled) 391 | 392 | #define EIO_RESULT(req) ((req)->result) 393 | /* returns a pointer to the result buffer allocated by eio */ 394 | #define EIO_BUF(req) ((req)->ptr2) 395 | #define EIO_STAT_BUF(req) ((EIO_STRUCT_STAT *)EIO_BUF(req)) 396 | #define EIO_STATVFS_BUF(req) ((EIO_STRUCT_STATVFS *)EIO_BUF(req)) 397 | #define EIO_PATH(req) ((char *)(req)->ptr1) 398 | 399 | /* submit a request for execution */ 400 | void eio_submit (eio_req *req); 401 | /* cancel a request as soon fast as possible, if possible */ 402 | void eio_cancel (eio_req *req); 403 | 404 | /*****************************************************************************/ 405 | /* convenience functions */ 406 | 407 | eio_ssize_t eio_sendfile_sync (int ofd, int ifd, off_t offset, size_t count); 408 | 409 | #ifdef __cplusplus 410 | } 411 | #endif 412 | 413 | #endif 414 | 415 | -------------------------------------------------------------------------------- /se/libeio/xthread.h: -------------------------------------------------------------------------------- 1 | #ifndef XTHREAD_H_ 2 | #define XTHREAD_H_ 3 | 4 | /* whether word reads are potentially non-atomic. 5 | * this is conservative, likely most arches this runs 6 | * on have atomic word read/writes. 7 | */ 8 | #ifndef WORDACCESS_UNSAFE 9 | # if __i386 || __x86_64 10 | # define WORDACCESS_UNSAFE 0 11 | # else 12 | # define WORDACCESS_UNSAFE 1 13 | # endif 14 | #endif 15 | 16 | ///////////////////////////////////////////////////////////////////////////// 17 | 18 | #ifdef _WIN32 19 | 20 | //#define NTDDI_VERSION NTDDI_WIN2K // needed to get win2000 api calls, fails with mingw 21 | #define _WIN32_WINNT 0x400 // maybe working alternative for mingw 22 | #include //D 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | /* work around some bugs in ptw32 */ 31 | #if defined(__MINGW32__) && defined(_TIMESPEC_DEFINED) 32 | #define HAVE_STRUCT_TIMESPEC 1 33 | #endif 34 | 35 | #include 36 | #define sigset_t int 37 | #define sigfillset(a) 38 | #define pthread_sigmask(a,b,c) 39 | #define sigaddset(a,b) 40 | #define sigemptyset(s) 41 | 42 | typedef pthread_mutex_t xmutex_t; 43 | #define X_MUTEX_INIT PTHREAD_MUTEX_INITIALIZER 44 | #define X_MUTEX_CREATE(mutex) pthread_mutex_init (&(mutex), 0) 45 | #define X_LOCK(mutex) pthread_mutex_lock (&(mutex)) 46 | #define X_UNLOCK(mutex) pthread_mutex_unlock (&(mutex)) 47 | 48 | typedef pthread_cond_t xcond_t; 49 | #define X_COND_INIT PTHREAD_COND_INITIALIZER 50 | #define X_COND_CREATE(cond) pthread_cond_init (&(cond), 0) 51 | #define X_COND_SIGNAL(cond) pthread_cond_signal (&(cond)) 52 | #define X_COND_WAIT(cond,mutex) pthread_cond_wait (&(cond), &(mutex)) 53 | #define X_COND_TIMEDWAIT(cond,mutex,to) pthread_cond_timedwait (&(cond), &(mutex), &(to)) 54 | 55 | typedef pthread_t xthread_t; 56 | #define X_THREAD_PROC(name) static void *name (void *thr_arg) 57 | #define X_THREAD_ATFORK(a,b,c) 58 | 59 | static int 60 | xthread_create (xthread_t *tid, void *(*proc)(void *), void *arg) 61 | { 62 | int retval; 63 | pthread_attr_t attr; 64 | 65 | pthread_attr_init (&attr); 66 | pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED); 67 | 68 | retval = pthread_create (tid, &attr, proc, arg) == 0; 69 | 70 | pthread_attr_destroy (&attr); 71 | 72 | return retval; 73 | } 74 | 75 | #define respipe_read(a,b,c) PerlSock_recv ((a), (b), (c), 0) 76 | #define respipe_write(a,b,c) send ((a), (b), (c), 0) 77 | #define respipe_close(a) PerlSock_closesocket ((a)) 78 | 79 | #else 80 | ///////////////////////////////////////////////////////////////////////////// 81 | 82 | #if __linux && !defined(_GNU_SOURCE) 83 | # define _GNU_SOURCE 84 | #endif 85 | 86 | /* just in case */ 87 | #define _REENTRANT 1 88 | 89 | #if __solaris 90 | # define _POSIX_PTHREAD_SEMANTICS 1 91 | /* try to bribe solaris headers into providing a current pthread API 92 | * despite environment being configured for an older version. 93 | */ 94 | # define __EXTENSIONS__ 1 95 | #endif 96 | 97 | #include 98 | #include 99 | #include 100 | #include 101 | #include 102 | 103 | typedef pthread_mutex_t xmutex_t; 104 | #if __linux && defined (PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP) 105 | # define X_MUTEX_INIT PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP 106 | # define X_MUTEX_CREATE(mutex) \ 107 | do { \ 108 | pthread_mutexattr_t attr; \ 109 | pthread_mutexattr_init (&attr); \ 110 | pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_ADAPTIVE_NP); \ 111 | pthread_mutex_init (&(mutex), &attr); \ 112 | } while (0) 113 | #else 114 | # define X_MUTEX_INIT PTHREAD_MUTEX_INITIALIZER 115 | # define X_MUTEX_CREATE(mutex) pthread_mutex_init (&(mutex), 0) 116 | #endif 117 | #define X_LOCK(mutex) pthread_mutex_lock (&(mutex)) 118 | #define X_UNLOCK(mutex) pthread_mutex_unlock (&(mutex)) 119 | 120 | typedef pthread_cond_t xcond_t; 121 | #define X_COND_INIT PTHREAD_COND_INITIALIZER 122 | #define X_COND_CREATE(cond) pthread_cond_init (&(cond), 0) 123 | #define X_COND_SIGNAL(cond) pthread_cond_signal (&(cond)) 124 | #define X_COND_WAIT(cond,mutex) pthread_cond_wait (&(cond), &(mutex)) 125 | #define X_COND_TIMEDWAIT(cond,mutex,to) pthread_cond_timedwait (&(cond), &(mutex), &(to)) 126 | 127 | typedef pthread_t xthread_t; 128 | #define X_THREAD_PROC(name) static void *name (void *thr_arg) 129 | #define X_THREAD_ATFORK(prepare,parent,child) pthread_atfork (prepare, parent, child) 130 | 131 | // the broken bsd's once more 132 | #ifndef PTHREAD_STACK_MIN 133 | # define PTHREAD_STACK_MIN 0 134 | #endif 135 | 136 | #ifndef X_STACKSIZE 137 | # define X_STACKSIZE sizeof (void *) * 4096 138 | #endif 139 | 140 | static int 141 | xthread_create (xthread_t *tid, void *(*proc)(void *), void *arg) 142 | { 143 | int retval; 144 | sigset_t fullsigset, oldsigset; 145 | pthread_attr_t attr; 146 | 147 | pthread_attr_init (&attr); 148 | pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED); 149 | pthread_attr_setstacksize (&attr, PTHREAD_STACK_MIN < X_STACKSIZE ? X_STACKSIZE : PTHREAD_STACK_MIN); 150 | #ifdef PTHREAD_SCOPE_PROCESS 151 | pthread_attr_setscope (&attr, PTHREAD_SCOPE_PROCESS); 152 | #endif 153 | 154 | sigfillset (&fullsigset); 155 | 156 | pthread_sigmask (SIG_SETMASK, &fullsigset, &oldsigset); 157 | retval = pthread_create (tid, &attr, proc, arg) == 0; 158 | pthread_sigmask (SIG_SETMASK, &oldsigset, 0); 159 | 160 | pthread_attr_destroy (&attr); 161 | 162 | return retval; 163 | } 164 | 165 | #define respipe_read(a,b,c) read ((a), (b), (c)) 166 | #define respipe_write(a,b,c) write ((a), (b), (c)) 167 | #define respipe_close(a) close ((a)) 168 | 169 | #endif 170 | 171 | #endif 172 | 173 | -------------------------------------------------------------------------------- /se/se-kqueue.c: -------------------------------------------------------------------------------- 1 | #include "se.h" 2 | 3 | #if defined(__APPLE__) || defined(__FreeBSD__) || defined(BSD) 4 | #include 5 | struct kevent events[SE_SIZE] = {{0}}, ev[3] = {{0}}; 6 | static unsigned long working_io_count = 0; 7 | static int in_loop = 0; 8 | 9 | /* libeio */ 10 | static int eio_inited = 0; 11 | static int eio_respipe [2]; 12 | void eio_want_poll(void) 13 | { 14 | char dummy = 0; 15 | write(eio_respipe [1], &dummy, 1); 16 | } 17 | 18 | void eio_done_poll(void) 19 | { 20 | char dummy = 0; 21 | read(eio_respipe [0], &dummy, 1); 22 | } 23 | 24 | void eio_event_loop(void) 25 | { 26 | struct pollfd pfd; 27 | pfd.fd = eio_respipe [0]; 28 | pfd.events = POLLIN; 29 | 30 | while(eio_nreqs()) { 31 | poll(&pfd, 1, -1); 32 | eio_poll(); 33 | } 34 | } 35 | /* end */ 36 | 37 | int se_create(int event_size) 38 | { 39 | if(eio_inited == 0) { 40 | eio_inited = 1; 41 | 42 | if(pipe(eio_respipe) || eio_init(eio_want_poll, eio_done_poll)) { 43 | eio_inited = 0; 44 | } 45 | } 46 | 47 | return kqueue(); 48 | } 49 | 50 | int se_loop(int loop_fd, int waitout, se_waitout_proc_t waitout_proc) 51 | { 52 | int n = 0, i = 0, r = 1; 53 | se_ptr_t *ptr = NULL; 54 | 55 | in_loop = 1; 56 | 57 | waitout *= 1000000; 58 | 59 | struct timespec tmout = { waitout / 1000000000, waitout % 1000000000 }; 60 | 61 | while(1) { 62 | update_time(); 63 | check_timeouts(); 64 | eio_event_loop(); 65 | 66 | if(waitout_proc) { 67 | r = waitout_proc(); 68 | } 69 | 70 | n = kevent(loop_fd, NULL, 0, events, SE_SIZE, &tmout); 71 | 72 | for(i = 0; i < n; i++) { 73 | ptr = events[i].udata; 74 | 75 | if(events[i].filter == EVFILT_READ && ptr->rfunc) { 76 | ptr->rfunc(ptr); 77 | 78 | } else if(events[i].filter == EVFILT_WRITE && ptr->wfunc) { 79 | ptr->wfunc(ptr); 80 | } 81 | } 82 | 83 | if(!r || (n == -1 && errno != EINTR) || (check_process_for_exit() && working_io_count == 0)) { 84 | if(check_process_for_exit()) { 85 | on_process_exit_handler(0, NULL, NULL); 86 | } 87 | 88 | break; 89 | } 90 | 91 | } 92 | 93 | in_loop = 0; 94 | 95 | return 0; 96 | } 97 | 98 | static int ev_set_fd(int loop_fd, int fd, unsigned ACT, se_ptr_t *ptr) 99 | { 100 | EV_SET(&ev[0], fd, EVFILT_READ, ACT, 0, 0, ptr); 101 | EV_SET(&ev[1], fd, EVFILT_WRITE, ACT, 0, 0, ptr); 102 | EV_SET(&ev[2], fd, EVFILT_SIGNAL, ACT, 0, 0, ptr); 103 | return kevent(loop_fd, ev, 3, NULL, 0, NULL); 104 | } 105 | 106 | se_ptr_t *se_add(int loop_fd, int fd, void *data) 107 | { 108 | se_ptr_t *ptr = malloc(sizeof(se_ptr_t)); 109 | 110 | if(!ptr) { 111 | return ptr; 112 | } 113 | 114 | ptr->loop_fd = loop_fd; 115 | ptr->fd = fd; 116 | ptr->rfunc = NULL; 117 | ptr->wfunc = NULL; 118 | ptr->data = data; 119 | 120 | int ret = 0; 121 | 122 | ret = ev_set_fd(loop_fd, fd, EV_ADD, ptr); 123 | 124 | if(ret < 0) { 125 | free(ptr); 126 | ptr = NULL; 127 | } 128 | 129 | ret = ev_set_fd(loop_fd, fd, EV_DISABLE, ptr); 130 | 131 | if(ret < 0) { 132 | free(ptr); 133 | ptr = NULL; 134 | } 135 | 136 | working_io_count += in_loop; 137 | 138 | return ptr; 139 | } 140 | 141 | int se_delete(se_ptr_t *ptr) 142 | { 143 | if(!ptr) { 144 | return -1; 145 | } 146 | 147 | ev_set_fd(ptr->loop_fd, ptr->fd, EV_DELETE, ptr); 148 | 149 | free(ptr); 150 | 151 | working_io_count -= in_loop; 152 | 153 | return 0; 154 | } 155 | 156 | int se_be_read(se_ptr_t *ptr, se_rw_proc_t func) 157 | { 158 | ptr->rfunc = func; 159 | ptr->wfunc = NULL; 160 | 161 | ev_set_fd(ptr->loop_fd, ptr->fd, EV_DISABLE, ptr); 162 | 163 | EV_SET(&ev[0], ptr->fd, EVFILT_READ, EV_ENABLE, 0, 0, ptr); 164 | return kevent(ptr->loop_fd, ev, 1, NULL, 0, NULL); 165 | } 166 | 167 | int se_be_write(se_ptr_t *ptr, se_rw_proc_t func) 168 | { 169 | ptr->rfunc = NULL; 170 | ptr->wfunc = func; 171 | 172 | ev_set_fd(ptr->loop_fd, ptr->fd, EV_DISABLE, ptr); 173 | 174 | EV_SET(&ev[0], ptr->fd, EVFILT_WRITE, EV_ENABLE, 0, 0, ptr); 175 | return kevent(ptr->loop_fd, ev, 1, NULL, 0, NULL); 176 | } 177 | 178 | int se_be_pri(se_ptr_t *ptr, se_rw_proc_t func) 179 | { 180 | ptr->rfunc = func; 181 | ptr->wfunc = NULL; 182 | 183 | ev_set_fd(ptr->loop_fd, ptr->fd, EV_DISABLE, ptr); 184 | 185 | EV_SET(&ev[0], ptr->fd, EVFILT_SIGNAL, EV_ENABLE, 0, 0, ptr); 186 | return kevent(ptr->loop_fd, ev, 1, NULL, 0, NULL); 187 | } 188 | 189 | int se_be_rw(se_ptr_t *ptr, se_rw_proc_t rfunc, se_rw_proc_t wfunc) 190 | { 191 | ptr->rfunc = rfunc; 192 | ptr->wfunc = wfunc; 193 | 194 | ev_set_fd(ptr->loop_fd, ptr->fd, EV_DISABLE, ptr); 195 | 196 | EV_SET(&ev[0], ptr->fd, EVFILT_READ, EV_ENABLE, 0, 0, ptr); 197 | EV_SET(&ev[1], ptr->fd, EVFILT_WRITE, EV_ENABLE, 0, 0, ptr); 198 | return kevent(ptr->loop_fd, ev, 2, NULL, 0, NULL); 199 | } 200 | 201 | #endif 202 | -------------------------------------------------------------------------------- /se/se-util.c: -------------------------------------------------------------------------------- 1 | #include "se-util.h" 2 | 3 | static struct hostent *localhost_ent = NULL; 4 | static uint16_t dns_tid = 0; 5 | static struct sockaddr_in dns_servers[4]; 6 | static int dns_server_count = 0; 7 | static unsigned char buf_4096[4096]; 8 | static struct sockaddr_in rt_addr = {0}; 9 | static void *dns_cache[3][64] = {{0}, {0}, {0}}; 10 | static int dns_cache_ttl = 180; 11 | 12 | int se_errno = 0; 13 | 14 | static int be_accept_f(se_ptr_t *ptr) 15 | { 16 | static int client_fd = -1; 17 | static struct sockaddr_in remote_addr; 18 | static socklen_t addr_len = sizeof(struct sockaddr_in); 19 | 20 | if(check_process_for_exit()) { 21 | return 1; 22 | } 23 | 24 | while(1) { 25 | #ifdef HAVE_ACCPEPT4 26 | client_fd = accept4(ptr->fd, (struct sockaddr *)&remote_addr, &addr_len, SOCK_NONBLOCK); 27 | 28 | if(errno == ENOSYS) { 29 | client_fd = accept(ptr->fd, (struct sockaddr *) &remote_addr, &addr_len); 30 | } 31 | 32 | #else 33 | client_fd = accept(ptr->fd, (struct sockaddr *) &remote_addr, &addr_len); 34 | #endif 35 | 36 | if(client_fd < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) { 37 | break; 38 | 39 | } 40 | 41 | if(client_fd > 0) { 42 | ((se_be_accept_cb)ptr->data)(client_fd, remote_addr.sin_addr); 43 | } 44 | } 45 | 46 | return 1; 47 | } 48 | 49 | se_ptr_t *se_accept(int loop_fd, int server_fd, se_be_accept_cb _be_accept) 50 | { 51 | se_ptr_t *ptr = se_add(loop_fd, server_fd, NULL); 52 | ptr->fd = server_fd; 53 | ptr->data = _be_accept; 54 | se_be_read(ptr, be_accept_f); 55 | return ptr; 56 | } 57 | 58 | void add_dns_cache(const char *name, struct in_addr addr, int do_recache) 59 | { 60 | int p = (now / dns_cache_ttl) % 3; 61 | 62 | if(do_recache == 1) { 63 | p = (p + 1) % 3; 64 | } 65 | 66 | dns_cache_item_t *n = NULL, 67 | *m = NULL; 68 | int nlen = strlen(name); 69 | uint32_t key1 = fnv1a_32((unsigned char *) name, nlen); 70 | uint32_t key2 = fnv1a_64((unsigned char *) name, nlen); 71 | int k = key1 % 64; 72 | n = dns_cache[p][k]; 73 | 74 | if(n == NULL) { 75 | m = malloc(sizeof(dns_cache_item_t)); 76 | 77 | if(m == NULL) { 78 | return; 79 | } 80 | 81 | m->key1 = key1; 82 | m->key2 = key2; 83 | m->next = NULL; 84 | m->recached = do_recache; 85 | memcpy(&m->addr, &addr, sizeof(struct in_addr)); 86 | dns_cache[p][k] = m; 87 | 88 | } else { 89 | while(n != NULL) { 90 | if(n->key1 == key1 && n->key2 == key2) { 91 | return; /// exists 92 | } 93 | 94 | if(n->next == NULL) { /// last 95 | m = malloc(sizeof(dns_cache_item_t)); 96 | 97 | if(m == NULL) { 98 | return; 99 | } 100 | 101 | m->key1 = key1; 102 | m->key2 = key2; 103 | m->next = NULL; 104 | m->recached = do_recache; 105 | memcpy(&m->addr, &addr, sizeof(struct in_addr)); 106 | n->next = m; 107 | return; 108 | } 109 | 110 | n = (dns_cache_item_t *) n->next; 111 | } 112 | } 113 | } 114 | 115 | int get_dns_cache(const char *name, struct in_addr *addr) 116 | { 117 | int p = (now / dns_cache_ttl) % 3; 118 | dns_cache_item_t *n = NULL, 119 | *m = NULL; 120 | /// clear old caches 121 | int q = (p + 2) % 3; 122 | int i = 0; 123 | 124 | for(i = 0; i < 64; i++) { 125 | n = dns_cache[q][i]; 126 | 127 | while(n) { 128 | m = n; 129 | n = n->next; 130 | free(m); 131 | } 132 | 133 | dns_cache[q][i] = NULL; 134 | } 135 | 136 | /// end 137 | int nlen = strlen(name); 138 | uint32_t key1 = fnv1a_32((unsigned char *) name, nlen); 139 | uint32_t key2 = fnv1a_64((unsigned char *) name, nlen); 140 | n = dns_cache[p][key1 % 64]; 141 | 142 | while(n != NULL) { 143 | if(n->key1 == key1 && n->key2 == key2) { 144 | break; 145 | } 146 | 147 | n = (dns_cache_item_t *) n->next; 148 | } 149 | 150 | if(n) { 151 | memcpy(addr, &n->addr, sizeof(struct in_addr)); 152 | 153 | if(n->recached != 1) { 154 | n->recached = 1; 155 | add_dns_cache(name, n->addr, 1); 156 | } 157 | 158 | return 1; 159 | } 160 | 161 | return 0; 162 | } 163 | 164 | #define _NTOHS(p) (((p)[0] << 8) | (p)[1]) 165 | int be_get_dns_result(se_ptr_t *ptr) 166 | { 167 | _se_util_epdata_t *epd = ptr->data; 168 | 169 | int len = 0; 170 | 171 | while((len = recvfrom(epd->fd, buf_4096, 2048, 0, NULL, NULL)) > 0 && len >= sizeof(dns_query_header_t)) { 172 | delete_timeout(epd->timeout_ptr); 173 | epd->timeout_ptr = NULL; 174 | int _dns_query_fd = epd->fd; 175 | se_delete(epd->se_ptr); 176 | close(epd->fd); 177 | epd->fd = -1; 178 | 179 | const unsigned char *p = NULL, *e = NULL; 180 | dns_query_header_t *header = NULL; 181 | uint16_t type = 0; 182 | int found = 0, stop = 0, dlen = 0, nlen = 0; 183 | int err = 0; 184 | header = (dns_query_header_t *) buf_4096; 185 | 186 | if(ntohs(header->nqueries) != 1) { 187 | err = 1; 188 | } 189 | 190 | header->tid = ntohs(header->tid); 191 | 192 | if(header->tid != epd->dns_tid) { 193 | err = 1; 194 | } 195 | 196 | /* Skip host name */ 197 | if(err == 0) { 198 | //static char hostname[1024] = {0}; 199 | //int hostname_len = 0; 200 | 201 | for(e = buf_4096 + len, nlen = 0, p = &header->data[0]; p < e 202 | && *p != '\0'; p++) { 203 | //hostname[hostname_len++] = (*p == 3 ? '.' : *p); 204 | nlen++; 205 | } 206 | 207 | //hostname[hostname_len] = '\0'; 208 | //printf("%s\n", hostname); 209 | } 210 | 211 | /* We sent query class 1, query type 1 */ 212 | if(&p[5] > e || _NTOHS(p + 1) != 0x01) { 213 | err = 1; 214 | } 215 | 216 | struct in_addr ips[10]; 217 | 218 | /* Go to the first answer section */ 219 | if(err == 0) { 220 | p += 5; 221 | 222 | /* Loop through the answers, we want A type answer */ 223 | for(found = stop = 0; !stop && &p[12] < e;) { 224 | /* Skip possible name in CNAME answer */ 225 | if(*p != 0xc0) { 226 | while(*p && &p[12] < e) { 227 | p++; 228 | } 229 | 230 | p--; 231 | } 232 | 233 | type = htons(((uint16_t *) p) [1]); 234 | 235 | if(type == 5) { 236 | /* CNAME answer. shift to the next section */ 237 | dlen = htons(((uint16_t *) p) [5]); 238 | p += 12 + dlen; 239 | 240 | } else if(type == 0x01) { 241 | dlen = htons(((uint16_t *) p) [5]); 242 | p += 12; 243 | 244 | if(p + dlen <= e) { 245 | memcpy(&ips[found], p, dlen); 246 | } 247 | 248 | p += dlen; 249 | 250 | if(++found == header->nanswers) { 251 | stop = 1; 252 | } 253 | 254 | if(found >= 10) { 255 | break; 256 | } 257 | 258 | } else { 259 | stop = 1; 260 | } 261 | } 262 | } 263 | 264 | if(found > 0) { 265 | rt_addr.sin_addr = ips[_dns_query_fd % found]; 266 | 267 | add_dns_cache(epd->dns_query_name, rt_addr.sin_addr, 0); 268 | 269 | epd->cb(epd->data, rt_addr); 270 | free(epd); 271 | 272 | return 0; 273 | 274 | } else { 275 | rt_addr.sin_addr.s_addr = INADDR_NONE; 276 | epd->cb(epd->data, rt_addr); 277 | free(epd); 278 | 279 | return 0; 280 | } 281 | 282 | free(epd); 283 | break; 284 | } 285 | 286 | return 0; 287 | } 288 | 289 | static void dns_query_timeout_handle(void *ptr) 290 | { 291 | _se_util_epdata_t *epd = ptr; 292 | se_delete(epd->se_ptr); 293 | close(epd->fd); 294 | delete_timeout(epd->timeout_ptr); 295 | se_errno = SE_DNS_QUERY_TIMEOUT; 296 | rt_addr.sin_addr.s_addr = INADDR_NONE; 297 | epd->cb(epd->data, rt_addr); 298 | se_errno = 0; 299 | free(epd); 300 | } 301 | 302 | int se_dns_query(int loop_fd, const char *name, int timeout, se_be_dns_query_cb cb, void *data) 303 | { 304 | if(get_dns_cache(name, &rt_addr.sin_addr)) { 305 | cb(data, rt_addr); 306 | return 1; 307 | } 308 | 309 | if(dns_server_count == 0) { /// init dns servers 310 | int p1 = 0, 311 | p2 = 0, 312 | p3 = 0, 313 | p4 = 0, 314 | i = 0; 315 | 316 | for(i = 0; i < 4; i++) { 317 | dns_servers[i].sin_family = AF_INET; 318 | dns_servers[i].sin_port = htons(53); 319 | } 320 | 321 | FILE *fp = NULL; 322 | char line[200], 323 | *p = NULL; 324 | 325 | if((fp = fopen("/etc/resolv.conf" , "r")) != NULL) { 326 | while(fgets(line , 200 , fp)) { 327 | if(line[0] == '#') { 328 | continue; 329 | } 330 | 331 | if(strncmp(line , "nameserver" , 10) == 0) { 332 | p = strtok(line , " "); 333 | p = strtok(NULL , " "); 334 | 335 | //p now is the dns ip :) 336 | if(sscanf(p, "%d.%d.%d.%d", &p1, &p2, &p3, &p4) == 4) { 337 | dns_servers[dns_server_count].sin_addr.s_addr = htonl(((p1 << 24) | 338 | (p2 << 16) | (p3 << 8) | (p4))); 339 | dns_server_count ++; 340 | } 341 | 342 | if(dns_server_count > 1) { 343 | break; 344 | } 345 | } 346 | } 347 | 348 | fclose(fp); 349 | } 350 | 351 | if(dns_server_count < 2) { 352 | dns_servers[dns_server_count].sin_addr.s_addr = inet_addr("8.8.8.8"); 353 | dns_server_count++; 354 | } 355 | 356 | if(dns_server_count < 2) { 357 | dns_servers[dns_server_count].sin_addr.s_addr = inet_addr("208.67.22.222"); 358 | dns_server_count++; 359 | } 360 | } 361 | 362 | if(++dns_tid > 65535 - 1) { 363 | dns_tid = 1; 364 | } 365 | 366 | int fd = socket(PF_INET, SOCK_DGRAM, 17); 367 | 368 | if(fd < 0) { 369 | return 0; 370 | } 371 | 372 | _se_util_epdata_t *epd = malloc(sizeof(_se_util_epdata_t)); 373 | 374 | if(!epd) { 375 | close(fd); 376 | return 0; 377 | } 378 | 379 | int nlen = strlen(name); 380 | 381 | if(nlen < 60) { 382 | memcpy(epd->dns_query_name, name, nlen); 383 | epd->dns_query_name[nlen] = '\0'; 384 | 385 | } else { 386 | epd->dns_query_name[0] = '-'; 387 | epd->dns_query_name[1] = '\0'; 388 | nlen = 1; 389 | } 390 | 391 | name = epd->dns_query_name; 392 | 393 | epd->fd = fd; 394 | epd->cb = cb; 395 | epd->data = data; 396 | epd->dns_tid = dns_tid; 397 | 398 | int opt = 1; 399 | ioctl(epd->fd, FIONBIO, &opt); 400 | 401 | int i = 0, n = 0; 402 | dns_query_header_t *header = NULL; 403 | const char *s; 404 | char *p; 405 | header = (dns_query_header_t *) buf_4096; 406 | header->tid = htons(dns_tid); 407 | header->flags = htons(0x100); 408 | header->nqueries = htons(1); 409 | header->nanswers = 0; 410 | header->nauth = 0; 411 | header->nother = 0; 412 | // Encode DNS name 413 | p = (char *) &header->data; /* For encoding host name into packet */ 414 | 415 | do { 416 | if((s = strchr(name, '.')) == NULL) { 417 | s = name + nlen; 418 | } 419 | 420 | n = s - name; /* Chunk length */ 421 | *p++ = n; /* Copy length */ 422 | 423 | for(i = 0; i < n; i++) { /* Copy chunk */ 424 | *p++ = name[i]; 425 | } 426 | 427 | if(*s == '.') { 428 | n++; 429 | } 430 | 431 | name += n; 432 | nlen -= n; 433 | } while(*s != '\0'); 434 | 435 | *p++ = 0; /* Mark end of host name */ 436 | *p++ = 0; /* Well, lets put this byte as well */ 437 | *p++ = 1; /* Query Type */ 438 | *p++ = 0; 439 | *p++ = 1; /* Class: inet, 0x0001 */ 440 | n = (unsigned char *) p - buf_4096; /* Total packet length */ 441 | 442 | sendto( 443 | epd->fd, 444 | buf_4096, 445 | n, 446 | 0, 447 | (struct sockaddr *) &dns_servers[epd->fd % dns_server_count], 448 | sizeof(struct sockaddr) 449 | ); 450 | 451 | sendto( 452 | epd->fd, 453 | buf_4096, 454 | n, 455 | 0, 456 | (struct sockaddr *) &dns_servers[(epd->fd + 1) % dns_server_count], 457 | sizeof(struct sockaddr) 458 | ); 459 | 460 | epd->timeout_ptr = add_timeout(epd, timeout, dns_query_timeout_handle); 461 | 462 | epd->se_ptr = se_add(loop_fd, epd->fd, epd); 463 | se_be_read(epd->se_ptr, be_get_dns_result); 464 | 465 | return 1; 466 | } 467 | 468 | int se_set_nonblocking(int fd, int nonblocking) 469 | { 470 | int flags = fcntl(fd, F_GETFL, 0); 471 | 472 | if(flags == -1) { 473 | return 0; 474 | } 475 | 476 | if(nonblocking) { 477 | flags |= O_NONBLOCK; 478 | 479 | } else { 480 | flags &= ~O_NONBLOCK; 481 | } 482 | 483 | return fcntl(fd, F_SETFL, flags) != -1; 484 | } 485 | 486 | static int __be_connect(se_ptr_t *ptr) 487 | { 488 | _se_util_epdata_t *epd = ptr->data; 489 | 490 | int result = 0; 491 | socklen_t result_len = sizeof(result); 492 | 493 | if(getsockopt(epd->fd, SOL_SOCKET, SO_ERROR, &result, &result_len) < 0) { 494 | // not connected, try next event 495 | return 0; 496 | } 497 | 498 | if(result != 0) { 499 | close(epd->fd); 500 | epd->fd = -1; 501 | } 502 | 503 | se_delete(epd->se_ptr); 504 | delete_timeout(epd->timeout_ptr); 505 | epd->connect_cb(epd->data, epd->fd); 506 | free(epd); 507 | 508 | return 1; 509 | } 510 | 511 | static void connect_timeout_handle(void *ptr) 512 | { 513 | _se_util_epdata_t *epd = ptr; 514 | se_delete(epd->se_ptr); 515 | close(epd->fd); 516 | delete_timeout(epd->timeout_ptr); 517 | se_errno = SE_CONNECT_TIMEOUT; 518 | epd->connect_cb(epd->data, -1); 519 | se_errno = 0; 520 | free(epd); 521 | } 522 | 523 | static void be_dns_query(void *data, struct sockaddr_in addr) 524 | { 525 | _se_util_epdata_t *epd = (_se_util_epdata_t *)data; 526 | 527 | addr.sin_port = htons(epd->port); 528 | 529 | delete_timeout(epd->timeout_ptr); 530 | epd->timeout_ptr = NULL; 531 | 532 | int ret = connect(epd->fd, (struct sockaddr *) &addr, sizeof(struct sockaddr_in)); 533 | 534 | if(ret == 0) { 535 | epd->connect_cb(epd->data, epd->fd); 536 | free(epd); 537 | return; 538 | 539 | } else if(ret == -1 && errno != EINPROGRESS) { 540 | close(epd->fd); 541 | epd->connect_cb(epd->data, -1); 542 | free(epd); 543 | return; 544 | } 545 | 546 | epd->se_ptr = se_add(epd->loop_fd, epd->fd, epd); 547 | epd->timeout_ptr = add_timeout(epd, 3000, connect_timeout_handle); 548 | se_be_write(epd->se_ptr, __be_connect); 549 | } 550 | 551 | int se_connect(int loop_fd, const char *host, int port, int timeout, se_be_connect_cb _be_connect, void *data) 552 | { 553 | #ifndef linux 554 | 555 | if(port < 1) { 556 | return -1; 557 | } 558 | 559 | #endif 560 | 561 | int fd = -1; 562 | 563 | if((fd = socket(port > 0 ? AF_INET : AF_UNIX, SOCK_STREAM, 0)) < 0) { 564 | return -1; 565 | } 566 | 567 | if(!se_set_nonblocking(fd , 1)) { 568 | close(fd); 569 | return -1; 570 | } 571 | 572 | _se_util_epdata_t *epd = malloc(sizeof(_se_util_epdata_t)); 573 | 574 | if(!epd) { 575 | close(fd); 576 | return -1; 577 | } 578 | 579 | epd->port = port; 580 | epd->connect_cb = _be_connect; 581 | epd->fd = fd; 582 | epd->data = data; 583 | epd->timeout_ptr = NULL; 584 | 585 | #ifdef linux 586 | 587 | if(port < 1) { /// connect to unix domain socket 588 | struct sockaddr_un un; 589 | 590 | bzero(&un, sizeof(struct sockaddr_un)); 591 | strcpy(un.sun_path, host); 592 | un.sun_family = AF_UNIX; 593 | int length = offsetof(struct sockaddr_un, sun_path) + strlen(un.sun_path); 594 | 595 | int ret = connect(fd, (struct sockaddr *) &un, length); 596 | 597 | if(ret == 0) { 598 | //epd->connect_cb(data, fd); 599 | free(epd); 600 | 601 | return fd; 602 | 603 | } else if(ret == -1 && errno != EINPROGRESS) { 604 | close(epd->fd); 605 | //epd->connect_cb(data, -1); 606 | free(epd); 607 | return -1; 608 | } 609 | 610 | epd->se_ptr = se_add(loop_fd, fd, epd); 611 | epd->timeout_ptr = add_timeout(epd, timeout, connect_timeout_handle); 612 | se_be_write(epd->se_ptr, __be_connect); 613 | return -2; // be yield 614 | } 615 | 616 | #endif 617 | 618 | rt_addr.sin_family = AF_INET; 619 | rt_addr.sin_port = htons(port); 620 | rt_addr.sin_addr.s_addr = inet_addr(host); // 按IP初始化 621 | 622 | if(rt_addr.sin_addr.s_addr == INADDR_NONE) { // 如果输入的是域名 623 | if(strcmp(host, "localhost") == 0) { 624 | if(localhost_ent == NULL) { 625 | localhost_ent = malloc(sizeof(struct hostent)); 626 | struct hostent *phost = (struct hostent *) gethostbyname(host); 627 | memcpy(localhost_ent, phost, sizeof(struct hostent)); 628 | } 629 | 630 | rt_addr.sin_addr.s_addr = ((struct in_addr *) localhost_ent->h_addr_list[0])->s_addr; 631 | 632 | } else if(!get_dns_cache(host, &rt_addr.sin_addr)) { 633 | //epd->timeout_ptr = add_timeout(epd, timeout, connect_timeout_handle); 634 | epd->loop_fd = loop_fd; 635 | se_dns_query(loop_fd, host, timeout, be_dns_query, epd); 636 | return -2; // be yield 637 | } 638 | } 639 | 640 | int ret = connect(fd, (struct sockaddr *) &rt_addr, sizeof(struct sockaddr_in)); 641 | 642 | if(ret == 0) { 643 | //epd->connect_cb(data, fd); 644 | free(epd); 645 | return fd; 646 | 647 | } else if(ret == -1 && errno != EINPROGRESS) { 648 | close(epd->fd); 649 | //epd->connect_cb(data, -1); 650 | free(epd); 651 | return -1; 652 | } 653 | 654 | epd->se_ptr = se_add(loop_fd, fd, epd); 655 | 656 | if(!epd->se_ptr) { 657 | close(epd->fd); 658 | free(epd); 659 | return -1; 660 | } 661 | 662 | epd->timeout_ptr = add_timeout(epd, timeout, connect_timeout_handle); 663 | se_be_write(epd->se_ptr, __be_connect); 664 | 665 | return -2; // be yield 666 | } 667 | -------------------------------------------------------------------------------- /se/se-util.h: -------------------------------------------------------------------------------- 1 | #if defined(__GLIBC__) && defined(__GLIBC_PREREQ) 2 | #if __GLIBC_PREREQ(2, 12) 3 | #define _GNU_SOURCE 4 | #include 5 | #define HAVE_ACCPEPT4 1 6 | #endif 7 | #endif 8 | 9 | #include 10 | #include 11 | #ifdef linux 12 | #include 13 | #include 14 | #endif 15 | 16 | #include "../merry.h" 17 | 18 | #ifndef _SE_UTIL_H 19 | #define _SE_UTIL_H 20 | 21 | #define SE_CONNECT_TIMEOUT -1002 22 | #define SE_DNS_QUERY_TIMEOUT -1001 23 | 24 | typedef void (*se_be_accept_cb)(int fd, struct in_addr client_addr); 25 | typedef void (*se_be_dns_query_cb)(void *data, struct sockaddr_in addr); 26 | typedef void (*se_be_connect_cb)(void *data, int fd); 27 | int se_set_nonblocking(int fd, int nonblocking); 28 | se_ptr_t *se_accept(int loop_fd, int server_fd, se_be_accept_cb _be_accept); 29 | int se_dns_query(int loop_fd, const char *name, int timeout, se_be_dns_query_cb cb, void *data); 30 | int se_connect(int loop_fd, const char *host, int port, int timeout, se_be_connect_cb _be_connect, void *data); 31 | 32 | typedef struct { 33 | uint32_t key1; 34 | uint32_t key2; 35 | struct in_addr addr; 36 | int recached; 37 | void *next; 38 | } dns_cache_item_t; 39 | 40 | typedef struct { 41 | void *se_ptr; 42 | void *timeout_ptr; 43 | 44 | char dns_query_name[60]; 45 | int loop_fd; 46 | int fd; 47 | int dns_tid; 48 | int port; 49 | void *data; 50 | se_be_dns_query_cb cb; 51 | se_be_connect_cb connect_cb; 52 | } _se_util_epdata_t; 53 | 54 | typedef struct { 55 | uint16_t tid; /* Transaction ID */ 56 | uint16_t flags; /* Flags */ 57 | uint16_t nqueries; /* Questions */ 58 | uint16_t nanswers; /* Answers */ 59 | uint16_t nauth; /* Authority PRs */ 60 | uint16_t nother; /* Other PRs */ 61 | unsigned char data[1]; /* Data, variable length */ 62 | } dns_query_header_t; 63 | 64 | #endif 65 | -------------------------------------------------------------------------------- /se/se.c: -------------------------------------------------------------------------------- 1 | #include "se.h" 2 | 3 | #ifdef linux 4 | #include 5 | #ifndef EPOLLRDHUP 6 | #define EPOLLRDHUP 0x2000 7 | #endif 8 | 9 | static struct epoll_event events[SE_SIZE], ev; 10 | static unsigned long working_io_count = 0; 11 | static int in_loop = 0; 12 | static unsigned long quitime = 0; 13 | 14 | /* libeio */ 15 | static int eio_inited = 0; 16 | static int eio_respipe [2]; 17 | void eio_want_poll(void) 18 | { 19 | char dummy = 0; 20 | write(eio_respipe [1], &dummy, 1); 21 | } 22 | 23 | void eio_done_poll(void) 24 | { 25 | char dummy = 0; 26 | read(eio_respipe [0], &dummy, 1); 27 | } 28 | 29 | void eio_event_loop(void) 30 | { 31 | struct pollfd pfd; 32 | pfd.fd = eio_respipe [0]; 33 | pfd.events = POLLIN; 34 | 35 | while(eio_nreqs()) { 36 | poll(&pfd, 1, -1); 37 | eio_poll(); 38 | } 39 | } 40 | /* end */ 41 | 42 | int se_create(int event_size) 43 | { 44 | if(eio_inited == 0) { 45 | eio_inited = 1; 46 | 47 | if(pipe(eio_respipe) || eio_init(eio_want_poll, eio_done_poll)) { 48 | eio_inited = 0; 49 | } 50 | } 51 | 52 | return epoll_create(event_size); 53 | } 54 | 55 | int se_loop(int loop_fd, int waitout, se_waitout_proc_t waitout_proc) 56 | { 57 | int n = 0, i = 0, r = 1; 58 | se_ptr_t *ptr = NULL; 59 | 60 | in_loop = 1; 61 | 62 | while(1) { 63 | update_time(); 64 | check_timeouts(); 65 | eio_event_loop(); 66 | 67 | if(waitout_proc) { 68 | r = waitout_proc(); 69 | } 70 | 71 | n = epoll_wait(loop_fd, events, SE_SIZE, waitout); 72 | 73 | for(i = 0; i < n; i++) { 74 | ptr = events[i].data.ptr; 75 | 76 | if(events[i].events & (EPOLLIN | EPOLLET) && ptr->rfunc) { 77 | ptr->rfunc(ptr); 78 | 79 | } else if(events[i].events & (EPOLLOUT | EPOLLET) && ptr->wfunc) { 80 | ptr->wfunc(ptr); 81 | } 82 | } 83 | 84 | if(!r || (n == -1 && errno != EINTR)) { 85 | 86 | break; 87 | 88 | } else if(check_process_for_exit()) { 89 | if(working_io_count > 0 && (quitime == 0 || time(NULL) - quitime < 10)) { 90 | if(quitime == 0) { 91 | quitime = time(NULL); 92 | } 93 | 94 | continue; 95 | } 96 | 97 | quitime = 0; 98 | on_process_exit_handler(0, NULL, NULL); 99 | 100 | break; 101 | } 102 | 103 | } 104 | 105 | in_loop = 0; 106 | 107 | return 0; 108 | } 109 | 110 | se_ptr_t *se_add(int loop_fd, int fd, void *data) 111 | { 112 | se_ptr_t *ptr = malloc(sizeof(se_ptr_t)); 113 | 114 | if(!ptr) { 115 | return NULL; 116 | } 117 | 118 | ptr->loop_fd = loop_fd; 119 | ptr->fd = fd; 120 | ptr->rfunc = NULL; 121 | ptr->wfunc = NULL; 122 | ptr->data = data; 123 | 124 | ev.data.ptr = ptr; 125 | ev.events = EPOLLPRI; 126 | 127 | int ret = epoll_ctl(loop_fd, EPOLL_CTL_ADD, fd, &ev); 128 | 129 | if(ret < 0) { 130 | free(ptr); 131 | ptr = NULL; 132 | } 133 | 134 | working_io_count += in_loop; 135 | 136 | return ptr; 137 | } 138 | 139 | int se_delete(se_ptr_t *ptr) 140 | { 141 | if(!ptr) { 142 | return -1; 143 | } 144 | 145 | if(epoll_ctl(ptr->loop_fd, EPOLL_CTL_DEL, ptr->fd, &ev) < 0) { 146 | return -1; 147 | } 148 | 149 | free(ptr); 150 | 151 | working_io_count -= in_loop; 152 | 153 | return 0; 154 | } 155 | 156 | int se_be_read(se_ptr_t *ptr, se_rw_proc_t func) 157 | { 158 | ptr->rfunc = func; 159 | ptr->wfunc = NULL; 160 | 161 | ev.data.ptr = ptr; 162 | ev.events = EPOLLIN | EPOLLET; 163 | 164 | return epoll_ctl(ptr->loop_fd, EPOLL_CTL_MOD, ptr->fd, &ev); 165 | } 166 | 167 | int se_be_write(se_ptr_t *ptr, se_rw_proc_t func) 168 | { 169 | ptr->rfunc = NULL; 170 | ptr->wfunc = func; 171 | 172 | ev.data.ptr = ptr; 173 | ev.events = EPOLLOUT | EPOLLET; 174 | 175 | return epoll_ctl(ptr->loop_fd, EPOLL_CTL_MOD, ptr->fd, &ev); 176 | } 177 | 178 | int se_be_pri(se_ptr_t *ptr, se_rw_proc_t func) 179 | { 180 | ptr->rfunc = func; 181 | ptr->wfunc = NULL; 182 | 183 | ev.data.ptr = ptr; 184 | ev.events = EPOLLPRI; 185 | 186 | return epoll_ctl(ptr->loop_fd, EPOLL_CTL_MOD, ptr->fd, &ev); 187 | } 188 | 189 | int se_be_rw(se_ptr_t *ptr, se_rw_proc_t rfunc, se_rw_proc_t wfunc) 190 | { 191 | ptr->rfunc = rfunc; 192 | ptr->wfunc = wfunc; 193 | 194 | ev.data.ptr = ptr; 195 | ev.events = EPOLLIN | EPOLLOUT | EPOLLET; 196 | 197 | return epoll_ctl(ptr->loop_fd, EPOLL_CTL_MOD, ptr->fd, &ev); 198 | } 199 | 200 | #endif 201 | -------------------------------------------------------------------------------- /se/se.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "../common/times.h" 10 | #include "../common/timeouts.h" 11 | #include "../common/process.h" 12 | #include "../common/smp.h" 13 | #include "libeio/eio.h" 14 | 15 | #ifndef _SE_H 16 | #define _SE_H 17 | 18 | #define SE_SIZE 4096 19 | typedef struct se_ptr_s se_ptr_t; 20 | typedef int (*se_rw_proc_t)(se_ptr_t *ptr); 21 | typedef int (*se_waitout_proc_t)(); 22 | 23 | struct se_ptr_s { 24 | unsigned int loop_fd; 25 | unsigned int fd; 26 | se_rw_proc_t rfunc; 27 | se_rw_proc_t wfunc; 28 | void *data; 29 | }; 30 | 31 | int se_create(int event_size); 32 | int se_loop(int loop_fd, int waitout, se_waitout_proc_t waitout_proc); 33 | se_ptr_t *se_add(int loop_fd, int fd, void *data); 34 | int se_delete(se_ptr_t *ptr); 35 | int se_be_read(se_ptr_t *ptr, se_rw_proc_t func); 36 | int se_be_write(se_ptr_t *ptr, se_rw_proc_t func); 37 | int se_be_pri(se_ptr_t *ptr, se_rw_proc_t func); 38 | int se_be_rw(se_ptr_t *ptr, se_rw_proc_t rfunc, se_rw_proc_t wfunc); 39 | 40 | #include "se-util.h" 41 | 42 | #endif // _SE_H 43 | --------------------------------------------------------------------------------