📄 tcputil.c
字号:
/*
* FILENAME: tcputil.c
*
* Copyright 2000-2002 InterNiche Technologies Inc. All rights reserved.
*
*
* MODULE: MTCP
*
* ROUTINES: msoq_check(), m_setlport(), m_tcpdrop(),
* ROUTINES: m_tcpclose(), m_data_upcall(), m_newtcpcb(), so_flush(),
* ROUTINES: so_lookup(), m_delsocket(), m_template(), m_connected(),
* ROUTINES: m_disconnecting(), m_sbdrop(), get_soq(), put_soq(),
* ROUTINES: socket_queue_name()
*
*
* PORTABLE: yes
*/
#include "ipport.h"
#include "mtcp.h"
#define Debug_tcputil 0xff
#if Debug_tcputil <= 0x03
#include "uartdrv.h"
#endif
//#include "ZPrint.h"
void tcp_wakeup(void * event); /* (yaxon add) */
struct queue msoq; /* global queue of M_SOCK structs */
static unshort nextlport; /* next lport to assign in m_setlport() */
/* NEXTLPORT_LL - lower limit for nextlport */
#ifndef NEXTLPORT_LL
#define NEXTLPORT_LL 1024
#endif
/* NEXTLPORT_UL - upper limit for nextlport */
#ifndef NEXTLPORT_UL
#define NEXTLPORT_UL 65534
#endif
#ifdef NET_STATS
struct tcpstat tcpstat; /* BSD tcp statistics */
#endif
int TCPTV_MSL = (4 * PR_SLOWHZ); /* max seg lifetime default */
#ifdef INCLUDE_SNMP
struct tcp_mib tcpmib;
#else /* no SNMP, support tcp_mib locally for tcp_stats() */
struct TcpMib tcpmib;
#endif
#ifdef MSOQ_CHECK
/* sanity check of soq */
void
msoq_check()
{
int ct;
M_SOCK so;
ct = 1;
if(msoq.q_head == NULL)
{
if(msoq.q_tail != NULL)
{
dtrap("tcputil 0\n");
}
if(msoq.q_len != 0)
{
dtrap("tcputil 1\n");
}
}
for(so = (M_SOCK)(msoq.q_head); so->next; so = so->next)
{
ct++;
}
if(so != (M_SOCK)(msoq.q_tail))
{
dtrap("tcputil 2\n");
}
if(ct != msoq.q_len)
{
dtrap("tcputil 3\n");
}
}
#endif /* MSOQ_CHECK */
/* FUNCTION: m_setlport()
*
* Sets the socket's lport (local port number) to a reasonable
* non-zero value.
*
* PARAM1: M_SOCK so; the socket whose lport is to be set
*
* RETURNS: void;
*/
void
m_setlport(M_SOCK so)
{
M_SOCK qso;
restart:
/* guess the nextlport based on the last one +1, but constrain
* it to be in the range [NEXTLPORT_LL...NEXTLPORT_UL] (inclusive)
*/
if ((nextlport >= NEXTLPORT_LL) && (nextlport < NEXTLPORT_UL))
nextlport++;
else
nextlport = NEXTLPORT_LL;
nextlport = htons(nextlport);
/* verify that nextlport is available by walking the socket
* list and verifying that it's not in use
*/
ENTER_CRIT_SECTION(&msoq);
for (qso = (M_SOCK)(msoq.q_head); qso->next; qso = qso->next)
{
/* if it's not available, start over with new nextlport */
if (qso->lport == nextlport)
{
EXIT_CRIT_SECTION(&msoq);
goto restart;
}
}
EXIT_CRIT_SECTION(&msoq);
/* use nextlport to set the socket's lport */
so->lport = nextlport;
nextlport = ntohs(nextlport);
}
/* FUNCTION: m_tcpdrop()
*
* Drop a TCP connection, reporting
* the specified error. If connection is synchronized,
* then send a RST to peer.
*
* In BSD this is tcp_drop().
*
* PARAM1: struct tcpcb *tp
* PARAM2: int err
*
* RETURNS:
*/
void
m_tcpdrop(struct tcpcb * tp, int err)
{
M_SOCK so = (M_SOCK)tp->t_inpcb;
/* set socket error for upcall to app */
so->error = err;
/* if socket was past LISTEN state, notify app that it's going away */
if((so->callback) && (tp->t_state > TCPS_LISTEN)){
#if Debug_tcputil <= 0x03
PrintFromUART(Debug_tcpin,"tcputil Close!\n");
#endif
so->callback(M_CLOSED, so, NULL);
}
/* If connected, send reset to peer */
if (TCPS_HAVERCVDSYN(tp->t_state))
{
tp->t_state = TCPS_CLOSED;
(void) tcp_output(tp);
TCP_STAT_INC(tcps_drops);
}
else
TCP_STAT_INC(tcps_conndrops);
m_tcpclose(tp);
}
/* FUNCTION: m_tcpclose()
*
* Close a TCP control block:
* discard all space held by the tcp
* discard internet protocol block
* wake up any sleepers
*
* In BSD this is tcp_close().
*
* PARAM1: struct tcpcb *tp
*
* RETURNS:
*/
void
m_tcpclose(struct tcpcb * tp)
{
M_SOCK so = (M_SOCK)tp->t_inpcb;
so_flush(so);
TCB_FREE (tp);
so->tp = NULL; /* prevent further refs to tp */
m_disconnected(so);
TCP_STAT_INC(tcps_closed);
}
/* FUNCTION: m_data_upcall()
*
* called by tcp_input() when data is received
* for a socket with an upcall handler set. The upcall handler is a
* m_socket structure member.
*
* The upcall routine description is as follows:
*
* int rx_upcall(struct socket so, PACKET pkt, int error);
*
* ....where: so is socket which got data. pkt - pkt containing recieved
* data, or NULL if error. error is 0 if good pkt, else BSD socket
* error
*
* The upcall() returns 0 if it accepted data, non-zero if not.
* End of file is signaled to the upcall by ESHUTDOWN eror code. If
* LOCK_NET_RESOURCE() is used, the resource is already locked when
* the upcall is called. The upcall will NOT be called from inside a
* CRIT_SECTION macro pairing.
*
*
* PARAM1: m_socket
*
* RETURNS: nothing
*/
void
m_data_upcall(M_SOCK so)
{
int err;
PACKET pkt;
/* don't upcall application if there's no data */
if (so->rcvdq.sb_cc == 0)
return;
/* don't re-enter the upcall routine */
if (so->state & SS_INUPCALL)
return;
/* Set flags. SS_UPCALLED is used by select() logic to wake sockets blocked
* on receive, SS_INUPCALL is the re-entry guard.
*/
so->state |= (SS_UPCALLED|SS_INUPCALL);
while(so->rcvdq.p_head)
{
pkt = so->rcvdq.p_head;
err = so->callback(M_RXDATA, so, pkt);
if(err) /* if app returned error, quit */
break;
/* dequeue the packet data the application just accepted */
get_soq(&so->rcvdq);
tcp_pktfree(pkt);
}
so->state &= ~SS_INUPCALL; /* clear re-entry flag */
return;
}
/* FUNCTION: tcp_newtcpcb()
*
* Create a new TCP control block, making an
* empty reassembly queue and hooking it to the argument
* protocol control block.
*
* PARAM1: struct inpcb *inp
*
* RETURNS:
*/
struct tcpcb *
m_newtcpcb(M_SOCK so)
{
struct tcpcb * tp;
short t_time;
tp = TCB_ALLOC(sizeof (*tp));
if (tp == NULL)
return (struct tcpcb *)NULL;
tp->t_maxseg = TCP_MSS;
tp->t_flags = 0; /* sends options! */
/* install back pointer to socket */
tp->t_inpcb = (struct inpcb *)so;
so->tp = tp;
/*
* Init srtt to TCPTV_SRTTBASE (0), so we can tell that we have no
* rtt estimate. Set rttvar so that srtt + 2 * rttvar gives
* reasonable initial retransmit time.
*/
tp->t_srtt = TCPTV_SRTTBASE;
tp->t_rttvar = TCPTV_SRTTDFLT << 2;
t_time = ((TCPTV_SRTTBASE >> 2) + (TCPTV_SRTTDFLT << 2)) >> 1;
TCPT_RANGESET(tp->t_rxtcur, t_time, TCPTV_MIN, TCPTV_REXMTMAX);
tp->snd_cwnd = (u_short)(mt_deftxwin);
tp->snd_ssthresh = 65535; /* XXX */
return (tp);
}
/* FUNCTION: so_flush()
*
* Free all the buffers in a socket's receive and send
* queues in preparation for termination.
*
* PARAM1: socket
*
* RETURNS: none
*/
void
so_flush(M_SOCK so)
{
while(so->sendq.p_head)
tcp_pktfree(get_soq(&so->sendq));
while(so->rcvdq.p_head)
tcp_pktfree(get_soq(&so->rcvdq));
while(so->oosq.p_head)
tcp_pktfree(get_soq(&so->oosq)); //free oosq modify by zealea
so->state |= (SS_CANTRCVMORE|SS_CANTRCVMORE);
}
/* FUNCTION: so_lookup()
*
* Look up the first socket matching the passed received
* IP and TCP headers.
* This allows the socket to contain wildcard(0) foreign tupple members,
* but tries for an exact match first.
*
* PARAM1: IP header with IP addresses to match
* PARAM2: TCP header with ports to match
*
* RETURNS: matching socket if found, else null.
*/
M_SOCK
so_lookup(struct ip * pip, struct tcphdr * ptcp)
{
M_SOCK so; /* scratch */
M_SOCK wild; /* socket which had a wildcard match */
msoq_check();
wild = NULL;
for(so = (M_SOCK)msoq.q_head; so; so = so->next)
{
/* local port must always match - do quick test */
if(so->lport != ptcp->th_dport)
continue; /* not even a partial match */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -