R_API int r_socket_connect (RSocket *s, const char *host, const char *port, int proto, int timeout) { #if __WINDOWS__ struct sockaddr_in sa; struct hostent *he; WSADATA wsadata; if (WSAStartup (MAKEWORD (1, 1), &wsadata) == SOCKET_ERROR) { eprintf ("Error creating socket."); return R_FALSE; } s->fd = socket (AF_INET, SOCK_STREAM, 0); if (s->fd == -1) return R_FALSE; memset (&sa, 0, sizeof(sa)); sa.sin_family = AF_INET; he = (struct hostent *)gethostbyname (host); if (he == (struct hostent*)0) { close (s->fd); return R_FALSE; } sa.sin_addr = *((struct in_addr *)he->h_addr); sa.sin_port = htons (atoi (port)); #warning TODO: implement connect timeout on w32 if (connect (s->fd, (const struct sockaddr*)&sa, sizeof (struct sockaddr))) { close (s->fd); return R_FALSE; } return R_TRUE; #elif __UNIX__ if (proto==0) proto= R_SOCKET_PROTO_TCP; int gai, ret; struct addrinfo hints, *res, *rp; signal (SIGPIPE, SIG_IGN); if (proto == R_SOCKET_PROTO_UNIX) { if (!r_socket_unix_connect (s, host)) return R_FALSE; } else { memset (&hints, 0, sizeof (struct addrinfo)); hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ hints.ai_protocol = proto; gai = getaddrinfo (host, port, &hints, &res); if (gai != 0) { //eprintf ("Error in getaddrinfo: %s\n", gai_strerror (gai)); return R_FALSE; } for (rp = res; rp != NULL; rp = rp->ai_next) { s->fd = socket (rp->ai_family, rp->ai_socktype, rp->ai_protocol); if (s->fd == -1) continue; if (timeout>0) fcntl (s->fd, F_SETFL, O_NONBLOCK, 1); ret = connect (s->fd, rp->ai_addr, rp->ai_addrlen); if (timeout<1 && ret != -1) break; if (timeout>0) { struct timeval tv; fd_set fdset; FD_ZERO (&fdset); FD_SET (s->fd, &fdset); tv.tv_sec = timeout; tv.tv_usec = 0; if (select (s->fd + 1, NULL, &fdset, NULL, &tv) == 1) { int so_error; socklen_t len = sizeof so_error; ret = getsockopt (s->fd, SOL_SOCKET, SO_ERROR, &so_error, &len); fcntl (s->fd, F_SETFL, O_NONBLOCK, 0); } else { close (s->fd); return R_FALSE; } } //rp = NULL; close (s->fd); s->fd = -1; } freeaddrinfo (res); if (rp == NULL) { //eprintf ("Could not connect\n"); return R_FALSE; } } #endif #if HAVE_LIB_SSL if (s->is_ssl) { s->ctx = SSL_CTX_new (SSLv23_client_method ()); if (s->ctx == NULL) { r_socket_free (s); return R_FALSE; } s->sfd = SSL_new (s->ctx); SSL_set_fd (s->sfd, s->fd); if (SSL_connect (s->sfd) != 1) { r_socket_free (s); return R_FALSE; } } #endif return R_TRUE; }
R_API int r_socket_connect (RSocket *s, const char *host, const char *port, int proto, unsigned int timeout) { #if __WINDOWS__ && !defined(__CYGWIN__) && !defined(__MINGW64__) struct sockaddr_in sa; struct hostent *he; WSADATA wsadata; if (WSAStartup (MAKEWORD (1, 1), &wsadata) == SOCKET_ERROR) { eprintf ("Error creating socket."); return false; } s->fd = socket (AF_INET, SOCK_STREAM, 0); if (s->fd == -1) return false; memset (&sa, 0, sizeof(sa)); sa.sin_family = AF_INET; he = (struct hostent *)gethostbyname (host); if (he == (struct hostent*)0) { close (s->fd); return false; } sa.sin_addr = *((struct in_addr *)he->h_addr); s->port = r_socket_port_by_name (port); sa.sin_port = htons (s->port); #warning TODO: implement connect timeout on w32 if (connect (s->fd, (const struct sockaddr*)&sa, sizeof (struct sockaddr))) { close (s->fd); return false; } return true; #elif __UNIX__ || defined(__CYGWIN__) int gai, ret; struct addrinfo hints, *res, *rp; if (!proto) proto = R_SOCKET_PROTO_TCP; signal (SIGPIPE, SIG_IGN); if (proto == R_SOCKET_PROTO_UNIX) { if (!r_socket_unix_connect (s, host)) return false; } else { memset (&hints, 0, sizeof (struct addrinfo)); hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ hints.ai_protocol = proto; gai = getaddrinfo (host, port, &hints, &res); if (gai != 0) { //eprintf ("Error in getaddrinfo: %s\n", gai_strerror (gai)); return false; } for (rp = res; rp != NULL; rp = rp->ai_next) { int flag = 1; s->fd = socket (rp->ai_family, rp->ai_socktype, rp->ai_protocol); if (s->fd == -1) continue; ret = setsockopt (s->fd, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(flag)); if (ret < 0) { close (s->fd); s->fd = -1; continue; } if (timeout>0) { r_socket_block_time (s, 1, timeout); //fcntl (s->fd, F_SETFL, O_NONBLOCK, 1); } ret = connect (s->fd, rp->ai_addr, rp->ai_addrlen); if (timeout == 0 && ret == 0) { freeaddrinfo (res); return true; } else if (ret == 0 /* || nonblocking */) { struct timeval tv; fd_set fdset, errset; FD_ZERO (&fdset); FD_SET (s->fd, &fdset); tv.tv_sec = 1; //timeout; tv.tv_usec = 0; if (r_socket_is_connected (s)) { freeaddrinfo (res); return true; } if (select (s->fd + 1, NULL, NULL, &errset, &tv) == 1) { int so_error; socklen_t len = sizeof so_error; ret = getsockopt (s->fd, SOL_SOCKET, SO_ERROR, &so_error, &len); if (ret == 0 && so_error == 0) { //fcntl (s->fd, F_SETFL, O_NONBLOCK, 0); //r_socket_block_time (s, 0, 0); freeaddrinfo (res); return true; } } } close (s->fd); s->fd = -1; } freeaddrinfo (res); if (rp == NULL) { eprintf ("Could not resolve address '%s'\n", host); return false; } } #endif #if HAVE_LIB_SSL if (s->is_ssl) { s->ctx = SSL_CTX_new (SSLv23_client_method ()); if (s->ctx == NULL) { r_socket_free (s); return false; } s->sfd = SSL_new (s->ctx); SSL_set_fd (s->sfd, s->fd); if (SSL_connect (s->sfd) != 1) { r_socket_free (s); return false; } } #endif return true; }
R_API int r_socket_connect (RSocket *s, const char *host, const char *port, int proto) { #if __WINDOWS__ struct sockaddr_in sa; struct hostent *he; WSADATA wsadata; if (WSAStartup (MAKEWORD (1, 1), &wsadata) == SOCKET_ERROR) { eprintf ("Error creating socket."); return R_FALSE; } s->fd = socket (AF_INET, SOCK_STREAM, 0); if (s->fd == -1) return R_FALSE; memset (&sa, 0, sizeof(sa)); sa.sin_family = AF_INET; he = (struct hostent *)gethostbyname (host); if (he == (struct hostent*)0) { close (s->fd); return R_FALSE; } sa.sin_addr = *((struct in_addr *)he->h_addr); sa.sin_port = htons (atoi (port)); if (connect (s->fd, (const struct sockaddr*)&sa, sizeof (struct sockaddr))) { close (s->fd); return R_FALSE; } return R_TRUE; #elif __UNIX__ if (proto==0) proto= R_SOCKET_PROTO_TCP; int gai; struct addrinfo hints, *res, *rp; signal (SIGPIPE, SIG_IGN); if (proto == R_SOCKET_PROTO_UNIX) { if (!r_socket_unix_connect (s, host)) return R_FALSE; } else { memset (&hints, 0, sizeof (struct addrinfo)); hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ hints.ai_protocol = proto; gai = getaddrinfo (host, port, &hints, &res); if (gai != 0) { eprintf ("Error in getaddrinfo: %s\n", gai_strerror (gai)); return R_FALSE; } for (rp = res; rp != NULL; rp = rp->ai_next) { s->fd = socket (rp->ai_family, rp->ai_socktype, rp->ai_protocol); if (s->fd == -1) continue; if (connect (s->fd, rp->ai_addr, rp->ai_addrlen) != -1) break; close (s->fd); } if (rp == NULL) { eprintf ("Could not connect\n"); return R_FALSE; } freeaddrinfo (res); } #endif #if HAVE_LIB_SSL if (s->is_ssl) { s->ctx = SSL_CTX_new (SSLv23_client_method ()); if (s->ctx == NULL) { r_socket_free (s); return R_FALSE; } s->sfd = SSL_new (s->ctx); SSL_set_fd (s->sfd, s->fd); if (SSL_connect (s->sfd) != 1) { r_socket_free (s); return R_FALSE; } } #endif return R_TRUE; }
R_API bool r_socket_connect(RSocket *s, const char *host, const char *port, int proto, unsigned int timeout) { #if __WINDOWS__ struct sockaddr_in sa; struct hostent *he; WSADATA wsadata; TIMEVAL Timeout; Timeout.tv_sec = timeout; Timeout.tv_usec = 0; if (WSAStartup (MAKEWORD (1, 1), &wsadata) == SOCKET_ERROR) { eprintf ("Error creating socket."); return false; } s->fd = socket (AF_INET, SOCK_STREAM, 0); #ifdef _MSC_VER if (s->fd == INVALID_SOCKET) { #else if (s->fd == -1) { #endif return false; } unsigned long iMode = 1; int iResult = ioctlsocket (s->fd, FIONBIO, &iMode); if (iResult != NO_ERROR) { eprintf ("ioctlsocket error: %d\n", iResult); } memset (&sa, 0, sizeof(sa)); sa.sin_family = AF_INET; he = (struct hostent *)gethostbyname (host); if (he == (struct hostent*)0) { #ifdef _MSC_VER closesocket (s->fd); #else close (s->fd); #endif return false; } sa.sin_addr = *((struct in_addr *)he->h_addr); s->port = r_socket_port_by_name (port); sa.sin_port = htons (s->port); if (!connect (s->fd, (const struct sockaddr*)&sa, sizeof (struct sockaddr))) { #ifdef _MSC_VER closesocket (s->fd); #else close (s->fd); #endif return false; } iMode = 0; iResult = ioctlsocket (s->fd, FIONBIO, &iMode); if (iResult != NO_ERROR) { eprintf ("ioctlsocket error: %d\n", iResult); } if (timeout > 0) { r_socket_block_time (s, 1, timeout); } fd_set Write, Err; FD_ZERO (&Write); FD_ZERO (&Err); FD_SET (s->fd, &Write); FD_SET (s->fd, &Err); select (0, NULL, &Write, &Err, &Timeout); if (FD_ISSET (s->fd, &Write)) { return true; } return false; #elif __UNIX__ int ret; struct addrinfo hints = {0}; struct addrinfo *res, *rp; if (!proto) { proto = R_SOCKET_PROTO_TCP; } signal (SIGPIPE, SIG_IGN); if (proto == R_SOCKET_PROTO_UNIX) { if (!r_socket_unix_connect (s, host)) { return false; } } else { hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ hints.ai_protocol = proto; int gai = getaddrinfo (host, port, &hints, &res); if (gai != 0) { eprintf ("Error in getaddrinfo: %s\n", gai_strerror (gai)); return false; } for (rp = res; rp != NULL; rp = rp->ai_next) { int flag = 1; s->fd = socket (rp->ai_family, rp->ai_socktype, rp->ai_protocol); if (s->fd == -1) { perror ("socket"); continue; } ret = setsockopt (s->fd, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof (flag)); if (ret < 0) { perror ("setsockopt"); close (s->fd); s->fd = -1; continue; } if (timeout > 0) { r_socket_block_time (s, 1, timeout); //fcntl (s->fd, F_SETFL, O_NONBLOCK, 1); } ret = connect (s->fd, rp->ai_addr, rp->ai_addrlen); if (timeout == 0 && ret == 0) { freeaddrinfo (res); return true; } if (ret == 0 /* || nonblocking */) { struct timeval tv; fd_set fdset, errset; FD_ZERO (&fdset); FD_SET (s->fd, &fdset); tv.tv_sec = 1; //timeout; tv.tv_usec = 0; if (r_socket_is_connected (s)) { freeaddrinfo (res); return true; } if (select (s->fd + 1, NULL, NULL, &errset, &tv) == 1) { int so_error; socklen_t len = sizeof so_error; ret = getsockopt (s->fd, SOL_SOCKET, SO_ERROR, &so_error, &len); if (ret == 0 && so_error == 0) { //fcntl (s->fd, F_SETFL, O_NONBLOCK, 0); //r_socket_block_time (s, 0, 0); freeaddrinfo (res); return true; } } } close (s->fd); s->fd = -1; } freeaddrinfo (res); if (!rp) { eprintf ("Could not resolve address '%s' or failed to connect\n", host); return false; } } #endif #if HAVE_LIB_SSL if (s->is_ssl) { s->ctx = SSL_CTX_new (SSLv23_client_method ()); if (!s->ctx) { r_socket_free (s); return false; } s->sfd = SSL_new (s->ctx); SSL_set_fd (s->sfd, s->fd); if (SSL_connect (s->sfd) != 1) { r_socket_free (s); return false; } } #endif return true; } /* close the file descriptor associated with the RSocket s */ R_API int r_socket_close_fd(RSocket *s) { #ifdef _MSC_VER return s->fd != INVALID_SOCKET ? closesocket (s->fd) : false; #else return s->fd != -1 ? close (s->fd) : false; #endif } /* shutdown the socket and close the file descriptor */ R_API int r_socket_close(RSocket *s) { int ret = false; if (!s) { return false; } if (s->fd != -1) { #if __UNIX__ shutdown (s->fd, SHUT_RDWR); #endif #if __WINDOWS__ // https://msdn.microsoft.com/en-us/library/windows/desktop/ms740481(v=vs.85).aspx shutdown (s->fd, SD_SEND); if (r_socket_ready (s, 0, 250)) { do { char buf = 0; ret = recv (s->fd, &buf, 1, 0); } while (ret != 0 && ret != SOCKET_ERROR); } ret = closesocket (s->fd); #else ret = close (s->fd); #endif } #if HAVE_LIB_SSL if (s->is_ssl && s->sfd) { SSL_free (s->sfd); s->sfd = NULL; } #endif return ret; }