Пример #1
0
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);
	}
}
Пример #2
0
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);
}