📄 tcpss.c
字号:
*************************************************************************/
STATUS TCPSS_Net_Xopen(UINT8 *machine, UINT16 service, INT socketd)
{
TCP_PORT *prt;
INT pnum;
SCK_SOCKADDR_IP *dest;
DV_DEVICE_ENTRY *device;
/*
* check the IP number and don't allow broadcast addresses
*/
if (machine[3] == 255)
{
NERRS_Log_Error (NERR_RECOVERABLE, __FILE__, __LINE__);
return (-4);
}
/*
* get the hardware address for that host, or use the one for the
* gateway all handled by 'netdlayer' by ARPs.
*/
if ((pnum = TCP_Make_Port()) < 0) /* set up port structure and packets */
return (NU_NO_PORT_NUMBER);
prt = TCP_Ports[pnum]; /* create a new port */
prt->p_socketd = socketd;
/* Determine which device will be used for communication. This will allow
us to decide which IP address to use on the local side. */
/* The TCP port structure includes a route field that used to cache a route
to the foreign host. Fill it in here. This will save us the trouble of
looking up the route at the IP layer for every packet sent.
*/
/* Point to the destination. */
dest = (SCK_SOCKADDR_IP *) &prt->tp_route.rt_ip_dest;
dest->sck_family = SK_FAM_IP;
dest->sck_len = sizeof (*dest);
dest->sck_addr = IP_ADDR(machine);
IP_Find_Route(&prt->tp_route);
if (prt->tp_route.rt_route == NU_NULL)
{
prt->state = SCLOSED;
/* Increment the number of packets that could not be delivered. */
SNMP_ipOutNoRoutes_Inc;
return -1;
}
device = prt->tp_route.rt_route->rt_device;
prt->tcp_laddr = device->dev_addr.dev_ip_addr;
/* make a copy of the ip number that we are trying for */
prt->tcp_faddr = IP_ADDR(machine);
/* Store off the port index for the associated port. */
SCK_Sockets[prt->p_socketd]->s_port_index = pnum;
/*
* Make the connection, if you can, we will get an event notification
* later if it connects. Timeouts must be done at a higher layer.
*/
/* If the connection was made return the index into the TCP_Ports of
the new port. Else return failure. */
if ( TCPSS_Do_Connect (pnum, service) == NU_SUCCESS)
return (pnum);
else
{
TCP_Cleanup(prt);
return -1;
}
} /* end TCPSS_Net_Xopen() */
/*************************************************************************
*
* FUNCTION
*
* TCPSS_Do_Connect
*
* DESCRIPTION
*
* This routine sends the actual packet out to try and establish a
* connection.
*
* INPUTS
*
* pnum
* service
*
* OUTPUTS
*
* Nucleus Status Code
*
*************************************************************************/
static STATUS TCPSS_Do_Connect(INT pnum, UINT16 service)
{
TCP_PORT *prt;
STATUS status;
/* Get a pointer to the port. */
prt = TCP_Ports[pnum];
prt->out.port = service; /* service same as port num */
prt->out.tcp_flags = TSYN; /* want to start up sequence */
prt->state = SSYNS;
status = TCPSS_Send_SYN_FIN(prt, 4);
if (status == NU_SUCCESS)
{
/* Increment the number of TCP segments transmitted. */
SNMP_tcpOutSegs_Inc;
/* Increment the number active connections attempted. */
SNMP_tcpActiveOpens_Inc;
}
else
prt->state = SCLOSED; /* syn sent */
return(status);
} /* end TCPSS_Do_Connect() */
/*************************************************************************
*
* FUNCTION
*
* TCPSS_Send_SYN_FIN
*
* DESCRIPTION
*
* This routine is responsible for sending a packet containing either
* a SYN or FIN bit.
*
* INPUTS
*
* *prt
* options
*
* OUTPUTS
*
* stat
* -1
*
*************************************************************************/
STATUS TCPSS_Send_SYN_FIN(TCP_PORT *prt, INT16 options)
{
TCPLAYER *tcp_ptr;
NET_BUFFER *buf_ptr;
INT tcp_hlen;
STATUS stat;
UINT8 HUGE *options_ptr;
/* One buffer will be large enough for the SYN FIN */
buf_ptr = MEM_Buffer_Dequeue (&MEM_Buffer_Freelist);
if(buf_ptr == NU_NULL)
return -1;
/* Init the pointers */
buf_ptr->next = NU_NULL;
buf_ptr->next_buffer = NU_NULL;
/* Initialize each field in the buffer. */
/* Point the data pointer at an offset into the buffer large enough to leave
room for the IP and MAC layer headers. */
buf_ptr->data_ptr = (buf_ptr->mem_parent_packet +
(NET_MAX_TCP_HEADER_SIZE - sizeof (TCPLAYER)));
/* There are 4 bytes of option data in the SYN packet. */
buf_ptr->data_len = buf_ptr->mem_total_data_len = (sizeof (TCPLAYER) + options);
buf_ptr->mem_option_len = options;
/* Set the TCP data length to one. This is used for ack and seqnum
comparison. A SYN or FIN only bumps the seqnum by 1. */
buf_ptr->mem_tcp_data_len = 1;
/* Store the sequence number of this packet. */
buf_ptr->mem_seqnum = prt->out.nxt;
/* Initialize the list that this packet will be deallocated to when
transmission is complete.
*/
buf_ptr->mem_dlist = &prt->out.packet_list;
buf_ptr->mem_port_index = prt->pindex;
/* Initialize the number of times this packet has been retransmitted. */
buf_ptr->mem_retransmits = 0;
/* Update the number of packets in this port. */
prt->out.num_packets++;
/* Update the amount of data in this port. */
prt->out.contain++;
/* Compute the sizeof the TCP header in words */
tcp_hlen = ((sizeof(TCPLAYER) + options - 1) / 4) + 1;
/* Update the header information. */
TCP_Update_Headers(prt, buf_ptr, (UINT16)tcp_hlen);
/* A SYN or FIN flag counts as one byte of data in the sequence space. */
prt->out.nxt++;
options_ptr = (buf_ptr->data_ptr + sizeof (TCPLAYER));
tcp_ptr = (TCPLAYER *) buf_ptr->data_ptr;
/* Should option data be included. */
if (options)
{
/* Add the TCP mac segment size option to this packet. */
options_ptr[0] = 2;
options_ptr[1] = 4;
*(INT16 *)&options_ptr[2] = INTSWAP(MAX_SEGMENT_LEN);
}
/* Compute and fill in the checksum. */
PUT16(tcp_ptr, TCP_CHECK_OFFSET,
UTL_Checksum(buf_ptr, prt->tcp_laddr, prt->tcp_faddr, IP_TCP_PROT) );
/* If there is no timing being performed then time this transmission. */
if (prt->p_rtt == 0)
{
prt->p_rtt = NU_Retrieve_Clock();
prt->p_rtseq = buf_ptr->mem_seqnum;
}
/* Send this packet. */
stat = IP_Send(buf_ptr, &prt->tp_route, prt->tcp_faddr,
prt->tcp_laddr, 0, IP_TIME_TO_LIVE,
IP_TCP_PROT, 0, NU_NULL);
if (stat == NU_SUCCESS)
{
/* If the transmit was a success, set a retransmit event for this
packet.
*/
UTL_Timerset (TCPRETRANS, (UNSIGNED)prt->pindex,
(UNSIGNED)prt->p_rto, (INT32)prt->out.nxt);
/* Increment the number of TCP segments transmitted. */
SNMP_tcpOutSegs_Inc;
}
else
{
/* The packet was not sent. Dealocate the buffer. If the packet was
transmitted it will be deallocated later by TCP. */
MEM_One_Buffer_Chain_Free (buf_ptr, &MEM_Buffer_Freelist);
}
return (stat);
} /* end TCPSS_Send_SYN_FIN() */
/*************************************************************************
*
* FUNCTION
*
* TCPSS_Net_Close
*
* DESCRIPTION
*
* Start the closing process on port pnum.
*
* INPUTS
*
* pnum Number of the port to close.
* *sock_ptr
*
* OUTPUTS
*
* NU_SUCCESS
* -1
*
*************************************************************************/
STATUS TCPSS_Net_Close(INT pnum, struct sock_struct *sock_ptr)
{
TCP_PORT *prt;
INT16 return_status = -1;
NET_BUFFER *buf_ptr;
if ((pnum < 0) || (pnum > TCP_MAX_PORTS)) /* is a valid port? */
return (-1);
if ((prt = TCP_Ports[pnum]) != NU_NULL)
{
/* something there */
switch (prt->state)
{
case SLISTEN: /* we don't care anymore */
case SSYNS:
/* Increment the number of connection failures. */
SNMP_tcpAttemptFails_Inc;
/* Close the connection. */
prt->state = SCLOSED;
TCP_Cleanup(prt);
break;
case SEST: /* must initiate close */
/* Send FIN only if all data has been transmitted. */
if (prt->out.nextPacket == NU_NULL)
{
if(prt->portFlags & ACK_TIMER_SET)
{
/* Delete the ACK timeout timer. */
UTL_Timerunset(TCPACK, (UNSIGNED)prt->pindex, (INT32)1);
/* Clear the ACK timer flag in the port. */
prt->portFlags &= (~ACK_TIMER_SET);
}
prt->out.tcp_flags = TACK | TFIN;
TCPSS_Send_SYN_FIN(prt, 0);
prt->state = SFW1; /* wait for ACK of FIN */
/* Upon returning the socket will be released. So break
the port's link to this socket. */
prt->p_socketd = -1;
return_status = NU_SUCCESS;
}
else
{
if (prt->xmitFlag == NU_SET)
{
UTL_Timerunset (CONTX, (UNSIGNED)prt->pindex, (INT32)1);
prt->out.tcp_flags = TPUSH | TACK | TFIN;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -