home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / compsrcs / unix / volume04 / telnetd < prev    next >
Encoding:
Internet Message Format  |  1988-09-11  |  40.7 KB

  1. From: talcott!topaz!hedrick (Charles Hedrick)
  2. Subject: telnetd in the kernel
  3. Newsgroups: mod.sources
  4. Approved: jpn@panda.UUCP
  5.  
  6. Mod.sources:  Volume 4, Issue 90
  7. Submitted by: talcott!topaz!hedrick (Charles Hedrick)
  8.  
  9. [ I haven't tried any of this - you're on your own - mod ]
  10.  
  11. This is a modified version of the posting a couple of weeks ago by
  12. nyit!rick.  The original one moved the performance-critical part of
  13. rlogin into the kernel.  My version handles both rlogin and telnet.
  14. Note however, that it handles only the server part.  In our
  15. environment, many users have lines connected to terminal servers that
  16. speak Telnet.  We would like to be able to have a machine all of whose
  17. users are coming in via Telnet.  I am much less concerned about
  18. outgoing Telnet.  (After all, we can just hit BREAK and open another
  19. sesssion.  Why run Telnet on a host?)  Tests on a Pyramid 90X suggest
  20. that typing a file at 9600 baud via telnet uses a large fraction of
  21. the CPU.  Not all of that shows up in ps, but in vmstat, some extra
  22. system overhead show up.  Not only does telnet eat your CPU, but it is
  23. also more sensitive to load than it might be.  That is, under heavy
  24. load, you not only have to worry about your Emacs getting paged out.
  25. Your telnetd will also get delayed.  By moving telnetd into the
  26. kernel, the CPU usage is dramatically decreased.  I haven't done any
  27. really careful tests, but it appears that typing a file at 9600 baud
  28. uses 20% of the CPU briefly while buffers get filled, and less than
  29. 10% thereafter.  (I can't be sure.  It could be as low as 5%.)  More
  30. importantly, it makes your connection feel like a local terminal,
  31. assuming that your telnet user process is not adding any delay.
  32.  
  33. Rick's original code was quite simple, because rlogin is quite simple.
  34. rlogind simply does a magic IOCTL which causes the kernel to
  35. crosspatch the incoming network connection to the pty.  It stays that
  36. way until the user logs out or the connection goes away.
  37. Unfortunately, it is not practical to implement Telnet entirely in the
  38. kernel.  Telnet has things called "negotiations".  These allow one end
  39. to ask the other to turn off echoing, go into binary mode, and any of
  40. a number of wierder options.  These, and a few other Telnet commands,
  41. are all preceeded by an IAC character (decimal 255).  If you actually
  42. type an IAC character on your terminal, your telnet process will send
  43. two IAC's, so that it doesn't look like a negotiation.  This means
  44. that telnetd must scan the network for IAC's.  When it finds one, it
  45. must interpret the resulting command.  It must also scan the terminal
  46. output from the pty.  If it finds any IAC's, it must add an extra IAC,
  47. so that the result is seen by the other end as an IAC character,
  48. rather than a command.  It is reasonable to do the output processing
  49. in the kernel.  But it is not reasonable to do the input processing.
  50. So when my code sees an IAC in incoming data, it simply breaks the
  51. link and returns from the IOCTL.  The daemon reads the command, does
  52. whatever it needs to do, and then returns to the kernel with the
  53. IOCTL.  The IOCTL used to pass fd's for the network and pty to be
  54. crosspatched.  I now add 8-bit modes in the high-order end of the
  55. argument, one for the input side and one for the output side.  0 gives
  56. you rlogin.  1 gives you normal telnet.  2 gives you telnet binary
  57. (which currently is implemented only for input, just as in 4.2
  58. telnetd).
  59.  
  60. Some caveats about this code:
  61.   1) the kernel code is well tested.  So is rlogind.  telnetd is
  62.     not well tested.  It works with Unix, TOPS-20, and Bridge
  63.     terminal servers.  However none of those things is able
  64.     to generate certain of the telnet commands.  For example,
  65.     there is a Telnet protocol command to delete the previous
  66.     character.  Rather than send a rubout character, your
  67.     telnet user process can send a system-independent delete
  68.     character telnet command.  None of the systems we use do this.
  69.     We all just hit rubout, or whatever your delete character
  70.     is currently set to.  If there is a bug in this code, it
  71.     should be a fairly simple typo, and be easy enough to fix.
  72.   2) the telnetd code will work only with the modified kernel.
  73.     Rick's original rlogin was designed so it reverts to normal
  74.     code if you run it on a kernel without his patches.  The
  75.     changes to telnetd were more extensive, so I did not do it.
  76.     Presumably my version of telnetd will coredump if run on
  77.     kernel without these patches.
  78.   3) the kernel code is intended to be functionally identical to
  79.     the telnetd on which it is modelled.  In particular, I have
  80.     not fixed the bug involving bare CR's.  (According to the
  81.     telnet spec, if CR is not followed by LF, the server is
  82.     required to insert a NUL after the CR.  4.2 Telnet does
  83.     not do this.  Neither does my code.  All of the Telnet
  84.     user programs that we know about can handle CR's followed
  85.     by other things.  Implementing this would have taken more
  86.     time than I had to devote to the project.)
  87.   4) this code has been tested only on a Pyramid 90X.  It should work
  88.     unchanged with any release 3.0 Pyramid single-processor system.
  89.     The changes for a VAX should be fairly simple.  Actually, the
  90.     only one I know of is in nvs_output.  On the Pyramid, you
  91.     output something to the network by asking the network code
  92.     for some space, using sbnext.  This returns you a pointer.
  93.     You copy your data to the place pointed to.  You then do
  94.     tcp_usrreq(PRU_SEND ....  Apparently, on the VAX, things
  95.     work a bit differently.  You allocate an mbuf, copy the
  96.     data into the mbuf, and then pass the mbuf as an argument
  97.     to tcp_usrreq.  There are comments in nvs_output that suggest
  98.     what the code should probably look like, but I make no
  99.     guarantees.  To find it, search for the string "VAX" in
  100.     tty_nvs.c.  I believe that Pyramid operating system releases
  101.     older than 3.0 should be treated like a VAX.  To be sure,
  102.     find the code in tcp_usrreq that implements PRU_SEND.
  103.     (Just search for "case PRU_SEND" in ../netinet/tcp_usrreq.c.)
  104.     If that case contains a call to sbappend, then treat it like
  105.     a VAX.)
  106.   5) This code has not been symmetrized.  It will not run on a
  107.     Pyramid dual-processor system.  I think I know how to symmetrize
  108.     it.  But since I don't (yet) have a dual-processor machine, 
  109.     I have no way to test it.
  110.   6) in tty_nvs.c, set the flag NFS depending upon whether you have
  111.     Sun's NVS in your kernel.  Or if your compilation process
  112.     defines NFS externally, just remove the #define.
  113.  
  114. Even if you are not using telnet, you might want to look at this
  115. code.  I have improved rick's code in two major ways:
  116.   1) the original code used "busy waits" in the output code.
  117.     That is, when the network had enough data, the code would
  118.     dismiss for N milliseconds.  Every N msec it would check
  119.     to see if it was ready for more data.  I have added a
  120.     hook into sbwakeup, so that the code gets awakened when
  121.     there is more space.  It doesn't have to keep reactivating
  122.     and checking.
  123.   2) the original code has a table which gives the associations
  124.     between pty's and network connections.  If you have a
  125.     network connection and need to find the pty it goes to,
  126.     it does a linear search of that table.  I have added
  127.     a short to the socket buffer, and put the table index
  128.     into it.  This eliminates the search.  If you are not
  129.     using a Pyramid, make sure that this change to socketvar.h
  130.     isn't going to change the struct in some disasterous way.
  131.     It happened that on the Pyramid, there was a free short
  132.     in the place where I added that field.  If your compiler
  133.     allocates fields differently, it may not be free for you.
  134.  
  135. The rest of this posting consists of two pieces: a bunch of diffs to
  136. existing files, and a new file, tty_nvs.c.  If you have a Pyramid, you
  137. should modify .../conf/makefromsource (a simple makefile) to cause
  138. tty_nvs.c to be compiled and linked into the kernel.  I have no idea
  139. what you do on other machines.
  140.  
  141. *** ../conf/conf.c.HOLD    Thu Feb  6 00:13:04 1986
  142. --- ../conf/conf.c    Sun Apr 20 01:24:41 1986
  143. ***************
  144. *** 354,359
  145.   int    ptcopen(),ptcclose(),ptcread(),ptcwrite(),ptcselect();
  146.   int    ptyioctl(), ptsselect();
  147.   struct    tty pt_tty[];
  148.   #else
  149.   #define ptsopen        nodev
  150.   #define ptsclose    nodev
  151.  
  152. --- 354,361 -----
  153.   int    ptcopen(),ptcclose(),ptcread(),ptcwrite(),ptcselect();
  154.   int    ptyioctl(), ptsselect();
  155.   struct    tty pt_tty[];
  156. + struct socket *ptynvsso[NPTY];
  157. + int ptyoutmode[NPTY];
  158.   #else
  159.   #define ptsopen        nodev
  160.   #define ptsclose    nodev
  161. *** tty_pty.c.HOLD    Tue Aug 27 01:46:18 1985
  162. --- tty_pty.c    Sun Apr 20 04:45:42 1986
  163. ***************
  164. *** 26,31
  165.   extern int npty;    /* declared in conf.c */
  166.   extern struct    tty pt_tty[];
  167.   
  168.   /* NOTE: the following declaration is also make in conf.c
  169.        Keep the two in sync (should be put in a .h file somewhere) */
  170.   
  171.  
  172. --- 26,35 -----
  173.   extern int npty;    /* declared in conf.c */
  174.   extern struct    tty pt_tty[];
  175.   
  176. + #include "../h/socketvar.h"
  177. + extern struct socket *ptynvsso[];   /* socket indexed by pty minor dev# */
  178. +             /* decl in conf.c, so no dependence on NPTYS here */
  179.   /* NOTE: the following declaration is also make in conf.c
  180.        Keep the two in sync (should be put in a .h file somewhere) */
  181.   
  182. ***************
  183. *** 787,792
  184.       }
  185.       return (error);
  186.   }
  187.   
  188.   /*
  189.    * select routine for slave -- handles PF_REMOTE modes and PF_EOT states.
  190.  
  191. --- 791,837 -----
  192.       }
  193.       return (error);
  194.   }
  195. + /*
  196. +  * Transfer characters from NVS tty outq to associated socket
  197. +  * (Simply a jacket because timeout() accepts only 1 argument).
  198. +  *
  199. +  * Called at or below network IPL
  200. +  */
  201. + ptsnvsnet(tp)
  202. +     struct tty *tp;
  203. + {
  204. +     nvs_output(tp, &pt_ioctl[minor(tp->t_dev)].pt_send);
  205. + }
  206. + /*
  207. +  * Alternate t_oproc routine used when the pty is operating as an NVS
  208. +  */
  209. + ptsnvsstart(tp)
  210. +     register struct tty *tp;
  211. + {
  212. +     register int s;
  213. +     s = spl5();
  214. +     /*
  215. +      * TS_BUSY set means Ptsnvsnet() is either running or queued to run
  216. +      */
  217. +     if ((tp->t_state & TS_BUSY) == 0) {
  218. +         tp->t_state |= TS_BUSY;
  219. +         /*
  220. +          * If at low IPL, can make output happen now;
  221. +          * otherwise must sequence it through softclock
  222. +          */
  223. +         if (s == 0) {
  224. +             (void) spl0();        /* reduce IPL */
  225. +             nvs_output(tp, &pt_ioctl[minor(tp->t_dev)].pt_send);
  226. +         }
  227. +         else
  228. +             timeout(ptsnvsnet, (caddr_t)tp, 0);
  229. +     }
  230. +     splx(s);
  231. + }
  232.   
  233.   /*
  234.    * select routine for slave -- handles PF_REMOTE modes and PF_EOT states.
  235. *** uipc_socket2.c.HOLD    Tue Dec 10 19:57:26 1985
  236. --- uipc_socket2.c    Sun Apr 20 23:58:22 1986
  237. ***************
  238. *** 326,331
  239.       register struct sockbuf *sb;
  240.   {
  241.   
  242.       if (sb->sb_sel) {
  243.           selwakeup(sb->sb_sel, sb->sb_flags & SB_COLL);
  244.           sb->sb_sel = 0;
  245.  
  246. --- 326,340 -----
  247.       register struct sockbuf *sb;
  248.   {
  249.   
  250. +     if (sb->sb_flags & SB_NVS) {
  251. +         nvs_input(sb);
  252. +         return;
  253. +     }
  254. +     if (sb->sb_flags & SB_NVS_WAIT) {
  255. +       if (sbspace(sb) >= sb->sb_lowat)
  256. +         nvs_output_wake(sb);
  257. +       return;
  258. +     }
  259.       if (sb->sb_sel) {
  260.           selwakeup(sb->sb_sel, sb->sb_flags & SB_COLL);
  261.           sb->sb_sel = 0;
  262. *** ../netinet/tcp_usrreq.c.HOLD    Sat Apr 19 02:13:50 1986
  263. --- ../netinet/tcp_usrreq.c    Sat Apr 19 03:25:37 1986
  264. ***************
  265. *** 28,33
  266.   #include "../netinet/tcpip.h"
  267.   #include "../netinet/tcp_debug.h"
  268.   
  269.   /*
  270.    * TCP protocol interface to socket abstraction.
  271.    */
  272.  
  273. --- 28,35 -----
  274.   #include "../netinet/tcpip.h"
  275.   #include "../netinet/tcp_debug.h"
  276.   
  277. + #include "../h/ioctl.h"
  278.   /*
  279.    * TCP protocol interface to socket abstraction.
  280.    */
  281. ***************
  282. *** 220,225
  283.   
  284.   /* SOME AS YET UNIMPLEMENTED HOOKS */
  285.       case PRU_CONTROL:
  286.           error = EOPNOTSUPP;
  287.           break;
  288.   
  289.  
  290. --- 222,234 -----
  291.   
  292.   /* SOME AS YET UNIMPLEMENTED HOOKS */
  293.       case PRU_CONTROL:
  294. +         if ((int)m == SIOCJNVS) {
  295. +             if (tp->t_state == TCPS_ESTABLISHED)
  296. +                 error = nvs_ioc_join(so, *(int *)nam);
  297. +             else
  298. +                 error = ENOTCONN;
  299. +             break;
  300. +         }
  301.           error = EOPNOTSUPP;
  302.           break;
  303.   
  304. *** ioctl.h.HOLD    Thu Feb  6 01:03:11 1986
  305. --- ioctl.h    Thu Feb  6 01:03:11 1986
  306. ***************
  307. *** 394,399
  308.   #define    SIOCATMARK    _IOR(s,  7, int)        /* at oob mark? */
  309.   #define    SIOCSPGRP    _IOW(s,  8, int)        /* set process group */
  310.   #define    SIOCGPGRP    _IOR(s,  9, int)        /* get process group */
  311.   
  312.   #define    SIOCADDRT    _IOW(r, 10, struct rtentry)    /* add route */
  313.   #define    SIOCDELRT    _IOW(r, 11, struct rtentry)    /* delete route */
  314.  
  315. --- 394,400 -----
  316.   #define    SIOCATMARK    _IOR(s,  7, int)        /* at oob mark? */
  317.   #define    SIOCSPGRP    _IOW(s,  8, int)        /* set process group */
  318.   #define    SIOCGPGRP    _IOR(s,  9, int)        /* get process group */
  319. + #define SIOCJNVS    _IOW(s, 71, int)        /* join NVS pty&socket */
  320.   
  321.   #define    SIOCADDRT    _IOW(r, 10, struct rtentry)    /* add route */
  322.   #define    SIOCDELRT    _IOW(r, 11, struct rtentry)    /* delete route */
  323. *** socketvar.h.HOLD    Fri Dec  6 15:08:43 1985
  324. --- socketvar.h    Fri Dec  6 15:08:43 1985
  325. ***************
  326. *** 45,50
  327.           struct    mbuf *sb_mb;    /* the mbuf chain */
  328.           struct    proc *sb_sel;    /* process selecting read/write */
  329.           short    sb_flags;    /* flags, see below */
  330.       } so_rcv, so_snd;
  331.   #define    SB_LOCK        0x01        /* lock on data queue (so_rcv only) */
  332.   #define    SB_WANT        0x02        /* someone is waiting to lock */
  333.  
  334. --- 45,55 -----
  335.           struct    mbuf *sb_mb;    /* the mbuf chain */
  336.           struct    proc *sb_sel;    /* process selecting read/write */
  337.           short    sb_flags;    /* flags, see below */
  338. + /*
  339. +  * the following is gross, but if the comment above is right, we can't
  340. +  * add real pointer because it would make the structure too long
  341. +  */
  342. +         short    sb_nvs_index;    /* index into nvs data */
  343.       } so_rcv, so_snd;
  344.   #define    SB_LOCK        0x01        /* lock on data queue (so_rcv only) */
  345.   #define    SB_WANT        0x02        /* someone is waiting to lock */
  346. ***************
  347. *** 53,58
  348.   #define    SB_COLL        0x10        /* collision selecting */
  349.   #define SB_WAIT_SINGLE  0x20        /* someone waiting to lock (but only 
  350.                          wakeup 1 process when available) */
  351.       short    so_timeo;        /* connection timeout */
  352.       u_short    so_error;        /* error affecting connection */
  353.       short    so_oobmark;        /* chars to oob mark */
  354.  
  355. --- 58,65 -----
  356.   #define    SB_COLL        0x10        /* collision selecting */
  357.   #define SB_WAIT_SINGLE  0x20        /* someone waiting to lock (but only 
  358.                          wakeup 1 process when available) */
  359. + #define SB_NVS        0x40        /* socket crossbarred to NVS pty */
  360. + #define SB_NVS_WAIT    0x80        /* waiting for output buffer space */
  361.       short    so_timeo;        /* connection timeout */
  362.       u_short    so_error;        /* error affecting connection */
  363.       short    so_oobmark;        /* chars to oob mark */
  364. *** /src/usr.etc/in.telnetd.c.ORIG    Thu Oct 31 21:26:44 1985
  365. --- /src/usr.etc/in.telnetd.c    Sun Apr 20 06:06:04 1986
  366. ***************
  367. *** 52,58
  368.    */
  369.   char    ptyibuf[BUFSIZ], *ptyip = ptyibuf;
  370.   char    ptyobuf[BUFSIZ], *pfrontp = ptyobuf, *pbackp = ptyobuf;
  371. ! char    netibuf[BUFSIZ], *netip = netibuf;
  372.   char    netobuf[BUFSIZ], *nfrontp = netobuf, *nbackp = netobuf;
  373.   int    pcc, ncc;
  374.   
  375.  
  376. --- 54,60 -----
  377.    */
  378.   char    ptyibuf[BUFSIZ], *ptyip = ptyibuf;
  379.   char    ptyobuf[BUFSIZ], *pfrontp = ptyobuf, *pbackp = ptyobuf;
  380. ! unsigned char    netibuf[BUFSIZ], *netip = netibuf;
  381.   char    netobuf[BUFSIZ], *nfrontp = netobuf, *nbackp = netobuf;
  382.   int    pcc, ncc;
  383.   
  384. ***************
  385. *** 62,67
  386.   extern    int errno;
  387.   char    line[] = "/dev/ptyp0";
  388.   int    childsid;
  389.   
  390.   main(argc, argv)
  391.       char *argv[];
  392.  
  393. --- 64,70 -----
  394.   extern    int errno;
  395.   char    line[] = "/dev/ptyp0";
  396.   int    childsid;
  397. + char    remotehost[256];
  398.   
  399.   main(argc, argv)
  400.       char *argv[];
  401. ***************
  402. *** 140,145
  403.           host = hp->h_name;
  404.       else
  405.           host = ntoa(who->sin_addr);
  406.   
  407.       /* We identify who this is from. All of our children will
  408.        * inherit this id from us.
  409.  
  410. --- 143,149 -----
  411.           host = hp->h_name;
  412.       else
  413.           host = ntoa(who->sin_addr);
  414. +     strcpy(remotehost,host);
  415.   
  416.       /* We identify who this is from. All of our children will
  417.        * inherit this id from us.
  418. ***************
  419. *** 204,209
  420.   {
  421.       int on = 1;
  422.       char hostname[32];
  423.   
  424.       net = f, pty = p;
  425.       ioctl(f, FIONBIO, &on);
  426.  
  427. --- 208,214 -----
  428.   {
  429.       int on = 1;
  430.       char hostname[32];
  431. +     int arg;
  432.   
  433.       net = f, pty = p;
  434.       ioctl(f, FIONBIO, &on);
  435. ***************
  436. *** 220,227
  437.        * Show banner that getty never gave.
  438.        */
  439.       gethostname(hostname, sizeof (hostname));
  440. !     sprintf(nfrontp, BANNER, hostname, "");
  441. !     nfrontp += strlen(nfrontp);
  442.       for (;;) {
  443.           int ibits = 0, obits = 0;
  444.           register int c;
  445.  
  446. --- 225,233 -----
  447.        * Show banner that getty never gave.
  448.        */
  449.       gethostname(hostname, sizeof (hostname));
  450. !     sprintf(netobuf, BANNER, hostname, "");
  451. !     write(net,netobuf,strlen(netobuf));
  452.       for (;;) {
  453.           register int c;
  454.   
  455. ***************
  456. *** 223,229
  457.       sprintf(nfrontp, BANNER, hostname, "");
  458.       nfrontp += strlen(nfrontp);
  459.       for (;;) {
  460. -         int ibits = 0, obits = 0;
  461.           register int c;
  462.   
  463.           /*
  464.  
  465. --- 229,234 -----
  466.       write(net,netobuf,strlen(netobuf));
  467.   
  468.       for (;;) {
  469.           register int c;
  470.   
  471.           if (myopts[TELOPT_BINARY])
  472. ***************
  473. *** 226,237
  474.           int ibits = 0, obits = 0;
  475.           register int c;
  476.   
  477. !         /*
  478. !          * Never look for input if there's still
  479. !          * stuff in the corresponding output buffer
  480. !          */
  481. !         if (nfrontp - nbackp || pcc > 0)
  482. !             obits |= (1 << f);
  483.           else
  484.               ibits |= (1 << p);
  485.           if (pfrontp - pbackp || ncc > 0)
  486.  
  487. --- 231,238 -----
  488.       for (;;) {
  489.           register int c;
  490.   
  491. !         if (myopts[TELOPT_BINARY])
  492. !           arg = 2 << 24;
  493.           else
  494.             arg = 1 << 24;
  495.           arg |= 1 << 16;
  496. ***************
  497. *** 233,250
  498.           if (nfrontp - nbackp || pcc > 0)
  499.               obits |= (1 << f);
  500.           else
  501. !             ibits |= (1 << p);
  502. !         if (pfrontp - pbackp || ncc > 0)
  503. !             obits |= (1 << p);
  504. !         else
  505. !             ibits |= (1 << f);
  506. !         if (ncc < 0 && pcc < 0)
  507. !             break;
  508. !         select(16, &ibits, &obits, 0, 0);
  509. !         if (ibits == 0 && obits == 0) {
  510. !             sleep(5);
  511. !             continue;
  512. !         }
  513.   
  514.           /*
  515.            * Something to read from the network...
  516.  
  517. --- 234,242 -----
  518.           if (myopts[TELOPT_BINARY])
  519.             arg = 2 << 24;
  520.           else
  521. !           arg = 1 << 24;
  522. !         arg |= 1 << 16;
  523. !         arg |= p;
  524.   
  525.           if (ioctl(f, SIOCJNVS, (char *)&arg) == -1)
  526.             cleanup();
  527. ***************
  528. *** 246,264
  529.               continue;
  530.           }
  531.   
  532. !         /*
  533. !          * Something to read from the network...
  534. !          */
  535. !         if (ibits & (1 << f)) {
  536. !             ncc = read(f, netibuf, BUFSIZ);
  537. !             if (ncc < 0 && errno == EWOULDBLOCK)
  538. !                 ncc = 0;
  539. !             else {
  540. !                 if (ncc <= 0)
  541. !                     break;
  542. !                 netip = netibuf;
  543. !             }
  544. !         }
  545.   
  546.           /*
  547.            * Something to read from the pty...
  548.  
  549. --- 238,245 -----
  550.           arg |= 1 << 16;
  551.           arg |= p;
  552.   
  553. !         if (ioctl(f, SIOCJNVS, (char *)&arg) == -1)
  554. !           cleanup();
  555.   
  556.           ncc = read(f, netibuf, BUFSIZ);
  557.           if (ncc <= 0)
  558. ***************
  559. *** 260,293
  560.               }
  561.           }
  562.   
  563. !         /*
  564. !          * Something to read from the pty...
  565. !          */
  566. !         if (ibits & (1 << p)) {
  567. !             pcc = read(p, ptyibuf, BUFSIZ);
  568. !             if (pcc < 0 && errno == EWOULDBLOCK)
  569. !                 pcc = 0;
  570. !             else {
  571. !                 if (pcc <= 0)
  572. !                     break;
  573. !                 ptyip = ptyibuf;
  574. !             }
  575. !         }
  576. !         while (pcc > 0) {
  577. !             if ((&netobuf[BUFSIZ] - nfrontp) < 2)
  578. !                 break;
  579. !             c = *ptyip++ & 0377, pcc--;
  580. !             if (c == IAC)
  581. !                 *nfrontp++ = c;
  582. !             *nfrontp++ = c;
  583. !         }
  584. !         if ((obits & (1 << f)) && (nfrontp - nbackp) > 0)
  585. !             netflush();
  586. !         if (ncc > 0)
  587. !             telrcv();
  588. !         if ((obits & (1 << p)) && (pfrontp - pbackp) > 0)
  589. !             ptyflush();
  590.       }
  591.       cleanup();
  592.   }
  593.  
  594. --- 241,252 -----
  595.           if (ioctl(f, SIOCJNVS, (char *)&arg) == -1)
  596.             cleanup();
  597.   
  598. !         ncc = read(f, netibuf, BUFSIZ);
  599. !         if (ncc <= 0)
  600. !           {syslog(7,"in.telnetd ncc=%d, %d, %m",ncc,errno);
  601. !            break;
  602. !          }
  603. !         telrcv();
  604.       }
  605.       syslog(7,"in.telnetd from %s terminated: %m",remotehost);
  606.       cleanup();
  607. ***************
  608. *** 289,294
  609.           if ((obits & (1 << p)) && (pfrontp - pbackp) > 0)
  610.               ptyflush();
  611.       }
  612.       cleanup();
  613.   }
  614.       
  615.  
  616. --- 248,254 -----
  617.            }
  618.           telrcv();
  619.       }
  620. +     syslog(7,"in.telnetd from %s terminated: %m",remotehost);
  621.       cleanup();
  622.   }
  623.       
  624. ***************
  625. *** 310,315
  626.       register int c;
  627.       static int state = TS_DATA;
  628.       struct sgttyb b;
  629.   
  630.       while (ncc > 0) {
  631.           if ((&ptyobuf[BUFSIZ] - pfrontp) < 2)
  632.  
  633. --- 270,276 -----
  634.       register int c;
  635.       static int state = TS_DATA;
  636.       struct sgttyb b;
  637. +     struct auxchars aux;
  638.   
  639.       netip = netibuf;
  640.       while (ncc > 0) {
  641. ***************
  642. *** 311,316
  643.       static int state = TS_DATA;
  644.       struct sgttyb b;
  645.   
  646.       while (ncc > 0) {
  647.           if ((&ptyobuf[BUFSIZ] - pfrontp) < 2)
  648.               return;
  649.  
  650. --- 272,278 -----
  651.       struct sgttyb b;
  652.       struct auxchars aux;
  653.   
  654. +     netip = netibuf;
  655.       while (ncc > 0) {
  656.           c = *netip++ & 0377, ncc--;
  657.           switch (state) {
  658. ***************
  659. *** 312,319
  660.       struct sgttyb b;
  661.   
  662.       while (ncc > 0) {
  663. -         if ((&ptyobuf[BUFSIZ] - pfrontp) < 2)
  664. -             return;
  665.           c = *netip++ & 0377, ncc--;
  666.           switch (state) {
  667.   
  668.  
  669. --- 274,279 -----
  670.   
  671.       netip = netibuf;
  672.       while (ncc > 0) {
  673.           c = *netip++ & 0377, ncc--;
  674.           switch (state) {
  675.   
  676. ***************
  677. *** 322,332
  678.                   state = TS_IAC;
  679.                   break;
  680.               }
  681. !             if (inter > 0)
  682. !                 break;
  683. !             *pfrontp++ = c;
  684. !             if (!myopts[TELOPT_BINARY] && c == '\r')
  685. !                 state = TS_CR;
  686.               break;
  687.   
  688.           case TS_CR:
  689.  
  690. --- 282,289 -----
  691.                   state = TS_IAC;
  692.                   break;
  693.               }
  694. !             ptyobuf[0] = c;
  695. !             write(pty,ptyobuf,1);
  696.               break;
  697.   
  698.           case TS_IAC:
  699. ***************
  700. *** 329,340
  701.                   state = TS_CR;
  702.               break;
  703.   
  704. -         case TS_CR:
  705. -             if (c && c != '\n')
  706. -                 *pfrontp++ = c;
  707. -             state = TS_DATA;
  708. -             break;
  709.           case TS_IAC:
  710.               switch (c) {
  711.   
  712.  
  713. --- 286,291 -----
  714.               write(pty,ptyobuf,1);
  715.               break;
  716.   
  717.           case TS_IAC:
  718.               switch (c) {
  719.   
  720. ***************
  721. *** 352,358
  722.                * Are You There?
  723.                */
  724.               case AYT:
  725. !                 *nfrontp++ = BELL;
  726.                   break;
  727.   
  728.               /*
  729.  
  730. --- 303,311 -----
  731.                * Are You There?
  732.                */
  733.               case AYT:
  734. !    /* This assumes the Maryland ^T code is installed.
  735. !     * If not, you can following the original and
  736. !        * do ptyobuf[0] = BELL
  737. !        */
  738. !                 ioctl(pty, TIOCGAUXC, &aux);
  739. !                 ptyobuf[0] = aux.t_usest;
  740. !                 write(pty,ptyobuf,1);
  741.                   break;
  742.   
  743.               /*
  744. ***************
  745. *** 361,367
  746.                */
  747.               case EC:
  748.               case EL:
  749. -                 ptyflush();    /* half-hearted */
  750.                   ioctl(pty, TIOCGETP, &b);
  751.                   *pfrontp++ = (c == EC) ?
  752.                       b.sg_erase : b.sg_kill;
  753.  
  754. --- 314,319 -----
  755.                */
  756.               case EC:
  757.               case EL:
  758.                   ioctl(pty, TIOCGETP, &b);
  759.                   ptyobuf[0] = (c == EC) ?
  760.                       b.sg_erase : b.sg_kill;
  761. ***************
  762. *** 363,369
  763.               case EL:
  764.                   ptyflush();    /* half-hearted */
  765.                   ioctl(pty, TIOCGETP, &b);
  766. !                 *pfrontp++ = (c == EC) ?
  767.                       b.sg_erase : b.sg_kill;
  768.                   break;
  769.   
  770.  
  771. --- 315,321 -----
  772.               case EC:
  773.               case EL:
  774.                   ioctl(pty, TIOCGETP, &b);
  775. !                 ptyobuf[0] = (c == EC) ?
  776.                       b.sg_erase : b.sg_kill;
  777.                   write(pty,ptyobuf,1);
  778.                   break;
  779. ***************
  780. *** 365,370
  781.                   ioctl(pty, TIOCGETP, &b);
  782.                   *pfrontp++ = (c == EC) ?
  783.                       b.sg_erase : b.sg_kill;
  784.                   break;
  785.   
  786.               /*
  787.  
  788. --- 317,323 -----
  789.                   ioctl(pty, TIOCGETP, &b);
  790.                   ptyobuf[0] = (c == EC) ?
  791.                       b.sg_erase : b.sg_kill;
  792. +                 write(pty,ptyobuf,1);
  793.                   break;
  794.   
  795.               /*
  796. ***************
  797. *** 388,394
  798.                   continue;
  799.   
  800.               case IAC:
  801. !                 *pfrontp++ = c;
  802.                   break;
  803.               }
  804.               state = TS_DATA;
  805.  
  806. --- 341,348 -----
  807.                   continue;
  808.   
  809.               case IAC:
  810. !                 ptyobuf[0] = IAC;
  811. !                 write(pty,ptyobuf,1);
  812.                   break;
  813.               }
  814.               state = TS_DATA;
  815. ***************
  816. *** 424,431
  817.           case TS_DONT:
  818.               if (myopts[c]) {
  819.                   myopts[c] = 0;
  820. !                 sprintf(nfrontp, wont, c);
  821. !                 nfrontp += sizeof (wont) - 2;
  822.               }
  823.               state = TS_DATA;
  824.               continue;
  825.  
  826. --- 378,385 -----
  827.           case TS_DONT:
  828.               if (myopts[c]) {
  829.                   myopts[c] = 0;
  830. !                 sprintf(netobuf, wont, c);
  831. !                 write(net,netobuf,sizeof (wont) - 2);
  832.               }
  833.               state = TS_DATA;
  834.               continue;
  835. ***************
  836. *** 434,439
  837.               printf("telnetd: panic state=%d\n", state);
  838.               exit(1);
  839.           }
  840.       }
  841.   }
  842.   
  843.  
  844. --- 388,403 -----
  845.               printf("telnetd: panic state=%d\n", state);
  846.               exit(1);
  847.           }
  848. +     if ((state != TS_DATA) && (ncc <= 0)) {
  849. +       int ibits;
  850. +       ibits = 1 << net;
  851. +       select(1,&ibits,0,0,0);
  852. +       ncc = read(net, netibuf, BUFSIZ);
  853. +       if (ncc <= 0)
  854. +         {syslog(7,"in.telnetd ncc=%d, %d, %m",ncc,errno);
  855. +          cleanup();
  856. +        }
  857.       }
  858.             }
  859.   }
  860. ***************
  861. *** 435,440
  862.               exit(1);
  863.           }
  864.       }
  865.   }
  866.   
  867.   willoption(option)
  868.  
  869. --- 399,405 -----
  870.            cleanup();
  871.          }
  872.       }
  873. +           }
  874.   }
  875.   
  876.   willoption(option)
  877. ***************
  878. *** 466,472
  879.           fmt = dont;
  880.           break;
  881.       }
  882. !     sprintf(nfrontp, fmt, option);
  883.       nfrontp += sizeof (dont) - 2;
  884.   }
  885.   
  886.  
  887. --- 431,437 -----
  888.           fmt = dont;
  889.           break;
  890.       }
  891. !     sprintf(netobuf, fmt, option);
  892.       nfrontp += sizeof (dont) - 2;
  893.   }
  894.   
  895. ***************
  896. *** 527,533
  897.           break;
  898.       }
  899.       sprintf(nfrontp, fmt, option);
  900. !     nfrontp += sizeof (doopt) - 2;
  901.   }
  902.   
  903.   mode(on, off)
  904.  
  905. --- 492,498 -----
  906.           break;
  907.       }
  908.       sprintf(nfrontp, fmt, option);
  909. !     write(net, nfrontp, sizeof (doopt) - 2);
  910.   }
  911.   
  912.   mode(on, off)
  913. *** /src/etc/in.rlogind.c.ORIG    Sat Aug  3 20:53:22 1985
  914. --- /src/etc/in.rlogind.c    Sat Apr 19 07:10:27 1986
  915. ***************
  916. *** 148,153
  917.           ioctl(p, TIOCPKT, &on);
  918.           signal(SIGTSTP, SIG_IGN);
  919.           signal(SIGCHLD, cleanup);
  920.           for (;;) {
  921.               int ibits = 0, obits = 0;
  922.   
  923.  
  924. --- 150,170 -----
  925.           ioctl(p, TIOCPKT, &on);
  926.           signal(SIGTSTP, SIG_IGN);
  927.           signal(SIGCHLD, cleanup);
  928. +         /* BEGIN NVS support */
  929. +         /*
  930. +          * If kernel supports high-performance NVS operation,
  931. +          * invoke it and sleep until connection is broken.
  932. +          * If remote end dies: ioctl() returns 0.
  933. +          * If local job exits: ioctl() returns -1 / EINTR.
  934. +          * Any other return from ioctl() is interpreted to mean
  935. +          * the kernel doesn't support high-performance NVS
  936. +          * operation, so do the job the standard Berkeley way.
  937. +          */
  938. +         if (ioctl(f, SIOCJNVS, (char *)&p) == 0 ||
  939. +             errno == EINTR)
  940. +             cleanup();
  941. +         /* END NVS support */
  942.           for (;;) {
  943.               int ibits = 0, obits = 0;
  944.   
  945.  
  946. ****** new file: ../sys/tty_nvs.c ********
  947.  
  948. /*
  949.  * Network virtual terminals via sockets - server end
  950.  *
  951.  *    Rick Ace
  952.  *    New York Institute of Technology
  953.  *    Computer Graphics Laboratory
  954.  *    Old Westbury, New York  11568
  955.  */
  956.  
  957. /*
  958.  * The code in this module supports the NVS, or remote end of the connection
  959.  * (i.e., the link between the network and the pseudo-terminal).
  960.  * The purpose of this code is to emulate efficiently the character-
  961.  * shuffling functions performed by /etc/rlogind.  The rlogin on the other
  962.  * host will believe it is talking to rlogind, when it is in reality
  963.  * talking to the NVS kernel software herein.
  964.  *
  965.  * The NVS kernel software achieves performance improvements by handling
  966.  * incoming character traffic at interrupt level, eliminating the overhead
  967.  * and delays resulting from scheduling a user-mode process (rlogind).
  968.  * Outgoing character traffic is dumped directly into the socket by
  969.  * Ptsnvsstart() in tty_pty.c, further eliminating the need for service
  970.  * by a user-mode process.
  971.  *
  972.  * The implementation is broken into two main layers:
  973.  *    1)  high-level software, common to all NVSs (nvs_XXX subrs) 
  974.  *    2)  protocol-specific stuff (tcp_XXX, etc.) 
  975.  * Presently, there is only a TCP implementation for layer # 2.
  976.  */
  977.  
  978. #define NFS 1
  979.  
  980. #include "../h/param.h"
  981. #include "../h/conf.h"
  982. #include "../h/dir.h"
  983. #include "../h/user.h"
  984. #include "../h/proc.h"        /* for lint */
  985. #include "../h/file.h"
  986. #include "../h/tty.h"
  987. #include "../h/mbuf.h"
  988. #include "../h/protosw.h"
  989. #include "../h/socketvar.h"
  990. #ifdef NFS
  991. #include "../h/vnode.h"
  992. #include "../ufs/inode.h"
  993. #else NFS
  994. #include "../h/inode.h"
  995. #endif NFS
  996.  
  997. #define nvs_emsg    printf
  998.  
  999. #define MAXNVS    32        /* should be in a parameter file */
  1000.  
  1001. /*
  1002.  * tp-to-socket correspondence table.
  1003.  *
  1004.  * This table is searched linearly.  A highest-entry mark is maintained
  1005.  * to keep search overhead low.  If there is a need to support large
  1006.  * numbers of NVSs, the linear search should be replaced by hashing.
  1007.  */
  1008. struct nvsj {
  1009.     struct tty    *nvs_tp;    /* tty/pty context, or 0 if free */
  1010.     struct socket    *nvs_so;    /* socket context */
  1011.     int        nvs_in_mode;    /* input side mode */
  1012. } nvsj[MAXNVS + 1];
  1013.  
  1014. /* in modes */
  1015.  
  1016. #define IN_RLOGIN    0        /* no processing */
  1017. #define IN_TELNET    1        /* telnet, normal */
  1018. #define IN_BINARY    2        /* telnet binary */
  1019. #define IN_CR        3        /* cr seen in nonbinary */
  1020.  
  1021. /* out modes */
  1022.  
  1023. #define OUT_RLOGIN    0        /* special urgent mode stuff */
  1024. #define OUT_TELNET    1        /* special IAC processing */
  1025.  
  1026. /* currently this is not implemented */
  1027.  
  1028. #define IAC        255
  1029.  
  1030. struct nvsj    *nvshij = &nvsj[0];    /* highest active entry */
  1031.  
  1032. #ifndef lint
  1033. int    nvsj_n = MAXNVS;        /* for kernel debug utilities */
  1034. #endif
  1035.  
  1036. int    nvsichz;
  1037.  
  1038. extern struct socket *ptynvsso[ /* NPTY */ ]; /* socket indexed by pty minor */
  1039. extern int ptyoutmode[ /* NPTY */ ];
  1040.  
  1041. int    ptsstart(), ptsnvsstart(), ptsnvsnet();
  1042.  
  1043. /*
  1044.  * Mate a tty and a socket
  1045.  *
  1046.  * Returns UNIX error code
  1047.  * Must be called at splimp
  1048.  */
  1049. nvs_add(tp, so, anvs, inmode, outmode)
  1050.     struct tty *tp;
  1051.     struct socket *so;
  1052.     struct nvsj **anvs;    /* return addr of NVS context here */
  1053.     int inmode, outmode;
  1054. {
  1055.     register struct nvsj *nvs, *nx;
  1056.     extern int hz;                /* XXX */
  1057.  
  1058.     if (nvsichz == 0) 
  1059.         nvsichz = hz / 3;        /* XXX */
  1060.     if (tp->t_oproc != ptsstart) 
  1061.         return ENOTTY;        /* not a pty or not in right mode */
  1062.     nvs = 0;
  1063.     nx = &nvsj[MAXNVS - 1];
  1064.     do {
  1065.         if (nx->nvs_tp) {
  1066.             if (nx->nvs_tp == tp || nx->nvs_so == so) {
  1067.                 return EBUSY; /* tty or socket already an NVS */
  1068.                   }
  1069.         }
  1070.         else
  1071.             nvs = nx;    /* remember lowest empty slot */
  1072.     } while (--nx >= &nvsj[0]);
  1073.     if (nvs == 0) {
  1074.         return ENFILE;        /* all slots are in use */
  1075.           }
  1076.     /*
  1077.      * All is clear, mate them
  1078.      */
  1079.     if (nvs > nvshij) 
  1080.         nvshij = nvs;        /* update highest active entry */
  1081.     *anvs = nvs;            /* pass context pointer to caller */
  1082.     nvs->nvs_so = so;
  1083.     nvs->nvs_in_mode = inmode;
  1084.     nvs->nvs_tp = tp;
  1085.     so->so_rcv.sb_flags |= SB_NVS;
  1086.     so->so_rcv.sb_nvs_index = nvs - nvsj;
  1087.     so->so_snd.sb_nvs_index = nvs - nvsj;
  1088.     tp->t_oproc = ptsnvsstart;
  1089.     ptyoutmode[minor(tp->t_dev)] = outmode;
  1090.     ptynvsso[minor(tp->t_dev)] = so;
  1091.     sbwakeup(&so->so_rcv);        /* get characters flowing */
  1092.     ptsnvsstart(tp);        /* ditto */
  1093.     return 0;
  1094. }
  1095.  
  1096. /*
  1097.  * Undo a tty/socket correspondence
  1098.  *
  1099.  * Must be called at splimp
  1100.  */
  1101. nvs_del(nvs)
  1102.     struct nvsj *nvs;
  1103. {
  1104.     register struct tty *tp;
  1105.  
  1106.     nvs->nvs_so->so_rcv.sb_flags &= ~SB_NVS;
  1107.     tp = nvs->nvs_tp;
  1108.     if (tp->t_oproc == ptsnvsstart) 
  1109.         tp->t_oproc = ptsstart;
  1110.     ptynvsso[minor(tp->t_dev)] = 0;
  1111.     /*
  1112.      * Delete this entry and adjust Nvshij if necessary
  1113.      */
  1114.     nvs->nvs_tp = 0;        /* mark entry as free */
  1115.     if (nvshij == nvs) 
  1116.         while (nvshij > &nvsj[0] && nvshij->nvs_tp == 0) 
  1117.             nvshij--;
  1118. }
  1119.  
  1120. /*
  1121.  * Called from sbwakeup() when NVS has incoming characters from the net,
  1122.  * to transfer those characters from the socket to the tty's input queue
  1123.  *
  1124.  * Logic here is similar to that of soreceive() in uipc_socket.c
  1125.  */
  1126. nvs_input(sb)
  1127.     struct sockbuf *sb;        /* so_rcv */
  1128. {
  1129. #define STRUCT_OFF(strnam, elem) \
  1130.     ((char *)&((struct strnam *)0)->elem - (char *)0) 
  1131.     register struct socket *so;
  1132.     register struct nvsj *nvs;
  1133.     register struct tty *tp;
  1134.     register struct mbuf *m;
  1135.     register unsigned char *cp;
  1136.     register int n;
  1137.     struct mbuf *mz;
  1138.     int nvsmode,xflags;
  1139.     unsigned char inchar;
  1140.  
  1141.     /*
  1142.      * Convert so_rcv address to socket address (a bit gross),
  1143.      * then search the active-connection table for that socket
  1144.      */
  1145.     so = (struct socket *)((char *)sb - STRUCT_OFF(socket, so_rcv));
  1146.     nvs = &nvsj[sb->sb_nvs_index];
  1147.     if ((tp = nvs->nvs_tp) == 0) {
  1148.       nvs_emsg("nvs input no tp %x\n", so);
  1149.       return;
  1150.     }
  1151.     nvsmode = nvs->nvs_in_mode;  /* flags. use a register for speed */
  1152.     xflags = tp->t_xflags;  /* Pyramid extra flags for ATT mode */
  1153.     /*
  1154.      * Have located the tty, now pass it the data
  1155.      */
  1156.     so->so_state &= ~SS_RCVATMARK;        /* ignore out-of-band data */
  1157.     so->so_oobmark = 0;            /* ditto */
  1158.     /*
  1159.      * Process each mbuf on the socket's rcv queue
  1160.      */
  1161.     while (so->so_rcv.sb_cc > 0) {
  1162.         m = so->so_rcv.sb_mb;
  1163.         if (m == 0) 
  1164.             panic("nvs_input");
  1165.         cp = mtod(m, unsigned char *);
  1166.         for (n = m->m_len; --n >= 0; ) {
  1167.               inchar = *cp++;
  1168.  
  1169.             switch (nvsmode) {
  1170.             case IN_CR: 
  1171.               nvsmode = IN_TELNET;
  1172.               if ((inchar == 0) || (inchar == '\n'))
  1173.                 break;
  1174.             case IN_TELNET:
  1175.               if (inchar == '\r')
  1176.                 nvsmode = IN_CR;
  1177.             case IN_BINARY:
  1178.               if (inchar == IAC) {
  1179.                 n = m->m_len - (n + 1);  /* chars read */
  1180.                 m->m_off += n;
  1181.                 so->so_rcv.sb_cc -= n;
  1182.                 m->m_len -= n;
  1183.                 so->so_rcv.sb_flags &= ~SB_NVS;
  1184.                 wakeup((caddr_t)nvs);
  1185.                 return;
  1186.               }
  1187.             case IN_RLOGIN:
  1188. /*
  1189.  * The code from here to the call to linesw is Pyramid-specific, because
  1190.  * of implementing ATT terminal handling
  1191.  */
  1192.             if (xflags&BTLON) {
  1193.                 inchar = inchar&0377;
  1194.                 
  1195.                 if (xflags&XISTRIP)
  1196.                     inchar &= 0177;
  1197.                 if ((inchar == '\n') && (xflags&XINLCR)) {
  1198.                     inchar = '\r';
  1199.                 } else if (inchar == '\r') {
  1200.                     if (xflags&XIGNCR) {
  1201.                         break;
  1202.                     } else if (xflags&XICRNL)
  1203.                         inchar = '\n';
  1204.                 }
  1205.                 if ((inchar >= 'A') &&
  1206.                     (inchar <= 'Z') &&
  1207.                     (xflags&XIUCLC))
  1208.                         inchar |= 040;
  1209.             }
  1210.               (*linesw[tp->t_line].l_rint)(inchar, tp);
  1211.             }
  1212.               }
  1213.         sbfree(&so->so_rcv, m);
  1214.         MFREE(m, mz);
  1215.         so->so_rcv.sb_mb = m = mz;
  1216.     }
  1217.     nvs->nvs_in_mode = nvsmode;  /* put back possibly changed flags */
  1218.     /*
  1219.      * Notify protocol that more space is available in the socket
  1220.      */
  1221.     if ((so->so_state & SS_CANTRCVMORE) == 0 &&
  1222.         so->so_proto->pr_flags & PR_WANTRCVD &&
  1223.         so->so_pcb) 
  1224.         (*so->so_proto->pr_usrreq)(so, PRU_RCVD,
  1225.             (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0);
  1226.     /*
  1227.      * If socket closes at remote end first (not the most common case),
  1228.      * wake up the agent process so it can exit.
  1229.      */
  1230.     if (so->so_state & (SS_CANTRCVMORE | SS_CANTSENDMORE)) {
  1231.         so->so_rcv.sb_flags &= ~SB_NVS;
  1232.         wakeup((caddr_t)nvs);
  1233.     }
  1234. }
  1235.  
  1236. /*
  1237.  * Handle ioctl request on socket to join socket and pty, called
  1238.  * from protocol ioctl logic.  Protocol-specific validation is
  1239.  * done before you get here.
  1240.  *
  1241.  * If the connection was successfully established, sleep and wait
  1242.  * until it is broken at the remote end, or until a signal is
  1243.  * received on the local end.
  1244.  *
  1245.  * Returns
  1246.  *    0 = remote NVT closed the connection
  1247.  *    EINTR = interrupted by signal
  1248.  *    Anything else = an error establishing the connection
  1249.  */
  1250. nvs_ioc_join(so, ptyfd)
  1251.     struct socket *so;
  1252.     int ptyfd;        /* pty file descriptor */
  1253. {
  1254.     register struct file *fp;
  1255.     register struct inode *ip;
  1256.     register struct tty *tp;
  1257.     int error, s;
  1258.     struct nvsj *nvsp;
  1259.     int ptcopen();
  1260.     int inmode, outmode;
  1261.  
  1262.     outmode = (ptyfd >> 16) & 0xFF;
  1263.     inmode = ptyfd >> 24;
  1264.     ptyfd = ptyfd & 0xFFFF;
  1265.  
  1266.     /*
  1267.      * Validate file descriptor and ensure it references a pty
  1268.      */
  1269.     if ((unsigned)ptyfd >= NOFILE || (fp = u.u_ofile[ptyfd]) == 0) 
  1270.         return EBADF;
  1271. #ifdef NFS
  1272.     {
  1273.         register struct vnode *vp;
  1274.  
  1275.         vp = (struct vnode *)fp->f_data;
  1276.         if (fp->f_type != DTYPE_VNODE || vp->v_op != &ufs_vnodeops) 
  1277.             return ENOTTY;
  1278.         ip = VTOI(vp);
  1279.         if ((ip->i_mode & IFMT) != IFCHR ||
  1280.             cdevsw[major(ip->i_rdev)].d_open != ptcopen) 
  1281.             return ENOTTY;        /* really ENOTPTY :-) */
  1282.     }
  1283. #else NFS
  1284.     ip = (struct inode *)fp->f_data;
  1285.     if (fp->f_type != DTYPE_INODE ||
  1286.         (ip->i_mode & IFMT) != IFCHR ||
  1287.         cdevsw[major(ip->i_rdev)].d_open != ptcopen) 
  1288.         return ENOTTY;        /* really ENOTPTY :-) */
  1289. #endif NFS
  1290.     /*
  1291.      * Argument socket and pty are valid, now join them and wait
  1292.      */
  1293.     tp = cdevsw[major(ip->i_rdev)].d_ttys;
  1294.     s = splimp();
  1295.     if (error = nvs_add(tp + minor(ip->i_rdev), so, &nvsp, 
  1296.                 inmode, outmode)) {
  1297.         splx(s);
  1298.         return error;
  1299.     }
  1300.     if (setjmp(&u.u_qsave)) {
  1301.         /*
  1302.          * The process received a signal
  1303.          */
  1304.         nvs_del(nvsp);        /* disassociate pty&socket */
  1305.         splx(s);
  1306.         return EINTR;
  1307.     }
  1308.     while (nvsp->nvs_so->so_rcv.sb_flags & SB_NVS)
  1309.       sleep((caddr_t)nvsp, PZERO + 1); /* wait for signal or disconnect */
  1310.  
  1311.     /*
  1312.      * The remote disconnected.
  1313.      */
  1314.     nvs_del(nvsp);            /* disassociate pty&socket */
  1315.     splx(s);
  1316.     return 0;
  1317. }
  1318.  
  1319. /*
  1320.  * nvs_output_wake is called from sbwakeup when more space becomes
  1321.  * available in the socket output buffer.  The code that clears
  1322.  * SB_NVS_WAIT assumes that this is called at iplnet.  Let's hope
  1323.  * it is.
  1324.  */
  1325.  
  1326. nvs_output_wake(sb)
  1327.     struct sockbuf *sb;        /* so_snd */
  1328. {
  1329.     register struct socket *so;
  1330.     register struct nvsj *nvs;
  1331.     register struct tty *tp;
  1332.  
  1333.     nvs = &nvsj[sb->sb_nvs_index];
  1334.     if ((tp = nvs->nvs_tp) == 0) {
  1335.       nvs_emsg("nvs output wake no tp %x\n", sb);
  1336.       return;
  1337.     }
  1338.     sb->sb_flags &= ~(SB_NVS_WAIT | SB_WAIT);
  1339.     ptsnvsnet(tp);  /* calls nvs_output immediately */
  1340.       }
  1341.  
  1342. /*
  1343.  * Move characters from pty outq to network
  1344.  * TS_BUSY is assumed to be set upon entry
  1345.  *
  1346.  * Must be called at or below net IPL
  1347.  */
  1348. /*ARGSUSED*/
  1349. nvs_output(tp, urgentp)
  1350.     struct tty *tp;
  1351.     int *urgentp;        /* call by reference because I can zero it */
  1352. {
  1353.       register struct mbuf *m;
  1354.     register struct socket *so;
  1355.     register int error, s, space;
  1356.     unsigned char * dp;
  1357.     int outmode;
  1358.     int iacs,chars;
  1359.  
  1360.     s = splnet();
  1361.     if ((so = ptynvsso[minor(tp->t_dev)]) == 0) {    /* paranoid */
  1362.         /*
  1363.          * no longer an NVS!
  1364.          */
  1365.         statemask(tp,~TS_BUSY);
  1366.         if (tp->t_oproc) 
  1367.             (*tp->t_oproc)(tp);
  1368.         goto rspl;
  1369.     }
  1370.     if (so->so_state & SS_CANTSENDMORE) {
  1371.         while (getc(&tp->t_outq) >= 0) 
  1372.             ;
  1373.         *urgentp = 0;
  1374.     }
  1375.     outmode = ptyoutmode[minor(tp->t_dev)];
  1376.     /*
  1377.      * If there is urgent data to send, ship it now
  1378.      */
  1379.     if (*urgentp && (outmode == OUT_RLOGIN)) {
  1380.           MGET(m, M_DONTWAIT, MT_DATA);
  1381.         if (m == 0) 
  1382.           goto out;
  1383.  
  1384.         *mtod(m, unsigned char *) = *urgentp;
  1385.         *urgentp = 0;
  1386.         m->m_len = 1;
  1387.         error = (*so->so_proto->pr_usrreq)(so,
  1388.             PRU_SENDOOB, m, (struct mbuf *)0, (struct mbuf *)0);
  1389.         if (error) 
  1390.             nvs_emsg("nvs SENDOOB %d\n", error);
  1391.         goto out;
  1392.     }
  1393.     else *urgentp = 0;
  1394.     if ((tp->t_state & TS_TTSTOP) && (outmode != OUT_RLOGIN)) {
  1395.       spl5();
  1396.       statemask(tp,~TS_BUSY);
  1397.       goto out2;
  1398.     }
  1399.     while (tp->t_outq.c_cc > 0) {
  1400.         /*
  1401.          * Send a chunk of character traffic that may be pending
  1402.          */
  1403.       /*
  1404.        * We check for space in the socket first, because the most
  1405.        * common wait is due to flow control from the other end.
  1406.        * Since we are using a form of busy wait, we want to detect
  1407.        * this as soon as possible
  1408.        */
  1409.       space = sbspace(&so->so_snd);
  1410.       if (space < so->so_snd.sb_lowat) { /* not enough space */
  1411.         so->so_snd.sb_flags |= SB_NVS_WAIT | SB_WAIT; /* wait till space */
  1412.         spl5();  /* needed at out2 */
  1413.         goto out2;  /* don't resched.  net code will call us when space */
  1414.       }
  1415.       /*
  1416.        * Each time through the loop we do one contiguous piece of
  1417.        * data from the character list.  We have to do it this way
  1418.        * in order to be able to check for iacs efficiently.
  1419.        */
  1420.       iacs = 0;
  1421.       chars = ndqb(&tp->t_outq,0);
  1422.  
  1423.       if (outmode != OUT_RLOGIN) { /* look for IAC's */
  1424.         int count;
  1425.         unsigned char * cp = (unsigned char *)tp->t_outq.c_cf;
  1426.         
  1427.         for (count = chars; count > 0; count--)
  1428.           if (*cp++ == IAC)
  1429.         iacs++;
  1430.       }
  1431. /*
  1432.  * at this point chars is number of chars in first piece of buffer,
  1433.  * and iacs is number of iacs in that 
  1434.  */
  1435.  
  1436. /*
  1437.  *  The following code is specific to Pyramid release 3.0
  1438.  *  We are trying to copy data from the pty buffer out to the
  1439.  *  network.  On the Pyramid, sbnext is used to find where to
  1440.  *  copy the data to.  It returns (in dp) a pointer into an
  1441.  *  mbuf.  If there was already data on the queue, this is
  1442.  *  a pointer into an existing mbuf.  If not, it allocates a
  1443.  *  new one.  It returns the amount of space left in the mbuf.
  1444.  *  It sets m_len in the mbuf assuming that you are actually
  1445.  *  going to put that much data in.
  1446.  *
  1447.  *  On a VAX, things work differently.  Instead of calling
  1448.  *  sbnext to find a place to put your data, you allocate
  1449.  *  an mbuf yourself.  Then you copy the data into it as
  1450.  *  below.  Further down, you will find a call to pr_usrreq.
  1451.  *  On a VAX, the argument I have given as "1" would be the
  1452.  *  mbuf.  The second line below, with sbnext in it, and the
  1453.  *  following two lines, "if (space <= 0) goto out;", should
  1454.  *  probably be replaced by
  1455.  *    MGET(m, M_DONTWAIT, MT_DATA);
  1456.  *    if (m == 0) 
  1457.  *        goto out;
  1458.  *    if (space > MLEN) 
  1459.  *        space = MLEN;
  1460.  *    dp = mtod(m, unsigned char *);
  1461.  *      m->m_len = space;
  1462.  *  This effectively simulates sbnext, although in a somewhat
  1463.  *  less intelligent way than Pyramid's actual code.
  1464.  *  In the call to pr_usrreq below, you should probably change
  1465.  *  the argument "1" to "m".
  1466.  */
  1467.       space = MIN(space, chars + iacs);
  1468.       space = sbnext(&so->so_snd,&dp,space);
  1469.       if (space <= 0)
  1470.         goto out;  /* no mbufs. this does a busy wait until space */
  1471. /*
  1472.  * This is an optimization.  If there are no IAC's, we can just copy
  1473.  * the data from the pty directly into the tcp mbuf.  If there are
  1474.  * IAC's, we have to turn each single IAC into two IAC's.  We do
  1475.  * this by copying one character at a time.  If we decide to turn bare
  1476.  * CR into CR NUL, as required by the spec, we will have to do something
  1477.  * similar when we find a bare CR.  We will also have to remember when
  1478.  * the last character we process is a CR, for handling next time around.
  1479.  */
  1480.       if (iacs == 0) {
  1481.         q_to_b(&tp->t_outq, dp, space);
  1482.         so->so_snd.sb_cc += space;
  1483.       }
  1484.       else {
  1485.         int count = space;
  1486.         while (count-- > 1) { /* leave one extra for iac */
  1487.           unsigned char outchar;
  1488.           outchar = getc(&tp->t_outq);
  1489.           *dp++ = outchar;
  1490.           if (outchar == IAC) {
  1491.         *dp++ = outchar;
  1492.         count--;
  1493.           }
  1494.         }
  1495.         so->so_snd.sb_mb->m_len -= count;  /* either 1 or 0 left over */
  1496.         so->so_snd.sb_cc += space - count;
  1497.       }
  1498.  
  1499.       error = (*so->so_proto->pr_usrreq)(so,
  1500.            PRU_SEND, 1, (struct mbuf *)0, (struct mbuf *)0);
  1501. #ifdef lint
  1502.         /* Same actuals as above, better information for lint */
  1503.       error = tcp_usrreq(so,
  1504.            PRU_SEND, 1, (struct mbuf *)0, (struct mbuf *)0);
  1505. #endif
  1506.     }
  1507.  
  1508.  
  1509. out:    /*
  1510.      * Perpetuate myself if work remains
  1511.      */
  1512.     (void) spl5();            /* block out tty activity */
  1513.     if (tp->t_outq.c_cc > 0 || *urgentp)
  1514.         timeout(ptsnvsnet, (caddr_t)tp, nvsichz); /* TS_BUSY remains set */
  1515.     else
  1516.         statemask(tp,~TS_BUSY);
  1517. out2:    /*
  1518.      * Wake up sleepers
  1519.      */
  1520.     if (tp->t_outq.c_cc <= TTLOWAT(tp)) {
  1521.         if (tp->t_state&TS_ASLEEP) {
  1522.             statemask(tp,~TS_ASLEEP);
  1523.             wakeup((caddr_t)&tp->t_outq);
  1524.         }
  1525.         if (tp->t_wsel) {
  1526.             selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
  1527.             tp->t_wsel = 0;
  1528.             statemask(tp,~TS_WCOLL);
  1529.         }
  1530.     }
  1531. rspl:    splx(s);
  1532. }
  1533.  
  1534.  
  1535.