📄 transmit.c
字号:
*/
if (*len > 0 && room <= socket->send_lowat)
return (-1);
/* streams may be split up, modify '*len'
*/
*len = room;
return (0);
}
/*
* TCP transmitter
*/
static int tcp_transmit (Socket *socket, const void *buf, int len, int flags)
{
sock_type *sk = (sock_type*)socket->tcp_sock;
tcp_tick (sk);
tcp_Retransmitter (1);
if (sk->tcp.state < tcp_StateESTAB || sk->tcp.state >= tcp_StateLASTACK)
{
socket->so_state |= SS_CANTSENDMORE;
SOCK_DEBUGF ((socket, ", ENOTCONN (%s)", /* !! or EPIPE */
(sk->tcp.locflags & LF_GOT_FIN) ?
"got FIN" : "can't send"));
SOCK_ERR (ENOTCONN);
return (-1);
}
if (socket->so_state & SS_NBIO)
{
int in_len = len;
if (check_non_block_tx(socket,&len) < 0)
{
SOCK_DEBUGF ((socket, ", EWOULDBLOCK"));
SOCK_ERR (EWOULDBLOCK);
return (-1);
}
if (in_len != len)
SOCK_DEBUGF ((socket, " [%d]", len)); /* trace "len=x [y]" */
}
SOCK_DEBUGF ((socket, ", %s (%d) / TCP",
inet_ntoa(socket->remote_addr->sin_addr),
ntohs(socket->remote_addr->sin_port)));
#if 0
/* Must wait for room in send buffer
*/
if ((flags & MSG_WAITALL) || len > sock_tbleft(sk))
len = sock_write (sk, (BYTE*)buf, len);
else len = sock_fastwrite (sk, (BYTE*)buf, len);
#else
/* This is more efficient. The above sock_fastwrite() would
* effectively turn off Nagle's algorithm.
*/
ARGSUSED (flags);
len = sock_write (sk, (BYTE*)buf, len);
#endif
if (len <= 0) /* error in tcp_write() */
{
if (sk->tcp.state != tcp_StateESTAB)
{
SOCK_DEBUGF ((socket, ", ENOTCONN"));
SOCK_ERR (ENOTCONN); /* maybe EPIPE? */
}
else
{
SOCK_DEBUGF ((socket, ", ENETDOWN"));
SOCK_ERR (ENETDOWN);
}
return (-1);
}
return (len);
}
/*
* UDP transmitter
*/
static int udp_transmit (Socket *socket, const void *buf, int len)
{
sock_type *sk = (sock_type*) socket->udp_sock;
u_long dest = socket->remote_addr->sin_addr.s_addr;
int tx_room, rc;
int is_bcast, is_multi;
if (!tcp_tick(sk))
{
socket->so_state |= SS_CANTSENDMORE;
SOCK_DEBUGF ((socket, ", ENOTCONN (can't send)")); /* !! or EPIPE */
SOCK_ERR (ENOTCONN);
return (-1);
}
tcp_Retransmitter (1);
if ((socket->so_state & SS_NBIO) && check_non_block_tx(socket,&len) < 0)
{
SOCK_DEBUGF ((socket, ", EWOULDBLOCK"));
SOCK_ERR (EWOULDBLOCK);
return (-1);
}
is_bcast = (dest == INADDR_BROADCAST || dest == INADDR_ANY);
is_multi = IN_MULTICAST (ntohl(socket->remote_addr->sin_addr.s_addr));
SOCK_DEBUGF ((socket, ", %s (%d) / UDP %s",
inet_ntoa(socket->remote_addr->sin_addr),
ntohs(socket->remote_addr->sin_port),
is_multi ? "(mc)" : ""));
if (len == 0) /* 0-byte probe packet */
return ip_transmit (socket, NULL, 0);
tx_room = sock_tbleft (sk); /* always MTU-28 */
/* Special tests for broadcast messages
*/
if (is_bcast)
{
if (len > tx_room) /* don't allow fragments */
{
SOCK_DEBUGF ((socket, ", EMSGSIZE"));
SOCK_ERR (EMSGSIZE);
STAT (ipstats.ips_odropped++);
return (-1);
}
if (_pktserial) /* Link-layer doesn't allow broadcast */
{
SOCK_DEBUGF ((socket, ", EADDRNOTAVAIL"));
SOCK_ERR (EADDRNOTAVAIL);
STAT (ipstats.ips_odropped++);
return (-1);
}
}
/* set new TTL if setsockopt() used before sending to Class-D socket
*/
if (is_multi)
sk->udp.ttl = socket->ip_ttl;
#if defined(USE_FRAGMENTS)
if ((long)len > USHRT_MAX - sizeof(udp_Header))
{
SOCK_DEBUGF ((socket, ", EMSGSIZE"));
SOCK_ERR (EMSGSIZE);
STAT (ipstats.ips_toolong++);
return (-1);
}
if (len > tx_room)
return SEND_IP_FRAGMENTS (sk, UDP_PROTO, dest, buf, len);
#endif
rc = sock_write (sk, (BYTE*)buf, len);
if (rc <= 0) /* error in udp_write() */
{
SOCK_DEBUGF ((socket, ", ENETDOWN"));
SOCK_ERR (ENETDOWN);
return (-1);
}
return (rc);
}
/*
* Raw IP transmitter
*/
static int ip_transmit (Socket *socket, const void *tx, int len)
{
eth_address eth;
u_long dest;
unsigned tx_len, tx_room;
sock_type *sk = (sock_type*)socket->udp_sock;
struct ip *ip = (struct ip*) tx;
const BYTE *buf = (const BYTE*) tx;
WORD flags = 0;
DWORD offset;
UINT h_len, o_len;
tcp_tick (NULL); /* process other TCBs too */
tcp_Retransmitter (1);
/* This should never happen
*/
if (ip && (socket->so_state & SS_NBIO) &&
sock_tbleft(sk) < (len + socket->send_lowat))
{
SOCK_DEBUGF ((socket, ", EWOULDBLOCK"));
SOCK_ERR (EWOULDBLOCK);
return (-1);
}
if (ip)
{
offset = ntohs (ip->ip_off);
flags = offset & ~IP_OFFMASK;
offset = (offset & IP_OFFMASK) << 3; /* 0 <= ip_ofs <= 65536-8 */
}
SOCK_DEBUGF ((socket, ", %s / Raw",
inet_ntoa(socket->remote_addr->sin_addr)));
if (ip && (socket->inp_flags & INP_HDRINCL))
{
dest = ip->ip_dst.s_addr;
tx_len = len;
tx_room = mtu;
}
else
{
dest = socket->remote_addr->sin_addr.s_addr;
tx_len = len + sizeof (*ip);
tx_room = mtu + sizeof (*ip);
}
if (!dest || !_arp_resolve(ntohl(dest),ð,0))
{
SOCK_DEBUGF ((socket, ", no route"));
SOCK_ERR (EHOSTUNREACH);
STAT (ipstats.ips_noroute++);
return (-1);
}
#if defined(USE_FRAGMENTS)
if (!(socket->inp_flags & INP_HDRINCL) &&
tx_len + socket->ip_opt_len > tx_room)
{
sk = (sock_type*)socket->raw_sock;
if (flags & IP_DF)
{
SOCK_DEBUGF ((socket, ", EMSGSIZE"));
SOCK_ERR (EMSGSIZE);
STAT (ipstats.ips_toolong++);
return (-1);
}
return SEND_IP_FRAGMENTS (sk, sk->raw.ip_type, dest, buf, len);
}
#else
if (!(socket->inp_flags & INP_HDRINCL) &&
tx_len + socket->ip_opt_len > tx_room)
{
SOCK_DEBUGF ((socket, ", EMSGSIZE"));
SOCK_ERR (EMSGSIZE);
STAT (ipstats.ips_toolong++);
return (-1);
}
#endif
ip = (struct ip*) _eth_formatpacket (ð, IP_TYPE);
if (socket->inp_flags & INP_HDRINCL)
{
memcpy (ip, buf, len);
if (ip->ip_src.s_addr == 0)
{
ip->ip_src.s_addr = gethostid();
ip->ip_sum = 0;
ip->ip_sum = ~checksum ((void*)ip, ip->ip_hl << 2);
}
if (ip->ip_sum == 0)
ip->ip_sum = ~checksum ((void*)ip, ip->ip_hl << 2);
}
else
{
if (socket->ip_opt && socket->ip_opt_len > 0)
{
BYTE *data;
o_len = min (socket->ip_opt_len, sizeof(socket->ip_opt->ip_opts));
h_len = sizeof(*ip) + o_len;
data = (BYTE*)ip + h_len;
memcpy (ip+1, &socket->ip_opt->ip_opts, o_len);
memcpy (data, buf, len);
tx_len += o_len;
if (socket->ip_opt->ip_dst.s_addr) /* using source routing */
dest = socket->ip_opt->ip_dst.s_addr;
}
else
{
if (buf)
memcpy (ip+1, buf, len);
h_len = sizeof (*ip);
}
ip->ip_v = IPVERSION;
ip->ip_hl = h_len >> 2;
ip->ip_tos = socket->ip_tos;
ip->ip_len = htons (tx_len);
ip->ip_id = _get_ip_id();
ip->ip_off = 0;
ip->ip_ttl = socket->ip_ttl;
ip->ip_p = socket->so_proto;
ip->ip_src.s_addr = gethostid();
ip->ip_dst.s_addr = dest;
ip->ip_sum = 0;
ip->ip_sum = ~checksum (ip, h_len);
}
DEBUG_TX (NULL, ip);
if (!_eth_send(tx_len))
{
SOCK_DEBUGF ((socket, ", ENETDOWN"));
SOCK_ERR (ENETDOWN);
return (-1);
}
if (buf)
buf += tx_len;
return (len);
}
#endif /* USE_BSD_FUNC */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -