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; }
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; }