nexmon – Blame information for rev 1

Subversion Repositories:
Rev:
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