1 #include "uwsgi.h"
2
3 extern struct uwsgi_server uwsgi;
4
5 /*
6
7 poll based fd waiter.
8 Use it for blocking areas (like startup functions)
9 DO NOT USE IN REQUEST PLUGINS !!!
10
11 */
uwsgi_waitfd_event(int fd,int timeout,int event)12 int uwsgi_waitfd_event(int fd, int timeout, int event) {
13
14 int ret;
15 struct pollfd upoll;
16
17 if (!timeout)
18 timeout = uwsgi.socket_timeout;
19
20 timeout = timeout * 1000;
21 if (timeout < 0)
22 timeout = -1;
23
24 upoll.fd = fd;
25 upoll.events = event;
26 upoll.revents = 0;
27 ret = poll(&upoll, 1, timeout);
28
29 if (ret < 0) {
30 uwsgi_error("uwsgi_waitfd_event()/poll()");
31 }
32 else if (ret > 0) {
33 if (upoll.revents & event) {
34 return ret;
35 }
36 return -1;
37 }
38
39 return ret;
40 }
41
42 /*
43 consume data from an fd (blocking)
44 */
uwsgi_read_fd(int fd,size_t * size,int add_zero)45 char *uwsgi_read_fd(int fd, size_t *size, int add_zero) {
46
47 char stack_buf[4096];
48 ssize_t len;
49 char *buffer = NULL;
50
51 len = 1;
52 while (len > 0) {
53 len = read(fd, stack_buf, 4096);
54 if (len > 0) {
55 *size += len;
56 char *tmp = realloc(buffer, *size);
57 if (!tmp) {
58 uwsgi_error("uwsgi_read_fd()/realloc()");
59 exit(1);
60 }
61 buffer = tmp;
62 memcpy(buffer + (*size - len), stack_buf, len);
63 }
64 }
65
66 if (add_zero) {
67 *size = *size + 1;
68 buffer = realloc(buffer, *size);
69 if (!buffer) {
70 uwsgi_error("uwsgi_read_fd()/realloc()");
71 exit(1);
72 }
73 buffer[*size - 1] = 0;
74 }
75
76 return buffer;
77
78 }
79
80 // simply read the whole content of a file
uwsgi_simple_file_read(char * filename)81 char *uwsgi_simple_file_read(char *filename) {
82
83 struct stat sb;
84 char *buffer;
85 ssize_t len;
86 int fd = open(filename, O_RDONLY);
87 if (fd < 0) {
88 uwsgi_error_open(filename);
89 goto end;
90 }
91
92 if (fstat(fd, &sb)) {
93 uwsgi_error("fstat()");
94 close(fd);
95 goto end;
96 }
97
98 buffer = uwsgi_malloc(sb.st_size + 1);
99
100 len = read(fd, buffer, sb.st_size);
101 if (len != sb.st_size) {
102 uwsgi_error("read()");
103 free(buffer);
104 close(fd);
105 goto end;
106 }
107
108 close(fd);
109 if (buffer[sb.st_size - 1] == '\n' || buffer[sb.st_size - 1] == '\r') {
110 buffer[sb.st_size - 1] = 0;
111 }
112 buffer[sb.st_size] = 0;
113 return buffer;
114 end:
115 return (char *) "";
116
117 }
118
uwsgi_scheme_fd(char * url,size_t * size,int add_zero)119 static char *uwsgi_scheme_fd(char *url, size_t *size, int add_zero) {
120 int fd = atoi(url);
121 return uwsgi_read_fd(fd, size, add_zero);
122 }
123
uwsgi_scheme_exec(char * url,size_t * size,int add_zero)124 static char *uwsgi_scheme_exec(char *url, size_t *size, int add_zero) {
125 int cpipe[2];
126 if (pipe(cpipe)) {
127 uwsgi_error("pipe()");
128 exit(1);
129 }
130 uwsgi_run_command(url, NULL, cpipe[1]);
131 char *buffer = uwsgi_read_fd(cpipe[0], size, add_zero);
132 close(cpipe[0]);
133 close(cpipe[1]);
134 return buffer;
135 }
136
uwsgi_scheme_http(char * url,size_t * size,int add_zero)137 static char *uwsgi_scheme_http(char *url, size_t *size, int add_zero) {
138 char byte;
139 int body = 0;
140 char *buffer = NULL;
141
142 char *domain = url;
143 char *uri = strchr(domain, '/');
144 if (!uri) {
145 uwsgi_log("invalid http url\n");
146 exit(1);
147 }
148 uri[0] = 0;
149 uwsgi_log("domain: %s\n", domain);
150
151 char *colon = uwsgi_get_last_char(domain, ':');
152
153 if (colon) {
154 colon[0] = 0;
155 }
156
157
158 char *ip = uwsgi_resolve_ip(domain);
159 if (!ip) {
160 uwsgi_log("unable to resolve address %s\n", domain);
161 exit(1);
162 }
163
164 if (colon) {
165 colon[0] = ':';
166 ip = uwsgi_concat2(ip, colon);
167 }
168 else {
169 ip = uwsgi_concat2(ip, ":80");
170 }
171
172 int fd = uwsgi_connect(ip, 0, 0);
173
174 if (fd < 0) {
175 uwsgi_error("uwsgi_scheme_http()/connect()");
176 exit(1);
177 }
178
179 free(ip);
180
181 uri[0] = '/';
182
183 if (write(fd, "GET ", 4) != 4) { uwsgi_error("uwsgi_scheme_http()/write()"); exit(1);}
184 if (write(fd, uri, strlen(uri)) != (ssize_t) strlen(uri)) { uwsgi_error("uwsgi_scheme_http()/write()"); exit(1);}
185 if (write(fd, " HTTP/1.0\r\n", 11) != 11) { uwsgi_error("uwsgi_scheme_http()/write()"); exit(1);}
186 if (write(fd, "Host: ", 6) != 6) { uwsgi_error("uwsgi_scheme_http()/write()"); exit(1);}
187
188 uri[0] = 0;
189 if (write(fd, domain, strlen(domain)) != (ssize_t) strlen(domain)) { uwsgi_error("uwsgi_scheme_http()/write()"); exit(1);}
190 uri[0] = '/';
191
192 if (write(fd, "\r\nUser-Agent: uWSGI on ", 23) != 23) { uwsgi_error("uwsgi_scheme_http()/write()"); exit(1);}
193 if (write(fd, uwsgi.hostname, uwsgi.hostname_len) != uwsgi.hostname_len) { uwsgi_error("uwsgi_scheme_http()/write()"); exit(1);}
194 if (write(fd, "\r\n\r\n", 4) != 4) { uwsgi_error("uwsgi_scheme_http()/write()"); exit(1);}
195
196 int http_status_code_ptr = 0;
197
198 while (read(fd, &byte, 1) == 1) {
199 if (byte == '\r' && body == 0) {
200 body = 1;
201 }
202 else if (byte == '\n' && body == 1) {
203 body = 2;
204 }
205 else if (byte == '\r' && body == 2) {
206 body = 3;
207 }
208 else if (byte == '\n' && body == 3) {
209 body = 4;
210 }
211 else if (body == 4) {
212 *size = *size + 1;
213 char *tmp = realloc(buffer, *size);
214 if (!tmp) {
215 uwsgi_error("uwsgi_open_and_read()/realloc()");
216 exit(1);
217 }
218 buffer = tmp;
219 buffer[*size - 1] = byte;
220 }
221 else {
222 body = 0;
223 http_status_code_ptr++;
224 if (http_status_code_ptr == 10) {
225 if (byte != '2') {
226 uwsgi_log("Not usable HTTP response: %cxx\n", byte);
227 if (uwsgi.has_emperor) {
228 exit(UWSGI_EXILE_CODE);
229 }
230 else {
231 exit(1);
232 }
233 }
234 }
235 }
236 }
237
238 close(fd);
239
240 if (add_zero) {
241 *size = *size + 1;
242 char *tmp = realloc(buffer, *size);
243 if (!tmp) {
244 uwsgi_error("uwsgi_open_and_read()/realloc()");
245 exit(1);
246 }
247 buffer = tmp;
248 buffer[*size - 1] = 0;
249 }
250
251 return buffer;
252 }
253
254
uwsgi_scheme_emperor(char * url,size_t * size,int add_zero)255 static char *uwsgi_scheme_emperor(char *url, size_t *size, int add_zero) {
256
257 if (uwsgi.emperor_fd_config < 0) {
258 uwsgi_log("this is not a vassal instance\n");
259 exit(1);
260 }
261 ssize_t rlen;
262 struct uwsgi_header uh;
263 size_t remains = 4;
264 char *ptr = (char *) &uh;
265 while(remains) {
266 int ret = uwsgi_waitfd(uwsgi.emperor_fd_config, 5);
267 if (ret <= 0) {
268 uwsgi_log("[uwsgi-vassal] error waiting for config header %s !!!\n", url);
269 exit(1);
270 }
271 rlen = read(uwsgi.emperor_fd_config, ptr, remains);
272 if (rlen <= 0) {
273 uwsgi_log("[uwsgi-vassal] error reading config header from %s !!!\n", url);
274 exit(1);
275 }
276 ptr+=rlen;
277 remains-=rlen;
278 }
279
280 remains = uh.pktsize;
281 if (!remains) {
282 uwsgi_log("[uwsgi-vassal] invalid config from %s\n", url);
283 exit(1);
284 }
285
286 char *buffer = uwsgi_calloc(remains + add_zero);
287 ptr = buffer;
288 while (remains) {
289 int ret = uwsgi_waitfd(uwsgi.emperor_fd_config, 5);
290 if (ret <= 0) {
291 uwsgi_log("[uwsgi-vassal] error waiting for config %s !!!\n", url);
292 exit(1);
293 }
294 rlen = read(uwsgi.emperor_fd_config, ptr, remains);
295 if (rlen <= 0) {
296 uwsgi_log("[uwsgi-vassal] error reading config from %s !!!\n", url);
297 exit(1);
298 }
299 ptr+=rlen;
300 remains-=rlen;
301 }
302
303 *size = uh.pktsize + add_zero;
304 return buffer;
305 }
306
uwsgi_scheme_data(char * url,size_t * size,int add_zero)307 static char *uwsgi_scheme_data(char *url, size_t *size, int add_zero) {
308 char *buffer = NULL;
309 int fd = open(uwsgi.binary_path, O_RDONLY);
310 if (fd < 0) {
311 uwsgi_error_open(uwsgi.binary_path);
312 exit(1);
313 }
314 int slot = atoi(url);
315 if (slot < 0) {
316 uwsgi_log("invalid binary data slot requested\n");
317 exit(1);
318 }
319 uwsgi_log("requesting binary data slot %d\n", slot);
320 off_t fo = lseek(fd, 0, SEEK_END);
321 if (fo < 0) {
322 uwsgi_error("lseek()");
323 uwsgi_log("invalid binary data slot requested\n");
324 exit(1);
325 }
326 int i = 0;
327 uint64_t datasize = 0;
328 for (i = 0; i <= slot; i++) {
329 fo = lseek(fd, -8, SEEK_CUR);
330 if (fo < 0) {
331 uwsgi_error("lseek()");
332 uwsgi_log("invalid binary data slot requested\n");
333 exit(1);
334 }
335 ssize_t len = read(fd, &datasize, 8);
336 if (len != 8) {
337 uwsgi_error("read()");
338 uwsgi_log("invalid binary data slot requested\n");
339 exit(1);
340 }
341 if (datasize == 0) {
342 uwsgi_log("0 size binary data !!!\n");
343 exit(1);
344 }
345 fo = lseek(fd, -(datasize + 8), SEEK_CUR);
346 if (fo < 0) {
347 uwsgi_error("lseek()");
348 uwsgi_log("invalid binary data slot requested\n");
349 exit(1);
350 }
351
352 if (i == slot) {
353 *size = datasize;
354 if (add_zero) {
355 *size += 1;
356 }
357 buffer = uwsgi_malloc(*size);
358 memset(buffer, 0, *size);
359 len = read(fd, buffer, datasize);
360 if (len != (ssize_t) datasize) {
361 uwsgi_error("read()");
362 uwsgi_log("invalid binary data slot requested\n");
363 exit(1);
364 }
365 }
366 }
367 close(fd);
368
369 return buffer;
370 }
371
uwsgi_scheme_call(char * url,size_t * size,int add_zero)372 static char *uwsgi_scheme_call(char *url, size_t *size, int add_zero) {
373 char *(*func)(void) = dlsym(RTLD_DEFAULT, url);
374 if (!func) {
375 uwsgi_log("unable to find symbol %s\n", url);
376 exit(1);
377 }
378
379 char *s = func();
380 if (!s) {
381 uwsgi_log("called symbol %s did not return a string\n", url);
382 exit(1);
383 }
384 *size = strlen(s);
385 if (add_zero) {
386 *size += 1;
387 }
388 char *buffer = uwsgi_malloc(*size);
389 memset(buffer, 0, *size);
390 memcpy(buffer, s, strlen(s));
391
392 return buffer;
393 }
394
uwsgi_scheme_callint(char * url,size_t * size,int add_zero)395 static char *uwsgi_scheme_callint(char *url, size_t *size, int add_zero) {
396 int (*func)(void) = dlsym(RTLD_DEFAULT, url);
397 if (!func) {
398 uwsgi_log("unable to find symbol %s\n", url);
399 exit(1);
400 }
401
402 char *s = uwsgi_num2str(func());
403 *size = strlen(s);
404 if (add_zero) {
405 *size += 1;
406 }
407 char *buffer = uwsgi_malloc(*size);
408 memset(buffer, 0, *size);
409 memcpy(buffer, s, strlen(s));
410 free(s);
411
412 return buffer;
413 }
414
415
uwsgi_scheme_sym(char * url,size_t * size,int add_zero)416 static char *uwsgi_scheme_sym(char *url, size_t *size, int add_zero) {
417 void *sym_start_ptr = NULL, *sym_end_ptr = NULL;
418 char **raw_symbol = dlsym(RTLD_DEFAULT, url);
419 if (raw_symbol) {
420 sym_start_ptr = *raw_symbol;
421 sym_end_ptr = sym_start_ptr + strlen(sym_start_ptr);
422 goto found;
423 }
424 char *symbol = uwsgi_concat3("_binary_", url, "_start");
425 sym_start_ptr = dlsym(RTLD_DEFAULT, symbol);
426 if (!sym_start_ptr) {
427 uwsgi_log("unable to find symbol %s\n", symbol);
428 exit(1);
429 }
430 free(symbol);
431 symbol = uwsgi_concat3("_binary_", url, "_end");
432 sym_end_ptr = dlsym(RTLD_DEFAULT, symbol);
433 if (!sym_end_ptr) {
434 uwsgi_log("unable to find symbol %s\n", symbol);
435 exit(1);
436 }
437 free(symbol);
438
439 found:
440
441 *size = sym_end_ptr - sym_start_ptr;
442 if (add_zero) {
443 *size += 1;
444 }
445 char *buffer = uwsgi_malloc(*size);
446 memset(buffer, 0, *size);
447 memcpy(buffer, sym_start_ptr, sym_end_ptr - sym_start_ptr);
448
449 return buffer;
450 }
451
uwsgi_scheme_section(char * url,size_t * size,int add_zero)452 static char *uwsgi_scheme_section(char *url, size_t *size, int add_zero) {
453 #ifdef UWSGI_ELF
454 size_t s_len = 0;
455 char *buffer = uwsgi_elf_section(uwsgi.binary_path, url, &s_len);
456 if (!buffer) {
457 uwsgi_log("unable to find section %s in %s\n", url + 10, uwsgi.binary_path);
458 exit(1);
459 }
460 *size = s_len;
461 if (add_zero)
462 *size += 1;
463 return buffer;
464 #else
465 uwsgi_log("section:// scheme not supported on this platform\n");
466 exit(1);
467 #endif
468 }
469
uwsgi_register_scheme(char * name,char * (* func)(char *,size_t *,int))470 struct uwsgi_string_list *uwsgi_register_scheme(char *name, char * (*func)(char *, size_t *, int)) {
471 struct uwsgi_string_list *usl = NULL;
472 uwsgi_foreach(usl, uwsgi.schemes) {
473 if (!strcmp(usl->value, name)) goto found;
474 }
475
476 usl = uwsgi_string_new_list(&uwsgi.schemes, name);
477
478 found:
479 usl->custom_ptr = func;
480 return usl;
481 }
482
uwsgi_open_and_read(char * url,size_t * size,int add_zero,char * magic_table[])483 char *uwsgi_open_and_read(char *url, size_t *size, int add_zero, char *magic_table[]) {
484
485 struct stat sb;
486 char *buffer = NULL;
487 ssize_t len;
488 char *magic_buf;
489 int fd;
490
491 *size = 0;
492
493 // stdin ?
494 if (!strcmp(url, "-")) {
495 buffer = uwsgi_read_fd(0, size, add_zero);
496 goto end;
497 }
498 #ifdef UWSGI_EMBED_CONFIG
499 else if (url[0] == 0) {
500 *size = &UWSGI_EMBED_CONFIG_END - &UWSGI_EMBED_CONFIG;
501 if (add_zero) {
502 *size += 1;
503 }
504 buffer = uwsgi_malloc(*size);
505 memset(buffer, 0, *size);
506 memcpy(buffer, &UWSGI_EMBED_CONFIG, &UWSGI_EMBED_CONFIG_END - &UWSGI_EMBED_CONFIG);
507 goto end;
508 }
509 #endif
510
511 struct uwsgi_string_list *usl = uwsgi_check_scheme(url);
512 if (!usl) goto fallback;
513
514 char *(*func)(char *, size_t *, int) = (char *(*)(char *, size_t *, int)) usl->custom_ptr;
515 buffer = func(url + usl->len + 3, size, add_zero);
516 if (buffer) goto end;
517 // never here !!!
518 uwsgi_log("unable to parse config file %s\n", url);
519 exit(1);
520
521 // fallback to file
522 fallback:
523 fd = open(url, O_RDONLY);
524 if (fd < 0) {
525 uwsgi_error_open(url);
526 exit(1);
527 }
528
529 if (fstat(fd, &sb)) {
530 uwsgi_error("fstat()");
531 exit(1);
532 }
533
534 if (S_ISFIFO(sb.st_mode)) {
535 buffer = uwsgi_read_fd(fd, size, add_zero);
536 close(fd);
537 goto end;
538 }
539
540 // is it a potential virtual file (/proc, /sys...) ?
541 int is_virtual = 0;
542 if (sb.st_size == 0) {
543 is_virtual = 1;
544 sb.st_size = 4096;
545 }
546
547 buffer = uwsgi_malloc(sb.st_size + add_zero);
548
549 len = read(fd, buffer, sb.st_size);
550 if (!is_virtual) {
551 if (len != sb.st_size) {
552 }
553 }
554 else {
555 if (len >= 0) {
556 sb.st_size = len;
557 }
558 else {
559 uwsgi_error("read()");
560 exit(1);
561 }
562 }
563
564 close(fd);
565
566 *size = sb.st_size + add_zero;
567
568 if (add_zero)
569 buffer[sb.st_size] = 0;
570
571 end:
572
573 if (magic_table) {
574 // here we inject blobs
575 struct uwsgi_string_list *usl = NULL;
576 if (uwsgi.inject_before || uwsgi.inject_after) {
577 struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size);
578 uwsgi_foreach(usl, uwsgi.inject_before) {
579 size_t rlen = 0;
580 char *before = uwsgi_open_and_read(usl->value, &rlen, 0, NULL);
581 if (uwsgi_buffer_append(ub, before, rlen)) {
582 uwsgi_log("unable to inject data in the config file\n");
583 exit(1);
584 }
585 free(before);
586 }
587 if (uwsgi_buffer_append(ub, buffer, *size - add_zero)) {
588 uwsgi_log("unable to inject data in the config file\n");
589 exit(1);
590 }
591 uwsgi_foreach(usl, uwsgi.inject_after) {
592 size_t rlen = 0;
593 char *after = uwsgi_open_and_read(usl->value, &rlen, 0, NULL);
594 if (uwsgi_buffer_append(ub, after, rlen)) {
595 uwsgi_log("unable to inject data in the config file\n");
596 exit(1);
597 }
598 free(after);
599 }
600 if (add_zero) {
601 if (uwsgi_buffer_append(ub, "\0", 1)) {
602 uwsgi_log("unable to inject data in the config file\n");
603 exit(1);
604 }
605 }
606 *size = ub->pos;
607 // free resources
608 free(buffer);
609 buffer = ub->buf;
610 // aboid destroying buffer
611 ub->buf = NULL;
612 uwsgi_buffer_destroy(ub);
613 }
614 magic_buf = magic_sub(buffer, *size, size, magic_table);
615 free(buffer);
616 return magic_buf;
617 }
618
619 return buffer;
620 }
621
622 // attach an fd using UNIX sockets
uwsgi_attach_fd(int fd,int * count_ptr,char * code,size_t code_len)623 int *uwsgi_attach_fd(int fd, int *count_ptr, char *code, size_t code_len) {
624
625 struct msghdr msg;
626 ssize_t len;
627 char *id = NULL;
628
629 struct iovec iov;
630 struct cmsghdr *cmsg;
631 int *ret;
632 int i;
633 int count = *count_ptr;
634
635 void *msg_control = uwsgi_malloc(CMSG_SPACE(sizeof(int) * count));
636
637 memset(msg_control, 0, CMSG_SPACE(sizeof(int) * count));
638
639 if (code && code_len > 0) {
640 // allocate space for code and num_sockets
641 id = uwsgi_malloc(code_len + sizeof(int));
642 memset(id, 0, code_len);
643 iov.iov_len = code_len + sizeof(int);
644 }
645
646 iov.iov_base = id;
647
648 memset(&msg, 0, sizeof(msg));
649
650 msg.msg_name = NULL;
651 msg.msg_namelen = 0;
652
653 msg.msg_iov = &iov;
654 msg.msg_iovlen = 1;
655
656 msg.msg_control = msg_control;
657 msg.msg_controllen = CMSG_SPACE(sizeof(int) * count);
658
659 msg.msg_flags = 0;
660
661 len = recvmsg(fd, &msg, 0);
662 if (len <= 0) {
663 uwsgi_error("recvmsg()");
664 free(msg_control);
665 return NULL;
666 }
667
668 if (code && code_len > 0) {
669 if (uwsgi_strncmp(id, code_len, code, code_len)) {
670 free(msg_control);
671 return NULL;
672 }
673
674 if ((size_t) len == code_len + sizeof(int)) {
675 memcpy(&i, id + code_len, sizeof(int));
676 if (i > count) {
677 *count_ptr = i;
678 free(msg_control);
679 free(id);
680 return NULL;
681 }
682 }
683 }
684
685 cmsg = CMSG_FIRSTHDR(&msg);
686 if (!cmsg) {
687 free(msg_control);
688 return NULL;
689 }
690
691 if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
692 free(msg_control);
693 return NULL;
694 }
695
696 if ((size_t) (cmsg->cmsg_len - ((char *) CMSG_DATA(cmsg) - (char *) cmsg)) > (size_t) (sizeof(int) * (count + 1))) {
697 uwsgi_log("not enough space for sockets data, consider increasing it\n");
698 free(msg_control);
699 return NULL;
700 }
701
702 ret = uwsgi_malloc(sizeof(int) * (count + 1));
703 for (i = 0; i < count + 1; i++) {
704 ret[i] = -1;
705 }
706
707 memcpy(ret, CMSG_DATA(cmsg), cmsg->cmsg_len - ((char *) CMSG_DATA(cmsg) - (char *) cmsg));
708
709 free(msg_control);
710 if (code && code_len > 0) {
711 free(id);
712 }
713
714 return ret;
715 }
716
717 // signal free close
uwsgi_protected_close(int fd)718 void uwsgi_protected_close(int fd) {
719
720 sigset_t mask, oset;
721 sigfillset(&mask);
722 if (sigprocmask(SIG_BLOCK, &mask, &oset)) {
723 uwsgi_error("sigprocmask()");
724 exit(1);
725 }
726 close(fd);
727 if (sigprocmask(SIG_SETMASK, &oset, NULL)) {
728 uwsgi_error("sigprocmask()");
729 exit(1);
730 }
731 }
732
733 // signal free read
uwsgi_protected_read(int fd,void * buf,size_t len)734 ssize_t uwsgi_protected_read(int fd, void *buf, size_t len) {
735
736 sigset_t mask, oset;
737 sigfillset(&mask);
738 if (sigprocmask(SIG_BLOCK, &mask, &oset)) {
739 uwsgi_error("sigprocmask()");
740 exit(1);
741 }
742
743 ssize_t ret = read(fd, buf, len);
744
745 if (sigprocmask(SIG_SETMASK, &oset, NULL)) {
746 uwsgi_error("sigprocmask()");
747 exit(1);
748 }
749 return ret;
750 }
751
752
753 // pipe datas from a fd to another (blocking)
uwsgi_pipe(int src,int dst,int timeout)754 ssize_t uwsgi_pipe(int src, int dst, int timeout) {
755 char buf[8192];
756 size_t written = -1;
757 ssize_t len;
758
759 for (;;) {
760 int ret = uwsgi_waitfd(src, timeout);
761 if (ret > 0) {
762 len = read(src, buf, 8192);
763 if (len == 0) {
764 return written;
765 }
766 else if (len < 0) {
767 uwsgi_error("read()");
768 return -1;
769 }
770
771 size_t remains = len;
772 while (remains > 0) {
773 int ret = uwsgi_waitfd_write(dst, timeout);
774 if (ret > 0) {
775 len = write(dst, buf, remains);
776 if (len > 0) {
777 remains -= len;
778 written += len;
779 }
780 else if (len == 0) {
781 return written;
782 }
783 else {
784 uwsgi_error("write()");
785 return -1;
786 }
787 }
788 else if (ret == 0) {
789 goto timeout;
790 }
791 else {
792 return -1;
793 }
794 }
795 }
796 else if (ret == 0) {
797 goto timeout;
798 }
799 else {
800 return -1;
801 }
802 }
803
804 return written;
805 timeout:
806 uwsgi_log("timeout while piping from %d to %d !!!\n", src, dst);
807 return -1;
808 }
809
810 /*
811 even if it is marked as non-blocking, so not use in request plugins as it uses poll() and not the hooks
812 */
uwsgi_write_nb(int fd,char * buf,size_t remains,int timeout)813 int uwsgi_write_nb(int fd, char *buf, size_t remains, int timeout) {
814 char *ptr = buf;
815 while(remains > 0) {
816 int ret = uwsgi_waitfd_write(fd, timeout);
817 if (ret > 0) {
818 ssize_t len = write(fd, ptr, remains);
819 if (len <= 0) {
820 return -1;
821 }
822 ptr += len;
823 remains -= len;
824 continue;
825 }
826 return -1;
827 }
828
829 return 0;
830 }
831
832 /*
833 this is like uwsgi_write_nb() but with fast initial write and hooked wait (use it in request plugin)
834 */
uwsgi_write_true_nb(int fd,char * buf,size_t remains,int timeout)835 int uwsgi_write_true_nb(int fd, char *buf, size_t remains, int timeout) {
836 char *ptr = buf;
837 int ret;
838
839 while(remains > 0) {
840 errno = 0;
841 ssize_t len = write(fd, ptr, remains);
842 if (len > 0) goto written;
843 if (len == 0) return -1;
844 if (len < 0) {
845 if (uwsgi_is_again()) goto wait;
846 return -1;
847 }
848 wait:
849 ret = uwsgi.wait_write_hook(fd, timeout);
850 if (ret > 0) {
851 len = write(fd, ptr, remains);
852 if (len > 0) goto written;
853 }
854 return -1;
855 written:
856 ptr += len;
857 remains -= len;
858 continue;
859 }
860
861 return 0;
862 }
863
864
865
866
867 // like uwsgi_pipe but with fixed size
uwsgi_pipe_sized(int src,int dst,size_t required,int timeout)868 ssize_t uwsgi_pipe_sized(int src, int dst, size_t required, int timeout) {
869 char buf[8192];
870 size_t written = 0;
871 ssize_t len;
872
873 while (written < required) {
874 int ret = uwsgi_waitfd(src, timeout);
875 if (ret > 0) {
876 len = read(src, buf, UMIN(8192, required - written));
877 if (len == 0) {
878 return written;
879 }
880 else if (len < 0) {
881 uwsgi_error("read()");
882 return -1;
883 }
884
885 size_t remains = len;
886 while (remains > 0) {
887 int ret = uwsgi_waitfd_write(dst, timeout);
888 if (ret > 0) {
889 len = write(dst, buf, remains);
890 if (len > 0) {
891 remains -= len;
892 written += len;
893 }
894 else if (len == 0) {
895 return written;
896 }
897 else {
898 uwsgi_error("write()");
899 return -1;
900 }
901 }
902 else if (ret == 0) {
903 goto timeout;
904 }
905 else {
906 return -1;
907 }
908 }
909 }
910 else if (ret == 0) {
911 goto timeout;
912 }
913 else {
914 return -1;
915 }
916 }
917
918 return written;
919 timeout:
920 uwsgi_log("timeout while piping from %d to %d !!!\n", src, dst);
921 return -1;
922 }
923
924
925 // check if an fd is valid
uwsgi_valid_fd(int fd)926 int uwsgi_valid_fd(int fd) {
927 int ret = fcntl(fd, F_GETFL);
928 if (ret == -1) {
929 return 0;
930 }
931 return 1;
932 }
933
uwsgi_close_all_fds(void)934 void uwsgi_close_all_fds(void) {
935 int i;
936 for (i = 3; i < (int) uwsgi.max_fd; i++) {
937 #ifdef __APPLE__
938 fcntl(i, F_SETFD, FD_CLOEXEC);
939 #else
940 close(i);
941 #endif
942 }
943 }
944
uwsgi_read_uh(int fd,struct uwsgi_header * uh,int timeout)945 int uwsgi_read_uh(int fd, struct uwsgi_header *uh, int timeout) {
946 char *ptr = (char *) uh;
947 size_t remains = 4;
948 while(remains > 0) {
949 int ret = uwsgi_waitfd(fd, timeout);
950 if (ret > 0) {
951 ssize_t len = read(fd, ptr, remains);
952 if (len <= 0) {
953 return -1;
954 }
955 remains -=len;
956 ptr +=len;
957 continue;
958 }
959 return -1;
960 }
961
962 return 0;
963 }
964
uwsgi_read_nb(int fd,char * buf,size_t remains,int timeout)965 int uwsgi_read_nb(int fd, char *buf, size_t remains, int timeout) {
966 char *ptr = buf;
967 while(remains > 0) {
968 int ret = uwsgi_waitfd(fd, timeout);
969 if (ret > 0) {
970 ssize_t len = read(fd, ptr, remains);
971 if (len <= 0) {
972 return -1;
973 }
974 remains -=len;
975 ptr +=len;
976 continue;
977 }
978 return -1;
979 }
980
981 return 0;
982 }
983
984 /*
985 this is like uwsgi_read_nb() but with fast initial read and hooked wait (use it in request plugin)
986 */
uwsgi_read_true_nb(int fd,char * buf,size_t len,int timeout)987 ssize_t uwsgi_read_true_nb(int fd, char *buf, size_t len, int timeout) {
988 int ret;
989
990 errno = 0;
991 ssize_t rlen = read(fd, buf, len);
992 if (rlen > 0) {
993 return rlen;
994 }
995 if (rlen == 0) return -1;
996 if (rlen < 0) {
997 if (uwsgi_is_again()) goto wait;
998 }
999 return -1;
1000 wait:
1001 errno = 0;
1002 ret = uwsgi.wait_read_hook(fd, timeout);
1003 if (ret > 0) {
1004 errno = 0;
1005 rlen = read(fd, buf, len);
1006 if (rlen > 0) {
1007 return rlen;
1008 }
1009 return -1;
1010 }
1011 return ret;
1012 }
1013
1014
1015 /*
1016 like the previous one but consume the whole len (if possibile)
1017 */
1018
uwsgi_read_whole_true_nb(int fd,char * buf,size_t remains,int timeout)1019 int uwsgi_read_whole_true_nb(int fd, char *buf, size_t remains, int timeout) {
1020 char *ptr = buf;
1021 while(remains > 0) {
1022 ssize_t len = uwsgi_read_true_nb(fd, ptr, remains, timeout);
1023 if (len <= 0) return -1;
1024 ptr += len;
1025 remains -= len;
1026 }
1027 return 0;
1028 }
1029
1030 /*
1031 this is a pretty magic function used for reading a full uwsgi response
1032 it is true non blocking, so you can use it in request plugins
1033 buffer is expected to be at least 4 bytes, rlen is a get/set value
1034 */
1035
uwsgi_read_with_realloc(int fd,char ** buffer,size_t * rlen,int timeout,uint8_t * modifier1,uint8_t * modifier2)1036 int uwsgi_read_with_realloc(int fd, char **buffer, size_t *rlen, int timeout, uint8_t *modifier1, uint8_t *modifier2) {
1037 if (*rlen < 4) return -1;
1038 char *buf = *buffer;
1039 int ret;
1040
1041 // start reading the header
1042 char *ptr = buf;
1043 size_t remains = 4;
1044 while(remains > 0) {
1045 ssize_t len = read(fd, ptr, remains);
1046 if (len > 0) goto readok;
1047 if (len == 0) return -1;
1048 if (len < 0) {
1049 if (uwsgi_is_again()) goto wait;
1050 return -1;
1051 }
1052 wait:
1053 ret = uwsgi.wait_read_hook(fd, timeout);
1054 if (ret > 0) {
1055 len = read(fd, ptr, remains);
1056 if (len > 0) goto readok;
1057 }
1058 return -1;
1059 readok:
1060 ptr += len;
1061 remains -= len;
1062 continue;
1063 }
1064
1065 struct uwsgi_header *uh = (struct uwsgi_header *) buf;
1066 uint16_t pktsize = uh->pktsize;
1067 if (modifier1)
1068 *modifier1 = uh->modifier1;
1069 if (modifier2)
1070 *modifier2 = uh->modifier2;
1071
1072 if (pktsize > *rlen) {
1073 char *tmp_buf = realloc(buf, pktsize);
1074 if (!tmp_buf) {
1075 uwsgi_error("uwsgi_read_with_realloc()/realloc()");
1076 return -1;
1077 }
1078 *buffer = tmp_buf;
1079 buf = *buffer;
1080 }
1081
1082 *rlen = pktsize;
1083 // read the body
1084 remains = pktsize;
1085 ptr = buf;
1086 while(remains > 0) {
1087 ssize_t len = read(fd, ptr, remains);
1088 if (len > 0) goto readok2;
1089 if (len == 0) return -1;
1090 if (len < 0) {
1091 if (uwsgi_is_again()) goto wait2;
1092 return -1;
1093 }
1094 wait2:
1095 ret = uwsgi.wait_read_hook(fd, timeout);
1096 if (ret > 0) {
1097 len = read(fd, ptr, remains);
1098 if (len > 0) goto readok2;
1099 }
1100 return -1;
1101 readok2:
1102 ptr += len;
1103 remains -= len;
1104 continue;
1105 }
1106
1107 return 0;
1108
1109 }
1110
1111 /*
1112
1113 this is a commodity (big) function to send a buffer and wsgi_req body to a socket
1114 and to receive back data (and send them to the client)
1115
1116 */
1117
uwsgi_proxy_nb(struct wsgi_request * wsgi_req,char * addr,struct uwsgi_buffer * ub,size_t remains,int timeout)1118 int uwsgi_proxy_nb(struct wsgi_request *wsgi_req, char *addr, struct uwsgi_buffer *ub, size_t remains, int timeout) {
1119
1120 struct uwsgi_buffer *headers = NULL;
1121
1122 if (!ub) {
1123 return -1;
1124 }
1125
1126 int fd = uwsgi_connect(addr, 0, 1);
1127 if (fd < 0) {
1128 return -1;
1129 }
1130
1131 int ret = uwsgi.wait_write_hook(fd, timeout);
1132 if (ret <= 0) {
1133 goto end;
1134 }
1135
1136 // send the request (+ remaining data)
1137 if (uwsgi_write_true_nb(fd, ub->buf, ub->pos, timeout)) {
1138 goto end;
1139 }
1140
1141 // send the body
1142 while(remains > 0) {
1143 ssize_t rlen = 0;
1144 char *buf = uwsgi_request_body_read(wsgi_req, 8192, &rlen);
1145 if (!buf) {
1146 goto end;
1147 }
1148 if (buf == uwsgi.empty) break;
1149 // write data to the node
1150 if (uwsgi_write_true_nb(fd, buf, rlen, timeout)) {
1151 goto end;
1152 }
1153 remains -= rlen;
1154 }
1155
1156 // read the response
1157 headers = uwsgi_buffer_new(8192);
1158 // max 64k headers
1159 ub->limit = UMAX16;
1160 for(;;) {
1161 char buf[8192];
1162 ssize_t rlen = uwsgi_read_true_nb(fd, buf, 8192, timeout);
1163 if (rlen > 0) {
1164 if (headers) {
1165 if (uwsgi_buffer_append(headers, buf, rlen)) {
1166 goto end;
1167 }
1168 // check if we have a full HTTP response
1169 if (uwsgi_is_full_http(headers)) {
1170 int ret = uwsgi_blob_to_response(wsgi_req, headers->buf, headers->pos);
1171 if (ret) continue;
1172 uwsgi_buffer_destroy(headers);
1173 headers = NULL;
1174 }
1175 }
1176 else {
1177 if (uwsgi_response_write_body_do(wsgi_req, buf, rlen)) {
1178 break;
1179 }
1180 }
1181 continue;
1182 }
1183 break;
1184 }
1185 if (headers) uwsgi_buffer_destroy(headers);
1186
1187 close(fd);
1188 return 0;
1189 end:
1190 if (headers) uwsgi_buffer_destroy(headers);
1191 close(fd);
1192 return -1;
1193 }
1194
uwsgi_file_write_do(struct uwsgi_string_list * usl)1195 void uwsgi_file_write_do(struct uwsgi_string_list *usl) {
1196
1197 struct uwsgi_string_list *fl = usl;
1198 while(fl) {
1199 char *equal = strchr(fl->value, '=');
1200 if (equal) {
1201 *equal = 0;
1202 FILE *f = fopen(fl->value, "w");
1203 if (!f) {
1204 uwsgi_error_open("uwsgi_file_write_do()");
1205 exit(1);
1206 }
1207 uwsgi_log("writing \"%s\" to \"%s\" ...\n", equal+1, fl->value);
1208 if (fprintf(f, "%s\n", equal+1) <= 0 || ferror(f) || fclose(f)) {
1209 uwsgi_error("uwsgi_file_write_do()");
1210 exit(1);
1211 }
1212 }
1213 else {
1214 uwsgi_log("unable to write empty value for \"%s\"\n", fl->value);
1215 exit(1);
1216 }
1217 *equal = '=';
1218 fl = fl->next;
1219 }
1220 }
1221
uwsgi_fd_is_safe(int fd)1222 int uwsgi_fd_is_safe(int fd) {
1223 int i;
1224 for(i=0;i<uwsgi.safe_fds_cnt;i++) {
1225 if (uwsgi.safe_fds[i] == fd) {
1226 return 1;
1227 }
1228 }
1229 return 0;
1230 }
uwsgi_add_safe_fd(int fd)1231 void uwsgi_add_safe_fd(int fd) {
1232 // check if the fd is already safe
1233 if (uwsgi_fd_is_safe(fd)) return;
1234
1235 size_t len = sizeof(int) * (uwsgi.safe_fds_cnt+1);
1236 int *tmp = realloc(uwsgi.safe_fds, len);
1237 if (!tmp) {
1238 uwsgi_error("uwsgi_add_safe_fd()/realloc()");
1239 exit(1);
1240 }
1241 uwsgi.safe_fds = tmp;
1242 uwsgi.safe_fds[uwsgi.safe_fds_cnt] = fd;
1243 uwsgi.safe_fds_cnt++;
1244 }
1245
uwsgi_is_again()1246 int uwsgi_is_again() {
1247 if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) {
1248 return 1;
1249 }
1250 return 0;
1251 }
1252
uwsgi_disconnect(struct wsgi_request * wsgi_req)1253 void uwsgi_disconnect(struct wsgi_request *wsgi_req) {
1254 if (wsgi_req->socket) {
1255 wsgi_req->socket->proto_close(wsgi_req);
1256 }
1257 wsgi_req->fd_closed = 1;
1258 }
1259
uwsgi_ready_fd(struct wsgi_request * wsgi_req)1260 int uwsgi_ready_fd(struct wsgi_request *wsgi_req) {
1261 if (wsgi_req->async_ready_fd) return wsgi_req->async_last_ready_fd;
1262 return -1;
1263 }
1264
uwsgi_setup_schemes()1265 void uwsgi_setup_schemes() {
1266 uwsgi_register_scheme("emperor", uwsgi_scheme_emperor);
1267 uwsgi_register_scheme("http", uwsgi_scheme_http);
1268 uwsgi_register_scheme("data", uwsgi_scheme_data);
1269 uwsgi_register_scheme("sym", uwsgi_scheme_sym);
1270 uwsgi_register_scheme("section", uwsgi_scheme_section);
1271 uwsgi_register_scheme("fd", uwsgi_scheme_fd);
1272 uwsgi_register_scheme("exec", uwsgi_scheme_exec);
1273 uwsgi_register_scheme("call", uwsgi_scheme_call);
1274 uwsgi_register_scheme("callint", uwsgi_scheme_callint);
1275 }
1276
uwsgi_check_scheme(char * file)1277 struct uwsgi_string_list *uwsgi_check_scheme(char *file) {
1278 struct uwsgi_string_list *usl;
1279 uwsgi_foreach(usl, uwsgi.schemes) {
1280 char *url = uwsgi_concat2(usl->value, "://");
1281 int ret = uwsgi_startswith(file, url, strlen(url));
1282 free(url);
1283 if (!ret) return usl;
1284 }
1285 return NULL;
1286 }
1287
uwsgi_remap_fd(int fd,char * filename)1288 void uwsgi_remap_fd(int fd, char *filename) {
1289
1290 int fdin = open(filename, O_RDWR);
1291 if (fdin < 0) {
1292 uwsgi_error_open(filename);
1293 exit(1);
1294 }
1295
1296 /* stdin */
1297 if (fdin != fd) {
1298 if (dup2(fdin, fd) < 0) {
1299 uwsgi_error("uwsgi_remap_fd()/dup2()");
1300 exit(1);
1301 }
1302 close(fdin);
1303 }
1304 }
1305
uwsgi_is_connected(int fd)1306 int uwsgi_is_connected(int fd) {
1307 int soopt;
1308 socklen_t solen = sizeof(int);
1309
1310 if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *) (&soopt), &solen) < 0) {
1311 return 0;
1312 }
1313 /* is something bad ? */
1314 if (soopt) return 0;
1315 return 1;
1316 }
1317
1318
uwsgi_pass_cred(int fd,char * code,size_t code_len)1319 int uwsgi_pass_cred(int fd, char *code, size_t code_len) {
1320 #ifdef SCM_CREDENTIALS
1321 struct msghdr cr_msg;
1322 struct cmsghdr *cmsg;
1323 struct iovec cr_iov;
1324 void *cr_msg_control = uwsgi_calloc(CMSG_SPACE(sizeof(struct ucred)));
1325
1326 cr_iov.iov_base = code;
1327 cr_iov.iov_len = code_len;
1328
1329 cr_msg.msg_name = NULL;
1330 cr_msg.msg_namelen = 0;
1331
1332 cr_msg.msg_iov = &cr_iov;
1333 cr_msg.msg_iovlen = 1;
1334
1335 cr_msg.msg_flags = 0;
1336 cr_msg.msg_control = cr_msg_control;
1337 cr_msg.msg_controllen = CMSG_SPACE(sizeof(struct ucred));
1338
1339 cmsg = CMSG_FIRSTHDR(&cr_msg);
1340 cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred));
1341 cmsg->cmsg_level = SOL_SOCKET;
1342 cmsg->cmsg_type = SCM_CREDENTIALS;
1343
1344 struct ucred *u = (struct ucred*) CMSG_DATA(cmsg);
1345 u->pid = getpid();
1346 u->uid = getuid();
1347 u->gid = getgid();
1348
1349 if (sendmsg(fd, &cr_msg, 0) < 0) {
1350 uwsgi_error("uwsgi_pass_cred()/sendmsg()");
1351 free(cr_msg_control);
1352 return -1;
1353 }
1354
1355 free(cr_msg_control);
1356 return 0;
1357 #else
1358 return -1;
1359 #endif
1360 }
1361
uwsgi_pass_cred2(int fd,char * code,size_t code_len,struct sockaddr * addr,size_t addr_len)1362 int uwsgi_pass_cred2(int fd, char *code, size_t code_len, struct sockaddr *addr, size_t addr_len) {
1363 #ifdef SCM_CREDENTIALS
1364 struct msghdr cr_msg;
1365 struct cmsghdr *cmsg;
1366 struct iovec cr_iov;
1367 void *cr_msg_control = uwsgi_calloc(CMSG_SPACE(sizeof(struct ucred)));
1368
1369 cr_iov.iov_base = code;
1370 cr_iov.iov_len = code_len;
1371
1372 cr_msg.msg_name = addr;
1373 cr_msg.msg_namelen = addr_len;
1374
1375 cr_msg.msg_iov = &cr_iov;
1376 cr_msg.msg_iovlen = 1;
1377
1378 cr_msg.msg_flags = 0;
1379 cr_msg.msg_control = cr_msg_control;
1380 cr_msg.msg_controllen = CMSG_SPACE(sizeof(struct ucred));
1381
1382 cmsg = CMSG_FIRSTHDR(&cr_msg);
1383 cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred));
1384 cmsg->cmsg_level = SOL_SOCKET;
1385 cmsg->cmsg_type = SCM_CREDENTIALS;
1386
1387 struct ucred *u = (struct ucred*) CMSG_DATA(cmsg);
1388 u->pid = getpid();
1389 u->uid = getuid();
1390 u->gid = getgid();
1391
1392 if (sendmsg(fd, &cr_msg, 0) < 0) {
1393 uwsgi_error("uwsgi_pass_cred2()/sendmsg()");
1394 free(cr_msg_control);
1395 return -1;
1396 }
1397
1398 free(cr_msg_control);
1399 return 0;
1400 #else
1401 return -1;
1402 #endif
1403 }
1404
1405
uwsgi_recv_cred(int fd,char * code,size_t code_len,pid_t * pid,uid_t * uid,gid_t * gid)1406 int uwsgi_recv_cred(int fd, char *code, size_t code_len, pid_t *pid, uid_t *uid, gid_t *gid) {
1407 #ifdef SCM_CREDENTIALS
1408 struct iovec iov;
1409 int ret = -1;
1410
1411 void *msg_control = uwsgi_calloc(CMSG_SPACE(sizeof(struct ucred)));
1412
1413 iov.iov_base = uwsgi_malloc(code_len);
1414 iov.iov_len = code_len;
1415
1416 struct msghdr msg;
1417 memset(&msg, 0, sizeof(msg));
1418
1419 msg.msg_name = NULL;
1420 msg.msg_namelen = 0;
1421
1422 msg.msg_iov = &iov;
1423 msg.msg_iovlen = 1;
1424
1425 msg.msg_control = msg_control;
1426 msg.msg_controllen = CMSG_SPACE(sizeof(struct ucred));
1427
1428 ssize_t len = recvmsg(fd, &msg, 0);
1429 if (len <= 0) {
1430 uwsgi_error("uwsgi_recv_cred()/recvmsg()");
1431 goto clear;
1432 }
1433
1434 struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
1435 if (!cmsg) goto clear;
1436
1437 if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_CREDENTIALS) {
1438 goto clear;
1439 }
1440
1441 if (uwsgi_strncmp(code, code_len, iov.iov_base, iov.iov_len)) goto clear;
1442
1443 struct ucred *u = (struct ucred *) CMSG_DATA(cmsg);
1444 *pid = u->pid;
1445 *uid = u->uid;
1446 *gid = u->gid;
1447 ret = 0;
1448
1449 clear:
1450 free(msg_control);
1451 free(iov.iov_base);
1452 return ret;
1453 #else
1454 return -1;
1455 #endif
1456 }
1457
uwsgi_recv_cred2(int fd,char * buf,size_t buf_len,pid_t * pid,uid_t * uid,gid_t * gid)1458 ssize_t uwsgi_recv_cred2(int fd, char *buf, size_t buf_len, pid_t *pid, uid_t *uid, gid_t *gid) {
1459 #ifdef SCM_CREDENTIALS
1460 struct iovec iov;
1461 ssize_t ret = -1;
1462
1463 void *msg_control = uwsgi_calloc(CMSG_SPACE(sizeof(struct ucred)));
1464
1465 iov.iov_base = buf;
1466 iov.iov_len = buf_len;
1467
1468 struct msghdr msg;
1469 memset(&msg, 0, sizeof(msg));
1470
1471 msg.msg_name = NULL;
1472 msg.msg_namelen = 0;
1473
1474 msg.msg_iov = &iov;
1475 msg.msg_iovlen = 1;
1476
1477 msg.msg_control = msg_control;
1478 msg.msg_controllen = CMSG_SPACE(sizeof(struct ucred));
1479
1480 ssize_t len = recvmsg(fd, &msg, 0);
1481 if (len <= 0) {
1482 uwsgi_error("uwsgi_recv_cred2()/recvmsg()");
1483 goto clear;
1484 }
1485
1486 struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
1487 if (!cmsg) goto clear;
1488
1489 if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_CREDENTIALS) {
1490 goto clear;
1491 }
1492
1493 struct ucred *u = (struct ucred *) CMSG_DATA(cmsg);
1494 *pid = u->pid;
1495 *uid = u->uid;
1496 *gid = u->gid;
1497 ret = len;
1498
1499 clear:
1500 free(msg_control);
1501 return ret;
1502 #else
1503 return -1;
1504 #endif
1505 }
1506
1507