1 /*
2  * nghttp2 - HTTP/2 C Library
3  *
4  * Copyright (c) 2021 Tatsuhiro Tsujikawa
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining
7  * a copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sublicense, and/or sell copies of the Software, and to
11  * permit persons to whom the Software is furnished to do so, subject to
12  * the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be
15  * included in all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24  */
25 #include "shrpx_quic_listener.h"
26 #include "shrpx_worker.h"
27 #include "shrpx_config.h"
28 #include "shrpx_log.h"
29 
30 namespace shrpx {
31 
32 namespace {
readcb(struct ev_loop * loop,ev_io * w,int revent)33 void readcb(struct ev_loop *loop, ev_io *w, int revent) {
34   auto l = static_cast<QUICListener *>(w->data);
35   l->on_read();
36 }
37 } // namespace
38 
QUICListener(const UpstreamAddr * faddr,Worker * worker)39 QUICListener::QUICListener(const UpstreamAddr *faddr, Worker *worker)
40     : faddr_{faddr}, worker_{worker} {
41   ev_io_init(&rev_, readcb, faddr_->fd, EV_READ);
42   rev_.data = this;
43   ev_io_start(worker_->get_loop(), &rev_);
44 }
45 
~QUICListener()46 QUICListener::~QUICListener() {
47   ev_io_stop(worker_->get_loop(), &rev_);
48   close(faddr_->fd);
49 }
50 
on_read()51 void QUICListener::on_read() {
52   sockaddr_union su;
53   std::array<uint8_t, 64_k> buf;
54   size_t pktcnt = 0;
55   iovec msg_iov{buf.data(), buf.size()};
56 
57   msghdr msg{};
58   msg.msg_name = &su;
59   msg.msg_iov = &msg_iov;
60   msg.msg_iovlen = 1;
61 
62   uint8_t msg_ctrl[CMSG_SPACE(sizeof(in6_pktinfo))];
63   msg.msg_control = msg_ctrl;
64 
65   auto quic_conn_handler = worker_->get_quic_connection_handler();
66 
67   for (; pktcnt < 10;) {
68     msg.msg_namelen = sizeof(su);
69     msg.msg_controllen = sizeof(msg_ctrl);
70 
71     auto nread = recvmsg(faddr_->fd, &msg, 0);
72     if (nread == -1) {
73       return;
74     }
75 
76     ++pktcnt;
77 
78     Address local_addr{};
79     if (util::msghdr_get_local_addr(local_addr, &msg, su.storage.ss_family) !=
80         0) {
81       continue;
82     }
83 
84     util::set_port(local_addr, faddr_->port);
85 
86     if (LOG_ENABLED(INFO)) {
87       LOG(INFO) << "QUIC received packet: local="
88                 << util::to_numeric_addr(&local_addr)
89                 << " remote=" << util::to_numeric_addr(&su.sa, msg.msg_namelen)
90                 << " " << nread << " bytes";
91     }
92 
93     if (nread == 0) {
94       continue;
95     }
96 
97     Address remote_addr;
98     remote_addr.su = su;
99     remote_addr.len = msg.msg_namelen;
100 
101     quic_conn_handler->handle_packet(faddr_, remote_addr, local_addr,
102                                      buf.data(), nread);
103   }
104 }
105 
106 } // namespace shrpx
107