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