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