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 SClose(int sfd, int tlen) 10 { 11 #ifndef NO_SIGNALS 12 vsio_sigproc_t sigalrm, sigpipe; 13 14 if (sfd < 0) { 15 errno = EBADF; 16 return (-1); 17 } 18 19 if (tlen < 1) { 20 /* Don't time it, shut it down now. */ 21 if (SetSocketLinger(sfd, 0, 0) == 0) { 22 /* Linger disabled, so close() 23 * should not block. 24 */ 25 return (closesocket(sfd)); 26 } else { 27 /* This will result in a fd leak, 28 * but it's either that or hang forever. 29 */ 30 return (shutdown(sfd, 2)); 31 } 32 } 33 34 if (SSetjmp(gNetTimeoutJmp) != 0) { 35 alarm(0); 36 (void) SSignal(SIGALRM, (sio_sigproc_t) sigalrm); 37 (void) SSignal(SIGPIPE, (sio_sigproc_t) sigpipe); 38 if (SetSocketLinger(sfd, 0, 0) == 0) { 39 /* Linger disabled, so close() 40 * should not block. 41 */ 42 return closesocket(sfd); 43 } else { 44 /* This will result in a fd leak, 45 * but it's either that or hang forever. 46 */ 47 (void) shutdown(sfd, 2); 48 } 49 return (-1); 50 } 51 52 sigalrm = (vsio_sigproc_t) SSignal(SIGALRM, SIOHandler); 53 sigpipe = (vsio_sigproc_t) SSignal(SIGPIPE, SIG_IGN); 54 55 alarm((unsigned int) tlen); 56 for (;;) { 57 if (closesocket(sfd) == 0) { 58 errno = 0; 59 break; 60 } 61 if (errno != EINTR) 62 break; 63 } 64 alarm(0); 65 (void) SSignal(SIGALRM, (sio_sigproc_t) sigalrm); 66 67 if ((errno != 0) && (errno != EBADF)) { 68 if (SetSocketLinger(sfd, 0, 0) == 0) { 69 /* Linger disabled, so close() 70 * should not block. 71 */ 72 (void) closesocket(sfd); 73 } else { 74 /* This will result in a fd leak, 75 * but it's either that or hang forever. 76 */ 77 (void) shutdown(sfd, 2); 78 } 79 } 80 (void) SSignal(SIGPIPE, (sio_sigproc_t) sigpipe); 81 82 return ((errno == 0) ? 0 : (-1)); 83 #else 84 struct timeval tv; 85 int result; 86 time_t done, now; 87 fd_set ss; 88 89 if (sfd < 0) { 90 errno = EBADF; 91 return (-1); 92 } 93 94 if (tlen < 1) { 95 /* Don't time it, shut it down now. */ 96 if (SetSocketLinger(sfd, 0, 0) == 0) { 97 /* Linger disabled, so close() 98 * should not block. 99 */ 100 return (closesocket(sfd)); 101 } else { 102 /* This will result in a fd leak, 103 * but it's either that or hang forever. 104 */ 105 return (shutdown(sfd, 2)); 106 } 107 } 108 109 /* Wait until the socket is ready for writing (usually easy). */ 110 time(&now); 111 done = now + tlen; 112 113 forever { 114 tlen = done - now; 115 if (tlen <= 0) { 116 /* timeout */ 117 if (SetSocketLinger(sfd, 0, 0) == 0) { 118 /* Linger disabled, so close() 119 * should not block. 120 */ 121 (void) closesocket(sfd); 122 } else { 123 /* This will result in a fd leak, 124 * but it's either that or hang forever. 125 */ 126 (void) shutdown(sfd, 2); 127 } 128 errno = ETIMEDOUT; 129 return (kTimeoutErr); 130 } 131 132 errno = 0; 133 FD_ZERO(&ss); 134 FD_SET(sfd, &ss); 135 tv.tv_sec = tlen; 136 tv.tv_usec = 0; 137 result = select(sfd + 1, NULL, SELECT_TYPE_ARG234 &ss, NULL, SELECT_TYPE_ARG5 &tv); 138 if (result == 1) { 139 /* ready */ 140 break; 141 } else if (result == 0) { 142 /* timeout */ 143 if (SetSocketLinger(sfd, 0, 0) == 0) { 144 /* Linger disabled, so close() 145 * should not block. 146 */ 147 (void) closesocket(sfd); 148 } else { 149 /* This will result in a fd leak, 150 * but it's either that or hang forever. 151 */ 152 (void) shutdown(sfd, 2); 153 } 154 errno = ETIMEDOUT; 155 return (kTimeoutErr); 156 } else if (errno != EINTR) { 157 /* Error, done. This end may have been shutdown. */ 158 break; 159 } 160 time(&now); 161 } 162 163 /* Wait until the socket is ready for reading. */ 164 forever { 165 tlen = done - now; 166 if (tlen <= 0) { 167 /* timeout */ 168 if (SetSocketLinger(sfd, 0, 0) == 0) { 169 /* Linger disabled, so close() 170 * should not block. 171 */ 172 (void) closesocket(sfd); 173 } else { 174 /* This will result in a fd leak, 175 * but it's either that or hang forever. 176 */ 177 (void) shutdown(sfd, 2); 178 } 179 errno = ETIMEDOUT; 180 return (kTimeoutErr); 181 } 182 183 errno = 0; 184 FD_ZERO(&ss); 185 FD_SET(sfd, &ss); 186 tv.tv_sec = tlen; 187 tv.tv_usec = 0; 188 result = select(sfd + 1, SELECT_TYPE_ARG234 &ss, NULL, NULL, SELECT_TYPE_ARG5 &tv); 189 if (result == 1) { 190 /* ready */ 191 break; 192 } else if (result == 0) { 193 /* timeout */ 194 if (SetSocketLinger(sfd, 0, 0) == 0) { 195 /* Linger disabled, so close() 196 * should not block. 197 */ 198 (void) closesocket(sfd); 199 } else { 200 /* This will result in a fd leak, 201 * but it's either that or hang forever. 202 */ 203 (void) shutdown(sfd, 2); 204 } 205 errno = ETIMEDOUT; 206 return (kTimeoutErr); 207 } else if (errno != EINTR) { 208 /* Error, done. This end may have been shutdown. */ 209 break; 210 } 211 time(&now); 212 } 213 214 /* If we get here, close() won't block. */ 215 return closesocket(sfd); 216 #endif 217 } /* SClose */ 218