tcp.c

来自「mcf5307实验源代码」· C语言 代码 · 共 1,562 行 · 第 1/5 页

C
1,562
字号
    }

	/*  Received a SYN, someone is starting a connection.  */
	if(p->t.flags & TSYN)
	{

       Task_Entry = Task_Head;
       myport = intswap (p->t.dest);

       /* verify that the list is not empty */
       while (Task_Entry != NU_NULL)
       {
          /* search for a task table structure that matches myport */
          if (Task_Entry->local_port_num == myport)
             break;

          /* continue checking the next structure */
          Task_Entry = Task_Entry->next;
       } /* end while Task_Entry != NU_NULL */

       /* verify that there is a task table port entry free */
       if(NU_IGNORE_VALUE < (tasklist_num = NU_FindEmptyPort (Task_Entry)))
       {
           /* establish a portlist entry */
           if((portlist_num = netlisten (myport)) < 0)
           {
               /* Drop the packet by placing it back on the buffer_freelist. */
               dll_update_lists(&buffer_list, &buffer_freelist);

               return (1);
           }  /* end if establish a portlist entry */

           /* store the portlist entry number in the task table */
           Task_Entry->port_entry[tasklist_num] = portlist_num;

           /* send that port structure to tcpdo */
           prt = portlist[portlist_num];

           /* store the task ID in the port table */
           prt->TXTask = Task_Entry->Task_ID;
       }  /* end if for no port num back from nuke */
       else
       {
           /* Drop the packet by placing it back on the buffer_freelist. */
           dll_update_lists(&buffer_list, &buffer_freelist);

           return(1);
       }

       /* Preserve the Task_Entry information so we can cleanup in the case
          where the connection is aborted before being accepted.
        */
       prt->task_entry = Task_Entry;
       prt->task_num = tasklist_num;

       /*  remember anything important from the incoming TCP header */
       prt->out.size = intswap(p->t.window);
       prt->out.port = intswap(p->t.source);
       prt->in.nxt = longswap(p->t.seq)+1;

       /*  set the necessary fields in the outgoing TCP packet  */
       prt->tcpout.t.dest = p->t.source;
       prt->tcpout.t.ack = longswap(prt->in.nxt);
       prt->tcpout.t.flags = TSYN | TACK;

       prt->tcpout.t.hlen = 24 << 2;

       /*  initialize all of the low-level transmission stuff
           (IP and lower) */
       memcpy ((void *)prt->tcps.dest, (const void *)p->i.ipsource, 4);
       memcpy ((void *)prt->tcpout.i.ipdest, (const void *)p->i.ipsource, 4);
       memcpy ((void *)prt->tcpout.d.dest, (const void *)p->d.me, DADDLEN);

       /*  Send the SYN/ACK packet to the client.  */
       Send_SYN_FIN (prt, 4);

       /*  Indicate that a SYN has been received so get ready
           to get an ACK.  */
       prt->state = SSYNR;

       /* Increment the number of passive opens. */
       SNMP_tcpPassiveOpens_Inc;

    } /* end if */
    else
    {
        /* Send a reset if this is not a SYN packet. */
        tcpresetfin (p, (uint16)(tlen - hlen));
    }

    /* Drop the packet by placing it back on the buffer_freelist. */
    dll_update_lists(&buffer_list, &buffer_freelist);

    break;

  case SSYNR: /*  In the SYN Received State we expect that we got an ACK.
		  If we did, then we need to send an ACK and move on to
		  the connected state.  */

          if (p->t.flags & TRESET)
          {
              NU_Tcp_Log_Error (TCP_NO_HOST_RESET, TCP_RECOVERABLE,
                        __FILE__, __LINE__);

              /* Get the task entry.  The -1 indicates that we don't care about
                 the state as long as port number and port index match. */
              Task_Entry = NU_SearchTaskList(Task_Entry, prt->TXTask,
                                             prt->in.port, -1, prt->pindex);

              /* Clear this entry so that it can be re-used. */
              NU_UpdateTaskTable(Task_Entry);

              /* Return to the closed state */
              prt->state = SCLOSED;

              /* Increment the number of connection failures. */
              SNMP_tcpAttemptFails_Inc;

              /* Drop the packet by placing it back on the buffer_freelist. */
              dll_update_lists(&buffer_list, &buffer_freelist);
              return (1);
          } /* end if */

          /*   We are expecting an ACK, if we did not get it then send
           *   the SYN/ACK back.  */
          if(!(p->t.flags & TACK))
          {
               prt->tcpout.t.flags = TACK | TSYN;
               tcp_sendack (prt, 0);
               /* Preserve a pointer to the packet buffer just processed so we
                * can deallocate it.
                */

               /* Drop the packet by placing it back on the buffer_freelist. */
               dll_update_lists(&buffer_list, &buffer_freelist);
               break;
          } /* end if */

          /*  Update the header length for the TCP header.  */
          prt->tcpout.t.hlen = 20 << 2;

          /*  Set up for the timeout timer.  */
          prt->out.lasttime = n_clicks();

          /*  Indicate that a SYN has been sent.  */
          prt->out.nxt++;

          /*  Starting ACK value */
          prt->out.ack = longswap(p->t.ack);

          /*  Accept his window size.  */
          prt->out.size = intswap(p->t.window);
          prt->maxSendWin = prt->out.size;

          /*  Set up to send an ACK back.  */
          prt->tcpout.t.flags = TACK;

          /*  Move on to established state.  */
          prt->state = SEST;

#if SNMP_INCLUDED
          SNMP_tcpConnTableUpdate(SNMP_ADD, SEST, prt->tcpout.i.ipsource,
                                prt->in.port, prt->tcpout.i.ipdest,
                                prt->out.port);
#endif

          /*  Delete the timeout timer.  */
          Stimerunset(CONCLASS, TCPRETRANS, prt->pindex, prt->out.ack);

          /*  Remove the SYN packet from the window.  */
          rmqueue(&prt->out, prt->out.ack);

          /* Get the task entry.  The -1 indicates that we don't care about the
             state as long as port number and port index match. */
          Task_Entry = NU_SearchTaskList(Task_Entry, prt->TXTask, prt->in.port,
                                         -1, prt->pindex);

          /*  Indicate the connection is complete.  This one can be accepted.*/
          Task_Entry->stat_entry[Task_Entry->current_idx] = SEST;

          /* If there is a task waiting to accept a connection, resume him. */
          if(Task_Entry->acceptFlag)
          {
              /*  Send an event to wake up the suspended server.  */
              netputevent (CONCLASS, CONOPEN, pnum);
          }

          /*  Detemermine if the sender has specified a new maximum
              message size.  */
          checkmss (prt, p, hlen);

          /* fall through */
  case SEST:            /* normal data transmission */

	/*  See if the last packet acknowledged one that we sent.  If
	    so, ackcheck will update the buffer and begin transmission
	    on the next part of the data if any is left in the buffer. */

    if(!ackcheck(prt, p))
    {
        /* If this port is in the process of closing, then resume the task. */
        if(prt->closeFlag)
        {
			prt->closeFlag = NU_CLEAR;

//			sprintf(buffer,"closed 1: %u-%u",syntimes,++syntimes_add);
//			__TextOut(10,300,12,buffer);

			netputevent (CONCLASS, CONCLOSE, pnum);
        }
    }

    estab1986 (prt, p, tlen, hlen);

	return (0);

  case SSYNS:         /* check to see if the ACK is for our SYN */

	/* remember that tcpout is pre-set-up */

    if (p->t.flags & TACK)
	{		/* It is ACKING us */

        /* Is the ACK for the SYN that was sent?  If not we have a half open
           connection (i.e., the foreign host believes there is already a
           connection open on this port.  So send a reset and drop the packet.
        */
        if ((uint32)longswap (p->t.ack) != prt->out.nxt)
        {

            /* Send a reset. */
            tcpresetfin (p, (uint16)(tlen - hlen));

            NU_Tcp_Log_Error (TCP_ACK_INV, TCP_RECOVERABLE,__FILE__,
							  __LINE__);

            /* Drop the packet by placing it back on the buffer_freelist. */
            dll_update_lists(&buffer_list, &buffer_freelist);

            return (1);
        } /* end if */
	} /* end if */

	if (p->t.flags & TRESET)
	{
        NU_Tcp_Log_Error (TCP_NO_HOST_RESET, TCP_RECOVERABLE,
                  __FILE__, __LINE__);

        prt->state = SCLOSED;

        /* Increment the number of connection failures. */
        SNMP_tcpAttemptFails_Inc;

//		sprintf(buffer,"closed 2 :%u-%u",syntimes,++syntimes_add);
//		__TextOut(10,300,12,buffer);

		netputevent (CONCLASS, CONCLOSE, pnum);

        /* Cleanup after ourselves. */
		TCP_Cleanup(prt);

        /* Drop the packet by placing it back on the buffer_freelist. */
        dll_update_lists(&buffer_list, &buffer_freelist);
        return (1);
	} /* end if */

    if(p->t.flags & TSYN)     /* need to send ACK */
	{
       prt->tcpout.t.flags = TACK;
       prt->in.nxt = longswap(p->t.seq) + 1;
       prt->tcpout.t.ack = longswap(prt->in.nxt);
       prt->out.ack = longswap(p->t.ack);
       prt->out.size = intswap(p->t.window);  /* credit window */
       prt->maxSendWin = prt->out.size;
       tcp_sendack (prt, 0);
       if (p->t.flags & TACK)
       {

//		  sprintf(buffer,"Resp Syn:%u--%lu-%u",syntimes,prt,++syntimes_add);
//		  __TextOut(10,140,12,buffer);


		  prt->state = SEST;

#if SNMP_INCLUDED
          SNMP_tcpConnTableUpdate(SNMP_ADD, SEST, prt->tcpout.i.ipsource,
                                prt->in.port, prt->tcpout.i.ipdest,
                                prt->out.port);
#endif

          /*  Delete the timeout timer.  */
          Stimerunset(CONCLASS, TCPRETRANS, prt->pindex, prt->out.ack);

          /*  Remove it from the window.  */
          rmqueue(&prt->out, prt->out.ack);

		  check_suc=netputevent (CONCLASS, CONOPEN, pnum);

		  if ( check_suc == 1 )
		  {
//			sprintf(buffer,"put fail:%u",syntimes);
//			__TextOut(10,180,12,buffer);
		  }

		  checkmss (prt, p, hlen);
       } /* end if */
       else
       {
          prt->state=SSYNR;       /* syn received */
       }
	} /* end if */

    /* Drop the packet by placing it back on the buffer_freelist. */

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?