Beispiel #1
0
bool brpc_connect(brpc_addr_t *addr, int *_sockfd, brpc_tv_t tout)
{
	int sockfd;
	fd_set rset, wset;
	struct timeval tv;
	int res, err;
	socklen_t elen;
	bool was_blocking;

	if ((*_sockfd < 0) && ((*_sockfd = brpc_socket(addr, false, false)) < 0))
		return false;
	sockfd = *_sockfd;

	/* set nonblocking so that it can timeout */
	if (! setsockmode(sockfd, false, &was_blocking))
		goto error;
	switch (addr->domain) {
		case AF_INET:
		case AF_INET6:
			if (! setsocktos(sockfd))
				WARN("failed to set TOS.\n");
	}
#ifndef DISABLE_NAGLE
	/* NAGLE's good in this case: save one packet (ACK), locally, and read
	 * more in one syscall, remotely */
	if ((addr->domain == PF_INET) && (addr->socktype == SOCK_STREAM))
		if (disable_nagle(sockfd))
			WARN("failed to disable Nagle for socket [%d:%d] (%s).\n",
					addr->domain, addr->socktype, brpc_strerror());
#endif

	errno = 0;
	if (connect(sockfd, (struct sockaddr *)&addr->sockaddr, 
			addr->addrlen) == 0)
		return sockfd;
	else if (errno != EINPROGRESS) {
		WSYSERRNO;
		goto error;
	}

	FD_ZERO(&rset);
	FD_SET(sockfd, &rset);
	wset = rset;

	if (tout) {
		tv.tv_sec = tout / 1000000LU;
		tv.tv_usec = tout - (tv.tv_sec * 1000000LU);
	}

	if ((res = select(sockfd + 1, &rset, &wset, NULL, 
			tout ? &tv : NULL)) < 0) {
		WSYSERRNO;
		goto error;
	} else if (res == 0) {
		WERRNO(ETIMEDOUT);
		goto error;
	}

	if (FD_ISSET(sockfd, &rset) || FD_ISSET(sockfd, &wset)) {
		elen = sizeof(err);
		if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &err, &elen) < 0)
			goto error;

		if (err) {
			WERRNO(err);
			goto error;
		}
	} else {
		BUG("select returned %d for one descriptor, timeout not signaled,"
				" but no file descriptor set; socket: %d.\n", res, sockfd);
		abort();
	}
	
	/* reinstate previous blocking mode */
	if (! setsockmode(sockfd, was_blocking, NULL))
		goto error;
	
	return true;
error:
	close(sockfd);
	*_sockfd = -1;
	return false;
}
Beispiel #2
0
int connect_connections(const struct settings *settings,
		const struct client_request * req, SOCKET *client,
		unsigned int *clients) {

	const struct client_request_details * details = req->details;

	// Loop all the client requests for this thread
	while (details != NULL) {
		unsigned int i = details->n;

		if (settings->verbose) {
			char addr[NI_MAXHOST + NI_MAXSERV + 1];

			// Print the host/port
			addr_to_ipstr((const struct sockaddr *)&details->addr,
					details->addr_len, addr, sizeof(addr));

			printf("  Core %d: Connecting %d client%s to %s\n", req->cores,
					details->n, details->n > 1 ? "s" : "", addr);
		}

		// Connect all the clients
		while (i > 0) {
			int send_socket_size, recv_socket_size;

			SOCKET s = socket( AF_INET, settings->type, settings->protocol);

			if (s == INVALID_SOCKET) {
				fprintf(stderr, "%s:%d socket() error (%d) %s\n", __FILE__, __LINE__, ERRNO, strerror(ERRNO));
				return -1;
			}

#ifndef WIN32
#ifndef USE_EPOLL
			// In GNU world, a socket can't be >= FD_SETSIZE, otherwise it can't be placed into a set
			if ( s >= FD_SETSIZE ) {
				fprintf(stderr, "%s:%d socket() value too large for fd_set (%d >= %d)\n", __FILE__, __LINE__, s, FD_SETSIZE );
				return -1;
			}
#endif
#endif

			send_socket_size = set_socket_send_buffer(s, settings->socket_size);
			if (send_socket_size < 0) {
				fprintf(stderr, "%s:%d set_socket_send_buffer() error (%d) %s\n", __FILE__, __LINE__, ERRNO, strerror(ERRNO));
				goto cleanup;
			}

			recv_socket_size = set_socket_recv_buffer(s, settings->socket_size);
			if (recv_socket_size < 0) {
				fprintf(stderr, "%s:%d set_socket_recv_buffer() error (%d) %s\n", __FILE__, __LINE__, ERRNO, strerror(ERRNO));
				goto cleanup;
			}

			if (settings->verbose) {
				// TODO tidy this
				printf("client socket size: %d/%d\n", send_socket_size,
						recv_socket_size);
			}

			if (settings->disable_nagles) {
				if (disable_nagle(s) == SOCKET_ERROR) {
					fprintf(stderr, "%s:%d disable_nagle() error (%d) %s\n", __FILE__, __LINE__, ERRNO, strerror(ERRNO));
					goto cleanup;
				}

				// This works around a big where disabling Nagle's does not actually stop packets being grouped
				// I don't think its a bug, more that stack notices there are multiple packets queued that
				// haven't been sent yet, so optimistically groups them.
				if ( enable_maxseq ( s , settings->message_size ) == SOCKET_ERROR ) {
					fprintf(stderr, "%s:%d enable_maxseq() error (%d) %s\n", __FILE__, __LINE__, ERRNO, strerror(ERRNO));
					goto cleanup;
				}
			}

			if (set_socket_timeout(s, CONTROL_TIMEOUT) ) {
				fprintf(stderr, "%s:%d set_socket_timeout() error (%d) %s\n", __FILE__, __LINE__, ERRNO, strerror(ERRNO));
				goto cleanup;
			}

			if (connect_ign_signal(s, (const struct sockaddr *)&details->addr, (int)details->addr_len ) == SOCKET_ERROR) {
				fprintf(stderr, "%s:%d connect() error (%d) %s\n", __FILE__, __LINE__, ERRNO, strerror(ERRNO));
				goto cleanup;
			}

			// Always disable blocking (to work around linux bug)
			if (disable_blocking(s) == SOCKET_ERROR) {
				fprintf(stderr, "%s:%d disable_blocking() error (%d) %s\n", __FILE__, __LINE__, ERRNO, strerror(ERRNO));
				goto cleanup;
			}

			assert ( s != INVALID_SOCKET );
			assert ( *client == INVALID_SOCKET );

			*client++ = s; // Add socket s to the end of the array and move along
			(*clients)++; // Increment the count of clients

			i--;
			continue;

cleanup:
			// This cleanup section is within the loop so we can cleanup s
			closesocket(s);
			return -1;
		}

		// move onto the next client request
		details = details->next;
	}

	return 0;
}