📄 nettcp.c
字号:
"ACK+R+F", /* 21 = 16 + 4 + 1 */
"ACK+R+S", /* 22 = 16 + 4 + 2 */
"ACK+R+S+F", /* 23 = 16 + 4 + 2 + 1 */
"ACK+PUSH", /* 24 = 16 + 8 */
"ACK+P+F", /* 25 = 16 + 8 + 1 */
"ACK+P+S", /* 26 = 16 + 8 + 2 */
"ACK+P+S+F", /* 27 = 16 + 8 + 2 + 1 */
"ACK+P+R", /* 28 = 16 + 8 + 4 */
"A+P+R+F", /* 29 = 16 + 8 + 4 + 1 */
"A+P+R+S", /* 30 = 16 + 8 + 4 + 2 */
"A+P+R+S+F" /* 31 = 16 + 8 + 4 + 2 + 1 */
};
#if ECHO_SUPPORT > 0
//char tcpEchoStack[STACK_SIZE]; /* The TCP echo task stack. */
#endif
/***********************************/
/*** PUBLIC FUNCTION DEFINITIONS ***/
/***********************************/
/*
* Initialize the TCP subsystem.
*/
void tcpInit(void)
{
int i;
/* The TCB free list. */
memset(tcbs, 0, sizeof(tcbs));
topTcpCB = &tcbs[0];
for (i = 0; i < MAXTCP; i++) {
tcbs[i].next = &tcbs[i + 1];
/* Prev referencing self indicates that it's on the free list. */
tcbs[i].prev = &tcbs[i];
timerCreate(&tcbs[i].resendTimer);
timerCreate(&tcbs[i].keepTimer);
tcbs[i].state = CLOSED;
}
tcbs[MAXTCP - 1].next = NULL;
/* The TCB hash table. */
memset(&tcbTbl, 0, sizeof(tcbTbl));
/* The TCP stats. */
#if STATS_SUPPORT > 0
memset(&tcpStats, 0, sizeof(tcpStats));
tcpStats.headLine.fmtStr = "\t\tTCP STATISTICS\r\n";
tcpStats.curFree.fmtStr = "\tCURRENT FREE: %5lu\r\n";
tcpStats.curFree.val = MAXTCP;
tcpStats.minFree.fmtStr = "\tMINIMUM FREE: %5lu\r\n";
tcpStats.minFree.val = MAXTCP;
tcpStats.runt.fmtStr = "\tRUNT HEADERS: %5lu\r\n";
tcpStats.checksum.fmtStr = "\tBAD CHECKSUM: %5lu\r\n";
tcpStats.conout.fmtStr = "\tOUT CONNECTS: %5lu\r\n";
tcpStats.conin.fmtStr = "\tIN CONNECTS : %5lu\r\n";
tcpStats.resetOut.fmtStr = "\tRESETS SENT : %5lu\r\n";
tcpStats.resetIn.fmtStr = "\tRESETS REC'D: %5lu\r\n";
#endif
/* The new sequence number offset. */
newISNOffset = magic();
#if ECHO_SUPPORT > 0
/* Start the TCP echo server. */
/*
* porting to ros33
*/
// sta_tsk(TCPTASK_ID, 0); //start echotask
#endif
}
/************************************0001*************************************************************************/
/*
* Return a new TCP descriptor on success or an error code (negative) on
* failure.
*/
int tcpOpen(void)
{
int st;
TCPCB *tcb;
OS_ENTER_CRITICAL();
if ((tcb = topTcpCB) != NULL) {
topTcpCB = topTcpCB->next;
STATS(if (--tcpStats.curFree.val < tcpStats.minFree.val)
tcpStats.minFree.val = tcpStats.curFree.val;)
}
OS_EXIT_CRITICAL();
if (!tcb)
st = TCPERR_ALLOC;
else {
st = (int)(tcb - &tcbs[0]);
tcb->next = tcb; /* Self ref => unlinked. */
tcb->prev = NULL; /* Always NULL when neither free nor linked. */
tcb->freeOnClose = 0;
#if DEBUG_SUPPORT == 0
tcb->traceLevel = 0;
#else
tcb->traceLevel = LOG_INFO;
#endif
tcb->keepAlive = 0;
tcb->keepProbes = 0;
/* Grab semaphores. */
if (!tcb->connectSem)
if ((tcb->connectSem = OSSemCreate(0)) == 0)
st = TCPERR_ALLOC;
if (!tcb->readSem)
if ((tcb->readSem = OSSemCreate(0)) == 0)
st = TCPERR_ALLOC;
if (!tcb->writeSem)
if ((tcb->writeSem = OSSemCreate(0)) == 0)
st = TCPERR_ALLOC;
if (!tcb->mutex)
if ((tcb->mutex = OSSemCreate(1)) == 0)
st = TCPERR_ALLOC;
TCPDEBUG((tcb->traceLevel, TL_TCP, "tcpOpen[%d]: Opened", st));
}
return st;
}
/********************************************************0052***************************************/
/*
* Close a TCP connection and release the descriptor.
* Any outstanding packets in the queues are dropped.
* Return 0 on success when the peer acknowledges our message
* or an error code on failure.
*/
int tcpClose(u_int td)
{
int st = 0;
TCPCB *tcb = &tcbs[td];
/* Protect from race on tcb->state. */
OS_ENTER_CRITICAL();
if (td >= MAXTCP || tcb->prev == tcb) {
OS_EXIT_CRITICAL();
st = TCPERR_PARAM;
} else if (tcb->state == CLOSED) {
OS_EXIT_CRITICAL();
TCPDEBUG((tcb->traceLevel, TL_TCP, "tcpClose[%d]: Freeing closed", td));
tcbFree(tcb);
} else {
/*
* Initiate a half-close on our side by sending a FIN. The
* freeOnClose flag is set so the TCB will be freed when the
* state reaches CLOSED. Note that a timer will limit the
* time that we wait in FINWAIT2.
*/
tcb->freeOnClose = !0;
OS_EXIT_CRITICAL();
st = tcpDisconnect(td);
TCPDEBUG((tcb->traceLevel, TL_TCP, "tcpClose[%d]: Closed", td));
}
OSSemFree();
return st;
}
/*
* Bind an IP address and port number in the sockaddr structure as our
* address on a TCP connection.
* Note: The IP address must be zero (wild) or equal to localHost since that
* is all that ipDispatch() will recognize. You can only bind a CLOSED
* connection.
* Return 0 on success, an error code on failure.
*/
int tcpBind(u_int td, struct sockaddr_in *myAddr)
{
int st = 0;
TCPCB *tcb = &tcbs[td];
if (td >= MAXTCP || tcb->prev == tcb || !myAddr)
st = TCPERR_PARAM;
else if (myAddr->ipAddr != 0 && myAddr->ipAddr != localHost)
st = TCPERR_INVADDR;
else if (tcb->state != CLOSED)
st = TCPERR_CONNECT; /* Can't bind an active connection. */
else {
tcb->ipSrcAddr = htonl(myAddr->ipAddr); //该ip已经是net格式
tcb->tcpSrcPort = htons(myAddr->sin_port);
TCPDEBUG((tcb->traceLevel, TL_TCP, "tcpBind[%d]: to %s:%u mss %d",
(int)(tcb - &tcbs[0]),
ip_ntoa(tcb->ipSrcAddr), ntohs(tcb->tcpSrcPort),
tcb->mss));
}
return st;
}
/***************************************0053**********************************/
/*
* Establish a connection with a remote host. Unless tcpBind() has been called,
* the local IP address and port number are generated automatically.
* Return 0 on success, an error code on failure.
*/
int tcpConnectJiffy(u_int td, const struct sockaddr_in *remoteAddr, u_char tos, u_int timeout)
{
int st = 0;
TCPCB *tcb = &tcbs[td];
#if ONETASK_SUPPORT == 0
u_long abortTime;
#endif
long dTime = timeout;
u_int8 err;
/* We don't use the timeout argument when running in a single task!
We also don't want to be able to block.
And we want to be able to do a quick poll, without having to make a timeout of at least 1 jiffy. */
#if ONETASK_SUPPORT == 0
if (timeout)
abortTime = jiffyTime() + timeout;
#endif
if (td >= MAXTCP || tcb->prev == tcb || !remoteAddr)
st = TCPERR_PARAM;
else if (remoteAddr->ipAddr == 0 || remoteAddr->sin_port == 0)
st = TCPERR_INVADDR;
else if (tcb->ipSrcAddr == 0 && localHost == 0)
st = TCPERR_CONFIG;
else if (tcb->state != CLOSED)
st = TCPERR_CONNECT; /* Already connected! */
else {
tcbInit(tcb);
tcb->ipTOS = tos;
if (tcb->ipSrcAddr == 0)
tcb->ipSrcAddr = htonl(localHost);
if (tcb->tcpSrcPort == 0) {
OS_ENTER_CRITICAL();
tcb->tcpSrcPort = htons(tcpFreePort++);
OS_EXIT_CRITICAL();
}
tcb->ipDstAddr = htonl(remoteAddr->ipAddr);
tcb->tcpDstPort = htons(remoteAddr->sin_port);
/******************************************************************0097**********************************/
/* Initialize connection parameters. */
tcb->rcv.wnd = TCP_DEFWND;
tcb->mss = ipMTU(tcb->ipDstAddr) - sizeof(IPHdr) - sizeof(TCPHdr);
tcb->mss = MAX(tcb->mss, TCP_MINMSS);
tcb->minFreeBufs = ((tcb->mss + NBUFSZ) / NBUFSZ);
/*
* Load the connection structure and link the TCB into the connection
* table so that tcpInput can find it.
*/
tcb->conn.remoteIPAddr = tcb->ipDstAddr;
tcb->conn.remotePort = tcb->tcpDstPort;
tcb->conn.localIPAddr = tcb->ipSrcAddr;
tcb->conn.localPort = tcb->tcpSrcPort;
tcbLink(tcb);
TCPDEBUG((tcb->traceLevel, TL_TCP, "tcpConnect[%d]: to %s:%u mss %d",
(int)(tcb - &tcbs[0]),
ip_ntoa(tcb->ipDstAddr), ntohs(tcb->tcpDstPort),
tcb->mss));
/* Send SYN, go into SYN_SENT state */
tcb->flags |= ACTIVE;
sendSyn(tcb);
setState(tcb, SYN_SENT);
tcpOutput(tcb);
STATS(tcpStats.conout.val++;)
/* We don't use the timeout argument when running in a single task!
We also don't want to be able to block.
And want to be able to do a quick poll, without having to make a timeout of at least 1 jiffy. */
#if ONETASK_SUPPORT == 0
/* Wait for connection or failure. */
while(tcb->state != ESTABLISHED && !st) {
if (tcb->state == CLOSED) {
/*
* Post the connect semaphore in case another task was also
* waiting on it. Unlikely for connect but a single extra
* post costs little and improves robustness.
*/
OSSemPost(tcb->connectSem);
if (tcb->closeReason)
st = tcb->closeReason;
else
st = TCPERR_EOF;
} else if (!timeout || (dTime = diffJTime(abortTime)) > 0) {
OSSemPend(tcb->connectSem, (UINT)dTime, &err);
} else { /* Abort on timeout. */
closeSelf(tcb, TCPERR_TIMEOUT);
tcbUnlink(tcb);
}
}
#endif
}
TCPDEBUG((tcb->traceLevel, TL_TCP, "tcpConnect[%d]: %s",
(int)(tcb - &tcbs[0]), tcbStates[tcb->state]));
return st;
}
/*
* tcpDisconnect - Tell the peer that we will not be sending any more data
* (i.e. perform a half close on a connection). tcpRead() will then
* wait until the connection closes.
* Return 0 when the peer acknowledges our message or an error code on
* failure.
*/
int tcpDisconnect(u_int td)
{
int st = 0;
TCPCB *tcb = &tcbs[td];
TCPDEBUG((tcb->traceLevel, TL_TCP, "tcpDisconnect[%d]: state %s",
(int)(tcb - &tcbs[0]), tcbStates[tcb->state]));
if (td >= MAXTCP || tcb->prev == tcb)
st = TCPERR_PARAM;
else {
switch(tcb->state){
case LISTEN:
case SYN_SENT:
/*
* We haven't established a connection yet so we can just
* close this.
*/
closeSelf(tcb, 0);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -