|
|
1.1 root 1: #ifndef lint
2: static char *rcsid = "$Header: gaptelnet.c,v 2.2 86/05/16 11:03:33 jqj Exp $";
3: #endif
4:
5: /*
6: * XNS User telnet program.
7: */
8:
9: /* $Log: gaptelnet.c,v $
10: * Revision 2.2 86/05/16 11:03:33 jqj
11: * fix to correspond to new semantics for enumerations (global)
12: *
13: * Revision 2.1 86/03/01 09:26:04 jqj
14: * Accept data with datastream=0 for the sake of incorrectly implemented
15: * servers (e.g. InterLisp-D). If unrecognized inband controls arrive,
16: * don't choke.
17: *
18: * Revision 2.0 85/11/21 07:23:04 jqj
19: * 4.3BSD standard release
20: *
21: * Revision 1.3 85/11/20 14:00:08 jqj
22: * added symbolic entries for Gap connection types
23: *
24: * Revision 1.2 85/05/22 09:46:37 jqj
25: * VAX 4.3beta baseline version
26: *
27: * Revision 1.2 85/05/22 09:46:37 jqj
28: * Beta-test GAP telnet
29: *
30: * based on tcp/telnet:
31: * static char *rcsid = "$Header: gaptelnet.c,v 2.2 86/05/16 11:03:33 jqj Exp $";
32: * static char sccsid[] = "@(#)telnet.c 4.24 (Berkeley) 7/20/83";
33: */
34:
35: #include <sys/types.h>
36: #include <sys/socket.h>
37: #include <sys/ioctl.h>
38:
39: #include <netns/ns.h>
40: #include <netns/idp.h>
41: #include <netns/sp.h> /* for spphdr */
42: #include <netns/spidp.h>
43:
44: #include <stdio.h>
45: #include <ctype.h>
46: #include <errno.h>
47: #include <signal.h>
48:
49: #include <xnscourier/Clearinghouse2.h>
50: #include "GAP3.h"
51: #include "gapcontrols.h"
52: #include <xnscourier/except.h>
53: #include <xnscourier/CH.h>
54:
55: #define strip(x) ((x)&0177)
56:
57: char ttyobuf[BUFSIZ], *tfrontp = ttyobuf, *tbackp = ttyobuf;
58: char netobuf[BUFSIZ], *nfrontp = netobuf, *nbackp = netobuf;
59:
60:
61: int connected;
62: CourierConnection *cconn;
63: int net;
64: FILE *logfile;
65: int debug = 0;
66: int crmod = 0;
67: char *prompt;
68: char escape = CTRL(]);
69: char on = 1;
70:
71: char line[200];
72: int margc;
73: char *margv[20];
74:
75: jmp_buf toplevel;
76: jmp_buf peerdied;
77:
78: extern int errno;
79:
80: int tn(), quit(), suspend(), bye(), help();
81: int setescape(), status(), toggle(), setoptions();
82: int setcrmod(), setdebug(), setlog();
83:
84: #define HELPINDENT (sizeof ("connect"))
85:
86: struct cmd {
87: char *name; /* command name */
88: char *help; /* help string */
89: int (*handler)(); /* routine which executes command */
90: };
91:
92: char openhelp[] = "connect to a site";
93: char closehelp[] = "close current connection";
94: char quithelp[] = "exit telnet";
95: char zhelp[] = "suspend telnet";
96: char debughelp[] = "toggle debugging";
97: char escapehelp[] = "set escape character";
98: char statushelp[] = "print status information";
99: char helphelp[] = "print help information";
100: char crmodhelp[] = "toggle mapping of received carriage returns";
101: char loghelp[] = "toggle logging of session";
102:
103: struct cmd cmdtab[] = {
104: { "open", openhelp, tn },
105: { "close", closehelp, bye },
106: { "quit", quithelp, quit },
107: { "z", zhelp, suspend },
108: { "escape", escapehelp, setescape },
109: { "status", statushelp, status },
110: /* { "crmod", crmodhelp, setcrmod }, */
111: { "debug", debughelp, setdebug },
112: { "log", loghelp, setlog },
113: { "?", helphelp, help },
114: 0
115: };
116:
117: struct sockaddr_ns sin;
118:
119: int intr(), deadpeer();
120: char *control();
121: struct cmd *getcmd();
122:
123: struct tchars otc;
124: struct ltchars oltc;
125: struct sgttyb ottyb;
126:
127: char *hostname;
128: char hnamebuf[45];
129:
130:
131: main(argc, argv)
132: int argc;
133: char *argv[];
134: {
135: ioctl(0, TIOCGETP, (char *)&ottyb);
136: ioctl(0, TIOCGETC, (char *)&otc);
137: ioctl(0, TIOCGLTC, (char *)&oltc);
138: setbuf(stdin, 0);
139: setbuf(stdout, 0);
140: prompt = argv[0];
141: if (argc > 1 && !strcmp(argv[1], "-d"))
142: debug = SO_DEBUG, argv++, argc--;
143: if (argc != 1) {
144: if (setjmp(toplevel) != 0)
145: exit(0);
146: tn(argc, argv);
147: }
148: setjmp(toplevel);
149: for (;;)
150: command(1);
151: }
152:
153: tn(argc, argv)
154: int argc;
155: char *argv[];
156: {
157: register int c;
158: register struct ns_addr *host;
159: extern struct ns_addr *getXNSaddr();
160: Clearinghouse2_ObjectName hostoname, hdefault;
161: LongCardinal servicetype;
162:
163: if (connected) {
164: printf("?Already connected to %s\n", hostname);
165: return;
166: }
167: if (argc < 2) {
168: strcpy(line, "Connect ");
169: printf("(to) ");
170: gets(&line[strlen(line)]);
171: makeargv();
172: argc = margc;
173: argv = margv;
174: }
175: if (argc > 3) {
176: printf("usage: %s host-name [service-type]\n", argv[0]);
177: return;
178: }
179: if (argc == 2) servicetype = TTYService_sa; /* default to 1 */
180: else if (strcmp(argv[2],"sa") == 0) servicetype = TTYService_sa;
181: else if (strncmp(argv[2],"re",2) == 0 ||
182: strcmp(argv[2],"exec") == 0) servicetype = TTYService_exec;
183: else if (strcmp(argv[2],"its") == 0) servicetype = TTYService_its;
184: else servicetype = atoi(argv[2]);
185: CH_NameDefault(&hdefault);
186: hostoname = CH_StringToName(argv[1], &hdefault);
187: if ((host = CH_LookupAddrDN(hostoname,0,hnamebuf,sizeof(hnamebuf)))) {
188: sin.sns_family = AF_NS;
189: host->x_port = htons(IDPPORT_COURIER);
190: bcopy(host, (caddr_t)&sin.sns_addr, sizeof(host));
191: /* hnamebuf is filled in by CH_LookupAddrDN */
192: hostname = hnamebuf;
193: } else if ((host = getXNSaddr(argv[1]))) {
194: sin.sns_family = AF_NS;
195: bcopy(host, (caddr_t)&sin.sns_addr, sizeof(host));
196: strcpy(hnamebuf, argv[1]);
197: hostname = hnamebuf;
198: } else {
199: printf("%s: unknown host\n", argv[1]);
200: return;
201: }
202: cconn = CourierOpen(host);
203: if(cconn == NULL) {
204: fprintf(stderr,"Courier connection failed\n");
205: return;
206: }
207: net = *(int*)cconn;
208: signal(SIGINT, intr);
209: signal(SIGPIPE, deadpeer);
210: printf("Trying...\n");
211: if (createsession(cconn,servicetype) < 0)
212: return;
213: connected++;
214: call(status, "status", 0);
215: sleep(1);
216: if (setjmp(peerdied) == 0)
217: telnet(net);
218: fprintf(stderr, "\nConnection closed by foreign host.\n");
219: exit(1);
220: }
221:
222: /*
223: * create a session
224: */
225: createsession(cconn, servicetype)
226: CourierConnection *cconn;
227: LongCardinal servicetype;
228: {
229: GAP3_SessionParameterObject pobj;
230: GAP3_TransportObject tobjs[2];
231: GAP3_CommParamObject *cp;
232: struct {
233: Cardinal length;
234: GAP3_TransportObject *sequence;
235: } tobjlist;
236: Authentication1_Credentials creds;
237: Authentication1_Verifier verifier;
238:
239: pobj.designator = GAP3_oldTtyHost; /* 11 */
240: pobj.GAP3_oldTtyHost_case.charLength = GAP3_seven;
241: pobj.GAP3_oldTtyHost_case.parity = GAP3_none;
242: pobj.GAP3_oldTtyHost_case.stopBits = GAP3_oneStopBit;
243: pobj.GAP3_oldTtyHost_case.frameTimeout = 20;
244: /*
245: tobjs[0].designator = GAP3_rs232c;
246: cp = &tobjs[0].GAP3_rs232c_case.commParams;
247: cp->accessDetail.designator = GAP3_directConn;
248: cp->accessDetail.directConn_case.duplex = GAP3_fullduplex;
249: cp->accessDetail.directConn_case.lineType = GAP3_asynchronous;
250: cp->accessDetail.directConn_case.lineSpeed = GAP3_bps300;
251: tobjs[0].rs232c_case.preemptOthers = GAP3_preemptInactive;
252: tobjs[0].rs232c_case.preemptMe = GAP3_preemptInactive;
253: tobjs[0].rs232c_case.phoneNumber = "";
254: tobjs[0].rs232c_case.line.designator = GAP3_reserveNeeded;
255: tobjs[0].rs232c_case.line.reserveNeeded_case.lineNumber = 1;
256: */
257: tobjs[0].designator = GAP3_service;
258: tobjs[0].GAP3_service_case.id = servicetype; /* 1 == SA */
259:
260: tobjs[1].designator = GAP3_teletype;
261: tobjlist.length = 2;
262: tobjlist.sequence = tobjs;
263: MakeSimpleCredsAndVerifier(0, 0, &creds, &verifier);
264: DURING
265: (void) GAP3_Create(cconn, NULL, pobj, tobjlist, 0, creds, verifier);
266: HANDLER {
267: char *msg;
268: switch (Exception.Code) {
269: case GAP3_mediumConnectFailed:
270: msg = "medium connect failed";
271: break;
272: case GAP3_illegalTransport:
273: msg = "illegal transport type";
274: break;
275: case GAP3_tooManyGateStreams:
276: case GAP3_serviceTooBusy:
277: msg = "insufficient resources";
278: break;
279: case GAP3_serviceNotFound:
280: msg = "service type not found";
281: break;
282: case GAP3_userNotAuthenticated:
283: case GAP3_userNotAuthorized:
284: msg = "authentication problem";
285: break;
286: case REJECT_ERROR:
287: switch (CourierErrArgs(rejectionDetails,designator)){
288: case noSuchProgramNumber:
289: msg = "server does not support GAP";
290: break;
291: case noSuchVersionNumber:
292: msg = "server does not support our GAP version";
293: break;
294: default:
295: msg = "connection rejected";
296: }
297: break;
298: case PROTOCOL_VIOLATION:
299: msg = "protocol violation by remote server";
300: break;
301: default:
302: msg = "some random error";
303: break;
304: }
305: fprintf(stderr,"Error creating connection, %s\n",
306: msg);
307: return(-1);
308: } END_HANDLER;
309: return(0);
310: }
311:
312: /*
313: * Print status about the connection.
314: */
315: /*VARARGS*/
316: status()
317: {
318: if (connected)
319: printf("Connected to %s.\n", hostname);
320: else
321: printf("No connection.\n");
322: printf("Escape character is '%s'.\n", control(escape));
323: fflush(stdout);
324: }
325:
326: makeargv()
327: {
328: register char *cp;
329: register char **argp = margv;
330:
331: margc = 0;
332: for (cp = line; *cp;) {
333: while (isspace(*cp))
334: cp++;
335: if (*cp == '\0')
336: break;
337: *argp++ = cp;
338: margc += 1;
339: while (*cp != '\0' && !isspace(*cp))
340: cp++;
341: if (*cp == '\0')
342: break;
343: *cp++ = '\0';
344: }
345: *argp++ = 0;
346: }
347:
348: /*VARARGS*/
349: suspend()
350: {
351: register int save;
352:
353: save = mode(0);
354: kill(0, SIGTSTP);
355: /* reget parameters in case they were changed */
356: ioctl(0, TIOCGETP, (char *)&ottyb);
357: ioctl(0, TIOCGETC, (char *)&otc);
358: ioctl(0, TIOCGLTC, (char *)&oltc);
359: (void) mode(save);
360: }
361:
362: /*VARARGS*/
363: bye()
364: {
365: register char *op;
366:
367: (void) mode(0);
368: if (connected) {
369: sendoobdata(GAPCTLcleanup);
370: setsockopt(net, NSPROTO_SPP, SO_HEADERS_ON_OUTPUT, &on,
371: sizeof(on));
372: sppclose(net);
373: printf("Connection closed.\n");
374: connected = 0;
375: }
376: }
377:
378: /*VARARGS*/
379: quit()
380: {
381: call(bye, "bye", 0);
382: exit(0);
383: }
384:
385: /*
386: * Toggle debugging
387: */
388: setdebug(argc, argv)
389: {
390: debug = ~debug;
391: }
392:
393: /*
394: * Toggle logging
395: */
396: setlog(argc, argv)
397: int argc;
398: char *argv[];
399: {
400: if (argc > 2)
401: printf("Syntax: %s [filename]\n",argv[0]);
402: else if (logfile != (FILE*) 0) {
403: /* currently logging */
404: fclose(logfile);
405: printf("Log file closed\n");
406: logfile = (FILE*) 0;
407: if (argc == 2 && (logfile = fopen(argv[1],"a")) != (FILE*)0)
408: printf("Logging to %s\n",argv[1]);
409: } else {
410: /* not currently logging */
411: if (argc == 1)
412: printf("Logging already disabled\n");
413: else if (argc == 2 &&
414: (logfile = fopen(argv[1],"a")) != (FILE*)0 )
415: printf("Logging to %s\n",argv[1]);
416: }
417: }
418:
419: /*
420: * Help command.
421: */
422: help(argc, argv)
423: int argc;
424: char *argv[];
425: {
426: register struct cmd *c;
427:
428: if (argc == 1) {
429: printf("Commands may be abbreviated. Commands are:\n\n");
430: for (c = cmdtab; c->name; c++)
431: printf("%-*s\t%s\n", HELPINDENT, c->name, c->help);
432: return;
433: }
434: while (--argc > 0) {
435: register char *arg;
436: arg = *++argv;
437: c = getcmd(arg);
438: if (c == (struct cmd *)-1)
439: printf("?Ambiguous help command %s\n", arg);
440: else if (c == (struct cmd *)0)
441: printf("?Invalid help command %s\n", arg);
442: else
443: printf("%s\n", c->help);
444: }
445: }
446:
447: /*
448: * Call routine with argc, argv set from args (terminated by 0).
449: * VARARGS2
450: */
451: call(routine, args)
452: int (*routine)();
453: int args;
454: {
455: register int *argp;
456: register int argc;
457:
458: for (argc = 0, argp = &args; *argp++ != 0; argc++)
459: ;
460: (*routine)(argc, &args);
461: }
462:
463: struct tchars notc = { -1, -1, -1, -1, -1, -1 };
464: struct ltchars noltc = { -1, -1, -1, -1, -1, -1 };
465:
466: mode(f)
467: register int f;
468: {
469: static int prevmode = 0;
470: struct tchars *tc;
471: struct ltchars *ltc;
472: struct sgttyb sb;
473: int onoff, old;
474:
475: if (prevmode == f)
476: return (f);
477: old = prevmode;
478: prevmode = f;
479: sb = ottyb;
480: switch (f) {
481:
482: case 0:
483: onoff = 0;
484: tc = &otc;
485: ltc = &oltc;
486: break;
487:
488: case 1:
489: case 2:
490: sb.sg_flags |= CBREAK;
491: if (f == 1)
492: sb.sg_flags &= ~(ECHO|CRMOD);
493: else
494: sb.sg_flags |= ECHO|CRMOD;
495: sb.sg_erase = sb.sg_kill = -1;
496: tc = ¬c;
497: ltc = &noltc;
498: onoff = 1;
499: break;
500:
501: default:
502: return (old);
503: }
504: ioctl(fileno(stdin), TIOCSLTC, (char *)ltc);
505: ioctl(fileno(stdin), TIOCSETC, (char *)tc);
506: ioctl(fileno(stdin), TIOCSETP, (char *)&sb);
507: ioctl(fileno(stdin), FIONBIO, &onoff);
508: ioctl(fileno(stdout), FIONBIO, &onoff);
509: return (old);
510: }
511:
512: struct {struct sphdr hdr;
513: char data[BUFSIZ];
514: } sibuf;
515: char *sbp;
516: char tibuf[BUFSIZ], *tbp;
517: int scc, tcc;
518:
519: /*
520: * Select from tty and network...
521: */
522: telnet(s)
523: int s;
524: {
525: register int c;
526: int tin = fileno(stdin), tout = fileno(stdout);
527: int on = 1;
528: int ibits, obits;
529:
530: (void) mode(1);
531: ioctl(s, FIONBIO, &on);
532: changeSPPopts(net, GAPCTLnone, 1); /* datastream "normal", eom */
533: for (;;) {
534: ibits = obits = 0;
535: if (nfrontp - nbackp)
536: obits |= (1 << s);
537: else
538: ibits |= (1 << tin);
539: if (tfrontp - tbackp)
540: obits |= (1 << tout);
541: else
542: ibits |= (1 << s);
543: if (scc < 0 && tcc < 0)
544: break;
545: select(16, &ibits, &obits, 0, 0);
546: if (ibits == 0 && obits == 0) {
547: sleep(5);
548: continue;
549: }
550:
551: /*
552: * Something to read from the network...
553: */
554: if (ibits & (1 << s)) {
555: scc = read(s, &sibuf, sizeof (sibuf))
556: - sizeof(struct sphdr);
557: #ifdef DEBUG
558: if (debug)
559: printf("reading %d bytes from net\n", scc);
560: #endif
561: if (scc < 0 && errno == EWOULDBLOCK)
562: scc = 0;
563: else if (scc < 0)
564: break; /* protocol violation? */
565: else if (sibuf.hdr.sp_cc & SP_OB) {
566: /* status or OOB control */
567: switch ((u_char) *sibuf.data) {
568: case GAPCTLareYouThere:
569: sendoobdata(GAPCTLiAmHere);
570: break;
571: case GAPCTLmediumDown:
572: (void) mode(0);
573: longjmp(peerdied, -1);
574: /*NOTREACHED*/
575: default:
576: /* ignore others */
577: break;
578: }
579: scc = 0;
580: }
581: else if (sibuf.hdr.sp_dt == GAPCTLnone ||
582: sibuf.hdr.sp_dt == 0) {
583: /* normal case, plus Lisp bogosity */
584: sbp = sibuf.data;
585: }
586: else if(sibuf.hdr.sp_dt == GAPCTLcleanup){
587: sendoobdata(GAPCTLcleanup);
588: /* should get an END next */
589: scc = 0;
590: }
591: else if(sibuf.hdr.sp_dt == SPPSST_END) {
592: setsockopt(net, NSPROTO_SPP,
593: SO_HEADERS_ON_OUTPUT,
594: &on, sizeof(on));
595: sppclosereply(net);
596: (void) mode(0);
597: longjmp(peerdied, -1);
598: /*NOTREACHED*/
599: }
600: else scc = 0; /* ignore other inband controls */
601: }
602:
603: /*
604: * Something to read from the tty...
605: */
606: if (ibits & (1 << tin)) {
607: tcc = read(tin, tibuf, sizeof (tibuf));
608: if (tcc < 0 && errno == EWOULDBLOCK)
609: tcc = 0;
610: else {
611: if (tcc <= 0)
612: break;
613: tbp = tibuf;
614: }
615: }
616:
617: while (tcc > 0) {
618: register int c;
619:
620: if ((&netobuf[BUFSIZ] - nfrontp) < 2)
621: break;
622: c = *tbp++ & 0377, tcc--;
623: if (strip(c) == escape) {
624: command(0);
625: tcc = 0;
626: break;
627: }
628: /* We don't do any input translation at the moment */
629: #ifdef notdef
630: switch (c) {
631: case '\n':
632: *nfrontp++ = '\r';
633: *nfrontp++ = '\n';
634: break;
635: case '\r':
636: *nfrontp++ = '\r';
637: *nfrontp++ = '\n';
638: break;
639: default:
640: *nfrontp++ = c;
641: break;
642: }
643: #else
644: *nfrontp++ = c;
645: #endif /* notdef */
646: }
647: if ((obits & (1 << s)) && (nfrontp - nbackp) > 0)
648: netflush(s);
649: while (scc > 0) {
650: register int c;
651: c = *sbp++&0377; scc--;
652: /* nor do we do any output translation */
653: *tfrontp++ = c;
654: }
655: if ((obits & (1 << tout)) && (tfrontp - tbackp) > 0)
656: ttyflush(tout);
657: }
658: (void) mode(0);
659: }
660:
661: command(top)
662: int top;
663: {
664: register struct cmd *c;
665: int oldmode, wasopen;
666:
667: oldmode = mode(0);
668: if (!top)
669: putchar('\n');
670: else
671: signal(SIGINT, SIG_DFL);
672: for (;;) {
673: printf("%s> ", prompt);
674: if (gets(line) == 0) {
675: if (feof(stdin)) {
676: clearerr(stdin);
677: putchar('\n');
678: }
679: break;
680: }
681: if (line[0] == 0)
682: break;
683: makeargv();
684: c = getcmd(margv[0]);
685: if (c == (struct cmd *)-1) {
686: printf("?Ambiguous command\n");
687: continue;
688: }
689: if (c == 0) {
690: printf("?Invalid command\n");
691: continue;
692: }
693: (*c->handler)(margc, margv);
694: if (c->handler != help)
695: break;
696: }
697: if (!top) {
698: if (!connected)
699: longjmp(toplevel, 1);
700: (void) mode(oldmode);
701: }
702: }
703:
704: /*
705: * Set the escape character.
706: */
707: setescape(argc, argv)
708: int argc;
709: char *argv[];
710: {
711: register char *arg;
712: char buf[50];
713:
714: if (argc > 2)
715: arg = argv[1];
716: else {
717: printf("new escape character: ");
718: gets(buf);
719: arg = buf;
720: }
721: if (arg[0] != '\0')
722: escape = arg[0];
723: printf("Escape character is '%s'.\n", control(escape));
724: fflush(stdout);
725: }
726:
727: /*
728: * Construct a control character sequence
729: * for a special character.
730: */
731: char *
732: control(c)
733: register int c;
734: {
735: static char buf[3];
736:
737: if (c == 0177)
738: return ("^?");
739: if (c >= 040) {
740: buf[0] = c;
741: buf[1] = 0;
742: } else {
743: buf[0] = '^';
744: buf[1] = '@'+c;
745: buf[2] = 0;
746: }
747: return (buf);
748: }
749:
750: struct cmd *
751: getcmd(name)
752: register char *name;
753: {
754: register char *p, *q;
755: register struct cmd *c, *found;
756: register int nmatches, longest;
757:
758: longest = 0;
759: nmatches = 0;
760: found = 0;
761: for (c = cmdtab; p = c->name; c++) {
762: for (q = name; *q == *p++; q++)
763: if (*q == 0) /* exact match? */
764: return (c);
765: if (!*q) { /* the name was a prefix */
766: if (q - name > longest) {
767: longest = q - name;
768: nmatches = 1;
769: found = c;
770: } else if (q - name == longest)
771: nmatches++;
772: }
773: }
774: if (nmatches > 1)
775: return ((struct cmd *)-1);
776: return (found);
777: }
778:
779: deadpeer()
780: {
781: (void) mode(0);
782: longjmp(peerdied, -1);
783: }
784:
785: intr()
786: {
787: (void) mode(0);
788: longjmp(toplevel, -1);
789: }
790:
791: ttyflush(fd)
792: {
793: register int n;
794:
795: if ((n = tfrontp - tbackp) > 0) {
796: if (logfile != (FILE*)0)
797: fwrite(tbackp, 1, n, logfile);
798: n = write(fd, tbackp, n);
799: }
800: if (n < 0)
801: return;
802: tbackp += n;
803: if (tbackp == tfrontp)
804: tbackp = tfrontp = ttyobuf;
805: }
806:
807: netflush(fd)
808: {
809: int n;
810:
811: if ((n = nfrontp - nbackp) > 0)
812: n = write(fd, nbackp, n);
813: #ifdef DEBUG
814: if (debug)
815: printf("writing %d of %d bytes to net\n", n, nfrontp-nbackp);
816: #endif
817: if (n < 0) {
818: if (errno != ENOBUFS && errno != EWOULDBLOCK) {
819: (void) mode(0);
820: perror(hostname);
821: close(fd);
822: longjmp(peerdied, -1);
823: /*NOTREACHED*/
824: }
825: n = 0;
826: }
827: nbackp += n;
828: if (nbackp == nfrontp)
829: nbackp = nfrontp = netobuf;
830: }
831:
832: /*
833: * Send out of band data to other end of network
834: */
835: sendoobdata(value)
836: char value;
837: {
838: send(net, &value, 1, MSG_OOB);
839: }
840:
841: changeSPPopts(s, stream, eom)
842: int s; /* SPP socket */
843: u_char stream; /* datastream type */
844: char eom; /* Boolean EOM */
845: {
846: struct sphdr sphdr;
847: int off = 0;
848:
849: sphdr.sp_dt = stream;
850: sphdr.sp_cc = (eom ? SP_EM : 0);
851: setsockopt(s, NSPROTO_SPP, SO_HEADERS_ON_OUTPUT, &off, sizeof(off));
852: setsockopt(s, NSPROTO_SPP, SO_DEFAULT_HEADERS, &sphdr, sizeof(sphdr));
853: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.