1 
2 /*
3  * Copyright (C) Roman Arutyunyan
4  * Copyright (C) Nginx, Inc.
5  */
6 
7 
8 #include <ngx_config.h>
9 #include <ngx_core.h>
10 #include <ngx_event.h>
11 
12 
13 #if !(NGX_WIN32)
14 
15 struct ngx_udp_connection_s {
16     ngx_rbtree_node_t   node;
17     ngx_connection_t   *connection;
18     ngx_buf_t          *buffer;
19 };
20 
21 
22 static void ngx_close_accepted_udp_connection(ngx_connection_t *c);
23 static ssize_t ngx_udp_shared_recv(ngx_connection_t *c, u_char *buf,
24     size_t size);
25 static ngx_int_t ngx_insert_udp_connection(ngx_connection_t *c);
26 static ngx_connection_t *ngx_lookup_udp_connection(ngx_listening_t *ls,
27     struct sockaddr *sockaddr, socklen_t socklen,
28     struct sockaddr *local_sockaddr, socklen_t local_socklen);
29 
30 
31 void
ngx_event_recvmsg(ngx_event_t * ev)32 ngx_event_recvmsg(ngx_event_t *ev)
33 {
34     ssize_t            n;
35     ngx_buf_t          buf;
36     ngx_log_t         *log;
37     ngx_err_t          err;
38     socklen_t          socklen, local_socklen;
39     ngx_event_t       *rev, *wev;
40     struct iovec       iov[1];
41     struct msghdr      msg;
42     ngx_sockaddr_t     sa, lsa;
43     struct sockaddr   *sockaddr, *local_sockaddr;
44     ngx_listening_t   *ls;
45     ngx_event_conf_t  *ecf;
46     ngx_connection_t  *c, *lc;
47     static u_char      buffer[65535];
48 
49 #if (NGX_HAVE_MSGHDR_MSG_CONTROL)
50 
51 #if (NGX_HAVE_IP_RECVDSTADDR)
52     u_char             msg_control[CMSG_SPACE(sizeof(struct in_addr))];
53 #elif (NGX_HAVE_IP_PKTINFO)
54     u_char             msg_control[CMSG_SPACE(sizeof(struct in_pktinfo))];
55 #endif
56 
57 #if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO)
58     u_char             msg_control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
59 #endif
60 
61 #endif
62 
63     if (ev->timedout) {
64         if (ngx_enable_accept_events((ngx_cycle_t *) ngx_cycle) != NGX_OK) {
65             return;
66         }
67 
68         ev->timedout = 0;
69     }
70 
71     ecf = ngx_event_get_conf(ngx_cycle->conf_ctx, ngx_event_core_module);
72 
73     if (!(ngx_event_flags & NGX_USE_KQUEUE_EVENT)) {
74         ev->available = ecf->multi_accept;
75     }
76 
77     lc = ev->data;
78     ls = lc->listening;
79     ev->ready = 0;
80 
81     ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
82                    "recvmsg on %V, ready: %d", &ls->addr_text, ev->available);
83 
84     do {
85         ngx_memzero(&msg, sizeof(struct msghdr));
86 
87         iov[0].iov_base = (void *) buffer;
88         iov[0].iov_len = sizeof(buffer);
89 
90         msg.msg_name = &sa;
91         msg.msg_namelen = sizeof(ngx_sockaddr_t);
92         msg.msg_iov = iov;
93         msg.msg_iovlen = 1;
94 
95 #if (NGX_HAVE_MSGHDR_MSG_CONTROL)
96 
97         if (ls->wildcard) {
98 
99 #if (NGX_HAVE_IP_RECVDSTADDR || NGX_HAVE_IP_PKTINFO)
100             if (ls->sockaddr->sa_family == AF_INET) {
101                 msg.msg_control = &msg_control;
102                 msg.msg_controllen = sizeof(msg_control);
103             }
104 #endif
105 
106 #if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO)
107             if (ls->sockaddr->sa_family == AF_INET6) {
108                 msg.msg_control = &msg_control6;
109                 msg.msg_controllen = sizeof(msg_control6);
110             }
111 #endif
112         }
113 
114 #endif
115 
116         n = recvmsg(lc->fd, &msg, 0);
117 
118         if (n == -1) {
119             err = ngx_socket_errno;
120 
121             if (err == NGX_EAGAIN) {
122                 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, err,
123                                "recvmsg() not ready");
124                 return;
125             }
126 
127             ngx_log_error(NGX_LOG_ALERT, ev->log, err, "recvmsg() failed");
128 
129             return;
130         }
131 
132 #if (NGX_HAVE_MSGHDR_MSG_CONTROL)
133         if (msg.msg_flags & (MSG_TRUNC|MSG_CTRUNC)) {
134             ngx_log_error(NGX_LOG_ALERT, ev->log, 0,
135                           "recvmsg() truncated data");
136             continue;
137         }
138 #endif
139 
140         sockaddr = msg.msg_name;
141         socklen = msg.msg_namelen;
142 
143         if (socklen > (socklen_t) sizeof(ngx_sockaddr_t)) {
144             socklen = sizeof(ngx_sockaddr_t);
145         }
146 
147         if (socklen == 0) {
148 
149             /*
150              * on Linux recvmsg() returns zero msg_namelen
151              * when receiving packets from unbound AF_UNIX sockets
152              */
153 
154             socklen = sizeof(struct sockaddr);
155             ngx_memzero(&sa, sizeof(struct sockaddr));
156             sa.sockaddr.sa_family = ls->sockaddr->sa_family;
157         }
158 
159         local_sockaddr = ls->sockaddr;
160         local_socklen = ls->socklen;
161 
162 #if (NGX_HAVE_MSGHDR_MSG_CONTROL)
163 
164         if (ls->wildcard) {
165             struct cmsghdr  *cmsg;
166 
167             ngx_memcpy(&lsa, local_sockaddr, local_socklen);
168             local_sockaddr = &lsa.sockaddr;
169 
170             for (cmsg = CMSG_FIRSTHDR(&msg);
171                  cmsg != NULL;
172                  cmsg = CMSG_NXTHDR(&msg, cmsg))
173             {
174 
175 #if (NGX_HAVE_IP_RECVDSTADDR)
176 
177                 if (cmsg->cmsg_level == IPPROTO_IP
178                     && cmsg->cmsg_type == IP_RECVDSTADDR
179                     && local_sockaddr->sa_family == AF_INET)
180                 {
181                     struct in_addr      *addr;
182                     struct sockaddr_in  *sin;
183 
184                     addr = (struct in_addr *) CMSG_DATA(cmsg);
185                     sin = (struct sockaddr_in *) local_sockaddr;
186                     sin->sin_addr = *addr;
187 
188                     break;
189                 }
190 
191 #elif (NGX_HAVE_IP_PKTINFO)
192 
193                 if (cmsg->cmsg_level == IPPROTO_IP
194                     && cmsg->cmsg_type == IP_PKTINFO
195                     && local_sockaddr->sa_family == AF_INET)
196                 {
197                     struct in_pktinfo   *pkt;
198                     struct sockaddr_in  *sin;
199 
200                     pkt = (struct in_pktinfo *) CMSG_DATA(cmsg);
201                     sin = (struct sockaddr_in *) local_sockaddr;
202                     sin->sin_addr = pkt->ipi_addr;
203 
204                     break;
205                 }
206 
207 #endif
208 
209 #if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO)
210 
211                 if (cmsg->cmsg_level == IPPROTO_IPV6
212                     && cmsg->cmsg_type == IPV6_PKTINFO
213                     && local_sockaddr->sa_family == AF_INET6)
214                 {
215                     struct in6_pktinfo   *pkt6;
216                     struct sockaddr_in6  *sin6;
217 
218                     pkt6 = (struct in6_pktinfo *) CMSG_DATA(cmsg);
219                     sin6 = (struct sockaddr_in6 *) local_sockaddr;
220                     sin6->sin6_addr = pkt6->ipi6_addr;
221 
222                     break;
223                 }
224 
225 #endif
226 
227             }
228         }
229 
230 #endif
231 
232         c = ngx_lookup_udp_connection(ls, sockaddr, socklen, local_sockaddr,
233                                       local_socklen);
234 
235         if (c) {
236 
237 #if (NGX_DEBUG)
238             if (c->log->log_level & NGX_LOG_DEBUG_EVENT) {
239                 ngx_log_handler_pt  handler;
240 
241                 handler = c->log->handler;
242                 c->log->handler = NULL;
243 
244                 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
245                                "recvmsg: fd:%d n:%z", c->fd, n);
246 
247                 c->log->handler = handler;
248             }
249 #endif
250 
251             ngx_memzero(&buf, sizeof(ngx_buf_t));
252 
253             buf.pos = buffer;
254             buf.last = buffer + n;
255 
256             rev = c->read;
257 
258             c->udp->buffer = &buf;
259 
260             rev->ready = 1;
261             rev->active = 0;
262 
263             rev->handler(rev);
264 
265             if (c->udp) {
266                 c->udp->buffer = NULL;
267             }
268 
269             rev->ready = 0;
270             rev->active = 1;
271 
272             goto next;
273         }
274 
275 #if (NGX_STAT_STUB)
276         (void) ngx_atomic_fetch_add(ngx_stat_accepted, 1);
277 #endif
278 
279         ngx_accept_disabled = ngx_cycle->connection_n / 8
280                               - ngx_cycle->free_connection_n;
281 
282         c = ngx_get_connection(lc->fd, ev->log);
283         if (c == NULL) {
284             return;
285         }
286 
287         c->shared = 1;
288         c->type = SOCK_DGRAM;
289         c->socklen = socklen;
290 
291 #if (NGX_STAT_STUB)
292         (void) ngx_atomic_fetch_add(ngx_stat_active, 1);
293 #endif
294 
295         c->pool = ngx_create_pool(ls->pool_size, ev->log);
296         if (c->pool == NULL) {
297             ngx_close_accepted_udp_connection(c);
298             return;
299         }
300 
301         c->sockaddr = ngx_palloc(c->pool, socklen);
302         if (c->sockaddr == NULL) {
303             ngx_close_accepted_udp_connection(c);
304             return;
305         }
306 
307         ngx_memcpy(c->sockaddr, sockaddr, socklen);
308 
309         log = ngx_palloc(c->pool, sizeof(ngx_log_t));
310         if (log == NULL) {
311             ngx_close_accepted_udp_connection(c);
312             return;
313         }
314 
315         *log = ls->log;
316 
317         c->recv = ngx_udp_shared_recv;
318         c->send = ngx_udp_send;
319         c->send_chain = ngx_udp_send_chain;
320 
321         c->log = log;
322         c->pool->log = log;
323         c->listening = ls;
324 
325         if (local_sockaddr == &lsa.sockaddr) {
326             local_sockaddr = ngx_palloc(c->pool, local_socklen);
327             if (local_sockaddr == NULL) {
328                 ngx_close_accepted_udp_connection(c);
329                 return;
330             }
331 
332             ngx_memcpy(local_sockaddr, &lsa, local_socklen);
333         }
334 
335         c->local_sockaddr = local_sockaddr;
336         c->local_socklen = local_socklen;
337 
338         c->buffer = ngx_create_temp_buf(c->pool, n);
339         if (c->buffer == NULL) {
340             ngx_close_accepted_udp_connection(c);
341             return;
342         }
343 
344         c->buffer->last = ngx_cpymem(c->buffer->last, buffer, n);
345 
346         rev = c->read;
347         wev = c->write;
348 
349         rev->active = 1;
350         wev->ready = 1;
351 
352         rev->log = log;
353         wev->log = log;
354 
355         /*
356          * TODO: MT: - ngx_atomic_fetch_add()
357          *             or protection by critical section or light mutex
358          *
359          * TODO: MP: - allocated in a shared memory
360          *           - ngx_atomic_fetch_add()
361          *             or protection by critical section or light mutex
362          */
363 
364         c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1);
365 
366         c->start_time = ngx_current_msec;
367 
368 #if (NGX_STAT_STUB)
369         (void) ngx_atomic_fetch_add(ngx_stat_handled, 1);
370 #endif
371 
372         if (ls->addr_ntop) {
373             c->addr_text.data = ngx_pnalloc(c->pool, ls->addr_text_max_len);
374             if (c->addr_text.data == NULL) {
375                 ngx_close_accepted_udp_connection(c);
376                 return;
377             }
378 
379             c->addr_text.len = ngx_sock_ntop(c->sockaddr, c->socklen,
380                                              c->addr_text.data,
381                                              ls->addr_text_max_len, 0);
382             if (c->addr_text.len == 0) {
383                 ngx_close_accepted_udp_connection(c);
384                 return;
385             }
386         }
387 
388 #if (NGX_DEBUG)
389         {
390         ngx_str_t  addr;
391         u_char     text[NGX_SOCKADDR_STRLEN];
392 
393         ngx_debug_accepted_connection(ecf, c);
394 
395         if (log->log_level & NGX_LOG_DEBUG_EVENT) {
396             addr.data = text;
397             addr.len = ngx_sock_ntop(c->sockaddr, c->socklen, text,
398                                      NGX_SOCKADDR_STRLEN, 1);
399 
400             ngx_log_debug4(NGX_LOG_DEBUG_EVENT, log, 0,
401                            "*%uA recvmsg: %V fd:%d n:%z",
402                            c->number, &addr, c->fd, n);
403         }
404 
405         }
406 #endif
407 
408         if (ngx_insert_udp_connection(c) != NGX_OK) {
409             ngx_close_accepted_udp_connection(c);
410             return;
411         }
412 
413         log->data = NULL;
414         log->handler = NULL;
415 
416         ls->handler(c);
417 
418     next:
419 
420         if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
421             ev->available -= n;
422         }
423 
424     } while (ev->available);
425 }
426 
427 
428 static void
ngx_close_accepted_udp_connection(ngx_connection_t * c)429 ngx_close_accepted_udp_connection(ngx_connection_t *c)
430 {
431     ngx_free_connection(c);
432 
433     c->fd = (ngx_socket_t) -1;
434 
435     if (c->pool) {
436         ngx_destroy_pool(c->pool);
437     }
438 
439 #if (NGX_STAT_STUB)
440     (void) ngx_atomic_fetch_add(ngx_stat_active, -1);
441 #endif
442 }
443 
444 
445 static ssize_t
ngx_udp_shared_recv(ngx_connection_t * c,u_char * buf,size_t size)446 ngx_udp_shared_recv(ngx_connection_t *c, u_char *buf, size_t size)
447 {
448     ssize_t     n;
449     ngx_buf_t  *b;
450 
451     if (c->udp == NULL || c->udp->buffer == NULL) {
452         return NGX_AGAIN;
453     }
454 
455     b = c->udp->buffer;
456 
457     n = ngx_min(b->last - b->pos, (ssize_t) size);
458 
459     ngx_memcpy(buf, b->pos, n);
460 
461     c->udp->buffer = NULL;
462 
463     c->read->ready = 0;
464     c->read->active = 1;
465 
466     return n;
467 }
468 
469 
470 void
ngx_udp_rbtree_insert_value(ngx_rbtree_node_t * temp,ngx_rbtree_node_t * node,ngx_rbtree_node_t * sentinel)471 ngx_udp_rbtree_insert_value(ngx_rbtree_node_t *temp,
472     ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
473 {
474     ngx_int_t               rc;
475     ngx_connection_t       *c, *ct;
476     ngx_rbtree_node_t     **p;
477     ngx_udp_connection_t   *udp, *udpt;
478 
479     for ( ;; ) {
480 
481         if (node->key < temp->key) {
482 
483             p = &temp->left;
484 
485         } else if (node->key > temp->key) {
486 
487             p = &temp->right;
488 
489         } else { /* node->key == temp->key */
490 
491             udp = (ngx_udp_connection_t *) node;
492             c = udp->connection;
493 
494             udpt = (ngx_udp_connection_t *) temp;
495             ct = udpt->connection;
496 
497             rc = ngx_cmp_sockaddr(c->sockaddr, c->socklen,
498                                   ct->sockaddr, ct->socklen, 1);
499 
500             if (rc == 0 && c->listening->wildcard) {
501                 rc = ngx_cmp_sockaddr(c->local_sockaddr, c->local_socklen,
502                                       ct->local_sockaddr, ct->local_socklen, 1);
503             }
504 
505             p = (rc < 0) ? &temp->left : &temp->right;
506         }
507 
508         if (*p == sentinel) {
509             break;
510         }
511 
512         temp = *p;
513     }
514 
515     *p = node;
516     node->parent = temp;
517     node->left = sentinel;
518     node->right = sentinel;
519     ngx_rbt_red(node);
520 }
521 
522 
523 static ngx_int_t
ngx_insert_udp_connection(ngx_connection_t * c)524 ngx_insert_udp_connection(ngx_connection_t *c)
525 {
526     uint32_t               hash;
527     ngx_pool_cleanup_t    *cln;
528     ngx_udp_connection_t  *udp;
529 
530     if (c->udp) {
531         return NGX_OK;
532     }
533 
534     udp = ngx_pcalloc(c->pool, sizeof(ngx_udp_connection_t));
535     if (udp == NULL) {
536         return NGX_ERROR;
537     }
538 
539     udp->connection = c;
540 
541     ngx_crc32_init(hash);
542     ngx_crc32_update(&hash, (u_char *) c->sockaddr, c->socklen);
543 
544     if (c->listening->wildcard) {
545         ngx_crc32_update(&hash, (u_char *) c->local_sockaddr, c->local_socklen);
546     }
547 
548     ngx_crc32_final(hash);
549 
550     udp->node.key = hash;
551 
552     cln = ngx_pool_cleanup_add(c->pool, 0);
553     if (cln == NULL) {
554         return NGX_ERROR;
555     }
556 
557     cln->data = c;
558     cln->handler = ngx_delete_udp_connection;
559 
560     ngx_rbtree_insert(&c->listening->rbtree, &udp->node);
561 
562     c->udp = udp;
563 
564     return NGX_OK;
565 }
566 
567 
568 void
ngx_delete_udp_connection(void * data)569 ngx_delete_udp_connection(void *data)
570 {
571     ngx_connection_t  *c = data;
572 
573     if (c->udp == NULL) {
574         return;
575     }
576 
577     ngx_rbtree_delete(&c->listening->rbtree, &c->udp->node);
578 
579     c->udp = NULL;
580 }
581 
582 
583 static ngx_connection_t *
ngx_lookup_udp_connection(ngx_listening_t * ls,struct sockaddr * sockaddr,socklen_t socklen,struct sockaddr * local_sockaddr,socklen_t local_socklen)584 ngx_lookup_udp_connection(ngx_listening_t *ls, struct sockaddr *sockaddr,
585     socklen_t socklen, struct sockaddr *local_sockaddr, socklen_t local_socklen)
586 {
587     uint32_t               hash;
588     ngx_int_t              rc;
589     ngx_connection_t      *c;
590     ngx_rbtree_node_t     *node, *sentinel;
591     ngx_udp_connection_t  *udp;
592 
593 #if (NGX_HAVE_UNIX_DOMAIN)
594 
595     if (sockaddr->sa_family == AF_UNIX) {
596         struct sockaddr_un *saun = (struct sockaddr_un *) sockaddr;
597 
598         if (socklen <= (socklen_t) offsetof(struct sockaddr_un, sun_path)
599             || saun->sun_path[0] == '\0')
600         {
601             ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, 0,
602                            "unbound unix socket");
603             return NULL;
604         }
605     }
606 
607 #endif
608 
609     node = ls->rbtree.root;
610     sentinel = ls->rbtree.sentinel;
611 
612     ngx_crc32_init(hash);
613     ngx_crc32_update(&hash, (u_char *) sockaddr, socklen);
614 
615     if (ls->wildcard) {
616         ngx_crc32_update(&hash, (u_char *) local_sockaddr, local_socklen);
617     }
618 
619     ngx_crc32_final(hash);
620 
621     while (node != sentinel) {
622 
623         if (hash < node->key) {
624             node = node->left;
625             continue;
626         }
627 
628         if (hash > node->key) {
629             node = node->right;
630             continue;
631         }
632 
633         /* hash == node->key */
634 
635         udp = (ngx_udp_connection_t *) node;
636 
637         c = udp->connection;
638 
639         rc = ngx_cmp_sockaddr(sockaddr, socklen,
640                               c->sockaddr, c->socklen, 1);
641 
642         if (rc == 0 && ls->wildcard) {
643             rc = ngx_cmp_sockaddr(local_sockaddr, local_socklen,
644                                   c->local_sockaddr, c->local_socklen, 1);
645         }
646 
647         if (rc == 0) {
648             return c;
649         }
650 
651         node = (rc < 0) ? node->left : node->right;
652     }
653 
654     return NULL;
655 }
656 
657 #else
658 
659 void
ngx_delete_udp_connection(void * data)660 ngx_delete_udp_connection(void *data)
661 {
662     return;
663 }
664 
665 #endif
666