1 #include "syshdrs.h"
2 #ifdef PRAGMA_HDRSTOP
3 #	pragma hdrstop
4 #endif
5 
6 int
SCloseSocket(int sfd)7 SCloseSocket(int sfd)
8 {
9 	int result;
10 	DECL_SIGPIPE_VARS
11 
12 	IGNORE_SIGPIPE
13 	result = closesocket(sfd);
14 	RESTORE_SIGPIPE
15 
16 	return (result);
17 }	/* SCloseSocket */
18 
19 
20 
21 #ifndef NO_SIGNALS
22 extern Sjmp_buf gNetTimeoutJmp;
23 #endif
24 
25 int
SClose(int sfd,int tlen)26 SClose(int sfd, int tlen)
27 {
28 #ifdef UNIX_SIGNALS
29 	volatile sio_sigproc_t sigalrm = (sio_sigproc_t) 0;
30 	volatile sio_sigproc_t sigpipe = (sio_sigproc_t) 0;
31 	volatile alarm_time_t oalarm = 0;
32 	int result;
33 	int oerrno;
34 
35 	if (sfd < 0) {
36 		errno = EBADF;
37 		return (-1);
38 	}
39 
40 	if (GetSocketLinger(sfd, NULL) <= 0) {
41 		/* Linger wasn't on, so close shouldn't block.
42 		 * Take the regular way out.
43 		 */
44 		return (SCloseSocket(sfd));
45 	}
46 
47 	if (tlen < 1) {
48 		/* Don't time it, shut it down now. */
49 		if (SetSocketLinger(sfd, 0, 0) == 0) {
50 			/* Linger disabled, so close()
51 			 * should not block.
52 			 */
53 			return (SCloseSocket(sfd));
54 		} else {
55 			/* This may result in a fd leak,
56 			 * but it's either that or hang forever.
57 			 */
58 			(void) shutdown(sfd, 2);
59 			return (SCloseSocket(sfd));
60 		}
61 	}
62 
63 	if (SSetjmp(gNetTimeoutJmp) != 0) {
64 		(void) alarm(0);
65 		(void) SetSocketLinger(sfd, 0, 0);
66 		errno = 0;
67 		(void) shutdown(sfd, 2);
68 		result = closesocket(sfd);
69 		oerrno = errno;
70 		(void) SSignal(SIGALRM, (sio_sigproc_t) sigalrm);
71 		(void) SSignal(SIGPIPE, (sio_sigproc_t) sigpipe);
72 		(void) alarm(oalarm);
73 		errno = oerrno;
74 		return (result);
75 	}
76 
77 	sigalrm = (sio_sigproc_t) SSignal(SIGALRM, SIOHandler);
78 	sigpipe = (sio_sigproc_t) SSignal(SIGPIPE, SIG_IGN);
79 
80 	oalarm = alarm((alarm_time_t) tlen);
81 	for (errno = 0;;) {
82 		result = closesocket(sfd);
83 		if (result == 0)
84 			break;
85 		if (errno != EINTR)
86 			break;
87 	}
88 	oerrno = errno;
89 	(void) alarm(0);
90 
91 	if ((result != 0) && (errno != EBADF)) {
92 		(void) SetSocketLinger(sfd, 0, 0);
93 		(void) shutdown(sfd, 2);
94 		result = closesocket(sfd);
95 		oerrno = errno;
96 	}
97 
98 	(void) SSignal(SIGALRM, (sio_sigproc_t) sigalrm);
99 	(void) SSignal(SIGPIPE, (sio_sigproc_t) sigpipe);
100 	(void) alarm(oalarm);
101 	errno = oerrno;
102 
103 	return (result);
104 #else	/* ! UNIX_SIGNALS */
105 	if (sfd < 0) {
106 		errno = EBADF;
107 		return (-1);
108 	}
109 
110 	/* Sorry... it's up to you to make sure you don't block forever
111 	 * on closesocket() since this platform doesn't have alarm().
112 	 * Even so, it shouldn't be a problem unless you use linger mode
113 	 * on the socket, and nobody does that these days.
114 	 */
115 	return (SCloseSocket(sfd));
116 #endif
117 }	/* SClose */
118