Fix up lint errors.
[unix-history] / usr / src / usr.bin / telnet / sys_bsd.c
CommitLineData
897ce52e
KB
1/*
2 * Copyright (c) 1988 Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms are permitted
6 * provided that this notice is preserved and that due credit is given
7 * to the University of California at Berkeley. The name of the University
8 * may not be used to endorse or promote products derived from this
9 * software without specific prior written permission. This software
10 * is provided ``as is'' without express or implied warranty.
11 */
12
13#ifndef lint
80a47e22 14static char sccsid[] = "@(#)sys_bsd.c 1.12 (Berkeley) %G%";
897ce52e
KB
15#endif /* not lint */
16
e767b7ab
GM
17/*
18 * The following routines try to encapsulate what is system dependent
19 * (at least between 4.x and dos) which is used in telnet.c.
20 */
21
22#if defined(unix)
23
24#include <sys/ioctl.h>
115a5494 25#include <sys/types.h>
e767b7ab 26#include <sys/time.h>
b307f09e 27#include <sys/socket.h>
e767b7ab 28#include <signal.h>
b307f09e 29#include <errno.h>
e767b7ab 30
115a5494
GM
31#include "ring.h"
32
807a3a7d
GM
33#include "fdset.h"
34
e767b7ab
GM
35#include "defines.h"
36#include "externs.h"
37#include "types.h"
38
39int
b307f09e
GM
40 tout, /* Output file descriptor */
41 tin, /* Input file descriptor */
42 net,
e767b7ab
GM
43 HaveInput; /* There is input available to scan */
44
e767b7ab
GM
45static struct tchars otc = { 0 }, ntc = { 0 };
46static struct ltchars oltc = { 0 }, nltc = { 0 };
47static struct sgttyb ottyb = { 0 }, nttyb = { 0 };
48
b307f09e
GM
49static fd_set ibits, obits, xbits;
50
51
52init_sys()
53{
54 tout = fileno(stdout);
55 tin = fileno(stdin);
56 FD_ZERO(&ibits);
57 FD_ZERO(&obits);
58 FD_ZERO(&xbits);
59
60 errno = 0;
61}
62
e767b7ab 63
448f9c06 64TerminalWrite(buf, n)
e767b7ab
GM
65char *buf;
66int n;
67{
448f9c06 68 return write(tout, buf, n);
e767b7ab
GM
69}
70
448f9c06 71TerminalRead(buf, n)
e767b7ab
GM
72char *buf;
73int n;
74{
448f9c06 75 return read(tin, buf, n);
e767b7ab
GM
76}
77
78/*
79 *
80 */
81
82int
310e7d0b 83TerminalAutoFlush()
e767b7ab
GM
84{
85#if defined(LNOFLSH)
86 int flush;
87
88 ioctl(0, TIOCLGET, (char *)&flush);
89 return !(flush&LNOFLSH); /* if LNOFLSH, no autoflush */
90#else /* LNOFLSH */
91 return 1;
92#endif /* LNOFLSH */
93}
94
95/*
96 * TerminalSpecialChars()
97 *
98 * Look at an input character to see if it is a special character
99 * and decide what to do.
100 *
101 * Output:
102 *
103 * 0 Don't add this character.
104 * 1 Do add this character
105 */
106
107int
310e7d0b 108TerminalSpecialChars(c)
e767b7ab
GM
109int c;
110{
310e7d0b 111 void xmitAO(), xmitEL(), xmitEC(), intp(), sendbrk();
e767b7ab
GM
112
113 if (c == ntc.t_intrc) {
114 intp();
115 return 0;
116 } else if (c == ntc.t_quitc) {
117 sendbrk();
118 return 0;
119 } else if (c == nltc.t_flushc) {
120 xmitAO(); /* Transmit Abort Output */
121 return 0;
122 } else if (!MODE_LOCAL_CHARS(globalmode)) {
123 if (c == nttyb.sg_kill) {
124 xmitEL();
125 return 0;
126 } else if (c == nttyb.sg_erase) {
127 xmitEC(); /* Transmit Erase Character */
128 return 0;
129 }
130 }
131 return 1;
132}
133
134
135/*
136 * Flush output to the terminal
137 */
138
139void
310e7d0b 140TerminalFlushOutput()
e767b7ab
GM
141{
142 (void) ioctl(fileno(stdout), TIOCFLUSH, (char *) 0);
143}
144
145void
310e7d0b 146TerminalSaveState()
e767b7ab
GM
147{
148 ioctl(0, TIOCGETP, (char *)&ottyb);
149 ioctl(0, TIOCGETC, (char *)&otc);
150 ioctl(0, TIOCGLTC, (char *)&oltc);
151
152 ntc = otc;
153 nltc = oltc;
154 nttyb = ottyb;
0e29050b
GM
155
156 termEofChar = ntc.t_eofc;
157 termEraseChar = nttyb.sg_erase;
158 termFlushChar = nltc.t_flushc;
159 termIntChar = ntc.t_intrc;
160 termKillChar = nttyb.sg_kill;
161 termQuitChar = ntc.t_quitc;
e767b7ab
GM
162}
163
164void
310e7d0b 165TerminalRestoreState()
e767b7ab
GM
166{
167}
168
169/*
170 * TerminalNewMode - set up terminal to a specific mode.
171 */
172
173
174void
448f9c06 175TerminalNewMode(f)
e767b7ab
GM
176register int f;
177{
178 static int prevmode = 0;
179 struct tchars *tc;
180 struct tchars tc3;
181 struct ltchars *ltc;
182 struct sgttyb sb;
183 int onoff;
184 int old;
185 struct tchars notc2;
186 struct ltchars noltc2;
187 static struct tchars notc = { -1, -1, -1, -1, -1, -1 };
188 static struct ltchars noltc = { -1, -1, -1, -1, -1, -1 };
189
190 globalmode = f;
191 if (prevmode == f)
192 return;
193 old = prevmode;
194 prevmode = f;
195 sb = nttyb;
196
197 switch (f) {
198
199 case 0:
200 onoff = 0;
201 tc = &otc;
202 ltc = &oltc;
203 break;
204
205 case 1: /* remote character processing, remote echo */
206 case 2: /* remote character processing, local echo */
207 case 6: /* 3270 mode - like 1, but with xon/xoff local */
208 /* (might be nice to have "6" in telnet also...) */
209 sb.sg_flags |= CBREAK;
210 if ((f == 1) || (f == 6)) {
211 sb.sg_flags &= ~(ECHO|CRMOD);
212 } else {
213 sb.sg_flags |= ECHO|CRMOD;
214 }
215 sb.sg_erase = sb.sg_kill = -1;
216 if (f == 6) {
217 tc = &tc3;
218 tc3 = notc;
219 /* get XON, XOFF characters */
220 tc3.t_startc = otc.t_startc;
221 tc3.t_stopc = otc.t_stopc;
222 } else {
223 /*
224 * If user hasn't specified one way or the other,
225 * then default to not trapping signals.
226 */
227 if (!donelclchars) {
228 localchars = 0;
229 }
230 if (localchars) {
231 notc2 = notc;
232 notc2.t_intrc = ntc.t_intrc;
233 notc2.t_quitc = ntc.t_quitc;
234 tc = &notc2;
235 } else {
236 tc = &notc;
237 }
238 }
239 ltc = &noltc;
240 onoff = 1;
241 break;
242 case 3: /* local character processing, remote echo */
243 case 4: /* local character processing, local echo */
244 case 5: /* local character processing, no echo */
245 sb.sg_flags &= ~CBREAK;
246 sb.sg_flags |= CRMOD;
247 if (f == 4)
248 sb.sg_flags |= ECHO;
249 else
250 sb.sg_flags &= ~ECHO;
251 notc2 = ntc;
252 tc = &notc2;
253 noltc2 = oltc;
254 ltc = &noltc2;
255 /*
256 * If user hasn't specified one way or the other,
257 * then default to trapping signals.
258 */
259 if (!donelclchars) {
260 localchars = 1;
261 }
262 if (localchars) {
263 notc2.t_brkc = nltc.t_flushc;
264 noltc2.t_flushc = -1;
265 } else {
266 notc2.t_intrc = notc2.t_quitc = -1;
267 }
268 noltc2.t_suspc = escape;
269 noltc2.t_dsuspc = -1;
270 onoff = 1;
271 break;
272
273 default:
274 return;
275 }
448f9c06
GM
276 ioctl(tin, TIOCSLTC, (char *)ltc);
277 ioctl(tin, TIOCSETC, (char *)tc);
278 ioctl(tin, TIOCSETP, (char *)&sb);
e767b7ab 279#if (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR))
448f9c06
GM
280 ioctl(tin, FIONBIO, (char *)&onoff);
281 ioctl(tout, FIONBIO, (char *)&onoff);
e767b7ab
GM
282#endif /* (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) */
283#if defined(TN3270)
284 if (noasynch == 0) {
448f9c06 285 ioctl(tin, FIOASYNC, (char *)&onoff);
e767b7ab
GM
286 }
287#endif /* defined(TN3270) */
288
289 if (MODE_LINE(f)) {
290 void doescape();
291
80a47e22 292 (void) signal(SIGTSTP, (int (*)())doescape);
e767b7ab 293 } else if (MODE_LINE(old)) {
80a47e22 294 (void) signal(SIGTSTP, SIG_DFL);
e767b7ab
GM
295 sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1)));
296 }
297}
298
299
300int
301NetClose(net)
302int net;
303{
304 return close(net);
305}
306
307
308void
310e7d0b 309NetNonblockingIO(fd, onoff)
e767b7ab
GM
310int
311 fd,
312 onoff;
313{
314 ioctl(fd, FIONBIO, (char *)&onoff);
315}
316
80a47e22 317#if defined(TN3270)
e767b7ab 318void
310e7d0b 319NetSigIO(fd, onoff)
e767b7ab
GM
320int
321 fd,
322 onoff;
323{
324 ioctl(fd, FIOASYNC, (char *)&onoff); /* hear about input */
325}
326
327void
310e7d0b 328NetSetPgrp(fd)
e767b7ab
GM
329int fd;
330{
331 int myPid;
332
333 myPid = getpid();
334#if defined(NOT43)
335 myPid = -myPid;
336#endif /* defined(NOT43) */
337 ioctl(fd, SIOCSPGRP, (char *)&myPid); /* set my pid */
338}
80a47e22 339#endif /*defined(TN3270)*/
310e7d0b
GM
340\f
341/*
342 * Various signal handling routines.
343 */
344
448f9c06 345static void
310e7d0b
GM
346deadpeer()
347{
348 setcommandmode();
349 longjmp(peerdied, -1);
350}
351
448f9c06 352static void
310e7d0b
GM
353intr()
354{
355 if (localchars) {
356 intp();
357 return;
358 }
359 setcommandmode();
360 longjmp(toplevel, -1);
361}
e767b7ab 362
448f9c06 363static void
310e7d0b
GM
364intr2()
365{
366 if (localchars) {
367 sendbrk();
368 return;
369 }
370}
e767b7ab 371
448f9c06 372static void
310e7d0b
GM
373doescape()
374{
375 command(0);
376}
377\f
b307f09e
GM
378void
379sys_telnet_init()
380{
310e7d0b 381#if defined(TN3270)
b307f09e
GM
382 int myPid;
383#endif /* defined(TN3270) */
384
80a47e22
GM
385 (void) signal(SIGINT, (int (*)())intr);
386 (void) signal(SIGQUIT, (int (*)())intr2);
387 (void) signal(SIGPIPE, (int (*)())deadpeer);
310e7d0b 388
b307f09e
GM
389 setconnmode();
390
391 NetNonblockingIO(net, 1);
392
393#if defined(TN3270)
394 if (noasynch == 0) { /* DBX can't handle! */
395 NetSigIO(net, 1);
396 NetSetPgrp(net);
397 }
398#endif /* defined(TN3270) */
399
400#if defined(SO_OOBINLINE)
80a47e22
GM
401 if (SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, 1) == -1) {
402 perror("SetSockOpt");
403 }
b307f09e
GM
404#endif /* defined(SO_OOBINLINE) */
405}
406
407/*
408 * Process rings -
409 *
410 * This routine tries to fill up/empty our various rings.
411 *
412 * The parameter specifies whether this is a poll operation,
413 * or a block-until-something-happens operation.
414 *
415 * The return value is 1 if something happened, 0 if not.
416 */
417
418int
419process_rings(netin, netout, netex, ttyin, ttyout, poll)
420int poll; /* If 0, then block until something to do */
421{
422 register int c;
423 /* One wants to be a bit careful about setting returnValue
424 * to one, since a one implies we did some useful work,
425 * and therefore probably won't be called to block next
426 * time (TN3270 mode only).
427 */
428 int returnValue = 0;
429 static struct timeval TimeValue = { 0 };
430
431 if (netout) {
432 FD_SET(net, &obits);
433 }
434 if (ttyout) {
435 FD_SET(tout, &obits);
436 }
437#if defined(TN3270)
438 if (ttyin) {
439 FD_SET(tin, &ibits);
440 }
441#else /* defined(TN3270) */
442 if (ttyin) {
443 FD_SET(tin, &ibits);
444 }
445#endif /* defined(TN3270) */
446#if defined(TN3270)
447 if (netin) {
448 FD_SET(net, &ibits);
449 }
450# else /* !defined(TN3270) */
451 if (netin) {
452 FD_SET(net, &ibits);
453 }
454# endif /* !defined(TN3270) */
455 if (netex) {
456 FD_SET(net, &xbits);
457 }
458 if ((c = select(16, &ibits, &obits, &xbits,
459 (poll == 0)? (struct timeval *)0 : &TimeValue)) < 0) {
460 if (c == -1) {
461 /*
462 * we can get EINTR if we are in line mode,
463 * and the user does an escape (TSTP), or
464 * some other signal generator.
465 */
466 if (errno == EINTR) {
467 return 0;
468 }
469# if defined(TN3270)
470 /*
471 * we can get EBADF if we were in transparent
472 * mode, and the transcom process died.
473 */
474 if (errno == EBADF) {
475 /*
476 * zero the bits (even though kernel does it)
477 * to make sure we are selecting on the right
478 * ones.
479 */
480 FD_ZERO(&ibits);
481 FD_ZERO(&obits);
482 FD_ZERO(&xbits);
483 return 0;
484 }
485# endif /* defined(TN3270) */
486 /* I don't like this, does it ever happen? */
487 printf("sleep(5) from telnet, after select\r\n");
b307f09e 488 sleep(5);
b307f09e
GM
489 }
490 return 0;
491 }
492
493 /*
494 * Any urgent data?
495 */
496 if (FD_ISSET(net, &xbits)) {
497 FD_CLR(net, &xbits);
498 SYNCHing = 1;
499 ttyflush(1); /* flush already enqueued data */
500 }
501
502 /*
503 * Something to read from the network...
504 */
505 if (FD_ISSET(net, &ibits)) {
506 int canread;
507
508 FD_CLR(net, &ibits);
509 canread = ring_empty_consecutive(&netiring);
510#if !defined(SO_OOBINLINE)
511 /*
512 * In 4.2 (and some early 4.3) systems, the
513 * OOB indication and data handling in the kernel
514 * is such that if two separate TCP Urgent requests
515 * come in, one byte of TCP data will be overlaid.
516 * This is fatal for Telnet, but we try to live
517 * with it.
518 *
519 * In addition, in 4.2 (and...), a special protocol
520 * is needed to pick up the TCP Urgent data in
521 * the correct sequence.
522 *
523 * What we do is: if we think we are in urgent
524 * mode, we look to see if we are "at the mark".
525 * If we are, we do an OOB receive. If we run
526 * this twice, we will do the OOB receive twice,
527 * but the second will fail, since the second
528 * time we were "at the mark", but there wasn't
529 * any data there (the kernel doesn't reset
530 * "at the mark" until we do a normal read).
531 * Once we've read the OOB data, we go ahead
532 * and do normal reads.
533 *
534 * There is also another problem, which is that
535 * since the OOB byte we read doesn't put us
536 * out of OOB state, and since that byte is most
537 * likely the TELNET DM (data mark), we would
538 * stay in the TELNET SYNCH (SYNCHing) state.
539 * So, clocks to the rescue. If we've "just"
540 * received a DM, then we test for the
541 * presence of OOB data when the receive OOB
542 * fails (and AFTER we did the normal mode read
543 * to clear "at the mark").
544 */
545 if (SYNCHing) {
546 int atmark;
547
548 ioctl(net, SIOCATMARK, (char *)&atmark);
549 if (atmark) {
550 c = recv(net, netiring.supply, canread, MSG_OOB);
551 if ((c == -1) && (errno == EINVAL)) {
552 c = recv(net, netiring.supply, canread, 0);
553 if (clocks.didnetreceive < clocks.gotDM) {
554 SYNCHing = stilloob(net);
555 }
556 }
557 } else {
558 c = recv(net, netiring.supply, canread, 0);
559 }
560 } else {
561 c = recv(net, netiring.supply, canread, 0);
562 }
563 settimer(didnetreceive);
564#else /* !defined(SO_OOBINLINE) */
565 c = recv(net, netiring.supply, canread, 0);
566#endif /* !defined(SO_OOBINLINE) */
567 if (c < 0 && errno == EWOULDBLOCK) {
568 c = 0;
569 } else if (c <= 0) {
570 return -1;
571 }
572 if (netdata) {
573 Dump('<', netiring.supply, c);
574 }
ad1c581e
GM
575 if (c)
576 ring_supplied(&netiring, c);
b307f09e
GM
577 returnValue = 1;
578 }
579
580 /*
581 * Something to read from the tty...
582 */
583 if (FD_ISSET(tin, &ibits)) {
584 FD_CLR(tin, &ibits);
448f9c06 585 c = TerminalRead(ttyiring.supply, ring_empty_consecutive(&ttyiring));
b307f09e
GM
586 if (c < 0 && errno == EWOULDBLOCK) {
587 c = 0;
588 } else {
b307f09e 589 /* EOF detection for line mode!!!! */
75ec5474 590 if ((c == 0) && MODE_LOCAL_CHARS(globalmode) && isatty(tin)) {
b307f09e
GM
591 /* must be an EOF... */
592 *ttyiring.supply = termEofChar;
593 c = 1;
594 }
b307f09e
GM
595 if (c <= 0) {
596 return -1;
597 }
ad1c581e 598 ring_supplied(&ttyiring, c);
b307f09e 599 }
b307f09e
GM
600 returnValue = 1; /* did something useful */
601 }
602
603 if (FD_ISSET(net, &obits)) {
604 FD_CLR(net, &obits);
605 returnValue |= netflush();
606 }
607 if (FD_ISSET(tout, &obits)) {
608 FD_CLR(tout, &obits);
609 returnValue |= ttyflush(SYNCHing|flushout);
610 }
611
612 return returnValue;
613}
e767b7ab 614#endif /* defined(unix) */