home *** CD-ROM | disk | FTP | other *** search
/ GEMini Atari / GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso / files / telecomm / ka9q_src / tcpuser.c < prev    next >
C/C++ Source or Header  |  1988-11-29  |  7KB  |  311 lines

  1. /* User calls to TCP */
  2. #include "global.h"
  3. #include "timer.h"
  4. #include "mbuf.h"
  5. #include "netuser.h"
  6. #include "internet.h"
  7. #include "tcp.h"
  8.  
  9. int16 tcp_window = DEF_WND;
  10.  
  11. struct tcb *
  12. open_tcp(lsocket,fsocket,mode,window,r_upcall,t_upcall,s_upcall,tos,user)
  13. struct socket *lsocket;    /* Local socket */
  14. struct socket *fsocket;    /* Remote socket */
  15. int mode;        /* Active/passive/server */
  16. int16 window;        /* Receive window (and send buffer) sizes */
  17. void (*r_upcall)();    /* Function to call when data arrives */
  18. void (*t_upcall)();    /* Function to call when ok to send more data */
  19. void (*s_upcall)();    /* Function to call when connection state changes */
  20. char tos;
  21. char *user;        /* User linkage area */
  22. {
  23.     struct connection conn;
  24.     register struct tcb *tcb;
  25.     void send_syn();
  26.  
  27.     if(lsocket == NULLSOCK){
  28.         net_error = INVALID;
  29.         return NULLTCB;
  30.     }
  31.     conn.local.address = lsocket->address;
  32.     conn.local.port = lsocket->port;
  33.     if(fsocket != NULLSOCK){
  34.         conn.remote.address = fsocket->address;
  35.         conn.remote.port = fsocket->port;
  36.     } else {
  37.         conn.remote.address = 0;
  38.         conn.remote.port = 0;
  39.     }
  40.     if((tcb = lookup_tcb(&conn)) == NULLTCB){
  41.         if((tcb = create_tcb(&conn)) == NULLTCB){
  42.             net_error = NO_SPACE;
  43.             return NULLTCB;
  44.         }
  45.     } else if(tcb->state != LISTEN){
  46.         net_error = CON_EXISTS;
  47.         return NULLTCB;
  48.     }
  49.     tcb->user = user;
  50.     if(window != 0)
  51.         tcb->window = tcb->rcv.wnd = window;
  52.     else
  53.         tcb->window = tcb->rcv.wnd = tcp_window;
  54.     tcb->r_upcall = r_upcall;
  55.     tcb->t_upcall = t_upcall;
  56.     tcb->s_upcall = s_upcall;
  57.     tcb->tos = tos;
  58.     switch(mode){
  59.     case TCP_SERVER:
  60.         tcb->flags |= CLONE;
  61.     case TCP_PASSIVE:    /* Note fall-thru */
  62.         setstate(tcb,LISTEN);
  63.         break;
  64.     case TCP_ACTIVE:
  65.         /* Send SYN, go into SYN_SENT state */
  66.         send_syn(tcb);
  67.         setstate(tcb,SYN_SENT);
  68.         tcp_output(tcb);
  69.         tcp_stat.conout++;
  70.         break;
  71.     }
  72.     return tcb;
  73. }
  74. /* User send routine */
  75. int
  76. send_tcp(tcb,bp)
  77. register struct tcb *tcb;
  78. struct mbuf *bp;
  79. {
  80.     int16 cnt;
  81.     void send_syn();
  82.  
  83.     if(tcb == NULLTCB || bp == NULLBUF){
  84.         free_p(bp);
  85.         net_error = INVALID;
  86.         return -1;
  87.     }
  88.     cnt = len_mbuf(bp);
  89. #ifdef    TIGHT
  90.     /* If this would overfill our send queue, reject it entirely */
  91.     af(tcb->sndcnt + cnt > tcb->window){
  92.         free_p(bp);
  93.         net_error = WOULDBLK;
  94.         return -1;
  95.     }
  96. #endif
  97.     switch(tcb->state){
  98.     case CLOSED:
  99.         free_p(bp);
  100.         net_error = NO_CONN;
  101.         return -1;
  102.     case LISTEN:    /* Change state from passive to active */
  103.         send_syn(tcb);
  104.         setstate(tcb,SYN_SENT);    /* Note fall-thru */
  105.     case SYN_SENT:
  106.     case SYN_RECEIVED:
  107.     case ESTABLISHED:
  108.     case CLOSE_WAIT:
  109.         append(&tcb->sndq,bp);
  110.         tcb->sndcnt += cnt;
  111.         tcp_output(tcb);
  112.         break;
  113.     case FINWAIT1:
  114.     case FINWAIT2:
  115.     case CLOSING:
  116.     case LAST_ACK:
  117.     case TIME_WAIT:
  118.         free_p(bp);
  119.         net_error = CON_CLOS;
  120.         return -1;
  121.     }
  122.     return cnt;
  123. }
  124. /* User receive routine */
  125. int
  126. recv_tcp(tcb,bp,cnt)
  127. register struct tcb *tcb;
  128. struct mbuf **bp;
  129. int16 cnt;
  130. {
  131.     if(tcb == NULLTCB || bp == (struct mbuf **)0){
  132.         net_error = INVALID;
  133.         return -1;
  134.     }
  135.     /* cnt == 0 means "I want it all" */
  136.     if(cnt == 0)
  137.         cnt = tcb->rcvcnt;
  138.     /* If there's something on the queue, just return it regardless
  139.      * of the state we're in.
  140.      */
  141.     if(tcb->rcvcnt != 0){
  142.         /* See if the user can take all of it */
  143.         if(tcb->rcvcnt <= cnt){
  144.             cnt = tcb->rcvcnt;
  145.             *bp = tcb->rcvq;
  146.             tcb->rcvq = NULLBUF;
  147.         } else {
  148.             if((*bp = alloc_mbuf(cnt)) == NULLBUF){
  149.                 net_error = NO_SPACE;
  150.                 return -1;
  151.             }
  152.             pullup(&tcb->rcvq,(*bp)->data,cnt);
  153.             (*bp)->cnt = cnt;
  154.         }
  155.         tcb->rcvcnt -= cnt;
  156.         tcb->rcv.wnd += cnt;
  157.         /* Do a window update if it was closed */
  158.         if(cnt == tcb->rcv.wnd){
  159.             tcb->flags |= FORCE;
  160.             tcp_output(tcb);
  161.         }
  162.         return cnt;
  163.     } else {
  164.         /* If there's nothing on the queue, our action depends on what state
  165.          * we're in (i.e., whether or not we're expecting any more data).
  166.          * If no more data is expected, then simply return 0; this is
  167.          * interpreted as "end of file".
  168.          */
  169.         switch(tcb->state){
  170.         case LISTEN:
  171.         case SYN_SENT:
  172.         case SYN_RECEIVED:
  173.         case ESTABLISHED:
  174.         case FINWAIT1:
  175.         case FINWAIT2:
  176.             *bp = NULLBUF;
  177.             net_error = WOULDBLK;
  178.             return -1;
  179.         case CLOSED:
  180.         case CLOSE_WAIT:
  181.         case CLOSING:
  182.         case LAST_ACK:
  183.         case TIME_WAIT:
  184.             *bp = NULLBUF;
  185.             return 0;
  186.         }
  187.     }
  188.     return 0;    /* Not reached, but lint doesn't know that */
  189. }
  190. /* This really means "I have no more data to send". It only closes the
  191.  * connection in one direction, and we can continue to receive data
  192.  * indefinitely.
  193.  */
  194. int
  195. close_tcp(tcb)
  196. register struct tcb *tcb;
  197. {
  198.     if(tcb == NULLTCB){
  199.         net_error = INVALID;
  200.         return -1;
  201.     }
  202.     switch(tcb->state){
  203.     case LISTEN:
  204.     case SYN_SENT:
  205.         close_self(tcb,NORMAL);
  206.         return 0;
  207.     case SYN_RECEIVED:
  208.     case ESTABLISHED:
  209.         tcb->sndcnt++;
  210.         tcb->snd.nxt++;
  211.         setstate(tcb,FINWAIT1);
  212.         tcp_output(tcb);
  213.         return 0;
  214.     case CLOSE_WAIT:
  215.         tcb->sndcnt++;
  216.         tcb->snd.nxt++;
  217.         setstate(tcb,LAST_ACK);
  218.         tcp_output(tcb);
  219.         return 0;
  220.     case FINWAIT1:
  221.     case FINWAIT2:
  222.     case CLOSING:
  223.     case LAST_ACK:
  224.     case TIME_WAIT:
  225.         net_error = CON_CLOS;
  226.         return -1;
  227.     }
  228.     return -1;    /* "Can't happen" */
  229. }
  230. /* Delete TCB, free resources. The user is not notified, even if the TCB is
  231.  * not in the CLOSED state. This function should normally be called by the
  232.  * user only in response to a state change upcall to CLOSED state.
  233.  */
  234. int
  235. del_tcp(tcb)
  236. register struct tcb *tcb;
  237. {
  238.     void unlink_tcb();
  239.     struct reseq *rp,*rp1;
  240.  
  241.     if(tcb == NULLTCB){
  242.         net_error = INVALID;
  243.         return -1;
  244.     }
  245.     unlink_tcb(tcb);
  246.     stop_timer(&tcb->timer);
  247.     stop_timer(&tcb->rtt_timer);
  248.     for(rp = tcb->reseq;rp != NULLRESEQ;rp = rp1){
  249.         rp1 = rp->next;
  250.         free_p(rp->bp);
  251.         free((char *)rp);
  252.     }
  253.     tcb->reseq = NULLRESEQ;
  254.     free_p(tcb->rcvq);
  255.     free_p(tcb->sndq);
  256.     free((char *)tcb);
  257.     return 0;
  258. }
  259. /* Do printf on a tcp connection */
  260. /*VARARGS*/
  261. tprintf(tcb,message,arg1,arg2,arg3)
  262. struct tcb *tcb;
  263. char *message,*arg1,*arg2,*arg3;
  264. {
  265.     struct mbuf *bp;
  266.     int len;
  267.  
  268.     if(tcb == NULLTCB)
  269.         return 0;
  270.  
  271.     bp = alloc_mbuf(100);
  272.     len = sprintf(bp->data,message,arg1,arg2,arg3);
  273.     bp->cnt = strlen(bp->data);
  274.     send_tcp(tcb,bp);
  275.     return len;
  276. }
  277. /* Return 1 if arg is a valid TCB, 0 otherwise */
  278. int
  279. tcpval(tcb)
  280. struct tcb *tcb;
  281. {
  282.     register int i;
  283.     register struct tcb *tcb1;
  284.  
  285.     if(tcb == NULLTCB)
  286.         return 0;    /* Null pointer can't be valid */
  287.     for(i=0;i<NTCB;i++){
  288.         for(tcb1=tcbs[i];tcb1 != NULLTCB;tcb1 = tcb1->next){
  289.             if(tcb1 == tcb)
  290.                 return 1;
  291.         }
  292.     }
  293.     return 0;
  294. }
  295. kick_tcp(tcb)
  296. register struct tcb *tcb;
  297. {
  298.     void tcp_timeout();
  299.  
  300.     if(!tcpval(tcb))
  301.         return -1;
  302.     tcp_timeout((char *)tcb);
  303.     return 0;
  304. }
  305. reset_tcp(tcb)
  306. register struct tcb *tcb;
  307. {
  308.     close_self(tcb,RESET);
  309. }
  310.  
  311.