home *** CD-ROM | disk | FTP | other *** search
/ The Pier Shareware 6 / The_Pier_Shareware_Number_6_(The_Pier_Exchange)_(1995).iso / 024 / psi110g.zip / TCPUSER.C < prev    next >
C/C++ Source or Header  |  1994-04-17  |  12KB  |  433 lines

  1. /* User calls to TCP
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  */
  4. #include "global.h"
  5. #include "timer.h"
  6. #include "mbuf.h"
  7. #include "netuser.h"
  8. #include "socket.h"
  9. #include "internet.h"
  10. #include "iface.h"
  11. #include "tcp.h"
  12. #include "ip.h"
  13. #include "icmp.h"
  14. #include "proc.h"
  15.   
  16. int16 Tcp_window = DEF_WND;
  17. extern struct iftcp def_iftcp;
  18.   
  19. struct tcb *
  20. open_tcp(lsocket,fsocket,mode,window,r_upcall,t_upcall,s_upcall,tos,user)
  21. struct socket *lsocket; /* Local socket */
  22. struct socket *fsocket; /* Remote socket */
  23. int mode;       /* Active/passive/server */
  24. int16 window;       /* Receive window (and send buffer) sizes */
  25. void (*r_upcall)__ARGS((struct tcb *,int));   /* Function to call when data arrives */
  26. void (*t_upcall)__ARGS((struct tcb *,int));   /* Function to call when ok to send more data */
  27. void (*s_upcall)__ARGS((struct tcb *,int,int));       /* Function to call when connection state changes */
  28. int tos;
  29. int user;       /* User linkage area */
  30. {
  31.     struct connection conn;
  32.     struct tcb *tcb;
  33.     struct iface *ifp = NULL;
  34.     struct route *rp;
  35.   
  36.     if(lsocket == NULLSOCK){
  37.         Net_error = INVALID;
  38.         return NULLTCB;
  39.     }
  40.     conn.local.address = lsocket->address;
  41.     conn.local.port = lsocket->port;
  42.     if(fsocket != NULLSOCK){
  43.         conn.remote.address = fsocket->address;
  44.         conn.remote.port = fsocket->port;
  45.     } else {
  46.         conn.remote.address = 0;
  47.         conn.remote.port = 0;
  48.     }
  49.     if((tcb = lookup_tcb(&conn)) == NULLTCB){
  50.         /* If we are about to start a new connection,
  51.          * but don't have a route, disallow it ! - WG7J
  52.          */
  53.         if(mode == TCP_ACTIVE) {
  54.             /* Is this to ourself ? */
  55.             if((ifp=ismyaddr(conn.remote.address)) == NULL) {
  56.                 /* No, do we have a route ? */
  57.                 if((rp = rt_lookup(conn.remote.address)) == NULL) {
  58.                     /* We have no route to this system ! */
  59.                     Net_error = NOROUTE;
  60.                     return NULLTCB;
  61.                 } else
  62.                     ifp = rp->iface;
  63.             }
  64.         }
  65.         if((tcb = create_tcb(&conn)) == NULLTCB){
  66.             Net_error = NO_MEM;
  67.             return NULLTCB;
  68.         }
  69.     } else { /* if(tcb->state != TCP_LISTEN){
  70.               * prevent multiple servers being added to the
  71.               * server list in socket.c ! - WG7J
  72.               * Note that this bug still exists in vanilla KA9Q
  73.               */
  74.         Net_error = CON_EXISTS;
  75.         return NULLTCB;
  76.     }
  77.     tcb->user = user;
  78.     if(window != 0)
  79.         tcb->window = tcb->rcv.wnd = window;
  80.     else {
  81.         if(ifp)
  82.             tcb->window = tcb->rcv.wnd = ifp->tcp->window;
  83.         else
  84.             tcb->window = tcb->rcv.wnd = Tcp_window;
  85.     }
  86.     tcb->snd.wnd = 1;   /* Allow space for sending a SYN */
  87.     tcb->r_upcall = r_upcall;
  88.     tcb->t_upcall = t_upcall;
  89.     tcb->s_upcall = s_upcall;
  90.     tcb->tos = tos;
  91.     switch(mode){
  92.         case TCP_SERVER:
  93.             tcb->flags.clone = 1;
  94.         case TCP_PASSIVE:   /* Note fall-thru */
  95.         /* Point to the default tcp parameters */
  96.             tcb->parms = &def_iftcp;
  97.             setstate(tcb,TCP_LISTEN);
  98.             break;
  99.         case TCP_ACTIVE:
  100.         /* We already have a route, found earlier.
  101.          * Point to this interface's tcp parameters - WG7J
  102.          */
  103.             tcb->parms = ifp->tcp;
  104.         /* Set the interface specific mss values - WG7J */
  105.             tcb->cwind = tcb->mss = tcb->parms->mss;
  106.         /* Find a known rtt or load interface default - WG7J */
  107.             set_irtt(tcb);
  108.   
  109.         /* Send SYN, go into TCP_SYN_SENT state */
  110.             tcb->flags.active = 1;
  111.             send_syn(tcb);
  112.             setstate(tcb,TCP_SYN_SENT);
  113.             tcp_output(tcb);
  114.             break;
  115.     }
  116.     return tcb;
  117. }
  118. /* User send routine */
  119. int
  120. send_tcp(tcb,bp)
  121. register struct tcb *tcb;
  122. struct mbuf *bp;
  123. {
  124.     int16 cnt;
  125.   
  126.     if(tcb == NULLTCB || bp == NULLBUF){
  127.         free_p(bp);
  128.         Net_error = INVALID;
  129.         return -1;
  130.     }
  131.     cnt = len_p(bp);
  132.     switch(tcb->state){
  133.         case TCP_CLOSED:
  134.             free_p(bp);
  135.             Net_error = NO_CONN;
  136.             return -1;
  137.         case TCP_LISTEN:
  138.             if(tcb->conn.remote.address == 0 && tcb->conn.remote.port == 0){
  139.             /* Save data for later */
  140.                 append(&tcb->sndq,bp);
  141.                 tcb->sndcnt += cnt;
  142.                 break;
  143.             }
  144.         /* Change state from passive to active */
  145.             tcb->flags.active = 1;
  146.             send_syn(tcb);
  147.             setstate(tcb,TCP_SYN_SENT); /* Note fall-thru */
  148.         case TCP_SYN_SENT:
  149.         case TCP_SYN_RECEIVED:
  150.         case TCP_ESTABLISHED:
  151.         case TCP_CLOSE_WAIT:
  152.             append(&tcb->sndq,bp);
  153.             tcb->sndcnt += cnt;
  154.             tcp_output(tcb);
  155.             break;
  156.         case TCP_FINWAIT1:
  157.         case TCP_FINWAIT2:
  158.         case TCP_CLOSING:
  159.         case TCP_LAST_ACK:
  160.         case TCP_TIME_WAIT:
  161.             free_p(bp);
  162.             Net_error = CON_CLOS;
  163.             return -1;
  164.     }
  165.     return (int)cnt;
  166. }
  167. /* User receive routine */
  168. int
  169. recv_tcp(tcb,bpp,cnt)
  170. register struct tcb *tcb;
  171. struct mbuf **bpp;
  172. int16 cnt;
  173. {
  174.     if(tcb == NULLTCB || bpp == (struct mbuf **)NULL){
  175.         Net_error = INVALID;
  176.         return -1;
  177.     }
  178.     if(tcb->rcvcnt == 0){
  179.         /* If there's nothing on the queue, our action depends on what state
  180.          * we're in (i.e., whether or not we're expecting any more data).
  181.          * If no more data is expected, then simply return 0; this is
  182.          * interpreted as "end of file". Otherwise return -1.
  183.          */
  184.         switch(tcb->state){
  185.             case TCP_LISTEN:
  186.             case TCP_SYN_SENT:
  187.             case TCP_SYN_RECEIVED:
  188.             case TCP_ESTABLISHED:
  189.             case TCP_FINWAIT1:
  190.             case TCP_FINWAIT2:
  191.                 Net_error = WOULDBLK;
  192.                 return -1;
  193.             case TCP_CLOSED:
  194.             case TCP_CLOSE_WAIT:
  195.             case TCP_CLOSING:
  196.             case TCP_LAST_ACK:
  197.             case TCP_TIME_WAIT:
  198.                 *bpp = NULLBUF;
  199.                 return 0;
  200.         }
  201.     }
  202.     /* cnt == 0 means "I want it all" */
  203.     if(cnt == 0)
  204.         cnt = tcb->rcvcnt;
  205.     /* See if the user can take all of it */
  206.     if(tcb->rcvcnt <= cnt){
  207.         cnt = tcb->rcvcnt;
  208.         *bpp = tcb->rcvq;
  209.         tcb->rcvq = NULLBUF;
  210.     } else {
  211.         *bpp = ambufw(cnt);
  212.         pullup(&tcb->rcvq,(*bpp)->data,cnt);
  213.         (*bpp)->cnt = cnt;
  214.     }
  215.     tcb->rcvcnt -= cnt;
  216.     tcb->rcv.wnd += cnt;
  217.     /* Do a window update if it was closed */
  218.     if(cnt == tcb->rcv.wnd){
  219.         tcb->flags.force = 1;
  220.         tcp_output(tcb);
  221.     }
  222.     return (int)cnt;
  223. }
  224. /* This really means "I have no more data to send". It only closes the
  225.  * connection in one direction, and we can continue to receive data
  226.  * indefinitely.
  227.  */
  228. int
  229. close_tcp(tcb)
  230. register struct tcb *tcb;
  231. {
  232.     if(tcb == NULLTCB){
  233.         Net_error = INVALID;
  234.         return -1;
  235.     }
  236.     switch(tcb->state){
  237.         case TCP_CLOSED:
  238.             return 0;   /* Unlikely */
  239.         case TCP_LISTEN:
  240.         case TCP_SYN_SENT:
  241.             close_self(tcb,NORMAL);
  242.             return 0;
  243.         case TCP_SYN_RECEIVED:
  244.         case TCP_ESTABLISHED:
  245.             tcb->sndcnt++;
  246.             tcb->snd.nxt++;
  247.             setstate(tcb,TCP_FINWAIT1);
  248.             tcp_output(tcb);
  249.             return 0;
  250.         case TCP_CLOSE_WAIT:
  251.             tcb->sndcnt++;
  252.             tcb->snd.nxt++;
  253.             setstate(tcb,TCP_LAST_ACK);
  254.             tcp_output(tcb);
  255.             return 0;
  256.         case TCP_FINWAIT1:
  257.         case TCP_FINWAIT2:
  258.         case TCP_CLOSING:
  259.         case TCP_LAST_ACK:
  260.         case TCP_TIME_WAIT:
  261.             Net_error = CON_CLOS;
  262.             return -1;
  263.     }
  264.     return -1;  /* "Can't happen" */
  265. }
  266. /* Delete TCB, free resources. The user is not notified, even if the TCB is
  267.  * not in the TCP_CLOSED state. This function should normally be called by the
  268.  * user only in response to a state change upcall to TCP_CLOSED state.
  269.  */
  270. int
  271. del_tcp(conn)
  272. struct tcb *conn;
  273. {
  274.     register struct tcb *tcb;
  275.     struct tcb *tcblast = NULLTCB;
  276.     struct reseq *rp,*rp1;
  277.   
  278.     /* Remove from list */
  279.     for(tcb=Tcbs;tcb != NULLTCB;tcblast = tcb,tcb = tcb->next)
  280.         if(tcb == conn)
  281.             break;
  282.     if(tcb == NULLTCB){
  283.         Net_error = INVALID;
  284.         return -1;  /* conn was NULL, or not on list */
  285.     }
  286.     if(tcblast != NULLTCB)
  287.         tcblast->next = tcb->next;
  288.     else
  289.         Tcbs = tcb->next;   /* was first on list */
  290.   
  291.     stop_timer(&tcb->timer);
  292.     for(rp = tcb->reseq;rp != NULLRESEQ;rp = rp1){
  293.         rp1 = rp->next;
  294.         free_p(rp->bp);
  295.         free((char *)rp);
  296.     }
  297.     tcb->reseq = NULLRESEQ;
  298.     free_p(tcb->rcvq);
  299.     free_p(tcb->sndq);
  300.     free((char *)tcb);
  301.     return 0;
  302. }
  303. /* Return 1 if arg is a valid TCB, 0 otherwise */
  304. int
  305. tcpval(tcb)
  306. struct tcb *tcb;
  307. {
  308.     register struct tcb *tcb1;
  309.   
  310.     if(tcb == NULLTCB)
  311.         return 0;   /* Null pointer can't be valid */
  312.     for(tcb1=Tcbs;tcb1 != NULLTCB;tcb1 = tcb1->next){
  313.         if(tcb1 == tcb)
  314.             return 1;
  315.     }
  316.     return 0;
  317. }
  318. /* Kick a particular TCP connection */
  319. int
  320. kick_tcp(tcb)
  321. register struct tcb *tcb;
  322. {
  323.     if(!tcpval(tcb))
  324.         return -1;
  325.     tcb->flags.force = 1;   /* Send ACK even if no data */
  326.     tcp_timeout(tcb);
  327.     return 0;
  328. }
  329. /* Kick all TCP connections to specified address; return number kicked */
  330. int
  331. kick(addr)
  332. int32 addr;
  333. {
  334.     register struct tcb *tcb;
  335.     int cnt = 0;
  336.   
  337.     for(tcb=Tcbs;tcb != NULLTCB;tcb = tcb->next){
  338.         if(tcb->conn.remote.address == addr){
  339.             kick_tcp(tcb);
  340.             cnt++;
  341.         }
  342.     }
  343.     return cnt;
  344. }
  345. /* Clear all TCP connections */
  346. void
  347. reset_all()
  348. {
  349.     struct tcb *tcb, *tcb1;
  350.   
  351.     for(tcb=Tcbs;tcb != NULLTCB;tcb = tcb1) {
  352.         tcb1 = tcb->next;
  353.         reset_tcp(tcb);
  354.     }
  355.   
  356.     pwait(NULL);    /* Let the RSTs go forth */
  357. }
  358. void
  359. reset_tcp(tcb)
  360. register struct tcb *tcb;
  361. {
  362.     struct tcp fakeseg;
  363.     struct ip fakeip;
  364.   
  365.     if(tcb == NULLTCB)
  366.         return;
  367.     if(tcb->state != TCP_LISTEN){
  368.         /* Compose a fake segment with just enough info to generate the
  369.          * correct RST reply
  370.          */
  371.         memset((char *)&fakeseg,0,sizeof(fakeseg));
  372.         memset((char *)&fakeip,0,sizeof(fakeip));
  373.         fakeseg.dest = tcb->conn.local.port;
  374.         fakeseg.source = tcb->conn.remote.port;
  375.         fakeseg.flags.ack = 1;
  376.         /* Here we try to pick a sequence number with the greatest likelihood
  377.          * of being in his receive window.
  378.          */
  379.         fakeseg.ack = tcb->snd.nxt + tcb->snd.wnd - 1;
  380.         fakeip.dest = tcb->conn.local.address;
  381.         fakeip.source = tcb->conn.remote.address;
  382.         fakeip.tos = tcb->tos;
  383.         reset(&fakeip,&fakeseg);
  384.     }
  385.     close_self(tcb,RESET);
  386. }
  387. #ifdef  notused
  388. /* Return character string corresponding to a TCP well-known port, or
  389.  * the decimal number if unknown.
  390.  */
  391. char *
  392. tcp_port(n)
  393. int16 n;
  394. {
  395.     static char buf[32];
  396.   
  397.     switch(n){
  398.         case IPPORT_ECHO:
  399.             return "echo";
  400.         case IPPORT_DISCARD:
  401.             return "discard";
  402.         case IPPORT_FTPD:
  403.             return "ftp_data";
  404.         case IPPORT_FTP:
  405.             return "ftp";
  406.         case IPPORT_TELNET:
  407.             return "telnet";
  408.         case IPPORT_SMTP:
  409.             return "smtp";
  410.         case IPPORT_POP:
  411.             return "pop";
  412.         default:
  413.             sprintf(buf,"%u",n);
  414.             return buf;
  415.     }
  416. }
  417. #endif
  418.   
  419. void set_irtt(struct tcb *tcb) {
  420.     struct tcp_rtt *tp;
  421.   
  422.     if((tp = rtt_get(tcb->conn.remote.address)) != NULLRTT){
  423.         tcb->srtt = tp->srtt;
  424.         tcb->mdev = tp->mdev;
  425.     } else {
  426.         tcb->srtt = tcb->parms->irtt;
  427.         tcb->mdev = 0;
  428.     }
  429.     /* Initialize timer intervals */
  430.     set_timer(&tcb->timer,tcb->srtt);
  431. }
  432.   
  433.