1 #include "syshdrs.h" 2 3 #ifndef NO_SIGNALS 4 extern volatile Sjmp_buf gNetTimeoutJmp; 5 extern volatile Sjmp_buf gPipeJmp; 6 #endif 7 8 int 9 SConnect(int sfd, const struct sockaddr_in *const addr, int tlen) 10 { 11 #ifndef NO_SIGNALS 12 int result; 13 vsio_sigproc_t sigalrm; 14 15 if (SSetjmp(gNetTimeoutJmp) != 0) { 16 alarm(0); 17 (void) SSignal(SIGALRM, (sio_sigproc_t) sigalrm); 18 errno = ETIMEDOUT; 19 return (kTimeoutErr); 20 } 21 22 sigalrm = (vsio_sigproc_t) SSignal(SIGALRM, SIOHandler); 23 alarm((unsigned int) tlen); 24 25 errno = 0; 26 do { 27 result = connect(sfd, (struct sockaddr *) addr, 28 (int) sizeof(struct sockaddr_in)); 29 } while ((result < 0) && (errno == EINTR)); 30 31 alarm(0); 32 (void) SSignal(SIGALRM, (sio_sigproc_t) sigalrm); 33 return (result); 34 #else /* NO_SIGNALS */ 35 unsigned long opt; 36 fd_set ss, xx; 37 struct timeval tv; 38 int result; 39 int cErrno; 40 #if defined(WIN32) || defined(_WINDOWS) 41 int wsaErrno; 42 int soerr, soerrsize; 43 #else 44 int optval; 45 int optlen; 46 #endif 47 48 errno = 0; 49 if (tlen <= 0) { 50 do { 51 result = connect(sfd, (struct sockaddr *) addr, 52 (int) sizeof(struct sockaddr_in)); 53 SETERRNO 54 } while ((result < 0) && (errno == EINTR)); 55 return (result); 56 } 57 58 #ifdef FIONBIO 59 opt = 1; 60 if (ioctlsocket(sfd, FIONBIO, &opt) != 0) { 61 SETERRNO 62 return (-1); 63 } 64 #else 65 if (fcntl(sfd, F_GETFL, &opt) < 0) { 66 SETERRNO 67 return (-1); 68 } else if (fcntl(sfd, F_SETFL, opt | O_NONBLOCK) < 0) { 69 SETERRNO 70 return (-1); 71 } 72 #endif 73 74 errno = 0; 75 result = connect(sfd, (struct sockaddr *) addr, 76 (int) sizeof(struct sockaddr_in)); 77 if (result == 0) 78 return 0; /* Already?!? */ 79 80 if ((result < 0) 81 #if defined(WIN32) || defined(_WINDOWS) 82 && ((wsaErrno = WSAGetLastError()) != WSAEWOULDBLOCK) 83 && (wsaErrno != WSAEINPROGRESS) 84 #else 85 && (errno != EWOULDBLOCK) && (errno != EINPROGRESS) 86 #endif 87 ) { 88 SETERRNO 89 shutdown(sfd, 2); 90 return (-1); 91 } 92 cErrno = errno; 93 94 forever { 95 #if defined(WIN32) || defined(_WINDOWS) 96 WSASetLastError(0); 97 #endif 98 FD_ZERO(&ss); 99 FD_SET(sfd, &ss); 100 xx = ss; 101 tv.tv_sec = tlen; 102 tv.tv_usec = 0; 103 result = select(sfd + 1, NULL, SELECT_TYPE_ARG234 &ss, SELECT_TYPE_ARG234 &xx, SELECT_TYPE_ARG5 &tv); 104 if (result == 1) { 105 /* ready */ 106 break; 107 } else if (result == 0) { 108 /* timeout */ 109 errno = ETIMEDOUT; 110 SETWSATIMEOUTERR 111 /* Don't bother turning off FIONBIO */ 112 return (kTimeoutErr); 113 } else if (errno != EINTR) { 114 /* Don't bother turning off FIONBIO */ 115 SETERRNO 116 return (-1); 117 } 118 } 119 120 /* Supposedly once the select() returns with a writable 121 * descriptor, it is connected and we don't need to 122 * recall connect(). When select() returns an exception, 123 * the connection failed -- we can get the connect error 124 * doing a write on the socket which will err out. 125 */ 126 127 if (FD_ISSET(sfd, &xx)) { 128 #if defined(WIN32) || defined(_WINDOWS) 129 errno = 0; 130 soerr = 0; 131 soerrsize = sizeof(soerr); 132 result = getsockopt(sfd, SOL_SOCKET, SO_ERROR, (char *) &soerr, &soerrsize); 133 if ((result >= 0) && (soerr != 0)) { 134 errno = soerr; 135 } else { 136 errno = 0; 137 (void) send(sfd, "\0", 1, 0); 138 SETERRNO 139 } 140 #else 141 errno = 0; 142 (void) send(sfd, "\0", 1, 0); 143 #endif 144 result = errno; 145 shutdown(sfd, 2); 146 errno = result; 147 return (-1); 148 } 149 150 #if defined(WIN32) || defined(_WINDOWS) 151 #else 152 if (cErrno == EINPROGRESS) { 153 /* 154 * [from Linux connect(2) page] 155 * 156 * EINPROGRESS 157 * 158 * The socket is non-blocking and the connection can� 159 * not be completed immediately. It is possible to 160 * select(2) or poll(2) for completion by selecting 161 * the socket for writing. After select indicates 162 * writability, use getsockopt(2) to read the 163 * SO_ERROR option at level SOL_SOCKET to determine 164 * whether connect completed successfully (SO_ERROR 165 * is zero) or unsuccessfully (SO_ERROR is one of the 166 * usual error codes listed above, explaining the 167 * reason for the failure). 168 */ 169 optval = 0; 170 optlen = sizeof(optval); 171 if (getsockopt(sfd, SOL_SOCKET, SO_ERROR, &optval, &optlen) == 0) { 172 errno = optval; 173 if (errno != 0) 174 return (-1); 175 } 176 } 177 #endif 178 179 #ifdef FIONBIO 180 opt = 0; 181 if (ioctlsocket(sfd, FIONBIO, &opt) != 0) { 182 SETERRNO 183 shutdown(sfd, 2); 184 return (-1); 185 } 186 #else 187 if (fcntl(sfd, F_SETFL, opt) < 0) { 188 SETERRNO 189 shutdown(sfd, 2); 190 return (-1); 191 } 192 #endif 193 194 return (0); 195 #endif /* NO_SIGNALS */ 196 } /* SConnect */ 197