xref: /unit/src/nxt_conn.c (revision 564)
162Sigor@sysoev.ru 
262Sigor@sysoev.ru /*
362Sigor@sysoev.ru  * Copyright (C) Igor Sysoev
462Sigor@sysoev.ru  * Copyright (C) NGINX, Inc.
562Sigor@sysoev.ru  */
662Sigor@sysoev.ru 
762Sigor@sysoev.ru #include <nxt_main.h>
862Sigor@sysoev.ru 
962Sigor@sysoev.ru 
1062Sigor@sysoev.ru nxt_conn_io_t  nxt_unix_conn_io = {
1162Sigor@sysoev.ru     nxt_conn_io_connect,
1262Sigor@sysoev.ru     nxt_conn_io_accept,
1362Sigor@sysoev.ru 
1462Sigor@sysoev.ru     nxt_conn_io_read,
1562Sigor@sysoev.ru     nxt_conn_io_recvbuf,
1662Sigor@sysoev.ru     nxt_conn_io_recv,
1762Sigor@sysoev.ru 
1862Sigor@sysoev.ru     nxt_conn_io_write,
1962Sigor@sysoev.ru     nxt_event_conn_io_write_chunk,
2062Sigor@sysoev.ru 
2162Sigor@sysoev.ru #if (NXT_HAVE_LINUX_SENDFILE)
2262Sigor@sysoev.ru     nxt_linux_event_conn_io_sendfile,
2362Sigor@sysoev.ru #elif (NXT_HAVE_FREEBSD_SENDFILE)
2462Sigor@sysoev.ru     nxt_freebsd_event_conn_io_sendfile,
2562Sigor@sysoev.ru #elif (NXT_HAVE_MACOSX_SENDFILE)
2662Sigor@sysoev.ru     nxt_macosx_event_conn_io_sendfile,
2762Sigor@sysoev.ru #elif (NXT_HAVE_SOLARIS_SENDFILEV)
2862Sigor@sysoev.ru     nxt_solaris_event_conn_io_sendfilev,
2962Sigor@sysoev.ru #elif (NXT_HAVE_AIX_SEND_FILE)
3062Sigor@sysoev.ru     nxt_aix_event_conn_io_send_file,
3162Sigor@sysoev.ru #elif (NXT_HAVE_HPUX_SENDFILE)
3262Sigor@sysoev.ru     nxt_hpux_event_conn_io_sendfile,
3362Sigor@sysoev.ru #else
3462Sigor@sysoev.ru     nxt_event_conn_io_sendbuf,
3562Sigor@sysoev.ru #endif
3662Sigor@sysoev.ru 
3762Sigor@sysoev.ru     nxt_event_conn_io_writev,
3862Sigor@sysoev.ru     nxt_event_conn_io_send,
3962Sigor@sysoev.ru 
4062Sigor@sysoev.ru     nxt_conn_io_shutdown,
4162Sigor@sysoev.ru };
4262Sigor@sysoev.ru 
4362Sigor@sysoev.ru 
4462Sigor@sysoev.ru nxt_conn_t *
4565Sigor@sysoev.ru nxt_conn_create(nxt_mp_t *mp, nxt_task_t *task)
4662Sigor@sysoev.ru {
4762Sigor@sysoev.ru     nxt_conn_t    *c;
4862Sigor@sysoev.ru     nxt_thread_t  *thr;
4962Sigor@sysoev.ru 
5065Sigor@sysoev.ru     c = nxt_mp_zget(mp, sizeof(nxt_conn_t));
5162Sigor@sysoev.ru     if (nxt_slow_path(c == NULL)) {
5262Sigor@sysoev.ru         return NULL;
5362Sigor@sysoev.ru     }
5462Sigor@sysoev.ru 
5562Sigor@sysoev.ru     c->mem_pool = mp;
5662Sigor@sysoev.ru 
5762Sigor@sysoev.ru     c->socket.fd = -1;
5862Sigor@sysoev.ru 
5962Sigor@sysoev.ru     c->socket.log = &c->log;
6062Sigor@sysoev.ru     c->log = *task->log;
6162Sigor@sysoev.ru 
6262Sigor@sysoev.ru     /* The while loop skips possible uint32_t overflow. */
6362Sigor@sysoev.ru 
6462Sigor@sysoev.ru     while (c->log.ident == 0) {
6562Sigor@sysoev.ru         c->log.ident = nxt_task_next_ident();
6662Sigor@sysoev.ru     }
6762Sigor@sysoev.ru 
6862Sigor@sysoev.ru     thr = nxt_thread();
6962Sigor@sysoev.ru     thr->engine->connections++;
7062Sigor@sysoev.ru 
7162Sigor@sysoev.ru     c->task.thread = thr;
7262Sigor@sysoev.ru     c->task.log = &c->log;
7362Sigor@sysoev.ru     c->task.ident = c->log.ident;
7462Sigor@sysoev.ru     c->socket.task = &c->task;
7562Sigor@sysoev.ru     c->read_timer.task = &c->task;
7662Sigor@sysoev.ru     c->write_timer.task = &c->task;
7762Sigor@sysoev.ru 
7862Sigor@sysoev.ru     c->io = thr->engine->event.io;
7962Sigor@sysoev.ru     c->max_chunk = NXT_INT32_T_MAX;
8062Sigor@sysoev.ru     c->sendfile = NXT_CONN_SENDFILE_UNSET;
8162Sigor@sysoev.ru 
8262Sigor@sysoev.ru     c->socket.read_work_queue = &thr->engine->fast_work_queue;
8362Sigor@sysoev.ru     c->socket.write_work_queue = &thr->engine->fast_work_queue;
8462Sigor@sysoev.ru 
8562Sigor@sysoev.ru     nxt_conn_timer_init(&c->read_timer, c, c->socket.read_work_queue);
8662Sigor@sysoev.ru     nxt_conn_timer_init(&c->write_timer, c, c->socket.write_work_queue);
8762Sigor@sysoev.ru 
8862Sigor@sysoev.ru     nxt_log_debug(&c->log, "connections: %uD", thr->engine->connections);
8962Sigor@sysoev.ru 
9062Sigor@sysoev.ru     return c;
9162Sigor@sysoev.ru }
9262Sigor@sysoev.ru 
9362Sigor@sysoev.ru 
9462Sigor@sysoev.ru void
95386Sigor@sysoev.ru nxt_conn_free(nxt_task_t *task, nxt_conn_t *c)
96386Sigor@sysoev.ru {
97430Sigor@sysoev.ru     nxt_mp_t  *mp;
98430Sigor@sysoev.ru 
99386Sigor@sysoev.ru     task->thread->engine->connections--;
100386Sigor@sysoev.ru 
101430Sigor@sysoev.ru     mp = c->mem_pool;
102430Sigor@sysoev.ru     nxt_mp_free(mp, c);
103430Sigor@sysoev.ru     nxt_mp_release(mp);
104386Sigor@sysoev.ru }
105386Sigor@sysoev.ru 
106386Sigor@sysoev.ru 
107386Sigor@sysoev.ru void
10862Sigor@sysoev.ru nxt_conn_io_shutdown(nxt_task_t *task, void *obj, void *data)
10962Sigor@sysoev.ru {
110109Sigor@sysoev.ru     int         ret;
111109Sigor@sysoev.ru     nxt_conn_t  *c;
112109Sigor@sysoev.ru 
113109Sigor@sysoev.ru     static const struct linger  linger_off = {
114109Sigor@sysoev.ru         .l_onoff = 1,
115109Sigor@sysoev.ru         .l_linger = 0,
116109Sigor@sysoev.ru     };
11762Sigor@sysoev.ru 
11862Sigor@sysoev.ru     c = obj;
11962Sigor@sysoev.ru 
12062Sigor@sysoev.ru     nxt_debug(task, "event conn shutdown");
12162Sigor@sysoev.ru 
12262Sigor@sysoev.ru     if (c->socket.timedout) {
12362Sigor@sysoev.ru         /*
12462Sigor@sysoev.ru          * Resetting of timed out connection on close
12562Sigor@sysoev.ru          * releases kernel memory associated with socket.
12662Sigor@sysoev.ru          * This also causes sending TCP/IP RST to a peer.
12762Sigor@sysoev.ru          */
128109Sigor@sysoev.ru         ret = setsockopt(c->socket.fd, SOL_SOCKET, SO_LINGER, &linger_off,
129109Sigor@sysoev.ru                          sizeof(struct linger));
13062Sigor@sysoev.ru 
13162Sigor@sysoev.ru         if (nxt_slow_path(ret != 0)) {
132*564Svbart@nginx.com             nxt_alert(task, "setsockopt(%d, SO_LINGER) failed %E",
133*564Svbart@nginx.com                       c->socket.fd, nxt_socket_errno);
13462Sigor@sysoev.ru         }
13562Sigor@sysoev.ru     }
13662Sigor@sysoev.ru 
13762Sigor@sysoev.ru     c->write_state->close_handler(task, c, data);
13862Sigor@sysoev.ru }
13962Sigor@sysoev.ru 
14062Sigor@sysoev.ru 
14162Sigor@sysoev.ru void
14262Sigor@sysoev.ru nxt_conn_timer(nxt_event_engine_t *engine, nxt_conn_t *c,
14362Sigor@sysoev.ru     const nxt_conn_state_t *state, nxt_timer_t *timer)
14462Sigor@sysoev.ru {
14562Sigor@sysoev.ru     nxt_msec_t  value;
14662Sigor@sysoev.ru 
14762Sigor@sysoev.ru     if (state->timer_value != NULL) {
14862Sigor@sysoev.ru         value = state->timer_value(c, state->timer_data);
14962Sigor@sysoev.ru 
15062Sigor@sysoev.ru         if (value != 0) {
15162Sigor@sysoev.ru             timer->handler = state->timer_handler;
15262Sigor@sysoev.ru             nxt_timer_add(engine, timer, value);
15362Sigor@sysoev.ru         }
15462Sigor@sysoev.ru     }
15562Sigor@sysoev.ru }
15662Sigor@sysoev.ru 
15762Sigor@sysoev.ru 
15862Sigor@sysoev.ru void
15962Sigor@sysoev.ru nxt_conn_work_queue_set(nxt_conn_t *c, nxt_work_queue_t *wq)
16062Sigor@sysoev.ru {
16162Sigor@sysoev.ru     c->read_work_queue = wq;
16262Sigor@sysoev.ru     c->write_work_queue = wq;
16362Sigor@sysoev.ru     c->read_timer.work_queue = wq;
16462Sigor@sysoev.ru     c->write_timer.work_queue = wq;
16562Sigor@sysoev.ru }
166431Sigor@sysoev.ru 
167431Sigor@sysoev.ru 
168431Sigor@sysoev.ru nxt_sockaddr_t *
169431Sigor@sysoev.ru nxt_conn_local_addr(nxt_task_t *task, nxt_conn_t *c)
170431Sigor@sysoev.ru {
171431Sigor@sysoev.ru     int             ret;
172431Sigor@sysoev.ru     size_t          size, length;
173431Sigor@sysoev.ru     socklen_t       socklen;
174431Sigor@sysoev.ru     nxt_sockaddr_t  *sa;
175431Sigor@sysoev.ru 
176431Sigor@sysoev.ru     if (c->local != NULL) {
177431Sigor@sysoev.ru         return c->local;
178431Sigor@sysoev.ru     }
179431Sigor@sysoev.ru 
180431Sigor@sysoev.ru     /* AF_UNIX should not get in here. */
181431Sigor@sysoev.ru 
182431Sigor@sysoev.ru     switch (c->remote->u.sockaddr.sa_family) {
183431Sigor@sysoev.ru #if (NXT_INET6)
184431Sigor@sysoev.ru     case AF_INET6:
185431Sigor@sysoev.ru         socklen = sizeof(struct sockaddr_in6);
186431Sigor@sysoev.ru         length = NXT_INET6_ADDR_STR_LEN;
187431Sigor@sysoev.ru         size = offsetof(nxt_sockaddr_t, u) + socklen + length;
188431Sigor@sysoev.ru         break;
189431Sigor@sysoev.ru #endif
190431Sigor@sysoev.ru     case AF_INET:
191431Sigor@sysoev.ru     default:
192431Sigor@sysoev.ru         socklen = sizeof(struct sockaddr_in);
193431Sigor@sysoev.ru         length = NXT_INET_ADDR_STR_LEN;
194431Sigor@sysoev.ru         size = offsetof(nxt_sockaddr_t, u) + socklen + length;
195431Sigor@sysoev.ru         break;
196431Sigor@sysoev.ru     }
197431Sigor@sysoev.ru 
198431Sigor@sysoev.ru     sa = nxt_mp_get(c->mem_pool, size);
199431Sigor@sysoev.ru     if (nxt_slow_path(sa == NULL)) {
200431Sigor@sysoev.ru         return NULL;
201431Sigor@sysoev.ru     }
202431Sigor@sysoev.ru 
203431Sigor@sysoev.ru     sa->socklen = socklen;
204431Sigor@sysoev.ru     sa->length = length;
205431Sigor@sysoev.ru 
206431Sigor@sysoev.ru     ret = getsockname(c->socket.fd, &sa->u.sockaddr, &socklen);
207431Sigor@sysoev.ru     if (nxt_slow_path(ret != 0)) {
208*564Svbart@nginx.com         nxt_alert(task, "getsockname(%d) failed", c->socket.fd);
209431Sigor@sysoev.ru         return NULL;
210431Sigor@sysoev.ru     }
211431Sigor@sysoev.ru 
212431Sigor@sysoev.ru     c->local = sa;
213431Sigor@sysoev.ru 
214431Sigor@sysoev.ru     nxt_sockaddr_text(sa);
215431Sigor@sysoev.ru 
216431Sigor@sysoev.ru     /*
217431Sigor@sysoev.ru      * TODO: here we can adjust the end of non-freeable block
218431Sigor@sysoev.ru      * in c->mem_pool to the end of actual sockaddr length.
219431Sigor@sysoev.ru      */
220431Sigor@sysoev.ru 
221431Sigor@sysoev.ru     return sa;
222431Sigor@sysoev.ru }
223