nexmon – Blame information for rev 1
?pathlinks?
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 | } |