/ncftp-3.2.5/sio/SClose.c
C | 117 lines | 85 code | 17 blank | 15 comment | 18 complexity | 624def82ed8ba1b3156d3bd26630f7d5 MD5 | raw file
Possible License(s): AGPL-3.0
1#include "syshdrs.h"
2#ifdef PRAGMA_HDRSTOP
3# pragma hdrstop
4#endif
5
6int
7SCloseSocket(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
22extern Sjmp_buf gNetTimeoutJmp;
23#endif
24
25int
26SClose(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 */