📄 socket.c
字号:
for (sock = sk_list; sock; sock = next)
{
int s = sock->fd;
next = sock->next;
if (!FD_ISSET(s,&inuse[0]))
continue;
if (sock->local_addr == NULL) /* not bound to anything yet */
continue;
#if 0
_sock_debugf (NULL, "\nsock_daemon:%d", sock->fd);
#endif
switch (sock->so_type)
{
case SOCK_STREAM:
if (sock->tcp_sock)
next = tcp_sock_daemon (sock, sock->tcp_sock);
break;
case SOCK_DGRAM:
if (sock->udp_sock)
next = udp_sock_daemon (sock, sock->udp_sock);
break;
}
}
}
/*
* Start and stop critical regions from letting `sk_list' be
* destroyed (e.g. in sock_daemon) and thus confusing select(),
* connect() etc.
*/
void _sock_start_crit (void)
{
if (sk_block < INT_MAX)
++sk_block;
}
void _sock_stop_crit (void)
{
if (sk_block > 0)
{
--sk_block;
#ifdef SIGALRM /* handle SIGALRM raised in crit-section */
/* !!to-do */
#endif
if (!sk_block)
sock_daemon(); /* run blocked sock_daemon() */
}
}
#if defined(USE_BSD_FORTIFY) && defined(USE_DEBUG)
static void fortify_exit (void)
{
Socket *sock;
for (sock = sk_list; sock; sock = sock->next)
{
char *type = "<?>";
void *data = NULL;
tcp_Socket *tcp;
switch (sock->so_type)
{
case SOCK_STREAM:
type = "TCP";
data = sock->tcp_sock;
break;
case SOCK_DGRAM:
type = "UDP";
data = sock->udp_sock;
break;
case SOCK_RAW:
type = "Raw";
data = sock->raw_sock;
break;
}
SOCK_DEBUGF ((NULL, "\n%2d: inuse %d, type %s, data %08lX",
sock->fd, FD_ISSET(sock->fd,&inuse[0]) ? 1 : 0,
type, (DWORD)data));
tcp = sock->tcp_sock;
if (tcp)
{
if (tcp->ip_type == TCP_PROTO)
SOCK_DEBUGF ((NULL, " (ip_type %d, state %s, ports %u/%u, rdatalen %d)",
TCP_PROTO, tcpState[tcp->state],
tcp->myport, tcp->hisport, tcp->rdatalen));
else if (sock->so_state & SS_ISDISCONNECTING)
SOCK_DEBUGF ((NULL, " (closed)"));
else SOCK_DEBUGF ((NULL, " (aborted?)"));
}
}
Fortify_ListAllMemory();
Fortify_OutputStatistics();
}
#endif /* USE_BSD_FORTIFY && USE_DEBUG */
static int InitSockets (void)
{
extern int __pull_neterr_module; /* to make linker pull in */
__pull_neterr_module = 0; /* correct sys_errlist[] */
_watt_do_exit = 0; /* don't make sock_init() call exit() */
if (sock_init())
return (0);
#ifdef __DJGPP__
{
struct rlimit r;
getrlimit (RLIMIT_NOFILE, &r);
r.rlim_max = MAX_SOCKETS; /* We don't know this before we try it */
setrlimit (RLIMIT_NOFILE, &r);
}
sk_last = MAX_SOCKETS;
#else
sk_last = SK_FIRST;
#endif /* __DJGPP__ */
sk_list = NULL;
memset (&inuse, 0, sizeof(inuse));
addwattcpd (sock_daemon);
#if defined(USE_BSD_FORTIFY) && defined(USE_DEBUG)
(void) Fortify_EnterScope();
(void) Fortify_SetOutputFunc (bsd_fortify_print);
atexit (fortify_exit);
#endif
return (1);
}
/*
* _socklist_find
* Returns a pointer to the structure that contains the socket ID passed
* to the function. If socket `s' was not found, NULL is returned
*/
Socket *_socklist_find (int s)
{
Socket *sock;
if (!sk_init)
{
if (!InitSockets())
return (NULL);
sk_init = 1;
}
for (sock = sk_list; sock; sock = sock->next)
if (sock->fd == s)
return (sock);
return (NULL);
}
/*
* sock_list_add
* Adds a new socket to the sk_list
*/
static Socket *sock_list_add (int s, int type, int proto)
{
Socket *sock = SOCK_CALLOC (sizeof(*sock));
void *proto_sk;
if (!sock)
return (NULL);
switch (proto)
{
case IPPROTO_TCP:
/* Only tcp times out on inactivity
*/
sock->timeout = sock_delay;
sock->linger_time = TCP_LINGERTIME;
sock->tcp_sock = proto_sk = SOCK_CALLOC (sizeof(*sock->tcp_sock));
if (!sock->tcp_sock)
{
free (sock);
return (NULL);
}
break;
case IPPROTO_UDP:
sock->udp_sock = proto_sk = SOCK_CALLOC (sizeof(*sock->udp_sock));
if (!sock->udp_sock)
{
free (sock);
return (NULL);
}
break;
default:
sock->raw_sock = proto_sk = SOCK_CALLOC (sizeof(*sock->raw_sock));
if (!sock->raw_sock)
{
free (sock);
return (NULL);
}
sock->raw_sock->ip_type = IP_TYPE;
sock->raw_sock->next = NULL; /* !!to-do: make list of MAX_RAW_BUFS */
break;
}
#if defined(USE_FSEXT) && defined(__DJGPP__)
if (!__FSEXT_set_data (s,sock))
{
free (proto_sk);
free (sock);
SOCK_FATAL (("%s (%d) Fatal: cannot grow FSEXT table\r\n",
__FILE__, __LINE__));
return (NULL);
}
#else
ARGSUSED (proto_sk);
#endif
/* Link 'sock' into the 'sk_list'
*/
if (!sk_list)
{
sock->next = NULL;
sk_list = sock;
}
else
{
sock->next = sk_list;
sk_list = sock;
}
sock->fd = s;
sock->so_type = type;
sock->so_proto = proto;
sock->so_state = SS_UNCONNECTED;
sock->send_lowat = DEFAULT_SEND_LOWAT;
sock->recv_lowat = DEFAULT_RECV_LOWAT;
sock->ip_ttl = IPDEFTTL;
sock->ip_tos = 0;
sock->cookie = SAFETYTCP;
return (sock);
}
/*
* Select (and check) a suitable protocol for socket-type
*/
static __inline int set_proto (int type, int *proto)
{
if (type == SOCK_STREAM)
{
if (*proto == 0)
*proto = IPPROTO_TCP;
else if (*proto != IPPROTO_TCP)
{
SOCK_DEBUGF ((NULL, "\nsocket: invalid STREAM protocol (%d)", *proto));
return (-1);
}
_tcp_find_hook = sock_find_tcp;
}
else if (type == SOCK_DGRAM)
{
if (*proto == 0)
*proto = IPPROTO_UDP;
else if (*proto != IPPROTO_UDP)
{
SOCK_DEBUGF ((NULL, "\nsocket: invalid DGRAM protocol (%d)", *proto));
return (-1);
}
}
else if (type == SOCK_RAW)
{
if (*proto == IPPROTO_RAW) /* match all IP-protocols */
*proto = IPPROTO_IP;
_raw_ip_hook = sock_raw_recv; /* hook for _ip_handler() */
}
return (0);
}
/*
* socket
* Parameters:
* family - The protocol family. Only supports the AF_INET family
* type - SOCK_STREAM (tcp), SOCK_DGRAM (udp) or SOCK_RAW (ip)
* protocol - IPPROTO_TCP, IPPROTO_UDP or 0
*
* Return value - The socket ID number
*/
int socket (int family, int type, int protocol)
{
Socket *sock;
int s, ss;
if (!sk_init && !InitSockets())
{
SOCK_ERR (ENETDOWN);
return (-1);
}
sk_init = 1;
if (family != AF_INET)
{
SOCK_DEBUGF ((NULL, "\nsocket: invalid family (%d)", family));
SOCK_ERR (EAFNOSUPPORT);
return (-1);
}
if (type != SOCK_STREAM &&
type != SOCK_DGRAM &&
#if defined(USE_LIBPCAP)
type != SOCK_PACKET &&
#endif
type != SOCK_RAW)
{
SOCK_DEBUGF ((NULL, "\nsocket: invalid type (%d)", type));
SOCK_ERR (ESOCKTNOSUPPORT);
return (-1);
}
if (type == SOCK_RAW && (protocol < 0 || protocol > 255))
{
SOCK_DEBUGF ((NULL, "\nsocket: invalid SOCK_RAW proto (%d)", protocol));
SOCK_ERR (EINVAL);
return (-1);
}
if (set_proto (type, &protocol) < 0)
{
SOCK_ERR (EPROTONOSUPPORT);
return (-1);
}
s = sock_get_fd();
if (s < 0)
{
SOCK_ERR (EMFILE);
return (-1);
}
sock = sock_list_add (s, type, protocol);
ss = (sock ? s : -1);
switch (type)
{
case SOCK_STREAM:
SOCK_DEBUGF ((NULL, "\nsocket: fam:AF_INET type:STREAM, proto %d, %d",
protocol, ss));
break;
case SOCK_DGRAM:
SOCK_DEBUGF ((NULL, "\nsocket: fam:AF_INET type:DGRAM, proto %d, %d",
protocol, ss));
break;
case SOCK_RAW:
SOCK_DEBUGF ((NULL, "\nsocket: fam:AF_INET type:RAW, proto %d, %d",
protocol, ss));
break;
#if defined(USE_LIBPCAP)
case SOCK_PACKET:
SOCK_DEBUGF ((NULL, "\nsocket: fam:AF_INET type:PACK, proto %d, %d",
protocol, ss));
break;
#endif
}
if (!sock)
{
SOCK_ERR (ENOMEM);
return (-1);
}
#if defined(USE_LIBPCAP)
if (type == SOCK_PACKET) /* promiscuous mode */
{
char err_buf[256];
_pcap_w32 = pcap_open_live ("pkt", ETH_MAX, 1, 0, err_buf);
if (!_pcap_w32)
{
SOCK_ERR (EHOSTDOWN);
/* !!to-do: plug memory leak
*/
return (-1);
}
}
#endif
return (s);
}
/*
* Callback handlers for "ICMP Port/Host Unreachable" or
* "ICMP Parameter Problem" issued by lower layer (udp_cancel()
* and tcp_cancel() in pctcp.c)
*
* Note: a single ICMP message might apply to several sockets,
* but currrently there is a 1-to-1 relation between a
* 'socket' and a 'tcp' (or 'udp') structure.
*/
static int stream_cancel (const tcp_Socket *tcp)
{
Socket *socket;
for (socket = sk_list; socket; socket = socket->next)
if (socket->so_type == SOCK_STREAM && tcp == socket->tcp_sock)
{
socket->so_state |= SS_CONN_REFUSED;
socket->so_error = ECONNREFUSED;
}
return (1);
}
static int dgram_cancel (const udp_Socket *udp)
{
Socket *socket;
for (socket = sk_list; socket; socket = socket->next)
if (socket->so_type == SOCK_DGRAM && udp == socket->udp_sock)
{
socket->so_state |= SS_CONN_REFUSED;
socket->so_error = ECONNREFUSED;
}
return (1);
}
static int sol_callback (void *p, int icmp_type)
{
sock_type *s = (sock_type*)p;
SOCK_DEBUGF ((NULL, "\nsol_callback (s=%08lX, IP-type=%d, ICMP-type %d)",
(DWORD)p, s->udp.ip_type, icmp_type));
if (icmp_type == ICMP_UNREACH || icmp_type == ICMP_PARAMPROB)
{
if (s->udp.ip_type == UDP_PROTO)
return dgram_cancel (&s->udp);
if (s->udp.ip_type == TCP_PROTO)
return stream_cancel (&s->tcp);
}
return (0);
}
/*
* Open and listen routines for SOCK_DGRAM at the socket-level
*/
int _UDP_open (Socket *socket, struct in_addr host, WORD loc_port, WORD rem_port)
{
DWORD ip = ntohl (host.s_addr);
loc_port = ntohs (loc_port);
rem_port = ntohs (rem_port);
if (!udp_open (socket->udp_sock, loc_port, ip, rem_port, NULL))
return (0);
set_rcv_buf ((sock_type*)socket->udp_sock);
socket->udp_sock->sol_callb = sol_callback;
return (1);
}
int _UDP_listen (Socket *socket, struct in_addr host, WORD port)
{
udp_Socket *udp = socket->udp_sock;
port = ntohs (port);
if (socket->so_state & SS_PRIV)
{
int pool_size = sizeof(recv_buf) * MAX_DGRAMS;
void *pool = malloc (pool_size);
DWORD addr;
if (!pool)
{
SOCK_FATAL (("%s (%d) Fatal: Allocation failed\r\n",
__FILE__, __LINE__));
SOCK_ERR (ENOMEM);
return (-1);
}
socket->bcast_pool = (recv_buf**) pool;
/* Mapping `INADDR_ANY' to `INADDR_BROADCAST' causes udp_handler()
* to demux to the correct watt-socket; s->hisaddr = 0xFFFFFFFF in
* passive socket demux loop.
*/
if (host.s_addr == INADDR_ANY)
addr = INADDR_BROADCAST;
else addr = ntohl (host.s_addr);
udp_listen (udp, port, addr, 0, NULL);
/* Setup _recvdaemon() to enqueue broadcast/"unconnected" messages
*/
sock_recv_init (udp, pool, pool_size);
}
else
{
DWORD ip = ntohl (host.s_addr);
udp_listen (udp, port, ip, 0, NULL);
}
udp->sol_callb = sol_callback;
return (1);
}
/*
* Open and listen routines for SOCK_STREAM at the socket-level
*/
int _TCP_open (Socket *socket, struct in_addr host, WORD loc_port, WORD rem_port)
{
DWORD dest = ntohl (host.s_addr);
loc_port = ntohs (loc_port);
rem_port = ntohs (rem_port);
if (!tcp_open (socket->tcp_sock, loc_port, dest, rem_port, NULL))
return (0);
/*
* The paramters to tcp_open() is a bit tricky, but the internal Wattcp
* socket 's' contains the following elements that must match in the
* first 'for-loop' of tcp_handler().
*
* s->hisport != 0 i.e. active (non-listening) port
* s->myaddr == ip->destination, our IP-address
* s->hisaddr == ip->source, above 'dest' address
* s->myport == tcp->dstPort, above 'loc_port'
* s->hisport == tcp->srcPort, above 'rem_port'
*/
/* Advertise a large rcv-win from the next ACK
*/
set_rcv_buf ((sock_type*)socket->tcp_sock);
socket->tcp_sock->sol_callb = sol_callback;
return (1);
}
int _TCP_listen (Socket *socket, struct in_addr host, WORD port)
{
DWORD addr = ntohl (host.s_addr);
WORD loc_port = ntohs (port);
tcp_listen (socket->tcp_sock, loc_port, addr, 0, NULL, 0);
socket->tcp_sock->sol_callb = sol_callback;
return (1);
}
#ifdef NOT_USED
/*
* _sock_half_open -
* Return true if peer closed his side.
* There might still be data to read
*/
int _sock_half_open (const tcp_Socket *s)
{
if (!s || s->ip_type == UDP_PROTO || s->ip_type == IP_TYPE)
return (0);
return (s->state >= tcp_StateFINWT1 &&
s->state <= tcp_StateCLOSED);
}
#endif
#if 0 /* not finished */
/*
* socketpair() - Create a pair of connected sockets.
* Modified version based on Linux's version.
*/
int socketpair (int family, int type, int protocol, int usockvec[2])
{
Socket *sock1, *sock2;
int s1, s2;
if ((s1 = socket (family, type, protocol)) < 0)
return (fd1);
sock1 = socklist_find (s1);
/* Now grab another socket and try to connect the two together.
*/
if ((s2 = socket (family, type, protocol)) < 0)
{
close_s (s1);
return (-EINVAL);
}
sock2 = socklist_find (s2);
sock1->conn = sock2;
sock2->conn = sock1;
sock1->so_state = SS_CONNECTED;
sock2->so_state = SS_CONNECTED;
usockvec[0] = s1;
usockvec[1] = s2;
return (0);
}
#endif
#endif /* USE_BSD_FUNC */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -