home *** CD-ROM | disk | FTP | other *** search
/ Magazyn Amiga Shareware Floppies / ma64.dms / ma64.adf / FTPMount-1.0 / Source / tcp.c < prev    next >
C/C++ Source or Header  |  1995-09-06  |  37KB  |  1,723 lines

  1. /*
  2.  * This source file is Copyright 1995 by Evan Scott.
  3.  * All rights reserved.
  4.  * Permission is granted to distribute this file provided no
  5.  * fees beyond distribution costs are levied.
  6.  */
  7.  
  8. /*
  9.  * a message passing API for amitcp
  10.  */
  11.  
  12. #include <exec/types.h>
  13. #include <exec/ports.h>
  14.  
  15. #include <dos/dos.h>
  16. #include <dos/dostags.h>
  17.  
  18. #include <proto/exec.h>
  19. #include <proto/dos.h>
  20.  
  21. #define INLINES_AS_MACROS 1    /* SAS doesn't seem to do inlines properly */
  22. #include <proto/socket.h>
  23.  
  24. /* these particularly need to be the amitcp includes */
  25. #include <sys/errno.h>
  26. #include <sys/ioctl.h>
  27.  
  28. #include <netdb.h>
  29. #include <string.h>
  30.  
  31. #include "evtypes.h"
  32. #include "verify.h"
  33.  
  34. #include "tcp.h"
  35.  
  36. tcpmessage *new_tcpmessage(struct MsgPort *reply_port)
  37. {
  38.     tcpmessage *z;
  39.     
  40.     z = (tcpmessage *)allocate(sizeof(*z), V_tcpmessage);
  41.     if (!z) return nil;
  42.     
  43.     ensure(z, V_tcpmessage);
  44.     
  45.     z->header.mn_Node.ln_Type = NT_MESSAGE;
  46.     z->header.mn_Node.ln_Pri = 0;
  47.     z->header.mn_Node.ln_Name = "TCPMessage";
  48.     z->header.mn_ReplyPort = reply_port;
  49.     z->header.mn_Length = sizeof(*z);
  50.     
  51.     z->command = TCP_NOOP;
  52.     z->ident = nil;
  53.     z->address.l = 0;
  54.     z->port.w = 0;
  55.     
  56.     z->data = nil;
  57.     z->interrupt = nil;
  58.     z->length = 0;
  59.     z->result = 0;
  60.     z->error = NO_ERROR;
  61.     z->flags = 0;
  62.     
  63.     return z;
  64. }
  65.  
  66. void free_tcpmessage(tcpmessage *tm)
  67. {
  68.     verify(tm, V_tcpmessage);
  69.     
  70.     ensure(tm, 0);
  71.     
  72.     deallocate(tm, V_tcpmessage);
  73.     
  74.     return;
  75. }
  76.  
  77. tcpident *new_tcpident(sb32 fd)
  78. {
  79.     tcpident *ti;
  80.  
  81.     ti = (tcpident *)allocate(sizeof(*ti), V_tcpident);
  82.     if (!ti) return nil;
  83.  
  84.     ensure(ti, V_tcpident);
  85.  
  86.     ti->fd = fd;
  87.     ti->eof = false;
  88.  
  89.     return ti;
  90. }
  91.  
  92. void free_tcpident(tcpident *ti)
  93. {
  94.     verify(ti, V_tcpident);
  95.     
  96.     ensure(ti, 0);
  97.  
  98.     deallocate(ti, V_tcpident);
  99.  
  100.     return;
  101. }
  102.  
  103. void fix_read_set(struct List *wait_list, fd_set *reads, sb32 *max_fd)
  104. {
  105.     tcpmessage *tm;
  106.     tcpident *ti;
  107.     
  108.     FD_ZERO(reads);
  109.     *max_fd = -1;
  110.     
  111.     for (tm = (tcpmessage *)wait_list->lh_Head;
  112.             tm->header.mn_Node.ln_Succ;
  113.             tm = (tcpmessage *)tm->header.mn_Node.ln_Succ) {
  114.         ti = tm->ident;
  115.         verify(ti, V_tcpident);
  116.         
  117.         if (ti->fd > *max_fd) *max_fd = ti->fd;
  118.         
  119.         if (tm->command == TCP_LISTEN || tm->command == TCP_READ) {
  120.             FD_SET(ti->fd, reads);
  121.             break;
  122.         }
  123.     }
  124. }
  125.  
  126. void fix_write_set(struct List *wait_list, fd_set *writes, sb32 *max_fd)
  127. {
  128.     tcpmessage *tm;
  129.     tcpident *ti;
  130.     
  131.     FD_ZERO(writes);
  132.     *max_fd = -1;
  133.     
  134.     for (tm = (tcpmessage *)wait_list->lh_Head;
  135.             tm->header.mn_Node.ln_Succ;
  136.             tm = (tcpmessage *)tm->header.mn_Node.ln_Succ) {
  137.         ti = tm->ident;
  138.         verify(ti, V_tcpident);
  139.         
  140.         if (ti->fd > *max_fd) *max_fd = ti->fd;
  141.         
  142.         if (tm->command == TCP_WRITE) {
  143.             FD_SET(ti->fd, writes);
  144.             break;
  145.         }
  146.     }
  147. }
  148.  
  149. void non_blocking(struct Library *SocketBase, sb32 fd)
  150. {
  151.     long one;
  152.     
  153.     one = 1;
  154.     
  155.     IoctlSocket(fd, FIONBIO, (void *)&one);
  156. }
  157.  
  158. void unique_name(void *tp, b8 *s, b8 *buffer)
  159. {
  160.     b32 task;
  161.     
  162.     task = (b32)tp;
  163.  
  164.     buffer[0] = (task >> 28) & 0xf;
  165.     buffer[1] = (task >> 24) & 0xf;
  166.     buffer[2] = (task >> 20) & 0xf;
  167.     buffer[3] = (task >> 16) & 0xf;
  168.     buffer[4] = (task >> 12) & 0xf;
  169.     buffer[5] = (task >> 8) & 0xf;
  170.     buffer[6] = (task >> 4) & 0xf;
  171.     buffer[7] = task & 0xf;
  172.     
  173.     if (buffer[0] > 9) buffer[0] += 'a' - 10; else buffer[0] += '0';
  174.     if (buffer[1] > 9) buffer[1] += 'a' - 10; else buffer[1] += '0';
  175.     if (buffer[2] > 9) buffer[2] += 'a' - 10; else buffer[2] += '0';
  176.     if (buffer[3] > 9) buffer[3] += 'a' - 10; else buffer[3] += '0';
  177.     if (buffer[4] > 9) buffer[4] += 'a' - 10; else buffer[4] += '0';
  178.     if (buffer[5] > 9) buffer[5] += 'a' - 10; else buffer[5] += '0';
  179.     if (buffer[6] > 9) buffer[6] += 'a' - 10; else buffer[6] += '0';
  180.     if (buffer[7] > 9) buffer[7] += 'a' - 10; else buffer[7] += '0';
  181.     
  182.     strcpy(&buffer[8], s);
  183. }
  184.  
  185. void tcp_read(struct Library *SocketBase, tcpmessage *tm, struct List *wait_list, fd_set *reads, sb32 *max_fd)
  186. {
  187.     tcpident *ti;
  188.     sb32 result;
  189.     b8 *s;
  190.  
  191.     truth(SocketBase != nil);
  192.     truth(max_fd != nil);
  193.     truth(reads != nil);
  194.     truth(wait_list != nil);
  195.  
  196.     verify(tm, V_tcpmessage);
  197.     
  198.     ti = tm->ident;
  199.  
  200.     if (!ti) {
  201.         tm->result = 0;
  202.         tm->error = ERROR_NO_CONNECTION;
  203.         
  204.         ReplyMsg(&tm->header);
  205.         return;
  206.     }
  207.     
  208.     verify(ti, V_tcpident);
  209.     
  210.     if (tm->length == 0) {
  211.         tm->result = 0;
  212.         
  213.         if (ti->eof)
  214.             tm->error = ERROR_EOF;
  215.         else
  216.             tm->error = NO_ERROR;
  217.         
  218.         ReplyMsg(&tm->header);
  219.         return;
  220.     }
  221.     
  222.     /* socket has got to be set to non-blocking */
  223.     
  224.     if (tm->flags & FLAG_READLINE) {
  225.         s = tm->data;
  226.         tm->result = 0;
  227.         
  228.         while (1) {
  229.             result = recv(ti->fd, s, 1, 0);
  230.             if (result == 1) {
  231.                 tm->result++;
  232.                 if (*s == '\r' || *s == '\n') {
  233.                     if (tm->result == 1) {    /* blank line ... skip it */
  234.                         tm->result--;
  235.                         continue;
  236.                     }
  237.                     tm->error = NO_ERROR;
  238.                     
  239.                     ReplyMsg(&tm->header);
  240.                     return;
  241.                 }
  242.                 s++;
  243.                 if (tm->result == tm->length) {
  244.                     tm->error = NO_ERROR;
  245.                     ReplyMsg(&tm->header);
  246.                     return;
  247.                 }
  248.                 continue;
  249.             } else if (result == 0) {    /* got to be EOF */
  250.                 ti->eof = true;
  251.                 tm->error = ERROR_EOF;
  252.                 
  253.                 ReplyMsg(&tm->header);
  254.                 return;
  255.             } else {
  256.                 switch (Errno()) {
  257.                 case EINTR:
  258.                 case EWOULDBLOCK:    /* nothing there to read yet */
  259.                     AddTail(wait_list, (struct Node *)tm);
  260.                     FD_SET(ti->fd, reads);
  261.                     if (ti->fd > *max_fd) *max_fd = ti->fd;
  262.                     return;
  263.                 default:        /* something went wrong */
  264.                     tm->error = ERROR_LOST_CONNECTION;
  265.             
  266.                     ReplyMsg(&tm->header);
  267.                 }
  268.                 return;
  269.             }
  270.         }
  271.     } else {
  272.         result = recv(ti->fd, tm->data, tm->length, 0);
  273.         if (result == tm->length) {    /* satisfied immediately */
  274.             tm->result = tm->length;
  275.             tm->error = NO_ERROR;
  276.             
  277.             ReplyMsg(&tm->header);
  278.             return;
  279.         }
  280.     }
  281.     
  282.     if (result == 0) {    /* got to be EOF */
  283.         ti->eof = true;
  284.         tm->result = 0;
  285.         tm->error = ERROR_EOF;
  286.         
  287.         ReplyMsg(&tm->header);
  288.         return;
  289.     }
  290.     
  291.     /* from here we have the stuff we have to wait for */
  292.         
  293.     if (result < 0) {
  294.         switch (Errno()) {
  295.         case EINTR:
  296.         case EWOULDBLOCK:    /* nothing there to read yet */
  297.             tm->result = 0;
  298.             AddTail(wait_list, (struct Node *)tm);
  299.             FD_SET(ti->fd, reads);
  300.             if (ti->fd > *max_fd) *max_fd = ti->fd;
  301.             return;
  302.         default:        /* something went wrong */
  303.             tm->result = 0;
  304.             tm->error = ERROR_LOST_CONNECTION;
  305.             
  306.             ReplyMsg(&tm->header);
  307.             return;
  308.         }
  309.     }
  310.     
  311.     truth(result < tm->length);
  312.     
  313.     tm->result = result;
  314.     AddTail(wait_list, (struct Node *)tm);
  315.     FD_SET(ti->fd, reads);
  316.     if (ti->fd > *max_fd) *max_fd = ti->fd;
  317.     return;
  318. }
  319.  
  320. void tcp_write(struct Library *SocketBase, tcpmessage *tm, struct List *wait_list, fd_set *writes, sb32 *max_fd)
  321. {
  322.     tcpident *ti;
  323.     sb32 result;
  324.  
  325.     truth(SocketBase != nil);
  326.     truth(max_fd != nil);
  327.     truth(writes != nil);
  328.     truth(wait_list != nil);
  329.  
  330.     verify(tm, V_tcpmessage);
  331.     
  332.     ti = tm->ident;
  333.  
  334.     if (!ti) {
  335.         tm->result = 0;
  336.         tm->error = ERROR_NO_CONNECTION;
  337.         
  338.         ReplyMsg(&tm->header);
  339.         return;
  340.     }
  341.     
  342.     verify(ti, V_tcpident);
  343.     
  344.     if (tm->length == 0) {
  345.         tm->result = 0;
  346.         tm->error = NO_ERROR;
  347.         
  348.         ReplyMsg(&tm->header);
  349.         return;
  350.     }
  351.     
  352.     /* socket has got to be set to non-blocking */
  353.  
  354.     result = send(ti->fd, tm->data, tm->length, 0);
  355.     if (result == tm->length) {    /* satisfied immediately */
  356.         tm->result = tm->length;
  357.         tm->error = NO_ERROR;
  358.         
  359.         ReplyMsg(&tm->header);
  360.         return;
  361.     }
  362.     
  363.     /* from here we have the stuff we have to wait for */
  364.         
  365.     if (result < 0) {
  366.         switch (Errno()) {
  367.         case EWOULDBLOCK:
  368.         case EINTR:        /* write couldn't get through immediately */
  369.             tm->result = 0;
  370.             AddTail(wait_list, (struct Node *)tm);
  371.             FD_SET(ti->fd, writes);
  372.             if (ti->fd > *max_fd) *max_fd = ti->fd;
  373.             return;
  374.         default:        /* something has gone wrong */
  375.             tm->result = 0;
  376.             tm->error = ERROR_LOST_CONNECTION;
  377.             ReplyMsg(&tm->header);
  378.             return;
  379.         }
  380.     }
  381.     
  382.     truth(result < tm->length);
  383.     
  384.     tm->result = result;
  385.     AddTail(wait_list, (struct Node *)tm);
  386.     FD_SET(ti->fd, writes);
  387.     if (ti->fd > *max_fd) *max_fd = ti->fd;
  388.     return;
  389. }
  390.  
  391. void tcp_read_more(struct Library *SocketBase, tcpmessage *tm, struct List *wait_list, fd_set *reads, sb32 *max_fd)
  392. {
  393.     tcpident *ti;
  394.     sb32 result;
  395.     b8 *s;
  396.  
  397.     truth(SocketBase != nil);
  398.     truth(max_fd != nil);
  399.     truth(reads != nil);
  400.     truth(wait_list != nil);
  401.  
  402.     verify(tm, V_tcpmessage);
  403.     
  404.     ti = tm->ident;
  405.     verify(ti, V_tcpident);
  406.     
  407.     if (tm->flags & FLAG_READLINE) {
  408.         s = (b8 *)tm->data + tm->result;
  409.         
  410.         while (1) {
  411.             result = recv(ti->fd, s, 1, 0);
  412.             if (result == 1) {
  413.                 tm->result++;
  414.                 if (*s == '\r' || *s == '\n') {
  415.                     if (tm->result == 1) {    /* blank line ... skip it */
  416.                         tm->result--;
  417.                         continue;
  418.                     }
  419.                     tm->error = NO_ERROR;
  420.                     
  421.                     Remove((struct Node *)tm);
  422.                     ReplyMsg(&tm->header);
  423.                     
  424.                     fix_read_set(wait_list, reads, max_fd);
  425.                     return;
  426.                 }
  427.                 s++;
  428.                 if (tm->result == tm->length) {
  429.                     tm->error = NO_ERROR;
  430.                     
  431.                     Remove((struct Node *)tm);
  432.                     ReplyMsg(&tm->header);
  433.  
  434.                     fix_read_set(wait_list, reads, max_fd);
  435.                     return;
  436.                 }
  437.                 continue;
  438.             } else if (result == 0) {    /* got to be EOF */
  439.                 ti->eof = true;
  440.                 tm->error = ERROR_EOF;
  441.                 
  442.                 Remove((struct Node *)tm);
  443.                 ReplyMsg(&tm->header);
  444.  
  445.                 fix_read_set(wait_list, reads, max_fd);
  446.                 return;
  447.             } else {
  448.                 switch (Errno()) {
  449.                 case EINTR:
  450.                 case EWOULDBLOCK:    /* nothing there to read yet */
  451.                     return;
  452.                 default:        /* something went wrong */
  453.                     tm->error = ERROR_LOST_CONNECTION;
  454.                     
  455.                     Remove((struct Node *)tm);
  456.                     ReplyMsg(&tm->header);
  457.  
  458.                     fix_read_set(wait_list, reads, max_fd);
  459.                     return;
  460.                 }
  461.                 return;
  462.             }
  463.         }
  464.     } else {
  465.         result = recv(ti->fd, (b8 *)tm->data + tm->result, tm->length - tm->result, 0);
  466.         if (result == tm->length - tm->result) {    /* satisfied! */
  467.             tm->result = tm->length;
  468.             tm->error = NO_ERROR;
  469.         
  470.             Remove((struct Node *)tm);    /* remove from wait_list */
  471.             ReplyMsg(&tm->header);        /* send it back completed */
  472.         
  473.             fix_read_set(wait_list, reads, max_fd);
  474.  
  475.             return;
  476.         }
  477.     
  478.         if (result == 0) {    /* got to be EOF */
  479.             ti->eof = true;
  480.             tm->error = ERROR_EOF;
  481.         
  482.             Remove((struct Node *)tm);    /* as above */
  483.             ReplyMsg(&tm->header);
  484.         
  485.             fix_read_set(wait_list, reads, max_fd);
  486.  
  487.             return;
  488.         }
  489.     
  490.         /* have to wait some more */
  491.         
  492.         if (result < 0) {
  493.             switch (Errno()) {
  494.             case EINTR:
  495.             case EWOULDBLOCK:    /* nothing more to read yet */
  496.                 return;
  497.             default:        /* something went wrong */
  498.                 tm->error = ERROR_LOST_CONNECTION;
  499.             
  500.                 Remove((struct Node *)tm);
  501.                 ReplyMsg(&tm->header);
  502.             
  503.                 fix_read_set(wait_list, reads, max_fd);
  504.  
  505.                 return;
  506.             }
  507.         }
  508.     
  509.         truth(result < tm->length - tm->result);
  510.     
  511.         tm->result += result;
  512.         return;                /* keep waiting */
  513.     }
  514. }
  515.  
  516. void tcp_write_more(struct Library *SocketBase, tcpmessage *tm, struct List *wait_list, fd_set *writes, sb32 *max_fd)
  517. {
  518.     tcpident *ti;
  519.     sb32 result;
  520.  
  521.     truth(SocketBase != nil);
  522.     truth(max_fd != nil);
  523.     truth(writes != nil);
  524.     truth(wait_list != nil);
  525.  
  526.     verify(tm, V_tcpmessage);
  527.     
  528.     ti = tm->ident;
  529.     verify(ti, V_tcpident);
  530.     
  531.     result = send(ti->fd, (b8 *)tm->data + tm->result, tm->length - tm->result, 0);
  532.     if (result == tm->length - tm->result) {    /* satisfied! */
  533.         tm->result = tm->length;
  534.         tm->error = NO_ERROR;
  535.         
  536.         Remove((struct Node *)tm);
  537.         ReplyMsg(&tm->header);
  538.         
  539.         fix_write_set(wait_list, writes, max_fd);
  540.  
  541.         return;
  542.     }
  543.     
  544.     /* from here we have the stuff we have to wait some more for */
  545.         
  546.     if (result < 0) {
  547.         switch (Errno()) {
  548.         case EWOULDBLOCK:
  549.         case EINTR:        /* write blocked again */
  550.             return;
  551.         default:        /* something has gone wrong */
  552.             tm->error = ERROR_LOST_CONNECTION;
  553.             
  554.             Remove((struct Node *)tm);
  555.             ReplyMsg(&tm->header);
  556.             
  557.             fix_write_set(wait_list, writes, max_fd);
  558.  
  559.             return;
  560.         }
  561.     }
  562.     
  563.     truth(result < tm->length - tm->result);
  564.     
  565.     tm->result += result;
  566.     return;
  567. }
  568.  
  569. void tcp_listen(struct Library *SocketBase, tcpmessage *tm, struct List *wait_list, fd_set *reads, sb32 *max_fd)
  570. {
  571.     tcpident *ti;
  572.     sb32 result, socklen;
  573.     struct sockaddr_in sin;
  574.     struct hostent *he;
  575.     tcpmessage *wait_tm;
  576.  
  577.     truth(SocketBase != nil);
  578.     truth(max_fd != nil);
  579.     truth(reads != nil);
  580.     truth(wait_list != nil);
  581.  
  582.     verify(tm, V_tcpmessage);
  583.     
  584.     if (tm->ident) {
  585.         tm->result = false;
  586.         tm->error = ERROR_ALREADY_CONNECTED;
  587.         
  588.         ReplyMsg(&tm->header);
  589.         return;
  590.     }
  591.     
  592.     memset(&sin, 0, sizeof(sin));
  593.     
  594.     he = gethostbyname("localhost");
  595.     if (!he) {
  596.         tm->result = false;
  597.         tm->error = ERROR_UNKNOWN_HOST;
  598.         
  599.         ReplyMsg(&tm->header);
  600.         return;
  601.     }
  602.  
  603.     sin.sin_family = he->h_addrtype;
  604.     sin.sin_port = tm->port.w;
  605.     memcpy(&sin.sin_addr.s_addr, he->h_addr_list[0], he->h_length);
  606.  
  607.     ti = new_tcpident(0);    /* filled in later */
  608.     if (ti) {
  609.         wait_tm = new_tcpmessage(nil);
  610.         if (wait_tm) {
  611.             result = socket(AF_INET, SOCK_STREAM, 0);
  612.             if (result >= 0) {
  613.                 ti->fd = result;
  614.             
  615.                 result = bind(ti->fd, (struct sockaddr *)&sin, sizeof(sin));
  616.                 if (result == 0) {
  617.                     result = listen(ti->fd, 5);    /* random msq queue length */
  618.                     if (result == 0) {
  619.                         /*
  620.                          * strictly, we shouldn't need this 
  621.                          * ... but, we might (better safe etc)
  622.                          */
  623.                         non_blocking(SocketBase, ti->fd);
  624.                         
  625.                         socklen = sizeof(sin);
  626.                         result = getsockname(ti->fd, (struct sockaddr *)&sin, &socklen);
  627.                         
  628.                         /* we are listening! */
  629.                         tm->ident = ti;
  630.                         tm->port.w = sin.sin_port;
  631.                         
  632.                         wait_tm->ident = ti;
  633.                         
  634.                         wait_tm->command = TCP_LISTEN;
  635.                         wait_tm->port.w = sin.sin_port;    /* just for curiosity */
  636.                         
  637.                         /* note the reply port so we can send future accepts
  638.                            to the same place */
  639.                         wait_tm->header.mn_ReplyPort = tm->header.mn_ReplyPort;
  640.                     
  641.                         if (ti->fd > *max_fd) *max_fd = ti->fd;
  642.                         FD_SET(ti->fd, reads);
  643.                         AddTail(wait_list, (struct Node *)wait_tm);
  644.                         
  645.                         tm->result = true;
  646.                         tm->error = NO_ERROR;
  647.                         ReplyMsg(&tm->header);
  648.                         return;
  649.                     } else {
  650.                         tm->error = ERROR_ACCESS_DENIED;
  651.                     }
  652.                 } else {
  653.                     tm->error = ERROR_ACCESS_DENIED;
  654.                 }
  655.                 CloseSocket(ti->fd);
  656.             } else tm->error = ERROR_OOM;
  657.             free_tcpmessage(wait_tm);
  658.         } else tm->error = ERROR_OOM;
  659.         free_tcpident(ti);
  660.     } else tm->error = ERROR_OOM;
  661.  
  662.     tm->result = false;
  663.     
  664.     ReplyMsg(&tm->header);
  665.     return;
  666. }
  667.  
  668. void tcp_accept(struct Library *SocketBase, tcpmessage *tm, struct List *wait_list, struct MsgPort *replies)
  669. {
  670.     tcpident    *ti, *accept_ti;
  671.     tcpmessage    *accept_tm, *wait_tm;
  672.     struct sockaddr_in sin;
  673.     sb32        sin_len, result;
  674.     
  675.     truth(SocketBase != nil);
  676.     truth(wait_list != nil);
  677.     truth(replies != nil);
  678.     
  679.     verify(tm, V_tcpmessage);
  680.     
  681.     ti = tm->ident;
  682.     verify(ti, V_tcpident);
  683.     
  684.     sin_len = sizeof(sin);
  685.     
  686.     result = accept(ti->fd, (struct sockaddr *)&sin, &sin_len);
  687.     if (result < 0) {    /* this should never really happen I don't think, but ... */
  688.         /* nothing need be done */
  689.         return;
  690.     }
  691.     
  692.     non_blocking(SocketBase, result);
  693.     
  694.     accept_tm = new_tcpmessage(tm->header.mn_ReplyPort);
  695.     if (accept_tm) {
  696.         wait_tm = new_tcpmessage(nil);
  697.         if (wait_tm) {
  698.             accept_ti = new_tcpident(result);
  699.             if (accept_ti) {
  700.                 /* all systems go! */
  701.                 
  702.                 /* tell the parent that we have a new connection ... */
  703.                 accept_tm->command = TCP_ACCEPTED;
  704.                 accept_tm->address.l = sin.sin_addr.s_addr;
  705.                 accept_tm->port.w = sin.sin_port;
  706.                 
  707.                 accept_tm->ident = accept_ti;
  708.                 accept_tm->result = true;
  709.                 accept_tm->error = NO_ERROR;
  710.                 
  711.                 PutMsg(tm->header.mn_ReplyPort, &accept_tm->header);
  712.                 
  713.                 /* keep a copy on our files for book keeping purposes */
  714.                 wait_tm->command = TCP_CONNECTED;
  715.                 wait_tm->address.l = sin.sin_addr.s_addr;
  716.                 wait_tm->port.w = sin.sin_port;
  717.                 
  718.                 wait_tm->ident = accept_ti;
  719.                 
  720.                 /* this is a bit nasty ... it has to be on the head because
  721.                    we are traversing the list forward */
  722.                 AddHead(wait_list, (struct Node *)wait_tm);
  723.                 return;
  724.             }
  725.             free_tcpmessage(wait_tm);
  726.         }
  727.         free_tcpmessage(accept_tm);
  728.     }
  729.     
  730.     /* this is a bit sad ... it accepts and then it just closes for no 
  731.        apparent reason ... I don't see any alternative however */
  732.     
  733.     CloseSocket(result);
  734.     return;
  735. }
  736.  
  737. void tcp_close(struct Library *SocketBase, tcpmessage *tm, struct List *wait_list, fd_set *reads, fd_set *writes, sb32 *max_fd)
  738. {
  739.     tcpident *ti, *iti;
  740.     tcpmessage *itm, *nitm;
  741.     int ncons = 0, nlis = 0;
  742.  
  743.     truth(SocketBase != nil);
  744.     truth(max_fd != nil);
  745.     truth(reads != nil);
  746.     truth(wait_list != nil);
  747.  
  748.     verify(tm, V_tcpmessage);
  749.     
  750.     ti = tm->ident;
  751.     if (!ti || ti->connecting_port) {
  752.         tm->result = false;
  753.         tm->error = ERROR_NO_CONNECTION;
  754.         
  755.         ReplyMsg(&tm->header);
  756.         return;
  757.     }
  758.     
  759.     verify(ti, V_tcpident);
  760.     
  761.     /* 
  762.      * search through the waiting list and:
  763.      *     abort reads and writes that match
  764.      *     close TCP_CONNECTEDs
  765.      *    close TCP_LISTENs    
  766.      */
  767.  
  768.     for (itm = (tcpmessage *)wait_list->lh_Head;
  769.             nitm = (tcpmessage *)itm->header.mn_Node.ln_Succ;
  770.             itm = nitm) {
  771.         
  772.         verify(itm, V_tcpmessage);
  773.  
  774.         switch (itm->command) {
  775.         case TCP_READ:
  776.         case TCP_WRITE:
  777.             iti = itm->ident;
  778.             verify(iti, V_tcpident);
  779.             
  780.             if (iti == ti) {
  781.                 itm->error = ERROR_INTERRUPTED;
  782.                 itm->ident = nil;
  783.  
  784.                 Remove((struct Node *)itm);
  785.                 ReplyMsg(&itm->header);
  786.             }
  787.             break;
  788.         case TCP_LISTEN:
  789.             iti = itm->ident;
  790.             verify(iti, V_tcpident);
  791.             
  792.             if (iti == ti) {
  793.                 nlis++;
  794.                 
  795.                 Remove((struct Node *)itm);
  796.                 free_tcpmessage(itm);
  797.             }
  798.             break;
  799.         case TCP_CONNECTED:
  800.             iti = itm->ident;
  801.             verify(iti, V_tcpident);
  802.             
  803.             if (iti == ti) {
  804.                 ncons++;
  805.                 
  806.                 Remove((struct Node *)itm);
  807.                 free_tcpmessage(itm);
  808.             }
  809.             break;
  810.         }
  811.     }
  812.  
  813.     truth(ncons + nlis == 1);    /* one, and only one connection!!! */
  814.     
  815.     if (ti->fd >= 0)
  816.         CloseSocket(ti->fd);
  817.  
  818.     free_tcpident(ti);
  819.     
  820.     tm->ident = nil;
  821.     tm->result = true;
  822.     tm->error = NO_ERROR;
  823.     
  824.     ReplyMsg(&tm->header);
  825.     
  826.     fix_read_set(wait_list, reads, max_fd);
  827.     fix_write_set(wait_list, writes, max_fd);
  828.  
  829.     return;
  830. }
  831.  
  832. void do_connect(struct Library *SocketBase, tcpmessage *mess, struct MsgPort *pport, struct MsgPort *myport)
  833. {
  834.     /* bits of the following inspired by the source to NcFTP ... thanks go to Mike Gleason */
  835.     struct sockaddr_in sin;
  836.     struct hostent *he;
  837.     sb32 result, s;
  838.     
  839.     truth(SocketBase != nil);
  840.     truth(pport != nil);
  841.     truth(myport != nil);
  842.     verify(mess, V_tcpmessage);
  843.     
  844.     memset((void *)&sin, 0, sizeof(&sin));    /* not sure this is necessary ... ncftp does this.  JIC */
  845.     
  846.     sin.sin_port = mess->port.w;
  847.     sin.sin_family = AF_INET;
  848.  
  849.     if (mess->data) {    /* if they don't send a string, their address must be right */
  850.  
  851.         sin.sin_addr.s_addr = inet_addr(mess->data);
  852.         if (sin.sin_addr.s_addr == -1) {    /* not a direct dotted IP number */
  853.             he = gethostbyname(mess->data);
  854.             if (!he) {    /* oh well ... */
  855.                 mess->result = 0;
  856.                 mess->error = ERROR_UNKNOWN_HOST;
  857.                 
  858.                 PutMsg(pport, &mess->header);
  859.                 
  860.                 WaitPort(myport);
  861.                 GetMsg(myport);
  862.                 return;
  863.             }
  864.             
  865.             sin.sin_family = he->h_addrtype;
  866.             memcpy(&sin.sin_addr, he->h_addr_list[0], he->h_length);
  867.         }
  868.     } else {
  869.         sin.sin_addr.s_addr = mess->address.l;
  870.     }
  871.  
  872.     /* we have the address, now try the connect */
  873.     
  874.     s = socket(sin.sin_family, SOCK_STREAM, 0);    /* 0 for protocol legal? ncftp does it */
  875.     if (s < 0) {
  876.         mess->result = 0;
  877.         mess->error = ERROR_OOM;
  878.         
  879.         PutMsg(pport, &mess->header);
  880.         
  881.         WaitPort(myport);
  882.         GetMsg(myport);
  883.         return;
  884.     }
  885.     
  886.     result = connect(s, (struct sockaddr *)&sin, sizeof(sin));
  887.     if (result < 0) {
  888.         /* perhaps we should try the backup addresses, but nahhhh */
  889.         switch (Errno()) {
  890.         case ENETDOWN:
  891.         case ENETUNREACH:
  892.             mess->error = ERROR_UNREACHABLE;
  893.             break;
  894.         case ECONNREFUSED:
  895.             mess->error = ERROR_CONNECT_REFUSED;
  896.             break;
  897.         default:
  898.             mess->error = ERROR_CANT_CONNECT;
  899.             break;
  900.         }
  901.         
  902.         CloseSocket(s);
  903.         
  904.         mess->result = 0;
  905.         
  906.         PutMsg(pport, &mess->header);
  907.         
  908.         WaitPort(myport);
  909.         GetMsg(myport);
  910.         return;
  911.     }
  912.     
  913.     /* hurrah */
  914.     
  915.     /* now we have to transfer our socket to our parents "library domain" */
  916.     
  917.     result = ReleaseSocket(s, UNIQUE_ID);
  918.     if (result < 0) {    /* BUGGER!  just as everything was going so well too :( */
  919.         mess->result = 0;
  920.         mess->error = ERROR_OOM;
  921.  
  922.         CloseSocket(s);
  923.     } else {
  924.         mess->result = result;
  925.         mess->error = NO_ERROR;
  926.     }
  927.     
  928.     PutMsg(pport, &mess->header);
  929.  
  930.     WaitPort(myport);
  931.     GetMsg(myport);
  932.     return;
  933. }
  934.  
  935. void __saveds __asm connect_child(register __a0 b8 *parent_port)
  936. {
  937.     struct Library *SocketBase;
  938.     struct MsgPort *pport, *myport;
  939.     tcpmessage *mess;
  940.     
  941.     pport = FindPort(parent_port);
  942.     if (!pport) {
  943.         /* not a fuck of a lot we can do */
  944.         return;
  945.     }
  946.     
  947.     myport = CreatePort(0, 0);
  948.     if (myport) {
  949.         mess = new_tcpmessage(myport);
  950.         if (mess) {
  951.             SocketBase = OpenLibrary("bsdsocket.library", 0);
  952.             if (SocketBase) {
  953.                 /* tell them we are going */
  954.                 mess->command = TCP_STARTUP;
  955.                 mess->result = true;
  956.                 mess->error = NO_ERROR;
  957.             
  958.                 PutMsg(pport, &mess->header);
  959.             
  960.                 WaitPort(myport);
  961.                 GetMsg(myport);        /* should be guaranteed to be mess back */
  962.                 
  963.                 pport = mess->header.mn_ReplyPort;    /* may be a different port */
  964.                 mess->command = TCP_CONNECTED;
  965.                 mess->header.mn_ReplyPort = myport;    /* GOT TO BE THE SAME !!! (for ident purposes) */
  966.             
  967.                 do_connect(SocketBase, mess, pport, myport);
  968.                 
  969.                 CloseLibrary(SocketBase);
  970.             } else {
  971.                 /* tell them we are NOT going */
  972.                 mess->command = TCP_STARTUP;
  973.                 mess->result = false;
  974.                 mess->error = ERROR_NO_CONNECTION;
  975.                 
  976.                 PutMsg(pport, &mess->header);
  977.                 
  978.                 WaitPort(myport);
  979.                 GetMsg(myport);
  980.             }
  981.             free_tcpmessage(mess);
  982.             DeletePort(myport);
  983.             return;
  984.         }
  985.         DeletePort(myport);
  986.     }
  987.     
  988.     /* our half-hearted way of telling the parent something is wrong */
  989.     Signal(pport->mp_SigTask, 1 << pport->mp_SigBit);
  990.     
  991.     return;
  992. }
  993.  
  994. void tcp_connect(struct Library *SocketBase, tcpmessage *tm, struct List *wait_list, struct MsgPort *replies)
  995. {
  996.     struct Process *child;
  997.     b8 buffer[30];
  998.     struct MsgPort *tmp_port;
  999.     tcpmessage *child_tm;
  1000.  
  1001.     unique_name(FindTask(0), ": Evans TCP Handler", buffer);
  1002.     
  1003.     if (tm->ident) {
  1004.         tm->result = false;
  1005.         tm->error = ERROR_ALREADY_CONNECTED;
  1006.         
  1007.         ReplyMsg(&tm->header);
  1008.         return;
  1009.     }
  1010.     
  1011.     tm->ident = new_tcpident(-1);
  1012.     if (!tm->ident) {
  1013.         tm->result = false;
  1014.         tm->error = ERROR_OOM;
  1015.         
  1016.         ReplyMsg(&tm->header);
  1017.         return;
  1018.     }
  1019.  
  1020.     tmp_port = CreatePort(buffer, 0);
  1021.     if (!tmp_port) {
  1022.         free_tcpident(tm->ident);
  1023.         tm->ident = nil;
  1024.  
  1025.         tm->result = false;
  1026.         tm->error = ERROR_OOM;
  1027.         
  1028.         ReplyMsg(&tm->header);
  1029.         return;
  1030.     }
  1031.  
  1032.     /* start child */
  1033.     
  1034.     child = CreateNewProcTags(
  1035.         NP_Entry,    connect_child,
  1036.         NP_Name,    "TCP Connect Handler",
  1037.         NP_Arguments,    buffer,
  1038.         TAG_END,    0
  1039.     );
  1040.  
  1041.     if (!child) {
  1042.         tm->result = false;
  1043.         tm->error = ERROR_OOM;
  1044.         
  1045.         DeletePort(tmp_port);
  1046.         free_tcpident(tm->ident);
  1047.         tm->ident = nil;
  1048.  
  1049.         ReplyMsg(&tm->header);
  1050.         return;
  1051.     }
  1052.     
  1053.     /* the child should get back to us immediately ... so 
  1054.        synchronously wait for the startup message */
  1055.     
  1056.     Wait(1 << tmp_port->mp_SigBit);
  1057.     
  1058.     child_tm = (tcpmessage *)GetMsg(tmp_port);
  1059.     if (!child_tm) {    /* they had a problem, and failed */
  1060.         tm->result = false;
  1061.         tm->error = ERROR_OOM;
  1062.         
  1063.         DeletePort(tmp_port);
  1064.         free_tcpident(tm->ident);
  1065.         tm->ident = nil;
  1066.         
  1067.         ReplyMsg(&tm->header);
  1068.         return;
  1069.     }
  1070.     
  1071.     if (!child_tm->result) {    /* ditto */
  1072.         tm->error = child_tm->error;
  1073.  
  1074.         ReplyMsg((struct Message *)child_tm);
  1075.         
  1076.         tm->result = false;
  1077.         
  1078.         DeletePort(tmp_port);
  1079.         free_tcpident(tm->ident);
  1080.         tm->ident = nil;
  1081.         
  1082.         ReplyMsg(&tm->header);
  1083.         return;
  1084.     }
  1085.  
  1086.     /* well, all should be ok now */
  1087.     
  1088.     DeletePort(tmp_port);
  1089.     
  1090.     tmp_port = child_tm->header.mn_ReplyPort;
  1091.  
  1092.     child_tm->header.mn_ReplyPort = replies;
  1093.     child_tm->data = tm->data;
  1094.     child_tm->flags = tm->flags;
  1095.     child_tm->port = tm->port;
  1096.     child_tm->address = tm->address;
  1097.     
  1098.     PutMsg(tmp_port, &child_tm->header);
  1099.     
  1100.     /* that will come back when the child has resolved the connect */
  1101.     
  1102.     ((tcpident *)tm->ident)->connecting_port = tmp_port;    /* note: this is a special case for TCP_CONNECT ONLY */
  1103.     
  1104.     AddTail(wait_list, (struct Node *)tm);
  1105.     
  1106.     return;
  1107. }
  1108.  
  1109. void tcp_connected(struct Library *SocketBase, tcpmessage *tm, struct List *wait_list)
  1110. {
  1111.     tcpident *ti;
  1112.     tcpmessage *itm, *nitm, *wait_tm;
  1113.     struct MsgPort *their_port;    /* to identify which child */
  1114.     sb32 s;
  1115.     
  1116.     truth(SocketBase != nil);
  1117.     truth(wait_list != nil);
  1118.     verify(tm, V_tcpmessage);
  1119.     
  1120.     their_port = tm->header.mn_ReplyPort;
  1121.     
  1122.     if (tm->error == NO_ERROR) {
  1123.         s = ObtainSocket(tm->result, AF_INET, SOCK_STREAM, 0);    /* shudder */
  1124.     } else {
  1125.         s = -1;
  1126.     }
  1127.  
  1128.     /* it may have failed ... but we have to check after we have found the TCP_CONNECT */
  1129.     
  1130.     /* see which TCP_CONNECT in the wait list it corresponds to ... */
  1131.  
  1132.     for (itm = (tcpmessage *)wait_list->lh_Head;
  1133.             nitm = (tcpmessage *)itm->header.mn_Node.ln_Succ;
  1134.             itm = nitm) {
  1135.         if (itm->command == TCP_CONNECT) {
  1136.             ti = itm->ident;
  1137.             verify(ti, V_tcpident);
  1138.             
  1139.             if (ti->connecting_port == (void *)their_port) {
  1140.                 Remove((struct Node *)itm);
  1141.                 
  1142.                 if ((tm->error != NO_ERROR) || (s < 0)) {
  1143.                     if (tm->error != NO_ERROR) {
  1144.                         itm->result = false;
  1145.                         itm->error = tm->error;
  1146.                     } else {        /* this case is our Obtain failing */
  1147.                         itm->result = false;
  1148.                         /* bizarre error for bizarre case */
  1149.                         itm->error = ERROR_LOST_CONNECTION;
  1150.                     }
  1151.                     
  1152.                     ReplyMsg(&tm->header);
  1153.                     
  1154.                     /* NB: reusing tm */
  1155.                     tm = itm->interrupt;
  1156.                     itm->interrupt = nil;
  1157.                     
  1158.                     free_tcpident(ti);
  1159.                     itm->ident = nil;
  1160.                     
  1161.                     ReplyMsg(&itm->header);
  1162.                     if (tm) {
  1163.                         verify(tm, V_tcpmessage);
  1164.                         ReplyMsg(&tm->header);
  1165.                     }
  1166.                     return;
  1167.                 }
  1168.                 
  1169.                 non_blocking(SocketBase, s);
  1170.                 
  1171.                 /* ok, have to make a tcpmessage to wait here */
  1172.                 
  1173.                 wait_tm = new_tcpmessage(nil);
  1174.                 if (wait_tm) {
  1175.                     ti->connecting_port = nil;
  1176.                     ti->fd = s;
  1177.                     
  1178.                     wait_tm->ident = ti;
  1179.                     wait_tm->command = TCP_CONNECTED;
  1180.                     
  1181.                     wait_tm->address = tm->address;
  1182.                     wait_tm->port = tm->port;
  1183.                         
  1184.                     itm->address = tm->address;
  1185.                     itm->port = tm->port;
  1186.                         
  1187.                     itm->result = true;
  1188.                     itm->error = NO_ERROR;
  1189.                         
  1190.                     ReplyMsg(&tm->header);
  1191.                         
  1192.                     tm = itm->interrupt;
  1193.                     itm->interrupt = nil;
  1194.                         
  1195.                     ReplyMsg(&itm->header);
  1196.                         
  1197.                     if (tm) {
  1198.                         verify(tm, V_tcpmessage);
  1199.                         ReplyMsg(&tm->header);
  1200.                     }
  1201.                         
  1202.                     AddTail(wait_list, (struct Node *)wait_tm);
  1203.                         
  1204.                     return;
  1205.                 } else itm->error = ERROR_OOM;
  1206.                 
  1207.                 free_tcpident(ti);
  1208.                 itm->ident = nil;
  1209.                 
  1210.                 CloseSocket(s);
  1211.                 itm->result = false;
  1212.                 
  1213.                 ReplyMsg(&tm->header);
  1214.                 
  1215.                 tm = itm->interrupt;
  1216.                 itm->interrupt = nil;
  1217.                 
  1218.                 ReplyMsg(&itm->header);
  1219.                 if (tm) {
  1220.                     verify(tm, V_tcpmessage);
  1221.                     ReplyMsg(&tm->header);
  1222.                 }
  1223.                 
  1224.                 return;
  1225.             }
  1226.         }
  1227.     }
  1228.     
  1229.     /* hmmm, strange things are happening */
  1230.     if (s >= 0) CloseSocket(s);
  1231.     
  1232.     ReplyMsg(&tm->header);
  1233.     return;
  1234. }
  1235.  
  1236. void tcp_interrupt(tcpmessage *tm, struct List *wait_list, fd_set *reads, fd_set *writes, sb32 *max_fd)
  1237. {
  1238.     tcpident *ti;
  1239.     tcpmessage *itm, *nitm;
  1240.     struct MsgPort *port;
  1241.     
  1242.     verify(tm, V_tcpmessage);
  1243.     
  1244.     for (itm = (tcpmessage *)wait_list->lh_Head;
  1245.             nitm = (tcpmessage *)itm->header.mn_Node.ln_Succ;
  1246.             itm = nitm) {
  1247.         
  1248.         verify(itm, V_tcpmessage);
  1249.  
  1250.         if (itm == tm->interrupt) {
  1251.             switch (itm->command) {
  1252.             case TCP_READ:
  1253.                 Remove((struct Node *)itm);
  1254.                 
  1255.                 itm->error = ERROR_INTERRUPTED;
  1256.                 ReplyMsg(&itm->header);
  1257.                 
  1258.                 tm->result = true;
  1259.                 tm->error = NO_ERROR;
  1260.                 
  1261.                 ReplyMsg(&tm->header);
  1262.                 
  1263.                 fix_read_set(wait_list, reads, max_fd);
  1264.                 return;
  1265.             case TCP_WRITE:
  1266.                 Remove((struct Node *)itm);
  1267.                 
  1268.                 itm->error = ERROR_INTERRUPTED;
  1269.                 ReplyMsg(&itm->header);
  1270.                 
  1271.                 tm->result = true;
  1272.                 tm->error = NO_ERROR;
  1273.                 
  1274.                 ReplyMsg(&tm->header);
  1275.                 
  1276.                 fix_write_set(wait_list, writes, max_fd);
  1277.                 return;
  1278.             case TCP_CONNECT:
  1279.                 /* this is the fun one */
  1280.                 ti = itm->ident;
  1281.                 verify(ti, V_tcpident);
  1282.                 
  1283.                 port = ti->connecting_port;
  1284.                 
  1285.                 itm->interrupt = tm;
  1286.                 Signal(port->mp_SigTask, SIGBREAKF_CTRL_C);
  1287.                 return;
  1288.             }
  1289.         }
  1290.     }
  1291.     
  1292.     tm->result = false;
  1293.     tm->error = ERROR_NO_CONNECTION;
  1294.     
  1295.     ReplyMsg(&tm->header);
  1296.     return;
  1297. }
  1298.  
  1299. void tcp_peername(struct Library *SocketBase, tcpmessage *tm)
  1300. /*
  1301.  * this one is a strange one ... it may have the potential to block
  1302.  * I don't really want to write a bloody child process thingy just for
  1303.  * this trivial bloody function 
  1304.  */
  1305. {
  1306.     tcpident *ti;
  1307.     struct sockaddr_in sin;
  1308.     struct hostent *he;
  1309.     sb32 sin_len, len;
  1310.  
  1311.     truth(SocketBase != nil);
  1312.     verify(tm, V_tcpmessage);
  1313.     
  1314.     ti = tm->ident;
  1315.     if (!ti) {
  1316.         tm->result = false;
  1317.         tm->error = ERROR_NO_CONNECTION;
  1318.         
  1319.         ReplyMsg(&tm->header);
  1320.         return;
  1321.     }
  1322.     
  1323.     verify(ti, V_tcpident);
  1324.     
  1325.     sin_len = sizeof(sin);
  1326.     
  1327.     if (getpeername(ti->fd, (struct sockaddr *)&sin, &sin_len) < 0) {
  1328.         if (Errno() == ENOTCONN) {
  1329.             tm->error = ERROR_NO_CONNECTION;
  1330.         } else {
  1331.             tm->error = ERROR_OOM;
  1332.         }
  1333.         tm->result = false;
  1334.         
  1335.         ReplyMsg(&tm->header);
  1336.         return;
  1337.     }
  1338.     
  1339.     he = gethostbyaddr((void *)&sin.sin_addr.s_addr, 4, AF_INET);
  1340.     if (!he) {
  1341.         tm->error = ERROR_UNKNOWN_HOST;
  1342.         tm->result = false;
  1343.         
  1344.         ReplyMsg(&tm->header);
  1345.         return;
  1346.     }
  1347.     
  1348.     len = strlen(he->h_name);
  1349.     if (len >= tm->length) {
  1350.         len = tm->length - 1;
  1351.     }
  1352.     
  1353.     memcpy(tm->data, he->h_name, len);
  1354.     ((b8 *)tm->data)[len] = 0;
  1355.     
  1356.     tm->error = NO_ERROR;
  1357.     tm->result = true;
  1358.     
  1359.     ReplyMsg(&tm->header);
  1360.     return;
  1361. }
  1362.  
  1363. void tcp_service(struct Library *SocketBase, tcpmessage *tm)
  1364. {
  1365.     struct servent *se;
  1366.     
  1367.     truth(SocketBase != nil);
  1368.     verify(tm, V_tcpmessage);
  1369.  
  1370.     se = getservbyname(tm->data, "tcp");
  1371.     if (!se) {
  1372.         tm->result = false;
  1373.         tm->error = ERROR_UNKNOWN_COMMAND;
  1374.     } else {
  1375.         tm->result = true;
  1376.         tm->error = NO_ERROR;
  1377.         
  1378.         tm->port.w = se->s_port;
  1379.     }
  1380.     
  1381.     ReplyMsg(&tm->header);
  1382.     return;
  1383. }
  1384.  
  1385. struct MsgPort *running_running(tcpmessage *emergency, struct MsgPort *commands)
  1386. {
  1387.     b32        tcp_signal, signal_tmp;
  1388.     tcpmessage    *tm, *tm2;
  1389.     tcpident    *ti;
  1390.     struct Library    *SocketBase = nil;
  1391.     struct List    waiting;
  1392.     fd_set        read_set, write_set, read_tmp, write_tmp;
  1393.     sb32        max_fd, n;
  1394.     struct MsgPort    *death_port;
  1395.     
  1396.     NewList(&waiting);    /* list of waiting requests */
  1397.     
  1398.     FD_ZERO(&read_set);
  1399.     FD_ZERO(&write_set);
  1400.     
  1401.     max_fd = -1;
  1402.     
  1403.     tcp_signal = (1 << commands->mp_SigBit);
  1404.     
  1405.     while (1) {
  1406.         if (SocketBase) {
  1407.             read_tmp = read_set;
  1408.             write_tmp = write_set;
  1409.             signal_tmp = tcp_signal;
  1410.             
  1411.             n = WaitSelect(max_fd + 1, &read_tmp, &write_tmp, nil, nil, &signal_tmp);
  1412.         } else {
  1413.             n = 0;
  1414.             Wait(tcp_signal);
  1415.         }
  1416.         
  1417.         while (tm = (tcpmessage *)GetMsg(commands)) {
  1418.             /* a message from our parent (sponsor?) */
  1419.  
  1420.             verify(tm, V_tcpmessage);
  1421.             
  1422.             if (tm->header.mn_ReplyPort == commands) {
  1423.                 /* its been ReplyMsg'd to us */
  1424.                 free_tcpmessage(tm);
  1425.                 continue;
  1426.             }
  1427.             
  1428.             switch (tm->command) {
  1429.             case TCP_NOOP:
  1430.                 tm->result = true;
  1431.                 ReplyMsg(&tm->header);
  1432.                 break;
  1433.             case TCP_CONNECT:
  1434.                 if (!SocketBase) {
  1435.                     SocketBase = OpenLibrary("bsdsocket.library", 0);
  1436.                     if (!SocketBase) {
  1437.                         tm->result = false;
  1438.                         tm->error = ERROR_NO_CONNECTION;
  1439.                         
  1440.                         ReplyMsg(&tm->header);
  1441.                         break;
  1442.                     }
  1443.                 }
  1444.                 tcp_connect(SocketBase, tm, &waiting, commands);
  1445.                 break;
  1446.             case TCP_LISTEN:
  1447.                 if (!SocketBase) {
  1448.                     SocketBase = OpenLibrary("bsdsocket.library", 0);
  1449.                     if (!SocketBase) {
  1450.                         tm->result = false;
  1451.                         tm->error = ERROR_NO_CONNECTION;
  1452.                         
  1453.                         ReplyMsg(&tm->header);
  1454.                         break;
  1455.                     }
  1456.                 }
  1457.                 tcp_listen(SocketBase, tm, &waiting, &read_set, &max_fd);
  1458.                 break;
  1459.             case TCP_READ:
  1460.                 if (!SocketBase) {    /* someone is frigging us around */
  1461.                     tm->result = 0;
  1462.                     tm->error = ERROR_NO_CONNECTION;
  1463.                     
  1464.                     ReplyMsg(&tm->header);
  1465.                     break;
  1466.                 }
  1467.                 tcp_read(SocketBase, tm, &waiting, &read_set, &max_fd);
  1468.                 break;
  1469.             case TCP_WRITE:
  1470.                 if (!SocketBase) {    /* someone is frigging us around */
  1471.                     tm->result = 0;
  1472.                     tm->error = ERROR_NO_CONNECTION;
  1473.                     
  1474.                     ReplyMsg(&tm->header);
  1475.                     break;
  1476.                 }
  1477.                 tcp_write(SocketBase, tm, &waiting, &write_set, &max_fd);
  1478.                 break;
  1479.             case TCP_CLOSE:
  1480.                 if (!SocketBase) {    /* someone is frigging us around */
  1481.                     tm->result = false;
  1482.                     tm->error = ERROR_NO_CONNECTION;
  1483.                     
  1484.                     ReplyMsg(&tm->header);
  1485.                     break;
  1486.                 }
  1487.                 tcp_close(SocketBase, tm, &waiting, &read_set, &write_set, &max_fd);
  1488.                 
  1489.                 if (IsListEmpty(&waiting)) {
  1490.                     /* absolutely everything has closed.  We can close
  1491.                        the socket library now in safety */
  1492.                     CloseLibrary(SocketBase);
  1493.                     SocketBase = nil;
  1494.                 }
  1495.                 break;
  1496.             case TCP_CONNECTED:
  1497.                 /* ahhh, a child is reporting back! */
  1498.                 
  1499.                 if (!SocketBase) {    /* someone is frigging us around */
  1500.                     tm->result = false;
  1501.                     tm->error = ERROR_NO_CONNECTION;
  1502.                     
  1503.                     ReplyMsg(&tm->header);
  1504.                     break;
  1505.                 }
  1506.                 
  1507.                 tcp_connected(SocketBase, tm, &waiting);
  1508.  
  1509.                 if (IsListEmpty(&waiting)) {
  1510.                     /* absolutely everything has closed.  We can close
  1511.                        the socket library now in safety */
  1512.                     CloseLibrary(SocketBase);
  1513.                     SocketBase = nil;
  1514.                 }
  1515.                 break;
  1516.             case TCP_INTERRUPT:
  1517.                 tcp_interrupt(tm, &waiting, &read_set, &write_set, &max_fd);
  1518.                 break;
  1519.             case TCP_NEWMESSAGE:
  1520.                 tm2 = new_tcpmessage(tm->header.mn_ReplyPort);
  1521.                 if (!tm2) {
  1522.                     tm->result = false;
  1523.                     tm->error = ERROR_OOM;
  1524.                     ReplyMsg(&tm->header);
  1525.                     break;
  1526.                 }
  1527.                 
  1528.                 tm2->ident = tm->ident;
  1529.                 
  1530.                 tm->data = tm2;
  1531.                 tm->result = true;
  1532.                 tm->error = NO_ERROR;
  1533.                 
  1534.                 ReplyMsg(&tm->header);
  1535.                 break;
  1536.             case TCP_DISPOSE:
  1537.                 free_tcpmessage(tm);
  1538.                 break;
  1539.             case TCP_DIE:
  1540.                 /* we have to assume they've done the right thing and
  1541.                    disposed of all messages (closing all connections) */
  1542.                 /* all we have to do is to free whatever is left over
  1543.                    and exit */
  1544.                 
  1545.                 death_port = tm->header.mn_ReplyPort;
  1546.  
  1547.                 free_tcpmessage(tm);
  1548.                 
  1549.                 if (SocketBase) {
  1550.                     CloseLibrary(SocketBase);
  1551.                     SocketBase = nil;
  1552.                 }
  1553.                 
  1554.                 while (tm = (tcpmessage *)RemHead(&waiting)) {
  1555.                     if (tm->ident && tm->command != TCP_CONNECT)
  1556.                         free_tcpident(tm->ident);
  1557.                     free_tcpmessage(tm);
  1558.                 }
  1559.                 
  1560.                 /* perhaps should do a little more ... */
  1561.                 
  1562.                 return death_port;
  1563.             case TCP_PEERNAME:
  1564.                 if (!SocketBase) {    /* someone is yankin' our chain */
  1565.                     tm->result = false;
  1566.                     tm->error = ERROR_NO_CONNECTION;
  1567.                     
  1568.                     ReplyMsg(&tm->header);
  1569.                     break;
  1570.                 }
  1571.                 tcp_peername(SocketBase, tm);
  1572.                 break;
  1573.             case TCP_SERVICE:
  1574.                 if (!SocketBase) {
  1575.                     SocketBase = OpenLibrary("bsdsocket.library", 0);
  1576.                     if (!SocketBase) {
  1577.                         tm->result = false;
  1578.                         tm->error = ERROR_NO_CONNECTION;
  1579.                         
  1580.                         ReplyMsg(&tm->header);
  1581.                         break;
  1582.                     }
  1583.                 }
  1584.                 tcp_service(SocketBase, tm);
  1585.                 if (IsListEmpty(&waiting)) {
  1586.                     /* absolutely everything has closed.  We can close
  1587.                        the socket library now in safety */
  1588.                     CloseLibrary(SocketBase);
  1589.                     SocketBase = nil;
  1590.                 }
  1591.                 break;
  1592.             default:
  1593.                 tm->result = false;
  1594.                 tm->error = ERROR_UNKNOWN_COMMAND;
  1595.                 ReplyMsg(&tm->header);
  1596.                 break;
  1597.             }
  1598.         }
  1599.         
  1600.         if (n < 0) {    /* hmmm ... this seems to happen when they close the library underneath us */
  1601.             /* should send back any waiting reads/writes/listens */
  1602.             CloseLibrary(SocketBase);
  1603.             SocketBase = nil;
  1604.             
  1605.             continue;
  1606.         }
  1607.         
  1608. #ifdef SDLFKJ
  1609.         truth (n >= 0);        /* I don't _think_ we should ever get SIGINTR ... */
  1610. #endif
  1611.  
  1612.         if (n <= 0) continue;    /* no fds are ready, so don't look through list */
  1613.         
  1614.         for (tm = (tcpmessage *)waiting.lh_Head; 
  1615.                 tm2 = (tcpmessage *)tm->header.mn_Node.ln_Succ; 
  1616.                 tm = tm2) {
  1617.  
  1618.             switch (tm->command) {
  1619.             case TCP_LISTEN:
  1620.                 ti = tm->ident;
  1621.                 verify(ti, V_tcpident);
  1622.  
  1623.                 if (FD_ISSET(ti->fd, &read_tmp)) {    /* ready to accept */
  1624.                     tcp_accept(SocketBase, tm, &waiting, commands);
  1625.                 }
  1626.                 break;
  1627.             case TCP_READ:
  1628.                 ti = tm->ident;
  1629.                 verify(ti, V_tcpident);
  1630.  
  1631.                 if (FD_ISSET(ti->fd, &read_tmp)) {    /* ready to continue reading */
  1632.                     tcp_read_more(SocketBase, tm, &waiting, &read_set, &max_fd);
  1633.                 }
  1634.                 break;
  1635.             case TCP_WRITE:
  1636.                 ti = tm->ident;
  1637.                 verify(ti, V_tcpident);
  1638.  
  1639.                 if (FD_ISSET(ti->fd, &write_tmp)) {    /* ready to continue writing */
  1640.                     tcp_write_more(SocketBase, tm, &waiting, &write_set, &max_fd);
  1641.                 }
  1642.                 break;
  1643.             }
  1644.         }
  1645.     }
  1646. }
  1647.  
  1648. void __saveds __asm tcp_handler(register __a0 b8 *parent_port)
  1649. {
  1650.     struct MsgPort *mp, *tcp_commands;
  1651.     tcpmessage *tm, *new_tm;
  1652.     
  1653.     mem_tracking_on();
  1654.     
  1655.     mp = FindPort(parent_port);
  1656.     if (!mp) {
  1657.         truth(FindPort(parent_port) != nil);    /* will display an alert */
  1658.         return;    /* OOOPS - not overly much we can do here */
  1659.     }
  1660.     
  1661.     tcp_commands = CreatePort(0, 0);
  1662.     if (!tcp_commands) {
  1663.         /* this is a signal jobbie because we can't send a message 
  1664.            so when they wait for the signal, and then can't GetMsg
  1665.            they should guess that something has gone wrong */
  1666.         Signal(mp->mp_SigTask, 1 << mp->mp_SigBit);
  1667.         return;
  1668.     }
  1669.     
  1670.     tm = new_tcpmessage(tcp_commands);
  1671.     if (!tm) {
  1672.         /* again ... our message doesn't exist, so just signal */
  1673.         Signal(mp->mp_SigTask, 1 << mp->mp_SigBit);
  1674.         DeletePort(tcp_commands);
  1675.         return;
  1676.     }
  1677.     
  1678.     new_tm = new_tcpmessage(tcp_commands);
  1679.     if (!new_tm) {
  1680.         Signal(mp->mp_SigTask, 1 << mp->mp_SigBit);
  1681.         DeletePort(tcp_commands);
  1682.         free_tcpmessage(tm);
  1683.         return;
  1684.     }
  1685.     
  1686.     new_tm->command = TCP_NEWMESSAGE;
  1687.     new_tm->header.mn_ReplyPort = mp;    
  1688.         /* just a guess ... if they want something different, they'se gonna haveta do it themselves */
  1689.  
  1690.     /* ok, we have enough to communicate ... tell them we started ok */
  1691.     
  1692.     tm->command = TCP_STARTUP;
  1693.     tm->data = tcp_commands;    /* this tells them where to send commands */
  1694.     tm->result = true;        /* not necessary but wth */
  1695.     
  1696.     PutMsg(mp, &tm->header);
  1697.     
  1698.     /* wait for it to come back */
  1699.     
  1700.     Wait(1 << tcp_commands->mp_SigBit);
  1701.     GetMsg(tcp_commands);    /* should be guaranteed to be tm back ;) */
  1702.     
  1703.     /* ok, time to carry on */
  1704.     /* send them a message to bootstrap their message system */
  1705.     
  1706.     PutMsg(mp, &new_tm->header);
  1707.     
  1708.     /* Reusing mp here for the death port */
  1709.  
  1710.     mp = running_running(tm, tcp_commands);
  1711.     
  1712.     DeletePort(tcp_commands);
  1713.     free_tcpmessage(tm);
  1714.     
  1715.     check_memory();
  1716.     
  1717.     Forbid();    /* once we are RemTask'd the Forbid will be lifted */
  1718.     
  1719.     Signal(mp->mp_SigTask, 1 << mp->mp_SigBit);    /* signal parent we are dead */
  1720.     
  1721.     return;
  1722. }
  1723.