Version 1.8.0.0
[socat.git] / xioshutdown.c
blobc1ec796672d8c10fc6f856c350ab87a733b1957e
1 /* source: xioshutdown.c */
2 /* Copyright Gerhard Rieger and contributors (see file CHANGES) */
3 /* Published under the GNU General Public License V.2, see file COPYING */
5 /* this is the source of the extended shutdown function */
8 #include "xiosysincludes.h"
9 #include "xioopen.h"
11 #include "xio-openssl.h"
13 static pid_t socat_kill_pid; /* here we pass the pid to be killed in sighandler */
15 static void signal_kill_pid(int dummy) {
16 int _errno;
17 _errno = errno;
18 diag_in_handler = 1;
19 Notice("SIGALRM while waiting for wo child process to die, killing it now");
20 Kill(socat_kill_pid, SIGTERM);
21 diag_in_handler = 0;
22 errno = _errno;
25 int xioshutdown(xiofile_t *sock, int how) {
26 int result = 0;
28 if (sock->tag == XIO_TAG_INVALID || sock->tag & XIO_TAG_CLOSED) {
29 Error("xioshutdown(): invalid file descriptor");
30 errno = EINVAL;
31 return -1;
34 if (sock->tag == XIO_TAG_DUAL) {
35 if ((how+1)&1) {
36 result = xioshutdown((xiofile_t *)sock->dual.stream[0], 0);
38 if ((how+1)&2) {
39 result |= xioshutdown((xiofile_t *)sock->dual.stream[1], 1);
41 return result;
44 switch (sock->stream.howtoshut) {
45 char writenull;
46 case XIOSHUT_NONE:
47 return 0;
48 case XIOSHUT_CLOSE:
49 if (Close(sock->stream.fd) < 0) {
50 Info2("close(%d): %s",
51 sock->stream.fd, strerror(errno));
53 return 0;
54 case XIOSHUT_DOWN:
55 result = Shutdown(sock->stream.fd, how);
56 if (result < 0) {
57 int level, _errno = errno;
58 switch (_errno) {
59 case EPIPE:
60 case ECONNRESET:
61 level = E_ERROR;
62 break;
63 default:
64 level = E_INFO; /* old behaviour */
65 break;
67 Msg3(level, "shutdown(%d, %d): %s",
68 sock->stream.fd, how, strerror(_errno));
69 errno = _errno;
70 return -1;
72 return 0;
73 #if _WITH_SOCKET
74 case XIOSHUT_NULL:
75 writenull = '\0'; /* assign something to make gcc happy */
76 /* send an empty packet; only useful on datagram sockets? */
77 xiowrite(sock, &writenull, 0);
78 return 0;
79 #endif /* _WITH_SOCKET */
80 default: ;
82 /* XIOSHUT_UNSPEC passes on */
84 if (false) {
86 #if WITH_OPENSSL
87 } else if ((sock->stream.dtype & XIODATA_MASK) == XIODATA_OPENSSL) {
88 xioshutdown_openssl(&sock->stream, how);
89 #endif /* WITH_OPENSSL */
91 } else if ((sock->stream.dtype & XIODATA_MASK) == XIODATA_PIPE) {
92 if ((how+1)&1) {
93 if (Close(sock->stream.fd) < 0) {
94 Info2("close(%d): %s",
95 sock->stream.fd, strerror(errno));
98 if ((how+1)&2) {
99 if (Close(sock->stream.para.bipipe.fdout) < 0) {
100 Info2("close(%d): %s",
101 sock->stream.para.bipipe.fdout, strerror(errno));
105 } else if ((sock->stream.dtype & XIODATA_MASK) == XIODATA_2PIPE) {
106 if ((how+1)&1) {
107 if (Close(sock->stream.fd) < 0) {
108 Info2("close(%d): %s",
109 sock->stream.fd, strerror(errno));
112 if ((how+1)&2) {
113 if (Close(sock->stream.para.exec.fdout) < 0) {
114 Info2("close(%d): %s",
115 sock->stream.para.exec.fdout, strerror(errno));
118 #if _WITH_SOCKET
119 } else if (sock->stream.howtoend == END_SHUTDOWN) {
120 if ((result = Shutdown(sock->stream.fd, how)) < 0) {
121 Info3("shutdown(%d, %d): %s",
122 sock->stream.fd, how, strerror(errno));
124 } else if (sock->stream.howtoend == END_SHUTDOWN_KILL) {
125 if ((result = Shutdown(sock->stream.fd, how)) < 0) {
126 Info3("shutdown(%d, %d): %s",
127 sock->stream.fd, how, strerror(errno));
129 if ((sock->stream.flags&XIO_ACCMODE) == XIO_WRONLY) {
130 pid_t pid;
131 int level;
133 /* the child process might want to flush some data before terminating
135 int status = 0;
137 /* we wait for the child process to die, but to prevent timeout
138 we raise an alarm after some time.
139 NOTE: the alarm does not terminate waitpid() on Linux/glibc (BUG?),
140 therefore we have to do the kill in the signal handler */
142 struct sigaction act;
143 sigfillset(&act.sa_mask);
144 act.sa_flags = 0;
145 act.sa_handler = signal_kill_pid;
146 Sigaction(SIGALRM, &act, NULL);
148 socat_kill_pid = sock->stream.para.exec.pid;
149 #if HAVE_SETITIMER
150 /*! with next feature release, we get usec resolution and an option */
151 #else
152 Alarm(1 /*! sock->stream.para.exec.waitdie */);
153 #endif /* !HAVE_SETITIMER */
154 pid = Waitpid(sock->stream.para.exec.pid, &status, 0);
155 if (pid < 0) {
156 if (errno == EINTR)
157 level = E_INFO;
158 else
159 level = E_WARN;
160 Msg3(level, "waitpid("F_pid", %p, 0): %s",
161 sock->stream.para.exec.pid, &status, strerror(errno));
163 Alarm(0);
165 } else if ((sock->stream.dtype & XIODATA_MASK) ==
166 (XIODATA_RECVFROM & XIODATA_MASK)) {
167 if (how >= 1) {
168 if (Close(sock->stream.fd) < 0) {
169 Info2("close(%d): %s",
170 sock->stream.fd, strerror(errno));
172 sock->stream.eof = 2;
173 sock->stream.fd = -1;
175 #endif /* _WITH_SOCKET */
176 #if 0
177 } else {
178 Error1("xioshutdown(): bad data type specification %d", sock->stream.dtype);
179 return -1;
180 #endif
183 #if 0
184 else if (sock->stream.howtoend == END_CLOSE &&
185 sock->stream.dtype == DATA_STREAM) {
186 return result;
188 #if WITH_TERMIOS
189 if (sock->stream.ttyvalid) {
190 if (Tcsetattr(sock->stream.fd, TCSAFLUSH, &sock->stream.savetty) < 0) {
191 Warn2("cannot restore terminal settings on fd %d: %s",
192 sock->stream.fd, strerror(errno));
195 #endif /* WITH_TERMIOS */
196 #endif
198 return result;