nexmon – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /* xiosocketpair.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 internal xiosocketpair function */ |
||
6 | |||
7 | #include "xiosysincludes.h" |
||
8 | #include "sycls.h" |
||
9 | #include "compat.h" |
||
10 | #include "error.h" |
||
11 | #include "xio.h" |
||
12 | |||
13 | |||
14 | #if defined(HAVE_DEV_PTMX) |
||
15 | # define PTMX "/dev/ptmx" /* Linux */ |
||
16 | #elif HAVE_DEV_PTC |
||
17 | # define PTMX "/dev/ptc" /* AIX */ |
||
18 | #endif |
||
19 | |||
20 | #define MAXPTYNAMELEN 64 |
||
21 | |||
22 | int xiopty(int useptmx, int *ttyfdp, int *ptyfdp) { |
||
23 | int ttyfd, ptyfd = -1; |
||
24 | char ptyname[MAXPTYNAMELEN]; |
||
25 | struct termios termarg; |
||
26 | |||
27 | if (useptmx) { |
||
28 | if ((ptyfd = Open(PTMX, O_RDWR|O_NOCTTY, 0620)) < 0) { |
||
29 | Warn1("open(\""PTMX"\", O_RDWR|O_NOCTTY, 0620): %s", |
||
30 | strerror(errno)); |
||
31 | /*!*/ |
||
32 | } else { |
||
33 | ;/*0 Info1("open(\""PTMX"\", O_RDWR|O_NOCTTY, 0620) -> %d", ptyfd);*/ |
||
34 | } |
||
35 | if (ptyfd >= 0) { |
||
36 | char *tn = NULL; |
||
37 | |||
38 | /* we used PTMX before forking */ |
||
39 | /*0 extern char *ptsname(int);*/ |
||
40 | #if HAVE_GRANTPT /* AIX, not Linux */ |
||
41 | if (Grantpt(ptyfd)/*!*/ < 0) { |
||
42 | Warn2("grantpt(%d): %s", ptyfd, strerror(errno)); |
||
43 | } |
||
44 | #endif /* HAVE_GRANTPT */ |
||
45 | #if HAVE_UNLOCKPT |
||
46 | if (Unlockpt(ptyfd)/*!*/ < 0) { |
||
47 | Warn2("unlockpt(%d): %s", ptyfd, strerror(errno)); |
||
48 | } |
||
49 | #endif /* HAVE_UNLOCKPT */ |
||
50 | #if HAVE_PROTOTYPE_LIB_ptsname /* AIX, not Linux */ |
||
51 | if ((tn = Ptsname(ptyfd)) == NULL) { |
||
52 | Warn2("ptsname(%d): %s", ptyfd, strerror(errno)); |
||
53 | } else { |
||
54 | Notice1("PTY is %s", tn); |
||
55 | } |
||
56 | #endif /* HAVE_PROTOTYPE_LIB_ptsname */ |
||
57 | #if 0 |
||
58 | if (tn == NULL) { |
||
59 | /*! ttyname_r() */ |
||
60 | if ((tn = Ttyname(ptyfd)) == NULL) { |
||
61 | Warn2("ttyname(%d): %s", ptyfd, strerror(errno)); |
||
62 | } |
||
63 | } |
||
64 | ptyname[0] = '\0'; strncat(ptyname, tn, MAXPTYNAMELEN-1); |
||
65 | #endif |
||
66 | if ((ttyfd = Open(tn, O_RDWR|O_NOCTTY, 0620)) < 0) { |
||
67 | Warn2("open(\"%s\", O_RDWR|O_NOCTTY, 0620): %s", tn, strerror(errno)); |
||
68 | } else { |
||
69 | /*0 Info2("open(\"%s\", O_RDWR|O_NOCTTY, 0620) -> %d", tn, ttyfd);*/ |
||
70 | } |
||
71 | |||
72 | #ifdef I_PUSH |
||
73 | /* Linux: I_PUSH def'd; pty: ioctl(, I_FIND, ...) -> -1 EINVAL */ |
||
74 | /* AIX: I_PUSH def'd; pty: ioctl(, I_FIND, ...) -> 1 */ |
||
75 | /* SunOS: I_PUSH def'd; pty: ioctl(, I_FIND, ...) -> 0 */ |
||
76 | /* HP-UX: I_PUSH def'd; pty: ioctl(, I_FIND, ...) -> 0 */ |
||
77 | if (Ioctl(ttyfd, I_FIND, "ldterm") == 0) { |
||
78 | Ioctl(ttyfd, I_PUSH, "ptem"); /* 0 */ |
||
79 | Ioctl(ttyfd, I_PUSH, "ldterm"); /* 0 */ |
||
80 | Ioctl(ttyfd, I_PUSH, "ttcompat"); /* HP-UX: -1 */ |
||
81 | } |
||
82 | #endif |
||
83 | } |
||
84 | } |
||
85 | #if HAVE_OPENPTY |
||
86 | if (ptyfd < 0) { |
||
87 | int result; |
||
88 | if ((result = Openpty(&ptyfd, &ttyfd, ptyname, NULL, NULL)) < 0) { |
||
89 | Error4("openpty(%p, %p, %p, NULL, NULL): %s", |
||
90 | &ptyfd, &ttyfd, ptyname, strerror(errno)); |
||
91 | return -1; |
||
92 | } |
||
93 | Notice1("PTY is %s", ptyname); |
||
94 | } |
||
95 | #endif /* HAVE_OPENPTY */ |
||
96 | |||
97 | if (Tcgetattr(ttyfd, &termarg) < 0) { |
||
98 | Error3("tcgetattr(%d, %p): %s", |
||
99 | ttyfd, &termarg, strerror(errno)); |
||
100 | } |
||
101 | #if 0 |
||
102 | cfmakeraw(&termarg); |
||
103 | #else |
||
104 | /*!!! share code with xioopts.c raw,echo=0 */ |
||
105 | termarg.c_iflag &= |
||
106 | ~(IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK|ISTRIP|INLCR|IGNCR|ICRNL|IXON|IXOFF |
||
107 | #ifdef IUCLC |
||
108 | |IUCLC |
||
109 | #endif |
||
110 | |IXANY|IMAXBEL); |
||
111 | termarg.c_iflag |= (0); |
||
112 | termarg.c_oflag &= ~(OPOST); |
||
113 | termarg.c_oflag |= (0); |
||
114 | termarg.c_cflag &= ~(0); |
||
115 | termarg.c_cflag |= (0); |
||
116 | termarg.c_lflag &= ~(ECHO|ECHONL|ISIG|ICANON |
||
117 | #ifdef XCASE |
||
118 | |XCASE |
||
119 | #endif |
||
120 | ); |
||
121 | termarg.c_lflag |= (0); |
||
122 | termarg.c_cc[VMIN] = 1; |
||
123 | termarg.c_cc[VTIME] = 0; |
||
124 | #endif |
||
125 | if (Tcsetattr(ttyfd, TCSADRAIN, &termarg) < 0) { |
||
126 | Error3("tcsetattr(%d, TCSADRAIN, %p): %s", |
||
127 | ttyfd, &termarg, strerror(errno)); |
||
128 | } |
||
129 | |||
130 | *ttyfdp = ttyfd; |
||
131 | *ptyfdp = ptyfd; |
||
132 | return 0; |
||
133 | } |
||
134 | |||
135 | /* generates a socket pair; supports not only PF_UNIX but also PF_INET */ |
||
136 | int xiosocketpair2(int pf, int socktype, int protocol, int sv[2]) { |
||
137 | int result; |
||
138 | |||
139 | switch (pf) { |
||
140 | struct sockaddr_in ssin, csin, xsin; /* server, client, compare */ |
||
141 | socklen_t cslen, xslen; |
||
142 | int sconn, slist, sserv; /* socket FDs */ |
||
143 | |||
144 | case PF_UNIX: |
||
145 | result = Socketpair(pf, socktype, protocol, sv); |
||
146 | if (result < 0) { |
||
147 | Error5("socketpair(%d, %d, %d, %p): %s", |
||
148 | pf, socktype, protocol, sv, strerror(errno)); |
||
149 | return -1; |
||
150 | } |
||
151 | break; |
||
152 | #if LATER |
||
153 | case PF_INET: |
||
154 | #if 1 /*!!! Linux */ |
||
155 | ssin.sin_family = pf; |
||
156 | ssin.sin_port = htons(1024+random()%(65536-1024)); |
||
157 | ssin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); |
||
158 | #endif /* */ |
||
159 | if ((s = Socket(pf, socktype, protocol)) < 0) { |
||
160 | Error4("socket(%d, %d, %d): %s", |
||
161 | pf, socktype, protocol, strerror(errno)); |
||
162 | } |
||
163 | if (Bind(s, (struct sockaddr *)&ssin, sizeof(ssin)) < 0) { |
||
164 | Error6("bind(%d, {%u, 0x%x:%u}, "F_Zu"): %s", |
||
165 | s, ssin.sin_family, ssin.sin_addr.s_addr, ssin.sin_port, |
||
166 | sizeof(ssin), strerror(errno)); |
||
167 | } |
||
168 | if (Connect(s, (struct sockaddr *)&ssin, sizeof(ssin)) < 0) { |
||
169 | Error6("connect(%d, {%u, 0x%x:%u}, "F_Zu"): %s", |
||
170 | s, ssin.sin_family, ssin.sin_addr.s_addr, ssin.sin_port, |
||
171 | sizeof(ssin), strerror(errno)); |
||
172 | return -1; |
||
173 | } |
||
174 | break; |
||
175 | #endif /* LATER */ |
||
176 | case PF_INET: |
||
177 | ssin.sin_family = pf; |
||
178 | ssin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); |
||
179 | if ((slist = Socket(pf, socktype, protocol)) < 0) { |
||
180 | Error4("socket(%d, %d, %d): %s", |
||
181 | pf, socktype, protocol, strerror(errno)); |
||
182 | } |
||
183 | while (true) { /* find a port we can bind to */ |
||
184 | ssin.sin_port = htons(1024+random()%(65536-1024)); |
||
185 | if (Bind(slist, (struct sockaddr *)&ssin, sizeof(ssin)) == 0) break; |
||
186 | if (errno == EADDRINUSE) { |
||
187 | Info6("bind(%d, {%u, 0x%x:%u}, "F_Zu"): %s", |
||
188 | slist, ssin.sin_family, ssin.sin_addr.s_addr, |
||
189 | ntohs(ssin.sin_port), sizeof(ssin), strerror(errno)); |
||
190 | continue; |
||
191 | } |
||
192 | Error6("bind(%d, {%u, 0x%x:%u}, "F_Zu"): %s", |
||
193 | slist, ssin.sin_family, ssin.sin_addr.s_addr, ssin.sin_port, |
||
194 | sizeof(ssin), strerror(errno)); |
||
195 | Close(slist); |
||
196 | return -1; |
||
197 | } |
||
198 | Listen(slist, 0); |
||
199 | if ((sconn = Socket(pf, socktype, protocol)) < 0) { |
||
200 | Error4("socket(%d, %d, %d): %s", |
||
201 | pf, socktype, protocol, strerror(errno)); |
||
202 | Close(slist); return -1; |
||
203 | } |
||
204 | /* for testing race condition: Sleep(30); */ |
||
205 | if (Connect(sconn, (struct sockaddr *)&ssin, sizeof(ssin)) < 0) { |
||
206 | Error6("connect(%d, {%u, 0x%x:%u}, "F_Zu"): %s", |
||
207 | sconn, ssin.sin_family, ssin.sin_addr.s_addr, |
||
208 | ntohs(ssin.sin_port), |
||
209 | sizeof(ssin), strerror(errno)); |
||
210 | Close(slist); Close(sconn); return -1; |
||
211 | } |
||
212 | cslen = sizeof(csin); |
||
213 | if (Getsockname(sconn, (struct sockaddr *)&csin, &cslen) < 0) { |
||
214 | Error4("getsockname(%d, %p, %p): %s", |
||
215 | sconn, &csin, &cslen, strerror(errno)); |
||
216 | Close(slist); Close(sconn); return -1; |
||
217 | } |
||
218 | do { |
||
219 | xslen = sizeof(xsin); |
||
220 | if ((sserv = Accept(slist, (struct sockaddr *)&xsin, &xslen)) < 0) { |
||
221 | Error4("accept(%d, %p, {"F_Zu"}): %s", |
||
222 | slist, &csin, sizeof(xslen), strerror(errno)); |
||
223 | Close(slist); Close(sconn); return -1; |
||
224 | } |
||
225 | if (!memcmp(&csin, &xsin, cslen)) { |
||
226 | break; /* expected connection */ |
||
227 | } |
||
228 | Warn4("unexpected connection to 0x%lx:%hu from 0x%lx:%hu", |
||
229 | ntohl(ssin.sin_addr.s_addr), ntohs(ssin.sin_port), |
||
230 | ntohl(xsin.sin_addr.s_addr), ntohs(xsin.sin_port)); |
||
231 | } while (true); |
||
232 | Close(slist); |
||
233 | sv[0] = sconn; |
||
234 | sv[1] = sserv; |
||
235 | break; |
||
236 | default: |
||
237 | Error1("xiosocketpair2(): pf=%u not implemented", pf); |
||
238 | return -1; |
||
239 | } |
||
240 | return 0; |
||
241 | } |
||
242 | |||
243 | /* |
||
244 | dual should only be != 0 when both directions are used |
||
245 | returns 0 on success |
||
246 | */ |
||
247 | int xiocommpair(int commtype, bool lefttoright, bool righttoleft, |
||
248 | int dual, xiofd_t *left, xiofd_t *right, ...) { |
||
249 | va_list ap; |
||
250 | int domain = -1, socktype = -1, protocol = -1; |
||
251 | int useptmx = 0; |
||
252 | /* arrays can be used with pipe(2) and socketpair(2): */ |
||
253 | int svlr[2] = {-1, -1}; /* left to right: rfd, wfd */ |
||
254 | int svrl[2] = {-1, -1}; /* right to left: rfd, wfd */ |
||
255 | |||
256 | /* get related parameters from parameter list */ |
||
257 | switch (commtype) { |
||
258 | case XIOCOMM_SOCKETPAIR: |
||
259 | case XIOCOMM_SOCKETPAIRS: |
||
260 | va_start(ap, right); |
||
261 | domain = va_arg(ap, int); |
||
262 | socktype = va_arg(ap, int); |
||
263 | protocol = va_arg(ap, int); |
||
264 | va_end(ap); |
||
265 | break; |
||
266 | case XIOCOMM_PTY: |
||
267 | case XIOCOMM_PTYS: |
||
268 | va_start(ap, right); |
||
269 | useptmx = va_arg(ap, int); |
||
270 | va_end(ap); |
||
271 | break; |
||
272 | default: |
||
273 | break; |
||
274 | } |
||
275 | |||
276 | switch (commtype) { |
||
277 | default: /* unspec */ |
||
278 | Warn1("internal: undefined communication type %d, defaulting to 0", |
||
279 | commtype); |
||
280 | commtype = 0; |
||
281 | /*PASSTHROUGH*/ |
||
282 | case XIOCOMM_SOCKETPAIRS: /* two socketpairs - the default */ |
||
283 | if (lefttoright) { |
||
284 | if (Socketpair(domain, socktype, protocol, svlr) < 0) { |
||
285 | Error5("socketpair(%d, %d, %d, %p): %s", |
||
286 | domain, socktype, protocol, svlr, strerror(errno)); |
||
287 | } |
||
288 | Shutdown(svlr[0], SHUT_WR); |
||
289 | } |
||
290 | if (righttoleft) { |
||
291 | if (Socketpair(domain, socktype, protocol, svrl) < 0) { |
||
292 | Error5("socketpair(%d, %d, %d, %p): %s", |
||
293 | domain, socktype, protocol, svrl, strerror(errno)); |
||
294 | } |
||
295 | Shutdown(svrl[0], SHUT_WR); |
||
296 | } |
||
297 | left->single = right->single = false; |
||
298 | left->dtype = right->dtype = XIODATA_STREAM; |
||
299 | left->howtoshut = right->howtoshut = XIOSHUT_DOWN; |
||
300 | left->howtoclose = right->howtoclose = XIOCLOSE_CLOSE; |
||
301 | break; |
||
302 | |||
303 | case XIOCOMM_PTYS: /* two ptys in raw mode, EOF in canonical mode */ |
||
304 | if (lefttoright) { |
||
305 | if (xiopty(useptmx, &svlr[0], &svlr[1]) < 0) return -1; |
||
306 | /* pty is write side, interpretes ^D in canonical mode */ |
||
307 | } |
||
308 | if (righttoleft) { |
||
309 | if (xiopty(useptmx, &svrl[0], &svrl[1]) < 0) return -1; |
||
310 | } |
||
311 | left->single = right->single = false; |
||
312 | left->dtype = right->dtype = XIODATA_PTY; |
||
313 | left->howtoshut = right->howtoshut = XIOSHUT_PTYEOF; |
||
314 | left->howtoclose = right->howtoclose = XIOCLOSE_CLOSE; |
||
315 | break; |
||
316 | |||
317 | case XIOCOMM_SOCKETPAIR: /* one socketpair */ |
||
318 | if (Socketpair(domain, socktype, protocol, svlr) < 0) { |
||
319 | Error5("socketpair(%d %d %d, %p): %s", |
||
320 | domain, socktype, protocol, svlr, strerror(errno)); |
||
321 | return -1; |
||
322 | } |
||
323 | left->single = right->single = true; |
||
324 | left->dtype = right->dtype = XIODATA_STREAM; |
||
325 | left->howtoshut = right->howtoshut = XIOSHUT_DOWN; |
||
326 | left->howtoclose = right->howtoclose = XIOCLOSE_CLOSE; |
||
327 | break; |
||
328 | |||
329 | case XIOCOMM_PTY: /* one pty in raw mode, EOF in canonical mode */ |
||
330 | if (xiopty(useptmx, &svlr[0], &svlr[1]) < 0) return -1; |
||
331 | left->single = right->single = true; |
||
332 | left->dtype = right->dtype = XIODATA_PTY; |
||
333 | left->howtoshut = XIOSHUT_PTYEOF; |
||
334 | right->howtoshut = XIOSHUT_CLOSE; |
||
335 | left->howtoclose = right->howtoclose = XIOCLOSE_CLOSE; |
||
336 | break; |
||
337 | |||
338 | case XIOCOMM_PIPES: /* two pipes */ |
||
339 | if (lefttoright) { |
||
340 | if (Pipe(svlr) < 0) { |
||
341 | Error2("pipe(%p): %s", svlr, strerror(errno)); |
||
342 | return -1; |
||
343 | } |
||
344 | } |
||
345 | if (righttoleft) { |
||
346 | if (Pipe(svrl) < 0) { |
||
347 | Error2("pipe(%p): %s", svrl, strerror(errno)); |
||
348 | return -1; |
||
349 | } |
||
350 | } |
||
351 | left->single = right->single = false; |
||
352 | left->dtype = right->dtype = XIODATA_STREAM; |
||
353 | left->howtoshut = right->howtoshut = XIOSHUT_CLOSE; |
||
354 | left->howtoclose = right->howtoclose = XIOCLOSE_CLOSE; |
||
355 | break; |
||
356 | |||
357 | case XIOCOMM_TCP: |
||
358 | case XIOCOMM_TCP4: /* one TCP/IPv4 socket pair */ |
||
359 | if (xiosocketpair2(PF_INET, SOCK_STREAM, 0, svlr) < 0) { |
||
360 | Error2("socketpair(PF_UNIX, PF_STREAM, 0, %p): %s", |
||
361 | svlr, strerror(errno)); |
||
362 | return -1; |
||
363 | } |
||
364 | left->single = right->single = true; |
||
365 | left->dtype = right->dtype = XIODATA_STREAM; |
||
366 | left->howtoshut = right->howtoshut = XIOSHUT_DOWN; |
||
367 | left->howtoclose = right->howtoclose = XIOCLOSE_CLOSE; |
||
368 | break; |
||
369 | } |
||
370 | |||
371 | if (dual && left->single) { |
||
372 | /* one pair */ |
||
373 | /* dual; we use different FDs for the channels to avoid conflicts |
||
374 | (happened in dual exec) */ |
||
375 | if ((svrl[1] = Dup(svlr[0])) < 0) { |
||
376 | Error2("dup(%d): %s", svrl[0], strerror(errno)); |
||
377 | return -1; |
||
378 | } |
||
379 | if ((svrl[0] = Dup(svlr[1])) < 0) { |
||
380 | Error2("dup(%d): %s", svlr[1], strerror(errno)); |
||
381 | return -1; |
||
382 | } |
||
383 | } else if (left->single) { |
||
384 | svrl[1] = svlr[0]; |
||
385 | svrl[0] = svlr[1]; |
||
386 | } |
||
387 | |||
388 | /* usually they are not to be passed to exec'd child processes */ |
||
389 | if (lefttoright) { |
||
390 | Fcntl_l(svlr[0], F_SETFD, 1); |
||
391 | Fcntl_l(svlr[1], F_SETFD, 1); |
||
392 | } |
||
393 | if (righttoleft && (!left->single || dual)) { |
||
394 | Fcntl_l(svrl[0], F_SETFD, 1); |
||
395 | Fcntl_l(svrl[1], F_SETFD, 1); |
||
396 | } |
||
397 | |||
398 | left->rfd = svrl[0]; |
||
399 | left->wfd = svlr[1]; |
||
400 | right->rfd = svlr[0]; |
||
401 | right->wfd = svrl[1]; |
||
402 | Notice4("xiocommpair() -> [%d:%d], [%d:%d]", |
||
403 | left->rfd, left->wfd, right->rfd, right->wfd); |
||
404 | return 0; |
||
405 | } |
||
406 |