1 /*
2 +----------------------------------------------------------------------+
3 | Swoole |
4 +----------------------------------------------------------------------+
5 | This source file is subject to version 2.0 of the Apache license, |
6 | that is bundled with this package in the file LICENSE, and is |
7 | available through the world-wide-web at the following url: |
8 | http://www.apache.org/licenses/LICENSE-2.0.html |
9 | If you did not receive a copy of the Apache2.0 license and are unable|
10 | to obtain it through the world-wide-web, please send a note to |
11 | license@swoole.com so we can mail you a copy immediately. |
12 +----------------------------------------------------------------------+
13 | Author: Tianfeng Han <mikan.tenny@gmail.com> |
14 +----------------------------------------------------------------------+
15 */
16
17 #include "swoole.h"
18
19 #include <stdarg.h>
20 #include <assert.h>
21 #include <fcntl.h>
22
23 #include <sys/stat.h>
24 #include <sys/resource.h>
25
26 #ifdef __MACH__
27 #include <sys/syslimits.h>
28 #endif
29
30 #include <algorithm>
31 #include <list>
32 #include <set>
33 #include <unordered_map>
34
35 #include "swoole_api.h"
36 #include "swoole_string.h"
37 #include "swoole_signal.h"
38 #include "swoole_memory.h"
39 #include "swoole_protocol.h"
40 #include "swoole_util.h"
41 #include "swoole_async.h"
42 #include "swoole_c_api.h"
43 #include "swoole_coroutine_c_api.h"
44 #include "swoole_ssl.h"
45
46 #if defined(HAVE_CCRANDOMGENERATEBYTES)
47 #include <CommonCrypto/CommonRandom.h>
48 #endif
49
50 using swoole::String;
51
52 #ifdef HAVE_GETRANDOM
53 #include <sys/random.h>
54 #else
getrandom(void * buffer,size_t size,unsigned int __flags)55 static ssize_t getrandom(void *buffer, size_t size, unsigned int __flags) {
56 #if defined(HAVE_CCRANDOMGENERATEBYTES)
57 /*
58 * arc4random_buf on macOs uses ccrng_generate internally from which
59 * the potential error is silented to respect the portable arc4random_buf interface contract
60 */
61 if (CCRandomGenerateBytes(buffer, size) == kCCSuccess) {
62 return size;
63 }
64 return -1;
65 #elif defined(HAVE_ARC4RANDOM)
66 arc4random_buf(buffer, size);
67 return size;
68 #else
69 int fd = open("/dev/urandom", O_RDONLY);
70 if (fd < 0) {
71 return -1;
72 }
73
74 size_t read_bytes;
75 ssize_t n;
76 for (read_bytes = 0; read_bytes < size; read_bytes += (size_t) n) {
77 n = read(fd, (char *) buffer + read_bytes, size - read_bytes);
78 if (n <= 0) {
79 break;
80 }
81 }
82
83 close(fd);
84
85 return read_bytes;
86 #endif
87 }
88 #endif
89
90 swoole::Global SwooleG = {};
91 __thread swoole::ThreadGlobal SwooleTG = {};
92
93 static std::unordered_map<std::string, void *> functions;
94 static swoole::Logger *g_logger_instance = nullptr;
95
96 #ifdef __MACH__
97 static __thread char _sw_error_buf[SW_ERROR_MSG_SIZE];
sw_error_()98 char *sw_error_() {
99 return _sw_error_buf;
100 }
101 #else
102 __thread char sw_error[SW_ERROR_MSG_SIZE];
103 #endif
104
105 static void swoole_fatal_error_impl(int code, const char *format, ...);
106
sw_logger()107 swoole::Logger *sw_logger() {
108 return g_logger_instance;
109 }
110
sw_malloc(size_t size)111 void *sw_malloc(size_t size) {
112 return SwooleG.std_allocator.malloc(size);
113 }
114
sw_free(void * ptr)115 void sw_free(void *ptr) {
116 return SwooleG.std_allocator.free(ptr);
117 }
118
sw_calloc(size_t nmemb,size_t size)119 void *sw_calloc(size_t nmemb, size_t size) {
120 return SwooleG.std_allocator.calloc(nmemb, size);
121 }
122
sw_realloc(void * ptr,size_t size)123 void *sw_realloc(void *ptr, size_t size) {
124 return SwooleG.std_allocator.realloc(ptr, size);
125 }
126
bug_report_message_init()127 static void bug_report_message_init() {
128 SwooleG.bug_report_message += "\n" + std::string(SWOOLE_BUG_REPORT) + "\n";
129
130 struct utsname u;
131 if (uname(&u) != -1) {
132 SwooleG.bug_report_message +=
133 swoole::std_string::format("OS: %s %s %s %s\n", u.sysname, u.release, u.version, u.machine);
134 }
135
136 #ifdef __VERSION__
137 SwooleG.bug_report_message += swoole::std_string::format("GCC_VERSION: %s\n", __VERSION__);
138 #endif
139
140 #ifdef SW_USE_OPENSSL
141 SwooleG.bug_report_message += swoole_ssl_get_version_message();
142
143 #endif
144 }
145
swoole_init(void)146 void swoole_init(void) {
147 if (SwooleG.init) {
148 return;
149 }
150
151 SwooleG = {};
152 sw_memset_zero(sw_error, SW_ERROR_MSG_SIZE);
153
154 SwooleG.running = 1;
155 SwooleG.init = 1;
156 SwooleG.std_allocator = {malloc, calloc, realloc, free};
157 SwooleG.fatal_error = swoole_fatal_error_impl;
158 SwooleG.cpu_num = SW_MAX(1, sysconf(_SC_NPROCESSORS_ONLN));
159 SwooleG.pagesize = getpagesize();
160
161 // DNS options
162 SwooleG.dns_tries = 1;
163 SwooleG.dns_resolvconf_path = SW_DNS_RESOLV_CONF;
164
165 // get system uname
166 uname(&SwooleG.uname);
167 // random seed
168 srandom(time(nullptr));
169
170 SwooleG.pid = getpid();
171
172 g_logger_instance = new swoole::Logger;
173
174 #ifdef SW_DEBUG
175 sw_logger()->set_level(0);
176 SwooleG.trace_flags = 0x7fffffff;
177 #else
178 sw_logger()->set_level(SW_LOG_INFO);
179 #endif
180
181 // init global shared memory
182 SwooleG.memory_pool = new swoole::GlobalMemory(SW_GLOBAL_MEMORY_PAGESIZE, true);
183 SwooleG.max_sockets = SW_MAX_SOCKETS_DEFAULT;
184 struct rlimit rlmt;
185 if (getrlimit(RLIMIT_NOFILE, &rlmt) < 0) {
186 swoole_sys_warning("getrlimit() failed");
187 } else {
188 SwooleG.max_sockets = SW_MAX((uint32_t) rlmt.rlim_cur, SW_MAX_SOCKETS_DEFAULT);
189 SwooleG.max_sockets = SW_MIN((uint32_t) rlmt.rlim_cur, SW_SESSION_LIST_SIZE);
190 }
191
192 SwooleTG.buffer_stack = new swoole::String(SW_STACK_BUFFER_SIZE);
193
194 if (!swoole_set_task_tmpdir(SW_TASK_TMP_DIR)) {
195 exit(4);
196 }
197
198 // init signalfd
199 #ifdef HAVE_SIGNALFD
200 swoole_signalfd_init();
201 SwooleG.use_signalfd = 1;
202 SwooleG.enable_signalfd = 1;
203 #endif
204
205 // init bug report message
206 bug_report_message_init();
207 }
208
209 SW_EXTERN_C_BEGIN
210
swoole_add_function(const char * name,void * func)211 SW_API int swoole_add_function(const char *name, void *func) {
212 std::string _name(name);
213 auto iter = functions.find(_name);
214 if (iter != functions.end()) {
215 swoole_warning("Function '%s' has already been added", name);
216 return SW_ERR;
217 } else {
218 functions.emplace(std::make_pair(_name, func));
219 return SW_OK;
220 }
221 }
222
swoole_get_function(const char * name,uint32_t length)223 SW_API void *swoole_get_function(const char *name, uint32_t length) {
224 auto iter = functions.find(std::string(name, length));
225 if (iter != functions.end()) {
226 return iter->second;
227 } else {
228 return nullptr;
229 }
230 }
231
swoole_add_hook(enum swGlobalHookType type,swHookFunc func,int push_back)232 SW_API int swoole_add_hook(enum swGlobalHookType type, swHookFunc func, int push_back) {
233 assert(type <= SW_GLOBAL_HOOK_END);
234 return swoole::hook_add(SwooleG.hooks, type, func, push_back);
235 }
236
swoole_call_hook(enum swGlobalHookType type,void * arg)237 SW_API void swoole_call_hook(enum swGlobalHookType type, void *arg) {
238 assert(type <= SW_GLOBAL_HOOK_END);
239 swoole::hook_call(SwooleG.hooks, type, arg);
240 }
241
swoole_isset_hook(enum swGlobalHookType type)242 SW_API bool swoole_isset_hook(enum swGlobalHookType type) {
243 assert(type <= SW_GLOBAL_HOOK_END);
244 return SwooleG.hooks[type] != nullptr;
245 }
246
swoole_version(void)247 SW_API const char *swoole_version(void) {
248 return SWOOLE_VERSION;
249 }
250
swoole_version_id(void)251 SW_API int swoole_version_id(void) {
252 return SWOOLE_VERSION_ID;
253 }
254
swoole_api_version_id(void)255 SW_API int swoole_api_version_id(void) {
256 return SWOOLE_API_VERSION_ID;
257 }
258
259 SW_EXTERN_C_END
260
swoole_clean(void)261 void swoole_clean(void) {
262 if (SwooleTG.timer) {
263 swoole_timer_free();
264 }
265 if (SwooleTG.reactor) {
266 swoole_event_free();
267 }
268 if (SwooleG.memory_pool != nullptr) {
269 delete SwooleG.memory_pool;
270 }
271 if (g_logger_instance) {
272 delete g_logger_instance;
273 g_logger_instance = nullptr;
274 }
275 if (SwooleTG.buffer_stack) {
276 delete SwooleTG.buffer_stack;
277 SwooleTG.buffer_stack = nullptr;
278 }
279 SwooleG = {};
280 }
281
swoole_set_log_level(int level)282 SW_API void swoole_set_log_level(int level) {
283 if (sw_logger()) {
284 sw_logger()->set_level(level);
285 }
286 }
287
swoole_set_trace_flags(int flags)288 SW_API void swoole_set_trace_flags(int flags) {
289 SwooleG.trace_flags = flags;
290 }
291
swoole_set_dns_server(const std::string & server)292 SW_API void swoole_set_dns_server(const std::string &server) {
293 char *_port;
294 int dns_server_port = SW_DNS_SERVER_PORT;
295 char dns_server_host[32];
296 strcpy(dns_server_host, server.c_str());
297 if ((_port = strchr((char *) server.c_str(), ':'))) {
298 dns_server_port = atoi(_port + 1);
299 if (dns_server_port <= 0 || dns_server_port > 65535) {
300 dns_server_port = SW_DNS_SERVER_PORT;
301 }
302 dns_server_host[_port - server.c_str()] = '\0';
303 }
304 SwooleG.dns_server_host = dns_server_host;
305 SwooleG.dns_server_port = dns_server_port;
306 }
307
swoole_get_dns_server()308 SW_API std::pair<std::string, int> swoole_get_dns_server() {
309 std::pair<std::string, int> result;
310 if (SwooleG.dns_server_host.empty()) {
311 result.first = "";
312 result.second = 0;
313 } else {
314 result.first = SwooleG.dns_server_host;
315 result.second = SwooleG.dns_server_port;
316 }
317 return result;
318 }
319
swoole_set_task_tmpdir(const std::string & dir)320 bool swoole_set_task_tmpdir(const std::string &dir) {
321 if (dir.at(0) != '/') {
322 swoole_warning("wrong absolute path '%s'", dir.c_str());
323 return false;
324 }
325
326 if (access(dir.c_str(), R_OK) < 0 && !swoole_mkdir_recursive(dir)) {
327 swoole_warning("create task tmp dir(%s) failed", dir.c_str());
328 return false;
329 }
330
331 sw_tg_buffer()->format("%s/" SW_TASK_TMP_FILE, dir.c_str());
332 SwooleG.task_tmpfile = sw_tg_buffer()->to_std_string();
333
334 if (SwooleG.task_tmpfile.length() >= SW_TASK_TMP_PATH_SIZE) {
335 swoole_warning("task tmp_dir is too large, the max size is '%d'", SW_TASK_TMP_PATH_SIZE - 1);
336 return false;
337 }
338
339 return true;
340 }
341
swoole_fork(int flags)342 pid_t swoole_fork(int flags) {
343 if (!(flags & SW_FORK_EXEC)) {
344 if (swoole_coroutine_is_in()) {
345 swoole_fatal_error(SW_ERROR_OPERATION_NOT_SUPPORT, "must be forked outside the coroutine");
346 }
347 if (SwooleTG.async_threads) {
348 swoole_trace("aio_task_num=%lu, reactor=%p", SwooleTG.async_threads->task_num, sw_reactor());
349 swoole_fatal_error(SW_ERROR_OPERATION_NOT_SUPPORT,
350 "can not create server after using async file operation");
351 }
352 }
353 if (flags & SW_FORK_PRECHECK) {
354 return 0;
355 }
356
357 pid_t pid = fork();
358 if (pid == 0) {
359 SwooleG.pid = getpid();
360 if (flags & SW_FORK_DAEMON) {
361 return pid;
362 }
363 /**
364 * [!!!] All timers and event loops must be cleaned up after fork
365 */
366 if (swoole_timer_is_available()) {
367 swoole_timer_free();
368 }
369 if (SwooleG.memory_pool) {
370 delete SwooleG.memory_pool;
371 }
372 if (!(flags & SW_FORK_EXEC)) {
373 // reset SwooleG.memory_pool
374 SwooleG.memory_pool = new swoole::GlobalMemory(SW_GLOBAL_MEMORY_PAGESIZE, true);
375 // reopen log file
376 sw_logger()->reopen();
377 // reset eventLoop
378 if (swoole_event_is_available()) {
379 swoole_event_free();
380 swoole_trace_log(SW_TRACE_REACTOR, "reactor has been destroyed");
381 }
382 } else {
383 /**
384 * close log fd
385 */
386 sw_logger()->close();
387 }
388 /**
389 * reset signal handler
390 */
391 swoole_signal_clear();
392 }
393
394 return pid;
395 }
396
397 #ifdef SW_DEBUG
swoole_dump_ascii(const char * data,size_t size)398 void swoole_dump_ascii(const char *data, size_t size) {
399 for (size_t i = 0; i < size; i++) {
400 printf("%u ", (unsigned) data[i]);
401 }
402 printf("\n");
403 }
404
swoole_dump_bin(const char * data,char type,size_t size)405 void swoole_dump_bin(const char *data, char type, size_t size) {
406 int i;
407 int type_size = swoole_type_size(type);
408 if (type_size <= 0) {
409 return;
410 }
411 int n = size / type_size;
412
413 for (i = 0; i < n; i++) {
414 printf("%d,", swoole_unpack(type, data + type_size * i));
415 }
416 printf("\n");
417 }
418
swoole_dump_hex(const char * data,size_t outlen)419 void swoole_dump_hex(const char *data, size_t outlen) {
420 for (size_t i = 0; i < outlen; ++i) {
421 if ((i & 0x0fu) == 0) {
422 printf("%08zX: ", i);
423 }
424 printf("%02X ", data[i]);
425 if (((i + 1) & 0x0fu) == 0) {
426 printf("\n");
427 }
428 }
429 printf("\n");
430 }
431 #endif
432
433 /**
434 * Recursive directory creation
435 */
swoole_mkdir_recursive(const std::string & dir)436 bool swoole_mkdir_recursive(const std::string &dir) {
437 char tmp[PATH_MAX];
438 size_t i, len = dir.length();
439
440 // PATH_MAX limit includes string trailing null character
441 if (len + 1 > PATH_MAX) {
442 swoole_warning("mkdir(%s) failed. Path exceeds the limit of %d characters", dir.c_str(), PATH_MAX - 1);
443 return false;
444 }
445 swoole_strlcpy(tmp, dir.c_str(), PATH_MAX);
446
447 if (dir[len - 1] != '/') {
448 strcat(tmp, "/");
449 }
450
451 len = strlen(tmp);
452 for (i = 1; i < len; i++) {
453 if (tmp[i] == '/') {
454 tmp[i] = 0;
455 if (access(tmp, R_OK) != 0) {
456 if (mkdir(tmp, 0755) == -1) {
457 swoole_sys_warning("mkdir(%s) failed", tmp);
458 return -1;
459 }
460 }
461 tmp[i] = '/';
462 }
463 }
464
465 return true;
466 }
467
swoole_type_size(char type)468 int swoole_type_size(char type) {
469 switch (type) {
470 case 'c':
471 case 'C':
472 return 1;
473 case 's':
474 case 'S':
475 case 'n':
476 case 'v':
477 return 2;
478 case 'l':
479 case 'L':
480 case 'N':
481 case 'V':
482 return 4;
483 default:
484 return 0;
485 }
486 }
487
swoole_dec2hex(ulong_t value,int base)488 char *swoole_dec2hex(ulong_t value, int base) {
489 assert(base > 1 && base < 37);
490
491 static char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
492 char buf[(sizeof(ulong_t) << 3) + 1];
493 char *ptr, *end;
494
495 end = ptr = buf + sizeof(buf) - 1;
496 *ptr = '\0';
497
498 do {
499 *--ptr = digits[value % base];
500 value /= base;
501 } while (ptr > buf && value);
502
503 return sw_strndup(ptr, end - ptr);
504 }
505
swoole_hex2dec(const char * hex,size_t * parsed_bytes)506 ulong_t swoole_hex2dec(const char *hex, size_t *parsed_bytes) {
507 size_t value = 0;
508 *parsed_bytes = 0;
509 const char *p = hex;
510
511 if (strncasecmp(hex, "0x", 2) == 0) {
512 p += 2;
513 }
514
515 while (1) {
516 char c = *p;
517 if ((c >= '0') && (c <= '9')) {
518 value = value * 16 + (c - '0');
519 } else {
520 c = toupper(c);
521 if ((c >= 'A') && (c <= 'Z')) {
522 value = value * 16 + (c - 'A') + 10;
523 } else {
524 break;
525 }
526 }
527 p++;
528 }
529 *parsed_bytes = p - hex;
530 return value;
531 }
532
533 #ifndef RAND_MAX
534 #define RAND_MAX 2147483647
535 #endif
536
swoole_rand(int min,int max)537 int swoole_rand(int min, int max) {
538 static int _seed = 0;
539 assert(max > min);
540
541 if (_seed == 0) {
542 _seed = time(nullptr);
543 srand(_seed);
544 }
545
546 int _rand = rand();
547 _rand = min + (int) ((double) ((double) (max) - (min) + 1.0) * ((_rand) / ((RAND_MAX) + 1.0)));
548 return _rand;
549 }
550
swoole_system_random(int min,int max)551 int swoole_system_random(int min, int max) {
552 static int dev_random_fd = -1;
553 char *next_random_byte;
554 int bytes_to_read;
555 unsigned random_value;
556
557 assert(max > min);
558
559 if (dev_random_fd == -1) {
560 dev_random_fd = open("/dev/urandom", O_RDONLY);
561 if (dev_random_fd < 0) {
562 return swoole_rand(min, max);
563 }
564 }
565
566 next_random_byte = (char *) &random_value;
567 bytes_to_read = sizeof(random_value);
568
569 if (read(dev_random_fd, next_random_byte, bytes_to_read) < bytes_to_read) {
570 swoole_sys_warning("read() from /dev/urandom failed");
571 return SW_ERR;
572 }
573 return min + (random_value % (max - min + 1));
574 }
575
swoole_redirect_stdout(int new_fd)576 void swoole_redirect_stdout(int new_fd) {
577 if (dup2(new_fd, STDOUT_FILENO) < 0) {
578 swoole_sys_warning("dup2(STDOUT_FILENO) failed");
579 }
580 if (dup2(new_fd, STDERR_FILENO) < 0) {
581 swoole_sys_warning("dup2(STDERR_FILENO) failed");
582 }
583 }
584
swoole_version_compare(const char * version1,const char * version2)585 int swoole_version_compare(const char *version1, const char *version2) {
586 int result = 0;
587
588 while (result == 0) {
589 char *tail1;
590 char *tail2;
591
592 unsigned long ver1 = strtoul(version1, &tail1, 10);
593 unsigned long ver2 = strtoul(version2, &tail2, 10);
594
595 if (ver1 < ver2) {
596 result = -1;
597 } else if (ver1 > ver2) {
598 result = +1;
599 } else {
600 version1 = tail1;
601 version2 = tail2;
602 if (*version1 == '\0' && *version2 == '\0') {
603 break;
604 } else if (*version1 == '\0') {
605 result = -1;
606 } else if (*version2 == '\0') {
607 result = +1;
608 } else {
609 version1++;
610 version2++;
611 }
612 }
613 }
614 return result;
615 }
616
617 /**
618 * Maximum common divisor
619 */
swoole_common_divisor(uint32_t u,uint32_t v)620 uint32_t swoole_common_divisor(uint32_t u, uint32_t v) {
621 assert(u > 0);
622 assert(v > 0);
623 uint32_t t;
624 while (u > 0) {
625 if (u < v) {
626 t = u;
627 u = v;
628 v = t;
629 }
630 u = u - v;
631 }
632 return v;
633 }
634
635 /**
636 * The least common multiple
637 */
swoole_common_multiple(uint32_t u,uint32_t v)638 uint32_t swoole_common_multiple(uint32_t u, uint32_t v) {
639 assert(u > 0);
640 assert(v > 0);
641
642 uint32_t m_cup = u;
643 uint32_t n_cup = v;
644 int res = m_cup % n_cup;
645
646 while (res != 0) {
647 m_cup = n_cup;
648 n_cup = res;
649 res = m_cup % n_cup;
650 }
651 return u * v / n_cup;
652 }
653
sw_snprintf(char * buf,size_t size,const char * format,...)654 size_t sw_snprintf(char *buf, size_t size, const char *format, ...) {
655 va_list args;
656 va_start(args, format);
657 int retval = vsnprintf(buf, size, format, args);
658 va_end(args);
659
660 if (size == 0) {
661 return retval;
662 } else if (sw_unlikely(retval < 0)) {
663 retval = 0;
664 buf[0] = '\0';
665 } else if (sw_unlikely(retval >= (int) size)) {
666 retval = size - 1;
667 buf[retval] = '\0';
668 }
669 return retval;
670 }
671
sw_vsnprintf(char * buf,size_t size,const char * format,va_list args)672 size_t sw_vsnprintf(char *buf, size_t size, const char *format, va_list args) {
673 int retval = vsnprintf(buf, size, format, args);
674 if (sw_unlikely(retval < 0)) {
675 retval = 0;
676 buf[0] = '\0';
677 } else if (sw_unlikely(retval >= (int) size)) {
678 retval = size - 1;
679 buf[retval] = '\0';
680 }
681 return retval;
682 }
683
swoole_itoa(char * buf,long value)684 int swoole_itoa(char *buf, long value) {
685 long i = 0, j;
686 long sign_mask;
687 unsigned long nn;
688
689 sign_mask = value >> (sizeof(long) * 8 - 1);
690 nn = (value + sign_mask) ^ sign_mask;
691 do {
692 buf[i++] = nn % 10 + '0';
693 } while (nn /= 10);
694
695 buf[i] = '-';
696 i += sign_mask & 1;
697 buf[i] = '\0';
698
699 int s_len = i;
700 char swap;
701
702 for (i = 0, j = s_len - 1; i < j; ++i, --j) {
703 swap = buf[i];
704 buf[i] = buf[j];
705 buf[j] = swap;
706 }
707 buf[s_len] = 0;
708 return s_len;
709 }
710
swoole_shell_exec(const char * command,pid_t * pid,bool get_error_stream)711 int swoole_shell_exec(const char *command, pid_t *pid, bool get_error_stream) {
712 pid_t child_pid;
713 int fds[2];
714 if (pipe(fds) < 0) {
715 return SW_ERR;
716 }
717
718 if ((child_pid = fork()) == -1) {
719 swoole_sys_warning("fork() failed");
720 close(fds[0]);
721 close(fds[1]);
722 return SW_ERR;
723 }
724
725 if (child_pid == 0) {
726 close(fds[SW_PIPE_READ]);
727
728 if (get_error_stream) {
729 if (fds[SW_PIPE_WRITE] == fileno(stdout)) {
730 dup2(fds[SW_PIPE_WRITE], fileno(stderr));
731 } else if (fds[SW_PIPE_WRITE] == fileno(stderr)) {
732 dup2(fds[SW_PIPE_WRITE], fileno(stdout));
733 } else {
734 dup2(fds[SW_PIPE_WRITE], fileno(stdout));
735 dup2(fds[SW_PIPE_WRITE], fileno(stderr));
736 close(fds[SW_PIPE_WRITE]);
737 }
738 } else {
739 if (fds[SW_PIPE_WRITE] != fileno(stdout)) {
740 dup2(fds[SW_PIPE_WRITE], fileno(stdout));
741 close(fds[SW_PIPE_WRITE]);
742 }
743 }
744
745 execl("/bin/sh", "sh", "-c", command, nullptr);
746 exit(127);
747 } else {
748 *pid = child_pid;
749 close(fds[SW_PIPE_WRITE]);
750 }
751 return fds[SW_PIPE_READ];
752 }
753
swoole_string_format(size_t n,const char * format,...)754 char *swoole_string_format(size_t n, const char *format, ...) {
755 char *buf = (char *) sw_malloc(n);
756 if (!buf) {
757 return nullptr;
758 }
759
760 int ret;
761 va_list va_list;
762 va_start(va_list, format);
763 ret = vsnprintf(buf, n, format, va_list);
764 va_end(va_list);
765 if (ret >= 0) {
766 return buf;
767 }
768 sw_free(buf);
769 return nullptr;
770 }
771
swoole_random_string(char * buf,size_t size)772 void swoole_random_string(char *buf, size_t size) {
773 static char characters[] = {
774 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U',
775 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
776 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
777 };
778 size_t i = 0;
779 for (; i < size; i++) {
780 buf[i] = characters[swoole_rand(0, sizeof(characters) - 1)];
781 }
782 buf[i] = '\0';
783 }
784
swoole_random_bytes(char * buf,size_t size)785 size_t swoole_random_bytes(char *buf, size_t size) {
786 size_t read_bytes = 0;
787 ssize_t n;
788
789 while (read_bytes < size) {
790 size_t amount_to_read = size - read_bytes;
791 n = getrandom(buf + read_bytes, amount_to_read, 0);
792 if (n == -1) {
793 if (errno == EINTR || errno == EAGAIN) {
794 continue;
795 } else {
796 break;
797 }
798 }
799 read_bytes += (size_t) n;
800 }
801
802 return read_bytes;
803 }
804
swoole_get_env(const char * name,int * value)805 bool swoole_get_env(const char *name, int *value) {
806 const char *e = getenv(name);
807 if (!e) {
808 return false;
809 }
810 *value = std::stoi(e);
811 return true;
812 }
813
swoole_get_systemd_listen_fds()814 int swoole_get_systemd_listen_fds() {
815 int ret;
816 if (!swoole_get_env("LISTEN_FDS", &ret)) {
817 swoole_warning("invalid LISTEN_FDS");
818 return -1;
819 } else if (ret >= SW_MAX_LISTEN_PORT) {
820 swoole_error_log(SW_LOG_ERROR, SW_ERROR_SERVER_TOO_MANY_LISTEN_PORT, "LISTEN_FDS is too big");
821 return -1;
822 }
823 return ret;
824 }
825
826 #ifdef HAVE_BOOST_STACKTRACE
827 #include <boost/stacktrace.hpp>
828 #include <iostream>
swoole_print_backtrace(void)829 void swoole_print_backtrace(void) {
830 std::cout << boost::stacktrace::stacktrace();
831 }
832 #elif defined(HAVE_EXECINFO)
833 #include <execinfo.h>
swoole_print_backtrace(void)834 void swoole_print_backtrace(void) {
835 int size = 16;
836 void *array[16];
837 int stack_num = backtrace(array, size);
838 char **stacktrace = backtrace_symbols(array, stack_num);
839 int i;
840
841 for (i = 0; i < stack_num; ++i) {
842 printf("%s\n", stacktrace[i]);
843 }
844 free(stacktrace);
845 }
846 #else
swoole_print_backtrace(void)847 void swoole_print_backtrace(void) {}
848 #endif
849
swoole_fatal_error_impl(int code,const char * format,...)850 static void swoole_fatal_error_impl(int code, const char *format, ...) {
851 size_t retval = 0;
852 va_list args;
853
854 retval += sw_snprintf(sw_error, SW_ERROR_MSG_SIZE, "(ERROR %d): ", code);
855 va_start(args, format);
856 retval += sw_vsnprintf(sw_error + retval, SW_ERROR_MSG_SIZE - retval, format, args);
857 va_end(args);
858 sw_logger()->put(SW_LOG_ERROR, sw_error, retval);
859 exit(1);
860 }
861
862 namespace swoole {
863 //-------------------------------------------------------------------------------
dump(char * _buf,size_t _len)864 size_t DataHead::dump(char *_buf, size_t _len) {
865 return sw_snprintf(_buf,
866 _len,
867 "DataHead[%p]\n"
868 "{\n"
869 " long fd = %ld;\n"
870 " uint64_t msg_id = %lu;\n"
871 " uint32_t len = %d;\n"
872 " int16_t reactor_id = %d;\n"
873 " uint8_t type = %d;\n"
874 " uint8_t flags = %d;\n"
875 " uint16_t server_fd = %d;\n"
876 " uint16_t ext_flags = %d;\n"
877 " double time = %f;\n"
878 "}\n",
879 this,
880 fd,
881 msg_id,
882 len,
883 reactor_id,
884 type,
885 flags,
886 server_fd,
887 ext_flags,
888 time);
889 }
890
print()891 void DataHead::print() {
892 sw_tg_buffer()->length = dump(sw_tg_buffer()->str, sw_tg_buffer()->size);
893 printf("%.*s", (int) sw_tg_buffer()->length, sw_tg_buffer()->str);
894 }
895
dirname(const std::string & file)896 std::string dirname(const std::string &file) {
897 size_t index = file.find_last_of('/');
898 if (index == std::string::npos) {
899 return std::string();
900 } else if (index == 0) {
901 return "/";
902 }
903 return file.substr(0, index);
904 }
905
hook_add(void ** hooks,int type,const Callback & func,int push_back)906 int hook_add(void **hooks, int type, const Callback &func, int push_back) {
907 if (hooks[type] == nullptr) {
908 hooks[type] = new std::list<Callback>;
909 }
910
911 std::list<Callback> *l = reinterpret_cast<std::list<Callback> *>(hooks[type]);
912 if (push_back) {
913 l->push_back(func);
914 } else {
915 l->push_front(func);
916 }
917
918 return SW_OK;
919 }
920
hook_call(void ** hooks,int type,void * arg)921 void hook_call(void **hooks, int type, void *arg) {
922 if (hooks[type] == nullptr) {
923 return;
924 }
925 std::list<Callback> *l = reinterpret_cast<std::list<Callback> *>(hooks[type]);
926 for (auto i = l->begin(); i != l->end(); i++) {
927 (*i)(arg);
928 }
929 }
930
931 /**
932 * return the first file of the intersection, in order of vec1
933 */
intersection(std::vector<std::string> & vec1,std::set<std::string> & vec2)934 std::string intersection(std::vector<std::string> &vec1, std::set<std::string> &vec2) {
935 std::string result = "";
936
937 std::find_if(vec1.begin(), vec1.end(), [&](std::string &str) -> bool {
938 auto iter = std::find(vec2.begin(), vec2.end(), str);
939 if (iter != vec2.end()) {
940 result = *iter;
941 return true;
942 }
943 return false;
944 });
945
946 return result;
947 }
948
microtime(void)949 double microtime(void) {
950 struct timeval t;
951 gettimeofday(&t, nullptr);
952 return (double) t.tv_sec + ((double) t.tv_usec / 1000000);
953 }
954
955 //-------------------------------------------------------------------------------
956 }; // namespace swoole
957