connection *connection_accept(server *srv, server_socket *srv_socket) { /* accept everything */ /* search an empty place */ int cnt; sock_addr cnt_addr; socklen_t cnt_len; /* accept it and register the fd */ /** * check if we can still open a new connections * * see #1216 */ if (srv->conns->used >= srv->max_conns) { return NULL; } cnt_len = sizeof(cnt_addr); #if defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK) #if defined(__NetBSD__) cnt = paccept(srv_socket->fd, (struct sockaddr *) &cnt_addr, &cnt_len, NULL, SOCK_CLOEXEC | SOCK_NONBLOCK); #else cnt = accept4(srv_socket->fd, (struct sockaddr *) &cnt_addr, &cnt_len, SOCK_CLOEXEC | SOCK_NONBLOCK); #endif #else cnt = accept(srv_socket->fd, (struct sockaddr *) &cnt_addr, &cnt_len); #endif if (-1 == cnt) { switch (errno) { case EAGAIN: #if EWOULDBLOCK != EAGAIN case EWOULDBLOCK: #endif case EINTR: /* we were stopped _before_ we had a connection */ case ECONNABORTED: /* this is a FreeBSD thingy */ /* we were stopped _after_ we had a connection */ break; case EMFILE: /* out of fds */ break; default: log_error_write(srv, __FILE__, __LINE__, "ssd", "accept failed:", strerror(errno), errno); } return NULL; } else { if (cnt_addr.plain.sa_family != AF_UNIX) { network_accept_tcp_nagle_disable(cnt); } return connection_accepted(srv, srv_socket, &cnt_addr, cnt); } }
static void paccept_block(bool pacceptblock, bool fcntlblock) { int srvr = -1, clnt = -1, as = -1; int ok, fl, n; char buf[10]; struct sockaddr_in sin, ba; struct sigaction sa; srvr = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); if (srvr == -1) FAIL("socket"); memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; #ifdef BSD4_4 sin.sin_len = sizeof(sin); #endif sin.sin_port = htons(0); sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); ok = bind(srvr, (const struct sockaddr *)&sin, (socklen_t)sizeof(sin)); if (ok == -1) FAIL("bind"); socklen_t addrlen = sizeof(struct sockaddr_in); ok = getsockname(srvr, (struct sockaddr *)&ba, &addrlen); if (ok == -1) FAIL("getsockname"); ok = listen(srvr, SOMAXCONN); if (ok == -1) FAIL("listen"); clnt = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); if (clnt == -1) FAIL("socket"); /* may not connect first time */ ok = connect(clnt, (struct sockaddr *) &ba, addrlen); as = paccept(srvr, NULL, NULL, NULL, pacceptblock ? 0 : SOCK_NONBLOCK); ok = connect(clnt, (struct sockaddr *) &ba, addrlen); if (ok == -1 && errno != EISCONN) FAIL("both connects failed"); #if 0 fl = fcntl(srvr, F_GETFL, 0); if (fl == -1) FAIL("fnctl getfl"); ok = fcntl(srvr, F_SETFL, fl & ~O_NONBLOCK); if (ok == -1) FAIL("fnctl setfl"); #endif if (as == -1) { /* not true under NetBSD */ as = paccept(srvr, NULL, NULL, NULL, pacceptblock ? 0 : SOCK_NONBLOCK); if (as == -1) FAIL("paccept"); } if (fcntlblock) { fl = fcntl(as, F_GETFL, 0); if (fl == -1) FAIL("fnctl"); if (fl != (O_RDWR|O_NONBLOCK)) FAIL("fl 0x%x != 0x%x\n", fl, O_RDWR|O_NONBLOCK); ok = fcntl(as, F_SETFL, fl & ~O_NONBLOCK); if (ok == -1) FAIL("fnctl setfl"); fl = fcntl(as, F_GETFL, 0); if (fl & O_NONBLOCK) FAIL("fl non blocking after reset"); } sa.sa_handler = ding; sa.sa_flags = 0; sigemptyset(&sa.sa_mask); sigaction(SIGALRM, &sa, NULL); alarm(1); n = read(as, buf, 10); if (pacceptblock || fcntlblock) { if (n == -1 && errno != EINTR) FAIL("read"); } else { if (n != -1 || errno != EWOULDBLOCK) FAIL("read"); } return; fail: close(srvr); close(clnt); close(as); }