📄 tcpapi.c
字号:
* after the tp is cleaned up
*/
so->state |= SS_NOFDREF;
/* set state so that tcp_output() does the desired close */
if((so->so_options & SO_LINGER) && (so->linger == 0))
{
/* application has explicitly set the socket to have a linger time
* of zero, which is how BSD let applications support TCP resets.
* Support this here:
*/
so_flush(so); /* flush socket data queues */
tp->t_state = TCPS_CLOSED; /* set up to send reset */
}
else /* adjust the state for normal shutdown */
{
switch(tp->t_state)
{
case TCPS_ESTABLISHED:
case TCPS_SYN_RECEIVED:
tp->t_state = TCPS_FIN_WAIT_1;
break;
case TCPS_LISTEN:
case TCPS_SYN_SENT:
tp->t_state = TCPS_CLOSED; /* this will force tp deletion below */
break;
case TCPS_CLOSE_WAIT:
tp->t_state = TCPS_LAST_ACK;
break;
default:
dtrap("tcpapi 0\n"); /* other states shouldn't happen */
break;
}
}
if (tp->t_template)
tcp_output(tp); /* send final data then FIN, or RST */
if (tp && (tp->t_state == TCPS_CLOSED))
{
m_tcpclose(tp);
tp=NULL;
}
/* if close was forced (LINGER & longer == 0) or tp was closed in tcp_output()
* (e.g. we sent a reset packet) then delete socket now
*/
if (tp == NULL)
m_delsocket(so);
rtn:
UNLOCK_NET_RESOURCE(NET_RESID);
return e;
}
/* FUNCTION: tcp_pktalloc()
*
* Allcate a packet for sending tcp data. when returned, pkt->nb_prot
* points to a buffer big enough for the data size passed.
*
* PARAM1: size of TCP data for packet, limited to MTU - header size
*
* RETURNS: pointer to a packet, or NULL if a big enough packet was not
* available.
*/
PACKET
tcp_pktalloc(int datasize)
{
PACKET pkt;
int headersize = 40 + MaxLnh;
LOCK_NET_RESOURCE(FREEQ_RESID);
pkt = pk_alloc(datasize + headersize);
UNLOCK_NET_RESOURCE(FREEQ_RESID);
if(!pkt)
return NULL;
/* default nb_prot starts after tcp header */
pkt->nb_prot = pkt->nb_buff + headersize;
pkt->nb_plen = pkt->m_len = 0; /* no data in new packet */
pkt->m_data = pkt->nb_prot; /* assume tcp data will start at nb_prot */
pkt->m_next = NULL;
return pkt;
}
/* FUNCTION: tcp_pktfree()
*
* tcp_pktfree(PACKET p) - free a packet allocated by (presumably)
* tcp_pktalloc(). This is a simple wrapper around pk_free() to lock
* and unlock the free-queue resource.
*
*
* PARAM1: PACKET p
*
* RETURNS:
*/
void
tcp_pktfree(PACKET p)
{
LOCK_NET_RESOURCE(FREEQ_RESID);
pk_free(p);
UNLOCK_NET_RESOURCE(FREEQ_RESID);
}
#ifdef BSDISH_SEND
/* FUNCTION: m_send()
*
* A workalike for the BSD sockets send() call
*
* PARAM1: M_SOCK socket,
* PARAM2: char * buffer
* PARAM3: unsigned length
*
* RETURNS: number of bytes actually sent, or -1 if error.
*/
int
m_send(M_SOCK so, char * data, unsigned datalen)
{
PACKET pkt;
struct tcpcb * tp;
unsigned sent, tosend;
int err;
LOCK_NET_RESOURCE(NET_RESID);
/* make sure connection is established. */
tp = so->tp;
if((tp == NULL) || (tp->t_state < TCPS_ESTABLISHED))
{
so->error = ESHUTDOWN;
UNLOCK_NET_RESOURCE(NET_RESID);
return -1;
}
#ifdef NOTDEF
/* see if we can copy the data to the end of the last queued send */
if(so->sendq.sb_cc)
{
struct tcphdr * ptcp;
pkt = (PACKET)so->sendq.q_tail; /* get last packet in send queue */
ptcp = (struct tcphdr *)(pkt->nb_prot - 20);
/* make sure we have not already sent this pkt */
if(ptcp->th_seq < tp->snd_nxt)
{
dtrap("tcpapi 1\n"); /* watch this first few times */
if((pkt->nb_blen - (pkt->nb_prot + pkt->nb_plen - pkt->nb_buff)) > datalen)
{
pkt->m_data += datalen;
MEMCPY(pkt->m_data, data, datalen);
so->sendq.sb_cc += datalen;
pkt->m_len += datalen;
tcp_output(so->tp);
UNLOCK_NET_RESOURCE(NET_RESID);
return datalen;
}
}
}
#endif /* NOTDEF */
sent = 0;
while(datalen > 0)
{
tosend = min(datalen, TCP_MSS);
pkt = tcp_pktalloc(tosend);
if(!pkt)
{
/* handle out-of-packets condition. */
if((so->state & SS_NBIO) == 0)
{
/* blocking socket; wait for packets to become free */
tcp_sleep(&so->sendq); /* let system spin a bit */
if((so->state & SS_ISCONNECTED) == 0)
{
/* socket closed while waiting, report this to caller. */
so->error = ESHUTDOWN;
goto rtnerr;
}
continue; /* else loop back to wait some more */
}
/* fall to here if this is a non-blocking socket */
if(sent == 0) /* no bytes went out */
{
so->error = EWOULDBLOCK;
goto rtnerr;
}
/* return number of bytes we sent before running out of buffers. */
return sent;
}
MEMCPY(pkt->m_data, data, tosend);
pkt->m_len = tosend; /* set length in packet mbuf vars */
sendagain:
UNLOCK_NET_RESOURCE(NET_RESID);
err = tcp_send(so, pkt); /* pass packet to tcp layer */
LOCK_NET_RESOURCE(NET_RESID);
/* See if socket is full to legal limit, */
if(err == EWOULDBLOCK)
{
/* If socket is non-blocking, return now */
if(so->state & SS_NBIO)
{
tcp_pktfree(pkt); /* free last packet we allocated */
if(sent == 0) /* if no data went out, set error to explain why */
{
so->error = err;
goto rtnerr;
}
goto rtn; /* else return amount of data sent OK */
}
/* else sleep until some data is acked by remote host. */
tcp_sleep(&so->sendq);
goto sendagain;
}
else if(err) /* error other than EWOULDBLOCK */
{
/* Return any other error code. Return -1 instead of "sent" so
* caller knows there was a hard error.
*/
so->error = err;
goto rtnerr;
}
/* packet sent OK, adjust data variables for next loop */
data += tosend; /* fix data pointer for amount copied */
datalen -= tosend; /* ...and data lengnth */
sent += tosend; /* ...and local byte counter */
}
rtn:
UNLOCK_NET_RESOURCE(NET_RESID);
return sent;
rtnerr:
UNLOCK_NET_RESOURCE(NET_RESID);
return -1;
}
#endif /* BSDISH_SEND */
#ifdef BSDISH_RECV
/* FUNCTION: m_recv()
*
* A workalike for the BSD sockets recv() call
*
* PARAM1: M_SOCK socket,
* PARAM2: char * buffer
* PARAM3: unsigned length
*
* RETURNS: number of bytes actually read, or -1 if error.
*/
int
m_recv(M_SOCK so, char * buf, unsigned buflen)
{
PACKET pkt;
int tocopy;
int len;
LOCK_NET_RESOURCE(NET_RESID);
len = 0; /* amount we have copied */
/* handle the no data case first */
while(so->rcvdq.sb_cc == 0)
{
/* If socket is disconnected (or disconnecting), indicate
* this to the caller by returning a zero.
*/
if((so->state & SS_CANTRCVMORE)
#ifdef MINI_TCP_OOSQ
&& (so->oosq.p_head == NULL)
#endif
)
{
so->error = ESHUTDOWN;
goto rtn;
}
/* If THE socket is non-blocking and no data is ready, it
* returns -1 and error is set to EWOULDBLOCK.
*/
if(so->state & SS_NBIO)
{
so->error = EWOULDBLOCK;
len = -1;
goto rtn;
}
UNLOCK_NET_RESOURCE(NET_RESID);
tk_yield();
LOCK_NET_RESOURCE(NET_RESID);
}
/* fall to here if socket has received data in queue */
while((buflen > 0) && so->rcvdq.sb_cc)
{
/* move data from 1st pkt to caller's buffer */
pkt = (PACKET)so->rcvdq.p_head;
tocopy = min(buflen, pkt->m_len);
MEMCPY(buf, pkt->m_data, tocopy);
buflen -= tocopy;
buf += tocopy;
len += tocopy;
/* dequeue data we moved */
if(tocopy >= (int)pkt->m_len)
{
/* we moved whole packet, free it */
tcp_pktfree(get_soq(&so->rcvdq));
/* see if we need to update TCP rcv window */
tcp_output(so->tp);
}
else /* acked a partial packet */
{
/* drop data from head of packet */
pkt->m_data += tocopy;
pkt->m_len -= tocopy;
so->rcvdq.sb_cc -= tocopy;
}
}
#ifdef NPDEBUG
if(len == 0)
{
dtrap("tcpapi 2\n"); /* should never happen */
}
#endif
rtn:
UNLOCK_NET_RESOURCE(NET_RESID);
return len;
}
#endif /* BSDISH_RECV */
/* FUNCTION: tcpt_rangeset
*
* Force a time value to be in a certain range.
*
* PARAM1: short value,
* PARAM2: short min.
* PARAM3: short max.
*
* RETURNS: the time value, set within the range.
*/
short
tcpt_rangeset(short value, short tvmin, short tvmax)
{
short tv = value;
if (value < tvmin)
tv = (short)tvmin;
else if (value > tvmax)
tv = (short)tvmax;
return tv;
}
#ifdef BSDISH_GETPEERNAME
/* m_getpeername() - NicheLite workalike to the BSD getpeername() */
int
m_getpeername(SOCKTYPE sock, struct sockaddr_in * addr)
{
LOCK_NET_RESOURCE(NET_RESID);
addr->sin_addr.s_addr = sock->fhost;
addr->sin_port = sock->lport;
UNLOCK_NET_RESOURCE(NET_RESID);
return 0; /* no real error checking */
}
#endif /* BSDISH_GETPEERNAME */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -