home *** CD-ROM | disk | FTP | other *** search
/ Media Share 9 / MEDIASHARE_09.ISO / hamradio / s920603.zip / TCPSOCK.C < prev    next >
C/C++ Source or Header  |  1992-05-21  |  8KB  |  360 lines

  1. #include "global.h"
  2. #include "tcp.h"
  3. #include "socket.h"
  4. #include "usock.h"
  5.  
  6. static void s_trcall __ARGS((struct tcb *tcb,int cnt));
  7. static void s_tscall __ARGS((struct tcb *tcb,int old,int new));
  8. static void s_ttcall __ARGS((struct tcb *tcb,int cnt));
  9. static void trdiscard __ARGS((struct tcb *tcb,int cnt));
  10. static void autobind __ARGS((struct usock *up));
  11.  
  12. int16 Lport = 1024;
  13.  
  14. int
  15. so_tcp(up,protocol)
  16. struct usock *up;
  17. int protocol;
  18. {
  19.     up->type = TYPE_TCP;
  20.     return 0;
  21. }
  22. int
  23. so_tcp_listen(up,backlog)
  24. struct usock *up;
  25. int backlog;
  26. {
  27.     int s;
  28.     struct sockaddr_in *local;
  29.     struct socket lsock;
  30.  
  31.     s = up->index;
  32.     if(up->name == NULLCHAR)
  33.         autobind(up);
  34.  
  35.     local = (struct sockaddr_in *)up->name;
  36.     lsock.address = local->sin_addr.s_addr;
  37.     lsock.port = local->sin_port;
  38.     up->cb.tcb = open_tcp(&lsock,NULLSOCK,
  39.      backlog ? TCP_SERVER:TCP_PASSIVE,0,
  40.     s_trcall,s_ttcall,s_tscall,up->tos,s);
  41.     return 0;
  42. }
  43. int
  44. so_tcp_conn(up)
  45. struct usock *up;
  46. {
  47.     int s;
  48.     struct tcb *tcb;
  49.     struct socket lsock,fsock;
  50.     struct sockaddr_in *local,*remote;
  51.  
  52.     if(up->name == NULLCHAR){
  53.         autobind(up);
  54.     }
  55.     if(checkipaddr(up->peername,up->namelen) == -1){
  56.         errno = EAFNOSUPPORT;
  57.         return -1;
  58.     }
  59.     s = up->index;
  60.     /* Construct the TCP-style ports from the sockaddr structs */
  61.     local = (struct sockaddr_in *)up->name;
  62.     remote = (struct sockaddr_in *)up->peername;
  63.  
  64.     if(local->sin_addr.s_addr == INADDR_ANY)
  65.         /* Choose a local address */
  66.         local->sin_addr.s_addr = locaddr(remote->sin_addr.s_addr);
  67.  
  68.     lsock.address = local->sin_addr.s_addr;
  69.     lsock.port = local->sin_port;
  70.     fsock.address = remote->sin_addr.s_addr;
  71.     fsock.port = remote->sin_port;
  72.  
  73.     /* Open the TCB in active mode */
  74.     up->cb.tcb = open_tcp(&lsock,&fsock,TCP_ACTIVE,0,
  75.      s_trcall,s_ttcall,s_tscall,up->tos,s);
  76.  
  77.     /* Wait for the connection to complete */
  78.     while((tcb = up->cb.tcb) != NULLTCB && tcb->state != TCP_ESTABLISHED){
  79.         if(up->noblock){
  80.             errno = EWOULDBLOCK;
  81.             return -1;
  82.         } else if((errno = pwait(up)) != 0){
  83.             return -1;
  84.         }
  85.     }
  86.     if(tcb == NULLTCB){
  87.         /* Probably got refused */
  88.         free(up->peername);
  89.         up->peername = NULLCHAR;
  90.         errno = ECONNREFUSED;
  91.         return -1;
  92.     }
  93.     return 0;
  94. }
  95. int
  96. so_tcp_recv(up,bpp,from,fromlen)
  97. struct usock *up;
  98. struct mbuf **bpp;
  99. char *from;
  100. int *fromlen;
  101. {
  102.     int cnt;
  103.     struct tcb *tcb;
  104.  
  105.     while((tcb = up->cb.tcb) != NULLTCB && tcb->r_upcall != trdiscard
  106.      && (cnt = recv_tcp(tcb,bpp,(int16)0)) == -1){
  107.         if(up->noblock){
  108.             errno = EWOULDBLOCK;
  109.             return -1;
  110.         } else if((errno = pwait(up)) != 0){
  111.             return -1;
  112.         }
  113.     }
  114.     if(tcb == NULLTCB){
  115.         /* Connection went away */
  116.         errno = ENOTCONN;
  117.         return -1;
  118.     } else if(tcb->r_upcall == trdiscard){
  119.         /* Receive shutdown has been done */
  120.         errno = ENOTCONN;    /* CHANGE */
  121.         return -1;
  122.     }
  123.     return cnt;
  124. }
  125. int
  126. so_tcp_send(up,bp,to)
  127. struct usock *up;
  128. struct mbuf *bp;
  129. char *to;
  130. {
  131.     struct tcb *tcb;
  132.     int cnt;
  133.  
  134.     if((tcb = up->cb.tcb) == NULLTCB){
  135.         free_p(bp);
  136.         errno = ENOTCONN;
  137.         return -1;
  138.     }        
  139.     cnt = send_tcp(tcb,bp);
  140.  
  141.     while((tcb = up->cb.tcb) != NULLTCB &&
  142.      tcb->sndcnt > tcb->window){
  143.         /* Send queue is full */
  144.         if(up->noblock){
  145.             errno = EWOULDBLOCK;
  146.             return -1;
  147.         } else if((errno = pwait(up)) != 0){
  148.             return -1;
  149.         }
  150.     }
  151.     if(tcb == NULLTCB){
  152.         errno = ENOTCONN;
  153.         return -1;
  154.     }
  155.     return cnt;
  156. }
  157. int
  158. so_tcp_qlen(up,rtx)
  159. struct usock *up;
  160. int rtx;
  161. {
  162.     int len;
  163.  
  164.     switch(rtx){
  165.     case 0:
  166.         len = up->cb.tcb->rcvcnt;
  167.         break;
  168.     case 1:
  169.         len = up->cb.tcb->sndcnt;
  170.         break;
  171.     }
  172.     return len;
  173. }
  174. int
  175. so_tcp_kick(up)
  176. struct usock *up;
  177. {
  178.     kick_tcp(up->cb.tcb);
  179.     return 0;
  180. }
  181. int
  182. so_tcp_shut(up,how)
  183. struct usock *up;
  184. int how;
  185. {
  186.     switch(how){
  187.     case 0:    /* No more receives -- replace upcall */
  188.         up->cb.tcb->r_upcall = trdiscard;
  189.         break;
  190.     case 1:    /* Send EOF */
  191.         close_tcp(up->cb.tcb);
  192.         break;
  193.     case 2:    /* Blow away TCB */
  194.         reset_tcp(up->cb.tcb);
  195.         up->cb.tcb = NULLTCB;
  196.         break;
  197.     }
  198.     return 0;
  199. }
  200. int
  201. so_tcp_close(up)
  202. struct usock *up;
  203. {
  204.     if(up->cb.tcb != NULLTCB){    /* In case it's been reset */
  205.         up->cb.tcb->r_upcall = trdiscard;
  206.         /* Tell the TCP_CLOSED upcall there's no more socket */
  207.         up->cb.tcb->user = -1;
  208.         close_tcp(up->cb.tcb);
  209.     }
  210.     return 0;
  211. }
  212. /* TCP receive upcall routine */
  213. static void
  214. s_trcall(tcb,cnt)
  215. struct tcb *tcb;
  216. int cnt;
  217. {
  218.     /* Wake up anybody waiting for data, and let them run */
  219.     psignal(itop(tcb->user),1);
  220.     pwait(NULL);
  221. }
  222. /* TCP transmit upcall routine */
  223. static void
  224. s_ttcall(tcb,cnt)
  225. struct tcb *tcb;
  226. int cnt;
  227. {
  228.     /* Wake up anybody waiting to send data, and let them run */
  229.     psignal(itop(tcb->user),1);
  230.     pwait(NULL);
  231. }
  232. /* TCP state change upcall routine */
  233. static void
  234. s_tscall(tcb,old,new)
  235. struct tcb *tcb;
  236. int old,new;
  237. {
  238.     int s,ns;
  239.     struct usock *up,*nup,*oup;
  240.     union sp sp;
  241.  
  242.     s = tcb->user;
  243.     oup = up = itop(s);
  244.  
  245.     switch(new){
  246.     case TCP_CLOSED:
  247.         /* Clean up. If the user has already closed the socket,
  248.          * then up will be null (s was set to -1 by the close routine).
  249.          * If not, then this is an abnormal close (e.g., a reset)
  250.          * and clearing out the pointer in the socket structure will
  251.          * prevent any further operations on what will be a freed
  252.          * control block. Also wake up anybody waiting on events
  253.          * related to this tcb so they will notice it disappearing.
  254.          */
  255.         if(up != NULLUSOCK){
  256.             up->cb.tcb = NULLTCB;
  257.             up->errcodes[0] = tcb->reason;
  258.             up->errcodes[1] = tcb->type;
  259.             up->errcodes[2] = tcb->code;
  260.         }
  261.         del_tcp(tcb);
  262.         break;
  263.     case TCP_SYN_RECEIVED:
  264.         /* Handle an incoming connection. If this is a server TCB,
  265.          * then we're being handed a "clone" TCB and we need to
  266.          * create a new socket structure for it. In either case,
  267.          * find out who we're talking to and wake up the guy waiting
  268.          * for the connection.
  269.          */
  270.         if(tcb->flags.clone){
  271.             /* Clone the socket */
  272.             ns = socket(AF_INET,SOCK_STREAM,0);
  273.             nup = itop(ns);
  274.             ASSIGN(*nup,*up);
  275.             tcb->user = ns;
  276.             nup->cb.tcb = tcb;
  277.             /* Allocate new memory for the name areas */
  278.             nup->name = mallocw(SOCKSIZE);
  279.             nup->peername = mallocw(SOCKSIZE);
  280.             nup->index = ns;
  281.             /* Store the new socket # in the old one */
  282.             up->rdysock = ns;
  283.             up = nup;
  284.             s = ns;
  285.         } else {
  286.             /* Allocate space for the peer's name */
  287.             up->peername = mallocw(SOCKSIZE);
  288.             /* Store the old socket # in the old socket */
  289.             up->rdysock = s;
  290.         }
  291.         /* Load the addresses. Memory for the name has already
  292.          * been allocated, either above or in the original bind.
  293.          */
  294.         sp.p = up->name;
  295.         sp.in->sin_family = AF_INET;
  296.         sp.in->sin_addr.s_addr = up->cb.tcb->conn.local.address;
  297.         sp.in->sin_port = up->cb.tcb->conn.local.port;
  298.         up->namelen = SOCKSIZE;
  299.  
  300.         sp.p = up->peername;
  301.         sp.in->sin_family = AF_INET;
  302.         sp.in->sin_addr.s_addr = up->cb.tcb->conn.remote.address;
  303.         sp.in->sin_port = up->cb.tcb->conn.remote.port;
  304.         up->peernamelen = SOCKSIZE;
  305.  
  306.         /* Wake up the guy accepting it, and let him run */
  307.         psignal(oup,1);
  308.         pwait(NULL);
  309.         break;
  310.     default:    /* Ignore all other state transitions */
  311.         break;
  312.     }
  313.     psignal(up,0);    /* In case anybody's waiting */
  314. }
  315. /* Discard data received on a TCP connection. Used after a receive shutdown or
  316.  * close_s until the TCB disappears.
  317.  */
  318. static void
  319. trdiscard(tcb,cnt)
  320. struct tcb *tcb;
  321. int cnt;
  322. {
  323.     struct mbuf *bp;
  324.  
  325.     recv_tcp(tcb,&bp,(int16)cnt);
  326.     free_p(bp);
  327. }
  328.  
  329. /* Issue an automatic bind of a local address */
  330. static void
  331. autobind(up)
  332. struct usock *up;
  333. {
  334.     struct sockaddr_in local;
  335.     int s;
  336.  
  337.     s = up->index;
  338.     local.sin_family = AF_INET;
  339.     local.sin_addr.s_addr = INADDR_ANY;
  340.     local.sin_port = Lport++;
  341.     bind(s,(char *)&local,sizeof(struct sockaddr_in));
  342. }
  343. char *
  344. tcpstate(up)
  345. struct usock *up;
  346. {
  347.     if(up->cb.tcb == NULLTCB)
  348.         return NULLCHAR;
  349.     return Tcpstates[up->cb.tcb->state];
  350. }
  351. int
  352. so_tcp_stat(up)
  353. struct usock *up;
  354. {
  355.     st_tcp(up->cb.tcb);
  356.     return 0;
  357. }
  358.  
  359.  
  360.