nexmon – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 /* source: xioshutdown.c */
2 /* Copyright Gerhard Rieger */
3 /* Published under the GNU General Public License V.2, see file COPYING */
4  
5 /* this is the source of the extended shutdown function */
6  
7  
8 #include "xiosysincludes.h"
9 #include "xioopen.h"
10  
11  
12 static int xioshut_sleep_kill(pid_t sub, unsigned long usec, int sig);
13  
14 static pid_t socat_kill_pid; /* here we pass the pid to be killed in sighandler */
15  
16 static void signal_kill_pid(int dummy) {
17 int _errno;
18 _errno = errno;
19 diag_in_handler = 1;
20 Notice("SIGALRM while waiting for w/o child process to die, killing it now");
21 Kill(socat_kill_pid, SIGTERM);
22 diag_in_handler = 0;
23 errno = _errno;
24 }
25  
26 /* how: SHUT_RD, SHUT_WR, or SHUT_RDWR */
27 int xioshutdown(xiofile_t *sock, int how) {
28 int fd;
29 int result = 0;
30  
31 Debug2("xioshutdown(%p, %d)", sock, how);
32 Debug2("xioshutdown(): dtype=0x%x, howtoshut=0x%04x",
33 sock->stream.dtype, sock->stream.howtoshut);
34  
35 if (sock->tag == XIO_TAG_INVALID) {
36 Error("xioshutdown(): invalid file descriptor");
37 errno = EINVAL;
38 return -1;
39 }
40  
41 /*Debug3("xioshutdown: flags=%d, dtype=%d, howtoclose=%d", sock->stream.flags, sock->stream.dtype, sock->stream.howtoclose);*/
42 if (sock->tag == XIO_TAG_DUAL) {
43 if ((how+1)&1) {
44 result = xioshutdown((xiofile_t *)sock->dual.stream[0], 0);
45 }
46 if ((how+1)&2) {
47 result |= xioshutdown((xiofile_t *)sock->dual.stream[1], 1);
48 }
49 return result;
50 }
51  
52 fd = XIO_GETWRFD(sock);
53  
54 /* let us bring how nearer to the resulting action */
55 if ((sock->stream.flags&XIO_ACCMODE) == XIO_WRONLY) {
56 how = ((how+1) & ~(SHUT_RD+1)) - 1;
57 } else if ((sock->stream.flags&XIO_ACCMODE) == XIO_RDONLY) {
58 how = ((how+1) & ~(SHUT_WR+1)) - 1;
59 }
60  
61 switch (sock->stream.howtoshut) {
62 #if WITH_PTY
63 case XIOSHUT_PTYEOF:
64 {
65 struct termios termarg;
66 int result;
67 Debug1("tcdrain(%d)", sock->stream.wfd);
68 result = tcdrain(sock->stream.wfd);
69 Debug1("tcdrain() -> %d", result);
70 if (Tcgetattr(sock->stream.wfd, &termarg) < 0) {
71 Error3("tcgetattr(%d, %p): %s",
72 sock->stream.wfd, &termarg, strerror(errno));
73 }
74 #if 0
75 /* these settings might apply to data still in the buff (despite the
76 TCSADRAIN */
77 termarg.c_iflag |= (IGNBRK | BRKINT | PARMRK | ISTRIP
78 | INLCR | IGNCR | ICRNL | IXON);
79 termarg.c_oflag |= OPOST;
80 termarg.c_lflag |= (/*ECHO | ECHONL |*/ ICANON | ISIG | IEXTEN);
81 //termarg.c_cflag |= (PARENB);
82 #else
83 termarg.c_lflag |= ICANON;
84 #endif
85 if (Tcsetattr(sock->stream.wfd, TCSADRAIN, &termarg) < 0) {
86 Error3("tcsetattr(%d, TCSADRAIN, %p): %s",
87 sock->stream.wfd, &termarg, strerror(errno));
88 }
89 if (Write(sock->stream.wfd, &termarg.c_cc[VEOF], 1) < 1) {
90 Warn3("write(%d, 0%o, 1): %s",
91 sock->stream.wfd, termarg.c_cc[VEOF], strerror(errno));
92 }
93 }
94 return 0;
95 #endif /* WITH_PTY */
96 #if WITH_OPENSSL
97 case XIOSHUT_OPENSSL:
98 sycSSL_shutdown(sock->stream.para.openssl.ssl);
99 /*! what about half/full close? */
100 return 0;
101 #endif /* WITH_OPENSSL */
102 default:
103 break;
104 }
105  
106 /* here handle special shutdown functions */
107 switch (sock->stream.howtoshut & XIOSHUTWR_MASK) {
108 char writenull;
109 case XIOSHUTWR_NONE:
110 return 0;
111 case XIOSHUTWR_CLOSE:
112 if (Close(fd) < 0) {
113 Info2("close(%d): %s", fd, strerror(errno));
114 }
115 return 0;
116 case XIOSHUTWR_DOWN:
117 if ((result = Shutdown(fd, how)) < 0) {
118 Info3("shutdown(%d, %d): %s", fd, how, strerror(errno));
119 }
120 return 0;
121 #if _WITH_SOCKET
122 case XIOSHUTWR_NULL:
123 /* send an empty packet; only useful on datagram sockets? */
124 xiowrite(sock, &writenull, 0);
125 return 0;
126 #endif /* _WITH_SOCKET */
127 default: break;
128 }
129  
130 #if 0
131 if (how == SHUT_RDWR) {
132 /* in this branch we handle only shutdown actions where read and write
133 shutdown are not independent */
134  
135 switch (sock->stream.howtoshut) {
136 #if _WITH_SOCKET
137 case XIOSHUT_DOWN:
138 if ((result = Shutdown(fd, how)) < 0) {
139 Info3("shutdown(%d, %d): %s", fd, how, strerror(errno));
140 }
141 break;
142 case XIOSHUT_KILL:
143 if ((result = Shutdown(fd, how)) < 0) {
144 Info3("shutdown(%d, %d): %s", fd, how, strerror(errno));
145 }
146 break;
147 #endif /* _WITH_SOCKET */
148 case XIOSHUT_CLOSE:
149 Close(fd);
150 #if WITH_TERMIOS
151 if (sock->stream.ttyvalid) {
152 if (Tcsetattr(fd, 0, &sock->stream.savetty) < 0) {
153 Warn2("cannot restore terminal settings on fd %d: %s",
154 fd, strerror(errno));
155 }
156 }
157 #endif /* WITH_TERMIOS */
158 /*PASSTHROUGH*/
159 case XIOSHUT_NONE:
160 break;
161 default:
162 Error1("xioshutdown(): bad shutdown action 0x%x", sock->stream.howtoshut);
163 return -1;
164 }
165  
166 #if 0 && _WITH_SOCKET
167 case XIODATA_RECVFROM:
168 if (how >= 1) {
169 if (Close(fd) < 0) {
170 Info2("close(%d): %s",
171 fd, strerror(errno));
172 }
173 sock->stream.eof = 2;
174 sock->stream.rfd = -1;
175 }
176 break;
177 #endif /* _WITH_SOCKET */
178 }
179 #endif
180  
181 if ((how+1) & 1) { /* contains SHUT_RD */
182 switch (sock->stream.dtype & XIODATA_READMASK) {
183 /* shutdown read channel */
184  
185 case XIOREAD_STREAM:
186 case XIODATA_2PIPE:
187 if (Close(fd) < 0) {
188 Info2("close(%d): %s", fd, strerror(errno));
189 }
190 break;
191 }
192 }
193  
194 if ((how+1) & 2) { /* contains SHUT_WR */
195 /* shutdown write channel */
196  
197 switch (sock->stream.howtoshut & XIOSHUTWR_MASK) {
198  
199 case XIOSHUTWR_CLOSE:
200 if (Close(fd) < 0) {
201 Info2("close(%d): %s", fd, strerror(errno));
202 }
203 /*PASSTHROUGH*/
204 case XIOSHUTWR_NONE:
205 break;
206  
207 #if _WITH_SOCKET
208 case XIOSHUTWR_DOWN:
209 if (Shutdown(fd, SHUT_WR) < 0) {
210 Info2("shutdown(%d, SHUT_WR): %s", fd, strerror(errno));
211 }
212 break;
213 #endif /* _WITH_SOCKET */
214  
215 #if 0
216 case XIOSHUTWR_DOWN_KILL:
217 if (Shutdown(fd, SHUT_WR) < 0) {
218 Info2("shutdown(%d, SHUT_WR): %s", fd, strerror(errno));
219 }
220 /*!!!*/
221 #endif
222 case XIOSHUTWR_SIGHUP:
223 /* the child process might want to flush some data before
224 terminating */
225 xioshut_sleep_kill(sock->stream.child.pid, 0, SIGHUP);
226 break;
227 case XIOSHUTWR_SIGTERM:
228 /* the child process might want to flush some data before
229 terminating */
230 xioshut_sleep_kill(sock->stream.child.pid, 1000000, SIGTERM);
231 break;
232 case XIOSHUTWR_SIGKILL:
233 /* the child process might want to flush some data before
234 terminating */
235 xioshut_sleep_kill(sock->stream.child.pid, 1000000, SIGKILL);
236 break;
237  
238 default:
239 Error1("xioshutdown(): unhandled howtoshut=0x%x during SHUT_WR",
240 sock->stream.howtoshut&XIOSHUTWR_MASK);
241 }
242 sock->stream.wfd = -1;
243 }
244  
245 return result;
246 }
247  
248 /* wait some time and then send signal to sub process. This is useful after
249 shutting down the connection to give process some time to flush its output
250 data */
251 static int xioshut_sleep_kill(pid_t sub, unsigned long usec, int sig) {
252 struct sigaction act;
253 int status = 0;
254  
255 /* we wait for the child process to die, but to prevent timeout
256 we raise an alarm after some time.
257 NOTE: the alarm does not terminate waitpid() on Linux/glibc
258 (BUG?),
259 therefore we have to do the kill in the signal handler */
260 {
261 struct sigaction act;
262 sigfillset(&act.sa_mask);
263 act.sa_flags = 0;
264 act.sa_handler = signal_kill_pid;
265 Sigaction(SIGALRM, &act, NULL);
266 }
267  
268 socat_kill_pid = sub;
269 #if HAVE_SETITIMER
270 /*! with next feature release, we get usec resolution and an option
271 */
272 #else
273 Alarm(1 /*! sock->stream.child.waitdie */);
274 #endif /* !HAVE_SETITIMER */
275 if (Waitpid(sub, &status, 0) < 0) {
276 Warn3("waitpid("F_pid", %p, 0): %s",
277 sub, &status, strerror(errno));
278 }
279 Alarm(0);
280 return 0;
281 }