3053 lines
96 KiB
C
3053 lines
96 KiB
C
/*
|
|
******************************************************************************
|
|
* SOURCE FILE
|
|
*
|
|
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: iplite_sock.c,v $ $Revision: 1.120.10.5 $
|
|
* $Source: /home/interpeak/CVSRoot/iplite2/src/iplite_sock.c,v $
|
|
* $Author: hxie $
|
|
* $State: Exp $ $Locker: $
|
|
*
|
|
* INTERPEAK_COPYRIGHT_STRING
|
|
* Design and implementation by Kenneth Jonsson <kenneth@interpeak.se>
|
|
******************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 1 DESCRIPTION
|
|
****************************************************************************
|
|
* Functions for socket API.
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 2 CONFIGURATION
|
|
****************************************************************************
|
|
*/
|
|
|
|
#define IPCOM_SKIP_NATIVE_SOCK_API
|
|
|
|
#ifndef IPCOM_KERNEL
|
|
#define IPCOM_KERNEL
|
|
#endif
|
|
#include "iplite_config.h"
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 3 INCLUDE FILES
|
|
****************************************************************************
|
|
*/
|
|
|
|
#if !defined(IPLITE_ONE_FILE) || defined(IPLITE_C)
|
|
|
|
#define IPCOM_USE_CLIB_PROTO
|
|
#include <ipcom_err.h>
|
|
#include <ipcom_clib.h>
|
|
#include <ipcom_cstyle.h>
|
|
#include <ipcom_inet.h>
|
|
|
|
#include "iplite_h.h"
|
|
#include "iplite_loopback.h"
|
|
#include "iplite_sock.h"
|
|
|
|
#ifdef IPCOM_USE_TCP
|
|
#include "iplite_tcp.h"
|
|
#endif
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 4 DEFINES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 5 TYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 6 EXTERN PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
#ifdef IP_PORT_OSE5_disabled_code
|
|
Ip_err ipcom_crt_block_wait(Ipcom_socket *sock, Ip_s32 milli_seconds, Ip_bool snd);
|
|
void ipcom_crt_block_post(Ipcom_socket *sock, Ip_bool snd);
|
|
#endif
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 7 LOCAL PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
IP_STATIC Ipcom_pkt *iplite_krecvfrom(Iplite_socket *sock, struct Ip_sockaddr *from, Ip_socklen_t *fromlen);
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 8 DATA
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 9 STATIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* iplite_bind_check_reuse
|
|
*===========================================================================
|
|
* Description: Checks if the source port is reused and if it is, whenever
|
|
* the reuse is ok or not.
|
|
* Parameters: sock - The socket for which to check port reuse.
|
|
* Returns: 0 = success, <0 = error code.
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
iplite_bind_check_reuse(Iplite_socket *sock)
|
|
{
|
|
/* Check if there is a socket bound to same local port&addr -> EADDRINUSE
|
|
* (Consider socket option SO_REUSEADDR and SO_REUSEPORT).
|
|
*/
|
|
Iplite_socket *cachesock = IP_NULL;
|
|
int reuse, last_sock = 0;
|
|
|
|
for (;;)
|
|
{
|
|
#ifdef IPCOM_USE_INET
|
|
if (sock->ipcom.domain == IP_AF_INET)
|
|
{
|
|
cachesock = iplite_ip4_socklookup(sock->proto,
|
|
IP_NULL, sock->sport,
|
|
IP_NULL, 0,
|
|
&last_sock);
|
|
#ifdef IPCOM_USE_INET6
|
|
if (cachesock && cachesock->ipcom.domain == IP_AF_INET6)
|
|
cachesock = IP_NULL;
|
|
#endif
|
|
}
|
|
#endif
|
|
#ifdef IPCOM_USE_INET6
|
|
if (sock->ipcom.domain == IP_AF_INET6)
|
|
cachesock = iplite_ip6_socklookup(sock->proto,
|
|
IP_NULL, sock->sport,
|
|
IP_NULL, 0,
|
|
&last_sock);
|
|
#endif
|
|
|
|
if (cachesock == IP_NULL)
|
|
break;
|
|
|
|
reuse = (sock->flags & cachesock->flags)
|
|
& (IPLITE_SOCKET_FLAG_REUSEPORT | IPLITE_SOCKET_FLAG_REUSEADDR);
|
|
|
|
/* Both sockets must have at least one of the two reuse flags set. */
|
|
if (reuse == 0)
|
|
return -IP_ERRNO_EADDRINUSE;
|
|
|
|
#ifdef IPCOM_USE_INET
|
|
if (sock->ipcom.domain == IP_AF_INET)
|
|
{
|
|
if (sock->d->ip4.saddr_n != IP_INADDR_ANY
|
|
&& iplite_ip4_get_addr_type(IP_NULL, sock->d->ip4.saddr_n) != IPLITE_ADDR_TYPE_UNICAST)
|
|
return 0;
|
|
|
|
if (sock->d->ip4.saddr_n != cachesock->d->ip4.saddr_n)
|
|
continue;
|
|
}
|
|
#endif
|
|
|
|
#ifdef IPCOM_USE_INET6
|
|
if (sock->ipcom.domain == IP_AF_INET6)
|
|
{
|
|
if (IP_IN6_IS_ADDR_MULTICAST(&sock->d->ip6.saddr))
|
|
return 0;
|
|
|
|
if (!IP_IN6_ARE_ADDR_EQUAL(&sock->d->ip6.saddr, &cachesock->d->ip6.saddr))
|
|
continue;
|
|
}
|
|
#endif
|
|
|
|
#ifdef IPCOM_USE_TCP
|
|
if (sock->tcb != IP_NULL
|
|
&& IP_BIT_ISSET(cachesock->flags, IPLITE_SOCKET_FLAG_CONNECTED))
|
|
return 0;
|
|
#endif
|
|
|
|
if (IP_BIT_ISFALSE(reuse, IPLITE_SOCKET_FLAG_REUSEPORT)
|
|
#ifdef IPCOM_USE_TCP
|
|
|| sock->tcb != IP_NULL
|
|
#endif
|
|
)
|
|
return -IP_ERRNO_EADDRINUSE;
|
|
}
|
|
|
|
/* bind ok. */
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* iplite_do_shutdown
|
|
*===========================================================================
|
|
* Description: The actual ipcom_shutdown() implementation
|
|
* Parameters: fd - The file descriptor to shut down.
|
|
* how - How the socket should be shut down.
|
|
* Returns: 0 = success, -1 = error
|
|
*/
|
|
IP_STATIC int
|
|
iplite_do_shutdown(Ip_fd fd, int how)
|
|
{
|
|
Iplite_socket *sock;
|
|
int ret;
|
|
int ret2;
|
|
int so_errno = -1; /* Close event */
|
|
|
|
ip_assert2(fd >= IPLITE_SOCKET_STARTFD);
|
|
ip_assert2(iplite.sockets[fd] != IP_NULL);
|
|
|
|
sock = iplite.sockets[fd];
|
|
if (sock == IP_NULL)
|
|
SOCK_ERROUT(IP_ERRNO_EBADF);
|
|
|
|
/* Set socket flags. */
|
|
switch (how)
|
|
{
|
|
case IP_SHUT_RDWR:
|
|
ret = iplite_do_shutdown(fd, IP_SHUT_RD);
|
|
ret2 = iplite_do_shutdown(fd, IP_SHUT_WR);
|
|
return ret == 0 ? ret2 : ret;
|
|
case IP_SHUT_RD:
|
|
if (IP_BIT_ISSET(sock->flags, IPLITE_SOCKET_FLAG_READ_CLOSED))
|
|
SOCK_ERROUT(IP_ERRNO_ESHUTDOWN);
|
|
IP_BIT_SET(sock->flags, IPLITE_SOCKET_FLAG_READ_CLOSED);
|
|
break;
|
|
case IP_SHUT_WR:
|
|
if (IP_BIT_ISSET(sock->flags, IPLITE_SOCKET_FLAG_WRITE_CLOSED))
|
|
SOCK_ERROUT(IP_ERRNO_ESHUTDOWN);
|
|
IP_BIT_SET(sock->flags, IPLITE_SOCKET_FLAG_WRITE_CLOSED);
|
|
if (sock->snd_poll_list.size)
|
|
so_errno = IP_ERRNO_EPIPE;
|
|
break;
|
|
default:
|
|
SOCK_ERROUT(IP_ERRNO_EINVAL);
|
|
}
|
|
|
|
#ifdef IPCOM_USE_TCP
|
|
if (sock->ipcom.type == IP_SOCK_STREAM)
|
|
iplite_tcp_shutdown(sock, how);
|
|
#endif
|
|
|
|
iplite_sock_data_avail(sock, so_errno, how);
|
|
|
|
return 0;
|
|
|
|
errout:
|
|
return IP_SOCKERR;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* iplite_sock_is_readable
|
|
*===========================================================================
|
|
* Description: Returns if a socket is readable or not
|
|
* Parameters: sock - socket to check for readability.
|
|
* Returns: IP_TRUE - socket is readable
|
|
* IP_FALSE - socket is not readable
|
|
*
|
|
*/
|
|
IP_STATIC Ip_bool
|
|
iplite_sock_is_readable(Iplite_socket *sock)
|
|
{
|
|
if (sock->ipcom.so_errno)
|
|
return IP_TRUE;
|
|
if (sock->ipcom.rcv_bytes > 0)
|
|
return IP_TRUE;
|
|
|
|
#ifdef IPCOM_USE_TCP
|
|
if (sock->tcb)
|
|
{
|
|
Iplite_tcp_tcb *tcb = sock->tcb;
|
|
|
|
if (tcb->state == IPLITE_TCPS_LISTEN)
|
|
{
|
|
if (IP_BIT_ISSET(tcb->flags, IPLITE_TCPC_FLAG_CONNABORTED))
|
|
return IP_TRUE;
|
|
if (tcb->backlog_done[0] != IP_SOCKERR)
|
|
return IP_TRUE;
|
|
}
|
|
}
|
|
#endif /* IPCOM_USE_TCP */
|
|
|
|
return (IP_BIT_ISSET(sock->flags,
|
|
IPLITE_SOCKET_FLAG_READ_CLOSED
|
|
| IPLITE_SOCKET_FLAG_PEER_WRITE_CLOSED));
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* iplite_sock_is_writable
|
|
*===========================================================================
|
|
* Description: Returns if a socket is writable or not
|
|
* Parameters: sock - socket to check for writability.
|
|
* Returns: IP_TRUE - socket is writable
|
|
* IP_FALSE - socket is not writable
|
|
*
|
|
*/
|
|
IP_STATIC Ip_bool
|
|
iplite_sock_is_writable(Iplite_socket *sock)
|
|
{
|
|
#ifdef IPCOM_USE_TCP
|
|
if (sock->tcb)
|
|
{
|
|
Iplite_tcp_tcb *tcb = sock->tcb;
|
|
|
|
if (sock->ipcom.so_errno)
|
|
return IP_TRUE;
|
|
|
|
return (tcb->state >= IPLITE_TCPS_ESTABLISHED
|
|
&& sock->snd_bytes < sock->snd_max_bytes);
|
|
}
|
|
#endif /* IPCOM_USE_TCP */
|
|
|
|
return IP_TRUE;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* iplite_sock_select_wait
|
|
*===========================================================================
|
|
* Description: Waits for sockets in a select to become ready.
|
|
* Parameters: sem - a valid semaphore with timeout or IP_NULL if the
|
|
* sockets should just be checked.
|
|
* timeout - maximum number of milliseconds to wait for
|
|
* sockets to become ready.
|
|
* Returns: 0
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
iplite_sock_select_wait(Ipcom_block sem, Ip_s32 msec)
|
|
{
|
|
if (sem != IPCOM_BLOCK_INVALID)
|
|
{
|
|
IPLITE_CODE_UNLOCK();
|
|
(void)ipcom_block_wait(sem, msec);
|
|
IPLITE_CODE_LOCK();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* iplite_sock_wr_select
|
|
*===========================================================================
|
|
* Description: Performs write select for sockets.
|
|
* Parameters: fd - first socket to consider
|
|
* nfds - maximum number of socket to consider
|
|
* writefds - set of sockets to check for write, will contain
|
|
* all sockets that are writable on return.
|
|
* sem - a valid semaphore with timeout or IP_NULL if the
|
|
* sockets should just be checked.
|
|
* timeout - maximum number of milliseconds to wait for
|
|
* sockets to become ready.
|
|
* Returns: <0 = error code
|
|
* ==0 = timeout
|
|
* >0 = number of ready sockets
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
iplite_sock_wr_select(int fd,
|
|
int nfds,
|
|
Ip_fd_set *writefds,
|
|
Ipcom_block *sem,
|
|
Ip_s32 msec)
|
|
{
|
|
int ready_socks;
|
|
Iplite_socket *sock;
|
|
|
|
for (;;fd++)
|
|
{
|
|
if (writefds == IP_NULL || fd == nfds)
|
|
return iplite_sock_select_wait(sem, msec);
|
|
|
|
if (IP_FD_ISSET(fd, writefds))
|
|
{
|
|
Iplite_poll_entry poll;
|
|
|
|
sock = iplite.sockets[fd];
|
|
if (sock == IP_NULL)
|
|
return -IP_ERRNO_EBADF;
|
|
|
|
if (iplite_sock_is_writable(sock))
|
|
/* Change operation to just calculate the number of
|
|
ready sockets */
|
|
sem = IP_NULL;
|
|
|
|
poll.sem = sem;
|
|
ipcom_list_insert_last(&iplite.sockets[fd]->snd_poll_list, &poll.list);
|
|
ready_socks = iplite_sock_wr_select(fd + 1, nfds, writefds, sem, msec);
|
|
ipcom_list_remove(&poll.list);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (ready_socks >= 0 && iplite_sock_is_writable(sock))
|
|
return ready_socks + 1;
|
|
IP_FD_CLR(fd, writefds);
|
|
return ready_socks;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* iplite_sock_select
|
|
*===========================================================================
|
|
* Description: Performs read and write select for sockets.
|
|
* Parameters: fd - first socket to consider
|
|
* nfds - maximum number of socket to consider
|
|
* readfds - set of sockets to check for read, will contain
|
|
* all sockets that are readable on return.
|
|
* writefds - set of sockets to check for write, will contain
|
|
* all sockets that are writable on return.
|
|
* sem - a valid semaphore with timeout or IP_NULL if the
|
|
* sockets should just be checked.
|
|
* timeout - maximum number of milliseconds to wait for
|
|
* sockets to become ready.
|
|
* Returns: <0 = error code
|
|
* ==0 = timeout
|
|
* >0 = number of ready sockets
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
iplite_sock_select(int fd,
|
|
int nfds,
|
|
Ip_fd_set *readfds,
|
|
Ip_fd_set *writefds,
|
|
Ipcom_block *sem,
|
|
Ip_s32 msec)
|
|
{
|
|
int ready_socks;
|
|
Iplite_socket *sock;
|
|
|
|
for (;;fd++)
|
|
{
|
|
if (readfds == IP_NULL || fd == nfds)
|
|
return iplite_sock_wr_select(IPLITE_SOCKET_STARTFD,
|
|
nfds,
|
|
writefds,
|
|
sem,
|
|
msec);
|
|
|
|
if (IP_FD_ISSET(fd, readfds))
|
|
{
|
|
Iplite_poll_entry poll;
|
|
|
|
sock = iplite.sockets[fd];
|
|
if (sock == IP_NULL)
|
|
return -IP_ERRNO_EBADF;
|
|
|
|
if (iplite_sock_is_readable(sock))
|
|
/* Change operation to just calculate the number of
|
|
ready sockets */
|
|
sem = IP_NULL;
|
|
|
|
poll.sem = sem;
|
|
ipcom_list_insert_last(&sock->rcv_poll_list, &poll.list);
|
|
ready_socks = iplite_sock_select(fd + 1,
|
|
nfds,
|
|
readfds,
|
|
writefds,
|
|
sem,
|
|
msec);
|
|
ipcom_list_remove(&poll.list);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (ready_socks >= 0 && iplite_sock_is_readable(sock))
|
|
return ready_socks + 1;
|
|
IP_FD_CLR(fd, readfds);
|
|
return ready_socks;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* iplite_sock_wakeup_poll_list
|
|
*===========================================================================
|
|
* Description: Wakes all processes polling for a socket
|
|
* Parameters: head - head of poll list
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC void
|
|
iplite_sock_wakeup_poll_list(Ipcom_list *head)
|
|
{
|
|
Iplite_poll_entry *poll_entry;
|
|
|
|
for (poll_entry = IPCOM_LIST_FIRST(head);
|
|
poll_entry != IP_NULL;
|
|
poll_entry = IPCOM_LIST_NEXT(&poll_entry->list))
|
|
ipcom_block_post(poll_entry->sem);
|
|
}
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 10 GLOBAL FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*===========================================================================
|
|
* iplite_get_sock
|
|
*===========================================================================
|
|
* Description: Returns the socket descriptor that matches the
|
|
* specified file descriptor. The caller must
|
|
* call ipnet_release_sock() when done using the
|
|
* socket.
|
|
* Parameters: fd - a file descriptor.
|
|
* Returns: The matching socket descriptor or IP_NULL if no
|
|
* matching socket exists.
|
|
*
|
|
*/
|
|
IP_GLOBAL Iplite_socket *
|
|
iplite_get_sock(int fd)
|
|
{
|
|
Iplite_socket *sock;
|
|
|
|
IPLITE_CODE_LOCK();
|
|
|
|
sock = iplite.sockets[fd];
|
|
if (sock == IP_NULL)
|
|
{
|
|
IPLITE_CODE_UNLOCK();
|
|
return IP_NULL;
|
|
}
|
|
|
|
return sock;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* iplite_release_sock
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters: sock - socket to release.
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
iplite_release_sock(Iplite_socket *sock)
|
|
{
|
|
IPCOM_UNUSED_ARG(sock);
|
|
IPLITE_CODE_UNLOCK();
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* iplite_is_sock_readable
|
|
*===========================================================================
|
|
* Description: Checks if the specified socket is readable.
|
|
* Parameters: sock - the socket to check.
|
|
* lowat - minimum number of bytes that must be present
|
|
* in the receive queue to cont the socket as
|
|
* readable. 0 means to use the socket lo
|
|
* watermask value.
|
|
* Returns: IP_TRUE = socket is readable
|
|
* IP_FALSE = socket is not readable
|
|
*
|
|
*/
|
|
IP_GLOBAL Ip_bool
|
|
iplite_is_sock_readable(Iplite_socket *sock, int lowat)
|
|
{
|
|
if (sock->ipcom.so_errno)
|
|
/* Sockets with pending error is always readable */
|
|
return IP_TRUE;
|
|
|
|
if (sock->ipcom.rcv_bytes >= IP_MAX(lowat, 1))
|
|
return IP_TRUE;
|
|
|
|
#ifdef IPCOM_USE_TCP
|
|
if (sock->tcb != IP_NULL)
|
|
{
|
|
if (sock->tcb->backlog_done != IP_NULL
|
|
&& sock->tcb->backlog_done[0] != IP_SOCKERR)
|
|
/* accept() would not block */
|
|
return IP_TRUE;
|
|
|
|
if (IP_BIT_ISSET(sock->flags, IPLITE_SOCKET_FLAG_READ_CLOSED)
|
|
|| IP_BIT_ISSET(sock->flags, IPLITE_SOCKET_FLAG_PEER_WRITE_CLOSED))
|
|
/* recv() would return EOF */
|
|
return IP_TRUE;
|
|
}
|
|
#endif
|
|
return IP_FALSE;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* iplite_is_sock_writable
|
|
*===========================================================================
|
|
* Description: Checks if the specified socket is writable.
|
|
* Parameters: sock - the socket to check.
|
|
* lowat - minimum number of bytes that must be available
|
|
* in the transmit queue to cont the socket as
|
|
* writable. 0 means to use the socket lo
|
|
* watermark value.
|
|
* Returns: IP_TRUE = socket is writable
|
|
* IP_FALSE = socket is not writable
|
|
*
|
|
*/
|
|
IP_GLOBAL Ip_bool
|
|
iplite_is_sock_writable(Iplite_socket *sock, int lowat)
|
|
{
|
|
if (sock->ipcom.so_errno
|
|
|| IP_BIT_ISSET(sock->flags, IPLITE_SOCKET_FLAG_WRITE_CLOSED))
|
|
return IP_TRUE;
|
|
|
|
if ((IP_BIT_ISSET(sock->flags, IPLITE_SOCKET_FLAG_CONNECTED)
|
|
|| sock->ipcom.type != IP_SOCK_STREAM)
|
|
&& sock->snd_max_bytes - sock->snd_bytes >= IP_MAX(lowat, 1))
|
|
return IP_TRUE;
|
|
|
|
return IP_FALSE;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* iplite_is_sock_exceptional
|
|
*===========================================================================
|
|
* Description: Checks if the specified socket is exceptional.
|
|
* Parameters: sock - the socket to check.
|
|
* lowat - unused. Added so this function has the same
|
|
* signature as the other iplite_is_sock_xxx().
|
|
* Returns: IP_TRUE = socket is exceptional
|
|
* IP_FALSE = socket is not exceptional.
|
|
*
|
|
*/
|
|
IP_GLOBAL Ip_bool
|
|
iplite_is_sock_exceptional(Iplite_socket *sock, int lowat)
|
|
{
|
|
/* exeptional socket is currently not supported */
|
|
IPCOM_UNUSED_ARG(sock);
|
|
IPCOM_UNUSED_ARG(lowat);
|
|
|
|
return IP_FALSE;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* iplite_next_ephemeral_port
|
|
*===========================================================================
|
|
* Description: Returns the next ephemeral port.
|
|
* Parameters:
|
|
* Returns: The next free ephemeral port or 0 if no port could be found.
|
|
* The port is retured in host byte order.
|
|
*
|
|
*/
|
|
IP_GLOBAL Ip_u16
|
|
iplite_next_ephemeral_port(void)
|
|
{
|
|
int i;
|
|
Ip_u16 firstport;
|
|
Ip_u16 eport;
|
|
Ip_u16 anonportmax;
|
|
Ip_u16 anonportmin;
|
|
|
|
anonportmax = IPLITE_CONF_SOCK_ANONPORTMAX;
|
|
anonportmin = IPLITE_CONF_SOCK_ANONPORTMIN;
|
|
firstport = anonportmin + ipcom_rand() % (1 + anonportmax - anonportmin);
|
|
eport = firstport;
|
|
|
|
do {
|
|
for (i = 0; i < IPLITE_CONF_MAX_SOCKETS; i++)
|
|
{
|
|
if (iplite.bound_sockets[i] == IP_NULL)
|
|
break;
|
|
if (iplite.bound_sockets[i]->sport == eport)
|
|
goto next_port;
|
|
}
|
|
|
|
return eport;
|
|
|
|
next_port:
|
|
if (eport++ == anonportmax)
|
|
eport = anonportmin;
|
|
} while (eport != firstport);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* iplite_queue_received_packet
|
|
*===========================================================================
|
|
* Description: Queues a packet on the passed socket. The start field of
|
|
* the packet should specify beginning of application data.
|
|
* Parameters:
|
|
* Returns: 0 = success, <0 = error code
|
|
*
|
|
*/
|
|
IP_GLOBAL int
|
|
iplite_queue_received_packet(Ipcom_pkt *pkt, Iplite_socket *sock)
|
|
{
|
|
if (sock->ipcom.rcv_bytes + pkt->end - pkt->start > (int) sock->rcv_max_bytes)
|
|
{
|
|
IPLITE_STATS(pkt_queue_emsgsize++);
|
|
return -IP_ERRNO_EMSGSIZE;
|
|
}
|
|
|
|
/* Add the packet to the socket receive queue */
|
|
sock->ipcom.rcv_bytes += pkt->end - pkt->start;
|
|
if (sock->rcv_head != IP_NULL)
|
|
sock->rcv_tail->next = pkt;
|
|
else
|
|
sock->rcv_head = pkt;
|
|
sock->rcv_tail = pkt;
|
|
pkt->next = IP_NULL;
|
|
|
|
IPCOM_PKT_TRACE(pkt, IPCOM_PKT_ID_SOCKRECVQ);
|
|
iplite_sock_data_avail(sock, 0, IP_SHUT_RD);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* iplite_sock_data_avail
|
|
*===========================================================================
|
|
* Description: Is called each time data arrives to the socket so that
|
|
* ipcom_recvfrom() and ipcom_accept() can be called without
|
|
* blocking.
|
|
* Parameters: sock - The socket on which data arrived.
|
|
* so_errno: 0 = data, -1 = close else socket errno.
|
|
* Returns: 0 = success
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
iplite_sock_data_avail(Iplite_socket *sock, int so_errno, int how)
|
|
{
|
|
unsigned select_mask;
|
|
|
|
if (so_errno != 0)
|
|
{
|
|
/* so_errno == -1 means a close event. */
|
|
if (so_errno != -1)
|
|
{
|
|
sock->ipcom.so_errno = so_errno;
|
|
ip_assert(sock->ipcom.so_errno > 0);
|
|
}
|
|
|
|
if (sock->ipcom.event_cb != IP_NULL
|
|
&& IP_BIT_ISFALSE(sock->flags, IPLITE_SOCKET_FLAG_CLOSED))
|
|
{
|
|
(void)sock->ipcom.event_cb((Ipcom_socket *)sock, IP_NULL,
|
|
sock->ipcom.so_errno ? IP_SOEVENT_CB_ERRNO : IP_SOEVENT_CB_CLOSE);
|
|
/* There must be no more events after the close event. */
|
|
if (sock->ipcom.so_errno == 0)
|
|
sock->ipcom.event_cb = IP_NULL;
|
|
}
|
|
}
|
|
|
|
switch (how)
|
|
{
|
|
case IP_SHUT_RD:
|
|
select_mask = IPLITE_SELECT_RD;
|
|
break;
|
|
case IP_SHUT_WR:
|
|
select_mask = IPLITE_SELECT_WR;
|
|
break;
|
|
case IP_SHUT_RDWR:
|
|
select_mask = IPLITE_SELECT_RD | IPLITE_SELECT_WR;
|
|
break;
|
|
#ifdef IPCOM_USE_TCP
|
|
case IP_SHUT_EX:
|
|
select_mask = 0;
|
|
break;
|
|
#endif
|
|
default:
|
|
IP_PANIC2();
|
|
select_mask = 0;
|
|
break;
|
|
}
|
|
|
|
/* Socket blocked in recvfrom() */
|
|
if (IP_BIT_ISSET(select_mask, IPLITE_SELECT_RD) || sock->ipcom.so_errno)
|
|
{
|
|
/* Wake up the process that is sleeping on the socket */
|
|
if (sock->ipcom.event_cb != IP_NULL)
|
|
sock->ipcom.event_cb(&sock->ipcom, IP_NULL, IP_SOEVENT_CB_SELREAD);
|
|
#ifdef IP_PORT_OSE5_disabled_code
|
|
if (sock->ipcom.descs)
|
|
ipcom_crt_block_post((Ipcom_socket *)sock, IP_FALSE);
|
|
else
|
|
#endif
|
|
iplite_sock_wakeup_poll_list(&sock->rcv_poll_list);
|
|
}
|
|
|
|
if (IP_BIT_ISSET(select_mask, IPLITE_SELECT_WR) || sock->ipcom.so_errno)
|
|
{
|
|
/* Wake up the process(es) that waiting to send on the socket */
|
|
if (sock->ipcom.event_cb != IP_NULL)
|
|
sock->ipcom.event_cb(&sock->ipcom, IP_NULL, IP_SOEVENT_CB_SELWRITE);
|
|
#ifdef IP_PORT_OSE5_disabled_code
|
|
if (sock->ipcom.descs)
|
|
ipcom_crt_block_post((Ipcom_socket *)sock, IP_TRUE);
|
|
else
|
|
#endif
|
|
if (iplite_sock_is_writable(sock))
|
|
iplite_sock_wakeup_poll_list(&sock->snd_poll_list);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* iplite_do_getname
|
|
*===========================================================================
|
|
* Description: Returns the socket address of the local side (if bound) or
|
|
* the peer side (if connected).
|
|
* Parameters: fd - Socket descriptor.
|
|
* name - Will hold the socket address if the call succeeds.
|
|
* namelenp - The length of the 'name' buffer, will be updated
|
|
* to hold the actual size of 'name'.
|
|
* local - Set to IP_TRUE if the name of local size should be
|
|
* returned and IP_FALSE if the peer socket name should be returned.
|
|
* Returns: 0 = success, <0 negative error code.
|
|
*
|
|
*/
|
|
IP_GLOBAL int
|
|
iplite_do_getname(Ip_fd fd, struct Ip_sockaddr *name, Ip_socklen_t *namelenp, Ip_bool local)
|
|
{
|
|
Iplite_socket *sock;
|
|
|
|
ip_assert(name != IP_NULL);
|
|
ip_assert(namelenp != IP_NULL);
|
|
|
|
if (fd >= IPLITE_CONF_MAX_SOCKETS || iplite.sockets[fd] == IP_NULL)
|
|
return -IP_ERRNO_EBADF;
|
|
sock = iplite.sockets[fd];
|
|
|
|
#ifdef IPCOM_USE_INET
|
|
if (sock->ipcom.domain == IP_AF_INET)
|
|
{
|
|
struct Ip_sockaddr_in *name_in;
|
|
|
|
if (*namelenp < sizeof(struct Ip_sockaddr_in))
|
|
return -IP_ERRNO_ENOBUFS;
|
|
|
|
*namelenp = sizeof(struct Ip_sockaddr_in);
|
|
name_in = (struct Ip_sockaddr_in *)name;
|
|
ipcom_memset(name_in->sin_zero, 0, sizeof(name_in->sin_zero));
|
|
name_in->sin_len = sizeof(struct Ip_sockaddr_in);
|
|
name_in->sin_family = IP_AF_INET;
|
|
if (local)
|
|
{
|
|
name_in->sin_addr.s_addr = sock->d->ip4.saddr_n;
|
|
name_in->sin_port = ip_htons(sock->sport);
|
|
}
|
|
else
|
|
{
|
|
name_in->sin_addr.s_addr = sock->d->ip4.daddr_n;
|
|
name_in->sin_port = ip_htons(sock->dport);
|
|
}
|
|
}
|
|
else
|
|
#endif /* IPCOM_USE_INET */
|
|
|
|
#ifdef IPCOM_USE_INET6
|
|
if (sock->ipcom.domain == IP_AF_INET6)
|
|
{
|
|
struct Ip_sockaddr_in6 *name_in6;
|
|
|
|
if (*namelenp < sizeof(struct Ip_sockaddr_in6))
|
|
return -IP_ERRNO_ENOBUFS;
|
|
|
|
*namelenp = sizeof(struct Ip_sockaddr_in6);
|
|
name_in6 = (struct Ip_sockaddr_in6 *) name;
|
|
name_in6->sin6_len = sizeof(struct Ip_sockaddr_in6);
|
|
name_in6->sin6_family = IP_AF_INET6;
|
|
name_in6->sin6_scope_id = sock->d->ip6.scope_id;
|
|
name_in6->sin6_flowinfo = sock->d->ip6.flowinfo_n;
|
|
if (local)
|
|
{
|
|
name_in6->sin6_addr = sock->d->ip6.saddr;
|
|
name_in6->sin6_port = ip_htons(sock->sport);
|
|
}
|
|
else
|
|
{
|
|
name_in6->sin6_addr = sock->d->ip6.daddr;
|
|
name_in6->sin6_port = ip_htons(sock->dport);
|
|
}
|
|
}
|
|
else
|
|
#endif /* IPCOM_USE_INET6 */
|
|
{
|
|
IP_PANIC();
|
|
return -IP_ERRNO_EPROTONOSUPPORT;
|
|
}
|
|
|
|
if (!local && IP_BIT_ISFALSE(sock->flags, IPLITE_SOCKET_FLAG_CONNECTED))
|
|
return -IP_ERRNO_ENOTCONN;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* iplite_do_bind
|
|
*===========================================================================
|
|
* Description: Bind a socket to the specified address and port.
|
|
* Parameters: sock - A pointer to the socket data.
|
|
* name - The socket name (address and port).
|
|
* namelen - The length of the name variable.
|
|
* check_reuse - Set to IP_TRUE if the name should be checked
|
|
* for address reuse.
|
|
* Returns: 0 = success, <0 = error code
|
|
*
|
|
*/
|
|
IP_GLOBAL int
|
|
iplite_do_bind(Iplite_socket *sock, IP_CONST struct Ip_sockaddr *name,
|
|
Ip_socklen_t namelen, Ip_bool check_reuse)
|
|
{
|
|
Ip_bool is_addr_any = IP_FALSE;
|
|
int insert_index;
|
|
int end_index;
|
|
int err;
|
|
|
|
ip_assert(!IP_BIT_ISSET(sock->flags, IPLITE_SOCKET_FLAG_BOUND));
|
|
|
|
#ifdef IPCOM_USE_INET
|
|
if (sock->ipcom.domain == IP_AF_INET)
|
|
{
|
|
struct Ip_sockaddr_in *name_in;
|
|
|
|
if (namelen < sizeof(struct Ip_sockaddr_in))
|
|
{
|
|
err = -IP_ERRNO_EINVAL;
|
|
goto errout;
|
|
}
|
|
name_in = (struct Ip_sockaddr_in*)name;
|
|
|
|
/* Verify that IP address is either ANY (0) or one of my addresses.
|
|
* Note: it is ok to bind to any of the multicastcast addresses
|
|
* or the broadcast address.
|
|
*/
|
|
if (iplite_ip4_get_addr_type(IP_NULL, name_in->sin_addr.s_addr) ==
|
|
IPLITE_ADDR_TYPE_NOT_LOCAL)
|
|
{
|
|
err = -IP_ERRNO_EADDRNOTAVAIL;
|
|
goto errout;
|
|
}
|
|
|
|
sock->d->ip4.saddr_n = name_in->sin_addr.s_addr;
|
|
is_addr_any = (sock->d->ip4.saddr_n == IP_INADDR_ANY);
|
|
|
|
sock->sport = ip_ntohs(name_in->sin_port);
|
|
}
|
|
#endif /* IPCOM_USE_INET */
|
|
|
|
#ifdef IPCOM_USE_INET6
|
|
if (sock->ipcom.domain == IP_AF_INET6)
|
|
{
|
|
struct Ip_sockaddr_in6 *name_in6;
|
|
Iplite_netif *netif;
|
|
|
|
if (namelen < sizeof(struct Ip_sockaddr_in6))
|
|
{
|
|
err = -IP_ERRNO_EINVAL;
|
|
goto errout;
|
|
}
|
|
name_in6 = (struct Ip_sockaddr_in6*) name;
|
|
|
|
if (iplite_ip6_is_scoped_addr(&name_in6->sin6_addr)
|
|
&& name_in6->sin6_scope_id != IPLITE_IF_LOOPBACK_INDEX)
|
|
{
|
|
netif = iplite_if_indextonetif(name_in6->sin6_scope_id);
|
|
if (netif == IP_NULL)
|
|
{
|
|
err = -IP_ERRNO_EADDRNOTAVAIL;
|
|
goto errout;
|
|
}
|
|
}
|
|
else
|
|
netif = IP_NULL;
|
|
|
|
/* Verify that IP address is either iplite_in6addr_any or one of my addresses.
|
|
* Note: it is ok to bind to any of the multicast addresses.
|
|
*/
|
|
if (iplite_ip6_get_addr_type(netif, &name_in6->sin6_addr) ==
|
|
IPLITE_ADDR_TYPE_NOT_LOCAL)
|
|
{
|
|
err = -IP_ERRNO_EADDRNOTAVAIL;
|
|
goto errout;
|
|
}
|
|
|
|
sock->d->ip6.saddr = name_in6->sin6_addr;
|
|
sock->d->ip6.scope_id = name_in6->sin6_scope_id;
|
|
if (IP_IN6_IS_ADDR_UNSPECIFIED(&sock->d->ip6.saddr))
|
|
is_addr_any = IP_TRUE;
|
|
else
|
|
is_addr_any = IP_FALSE;
|
|
|
|
sock->sport = ip_ntohs(name_in6->sin6_port);
|
|
}
|
|
#endif /* IPCOM_USE_INET6 */
|
|
|
|
if (sock->proto == IP_IPPROTO_TCP || sock->proto == IP_IPPROTO_UDP)
|
|
{
|
|
/* If port 0, pick an ephemereal port */
|
|
if (sock->sport == 0)
|
|
{
|
|
sock->sport = iplite_next_ephemeral_port();
|
|
if (sock->sport == 0)
|
|
{
|
|
err = -IP_ERRNO_EADDRINUSE;
|
|
goto errout;
|
|
}
|
|
}
|
|
|
|
if (check_reuse && sock->ipcom.type != IP_SOCK_RAW)
|
|
{
|
|
err = iplite_bind_check_reuse(sock);
|
|
if (err < 0)
|
|
goto errout;
|
|
}
|
|
}
|
|
|
|
/* Insert socket in socket port cache (iplite.bound_sockets) */
|
|
ip_assert(iplite.bound_sockets[IPLITE_CONF_MAX_SOCKETS - 1] == IP_NULL);
|
|
|
|
for (end_index = 0; iplite.bound_sockets[end_index] != IP_NULL; end_index++)
|
|
/* Empty block*/;
|
|
|
|
for (insert_index = 0; iplite.bound_sockets[insert_index] != IP_NULL; insert_index++)
|
|
{
|
|
if (iplite.bound_sockets[insert_index]->sport > sock->sport)
|
|
break;
|
|
if (iplite.bound_sockets[insert_index]->sport == sock->sport)
|
|
{
|
|
if (iplite.bound_sockets[insert_index]->ipcom.domain > sock->ipcom.domain)
|
|
break;
|
|
if (!is_addr_any)
|
|
break;
|
|
}
|
|
}
|
|
/* insert_index contains the index of the first entry to move */
|
|
while (end_index != insert_index)
|
|
{
|
|
iplite.bound_sockets[end_index] = iplite.bound_sockets[end_index - 1];
|
|
end_index--;
|
|
}
|
|
iplite.bound_sockets[insert_index] = sock;
|
|
#ifndef IPLITE_MEM_OPT
|
|
iplite.socket_last = IP_NULL;
|
|
#endif
|
|
|
|
IP_BIT_SET(sock->flags, IPLITE_SOCKET_FLAG_BOUND);
|
|
return 0;
|
|
|
|
errout:
|
|
if (sock != IP_NULL)
|
|
sock->sport = 0;
|
|
return err;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* iplite_do_socket
|
|
*===========================================================================
|
|
* Description: Creates a new socket.
|
|
* Parameters: domain - The address domain.
|
|
* type - The socket type.
|
|
* protcol - The protocol the stack must use for communication
|
|
* when using this socket.
|
|
* Returns: 0 >= The new socket descriptor.
|
|
* 0 < error, error code can be read from ipcom_errno.
|
|
*
|
|
*/
|
|
IP_GLOBAL Ip_fd
|
|
iplite_do_socket(int domain, int type, int protocol, Ip_bool user_context)
|
|
{
|
|
Ip_fd fd;
|
|
int i;
|
|
Iplite_socket *sock = IP_NULL;
|
|
Ip_size_t size, offset;
|
|
|
|
/* Raw IP socket. */
|
|
if (type == IP_SOCK_RAW)
|
|
goto type_ok;
|
|
|
|
#ifdef IPCOM_USE_PACKET
|
|
if (domain == IP_AF_PACKET
|
|
&& (type == IP_SOCK_DGRAM || type == IP_SOCK_RAW))
|
|
goto type_ok;
|
|
#endif
|
|
|
|
if (domain == IP_AF_INET || domain == IP_AF_INET6)
|
|
{
|
|
if (type == IP_SOCK_DGRAM)
|
|
{
|
|
/* UDP socket. */
|
|
if (protocol == 0)
|
|
protocol = IP_IPPROTO_UDP;
|
|
if (protocol == IP_IPPROTO_UDP)
|
|
goto type_ok;
|
|
}
|
|
#ifdef IPCOM_USE_TCP
|
|
if (type == IP_SOCK_STREAM)
|
|
{
|
|
if (protocol == 0)
|
|
protocol = IP_IPPROTO_TCP;
|
|
if (protocol == IP_IPPROTO_TCP)
|
|
goto type_ok;
|
|
}
|
|
#endif /* IPCOM_USE_TCP */
|
|
}
|
|
|
|
/* Bad type or protocol. */
|
|
SOCK_ERROUT(IP_ERRNO_EPROTONOSUPPORT);
|
|
|
|
type_ok:
|
|
#ifdef IPCOM_USE_INET
|
|
if (domain == IP_AF_INET)
|
|
goto domain_ok;
|
|
#endif
|
|
#ifdef IPCOM_USE_INET6
|
|
if (domain == IP_AF_INET6)
|
|
goto domain_ok;
|
|
#endif
|
|
#ifdef IPIPSEC2
|
|
if (domain == IP_AF_KEY)
|
|
goto domain_ok;
|
|
#endif
|
|
#ifdef IPCOM_USE_PACKET
|
|
if (domain == IP_AF_PACKET)
|
|
goto domain_ok;
|
|
#endif
|
|
|
|
/* Invalid domain. */
|
|
SOCK_ERROUT(IP_ERRNO_EAFNOSUPPORT);
|
|
|
|
/* Find an available socket descriptor slot. */
|
|
domain_ok:
|
|
for (i = 1; i <= IPLITE_CONF_MAX_SOCKETS - IPLITE_SOCKET_STARTFD; i++)
|
|
{
|
|
Ip_size_t max_hdrspace;
|
|
|
|
fd = (iplite.last_fd - IPLITE_SOCKET_STARTFD + i)
|
|
% (IPLITE_CONF_MAX_SOCKETS - IPLITE_SOCKET_STARTFD) + IPLITE_SOCKET_STARTFD;
|
|
if (iplite.sockets[fd] != IP_NULL)
|
|
continue;
|
|
|
|
max_hdrspace = 0;
|
|
size = sizeof(Iplite_socket);
|
|
|
|
#ifdef IPCOM_USE_INET
|
|
if (domain == IP_AF_INET)
|
|
{
|
|
max_hdrspace = IPLITE_IP_HDR_SIZE;
|
|
size += sizeof(Iplite_ip4_socket);
|
|
}
|
|
#endif /* IPCOM_USE_INET */
|
|
|
|
#ifdef IPCOM_USE_INET6
|
|
if (domain == IP_AF_INET6)
|
|
{
|
|
max_hdrspace = IPLITE_IP6_HDR_SIZE;
|
|
size += sizeof(Iplite_ip6_socket);
|
|
}
|
|
#endif /* IPCOM_USE_INET6 */
|
|
|
|
#ifdef IPCOM_USE_TCP
|
|
if (protocol == IP_IPPROTO_TCP)
|
|
size += sizeof(Iplite_tcp_tcb);
|
|
#endif /* IPCOM_USE_TCP */
|
|
|
|
#if defined(IP_PORT_VXWORKS) && defined(IPCOM_USE_SOCK_COMPAT)
|
|
|
|
|
|
size += ipcom_windnet_socklib_sock_size();
|
|
#endif
|
|
|
|
#ifdef IPIPSEC2
|
|
if (domain == IP_AF_KEY)
|
|
max_hdrspace = 8; /* to get 64 bit alignment. */
|
|
#endif /* IPIPSEC2 */
|
|
sock = iplite_kmalloc(size);
|
|
if (sock == IP_NULL)
|
|
SOCK_ERROUT(IP_ERRNO_ENOMEM);
|
|
|
|
/* Init socket */
|
|
ipcom_list_init(&sock->rcv_poll_list);
|
|
ipcom_list_init(&sock->snd_poll_list);
|
|
sock->ref_count = 1;
|
|
sock->ipcom.fd = (Ip_fd)fd;
|
|
sock->ipcom.domain = (Ip_u16)domain;
|
|
sock->proto = (Ip_u16)protocol;
|
|
sock->ipcom.type = (Ip_u16)type;
|
|
sock->max_hdrspace = (Ip_u16)max_hdrspace;
|
|
sock->uni_hop_limit = IPLITE_CONF_SOCK_BASE_HOP_LIMIT;
|
|
sock->multi_hop_limit = 1;
|
|
sock->ipcom.pid = ipcom_getpid();
|
|
sock->snd_max_bytes = IPLITE_CONF_SOCK_DEFAULT_SEND_BUF_SIZE;
|
|
sock->rcv_max_bytes = IPLITE_CONF_SOCK_DEFAULT_RECV_BUF_SIZE;
|
|
IP_BIT_SET(sock->flags, IPLITE_SOCKET_FLAG_LOOP_MULTICAST);
|
|
sock->transport_output = iplite_raw_output;
|
|
|
|
offset = sizeof(Iplite_socket);
|
|
|
|
#if defined(IP_PORT_VXWORKS) && defined(IPCOM_USE_SOCK_COMPAT)
|
|
|
|
if (size > offset)
|
|
{
|
|
sock->select_ctx = (void *)((Ip_u8 *)sock + offset);
|
|
offset += ipcom_windnet_socklib_sock_size();
|
|
}
|
|
#endif
|
|
|
|
if (size > offset)
|
|
sock->d = (Iplite_socket_domain *) ((Ip_u8 *)sock + offset);
|
|
|
|
if (domain == IP_AF_INET || domain == IP_AF_INET6)
|
|
{
|
|
switch (protocol)
|
|
{
|
|
case IP_IPPROTO_UDP:
|
|
sock->transport_output = iplite_udp_output;
|
|
sock->max_hdrspace += IPLITE_UDP_HDR_SIZE;
|
|
IP_BIT_SET(sock->flags, IPLITE_SOCKET_FLAG_ADDCHECKSUM);
|
|
sock->chk_offset = 6;
|
|
break;
|
|
#ifdef IPCOM_USE_TCP
|
|
case IP_IPPROTO_TCP:
|
|
sock->tcb = (Iplite_tcp_tcb *) ((Ip_u8 *)sock + offset);
|
|
sock->d = (Iplite_socket_domain *) (sock->tcb + 1);
|
|
iplite_tcp_sock_init(sock);
|
|
if (user_context)
|
|
/* Socket create in user-context, add an extra reference for the TCP module */
|
|
IPLITE_SOCK_ADD_REF(sock);
|
|
/* else: the TCP module will add an reference for the user when returning
|
|
the socket in accept() */
|
|
sock->max_hdrspace += IPLITE_TCP_HDR_SIZE;
|
|
IP_BIT_SET(sock->flags, IPLITE_SOCKET_FLAG_ADDCHECKSUM);
|
|
sock->chk_offset = 16;
|
|
break;
|
|
#endif /* IPCOM_USE_TCP */
|
|
case IP_IPPROTO_ICMPV6:
|
|
IP_BIT_SET(sock->flags, IPLITE_SOCKET_FLAG_ADDCHECKSUM);
|
|
sock->chk_offset = 2;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Success. */
|
|
iplite.last_fd = fd;
|
|
iplite.sockets[fd] = sock;
|
|
#ifdef IPCOM_USE_PACKET
|
|
if (sock->ipcom.domain == IP_AF_PACKET)
|
|
{
|
|
sock->transport_output = iplite_packet_output;
|
|
iplite.num_packet_sock++;
|
|
}
|
|
#endif
|
|
|
|
return fd;
|
|
}
|
|
|
|
/* No free socket slot found. */
|
|
(void)ipcom_errno_set(IP_ERRNO_EMFILE);
|
|
|
|
errout:
|
|
if (sock != IP_NULL)
|
|
iplite_kfree(sock);
|
|
return IP_SOCKERR;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* iplite_sock_drop_all_multicast_memberships
|
|
*===========================================================================
|
|
* Description: Drops all multicast memberships this socket has.
|
|
* Parameters: sock - a socket.
|
|
* netif - IP_NULL to dropp all multicast memberships or the
|
|
* interface for which all multicast memberships should be dropped.
|
|
* Returns: Number of multicast memberships that were dropped.
|
|
*/
|
|
IP_GLOBAL int
|
|
iplite_sock_drop_all_multicast_memberships(Iplite_socket *sock, Iplite_netif *netif, Ip_bool drop_ip4, Ip_bool drop_ip6)
|
|
{
|
|
int drop_count = 0;
|
|
|
|
#ifdef IPCOM_USE_INET
|
|
if (drop_ip4 && sock->ipcom.domain == IP_AF_INET)
|
|
{
|
|
struct Iplite_ip4_socket_multicast_data **mlt_it;
|
|
struct Iplite_ip4_socket_multicast_data *mlt;
|
|
|
|
mlt_it = &sock->d->ip4.multicast_addr_list;
|
|
while (*mlt_it != IP_NULL)
|
|
{
|
|
mlt = *mlt_it;
|
|
if (netif == IP_NULL || mlt->netif == netif)
|
|
{
|
|
drop_count++;
|
|
*mlt_it = mlt->next;
|
|
(void) iplite_ip4_remove_addr(mlt->netif, mlt->addr.s_addr);
|
|
iplite_kfree(mlt);
|
|
}
|
|
else
|
|
mlt_it = &mlt->next;
|
|
}
|
|
}
|
|
#else
|
|
(void)drop_ip4;
|
|
#endif /* IPCOM_USE_INET */
|
|
|
|
#ifdef IPCOM_USE_INET6
|
|
if (drop_ip6 && sock->ipcom.domain == IP_AF_INET6)
|
|
{
|
|
struct Iplite_ip6_socket_multicast_data **mlt_it;
|
|
struct Iplite_ip6_socket_multicast_data *mlt;
|
|
|
|
mlt_it = &sock->d->ip6.multicast_addr_list;
|
|
while (*mlt_it != IP_NULL)
|
|
{
|
|
mlt = *mlt_it;
|
|
if (netif == IP_NULL || mlt->netif == netif)
|
|
{
|
|
drop_count++;
|
|
*mlt_it = mlt->next;
|
|
(void) iplite_ip6_remove_addr(mlt->netif, &mlt->addr);
|
|
iplite_kfree(mlt);
|
|
}
|
|
else
|
|
mlt_it = &mlt->next;
|
|
}
|
|
}
|
|
#else
|
|
(void)drop_ip6;
|
|
#endif /* IPCOM_USE_INET6 */
|
|
|
|
return drop_count;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* iplite_do_socketselect
|
|
*===========================================================================
|
|
* Description: Checks if any of the sockets in a set is ready for reading,
|
|
* writing or have an exceptional condition.
|
|
* Parameters: ndfs - The first 'ndfs' descriptors are checked in each set
|
|
* i.e., the descriptors from 0 through nfds-1 in the descriptor
|
|
* sets are examined.
|
|
* readfds - The set of descriptors that should be checked for
|
|
* reading.
|
|
* writefds - The set of descriptors that should be checked for
|
|
* writing (sockets are always writeable)
|
|
* exceptfds - The set of descriptors that should be checked for
|
|
* exceptions (not supported, must be IP_NULL).
|
|
* Returns: The total number of ready descriptors in each set.
|
|
*
|
|
*/
|
|
IP_GLOBAL int
|
|
iplite_do_socketselect(int nfds,
|
|
Ip_fd_set *readfds,
|
|
Ip_fd_set *writefds,
|
|
Ip_fd_set *exceptfds,
|
|
struct Ip_timeval *timeout)
|
|
{
|
|
int num;
|
|
Ip_s32 msec;
|
|
Ipcom_block select_event = IPCOM_BLOCK_INVALID;
|
|
|
|
(void)exceptfds;
|
|
|
|
ip_assert2(nfds > IPLITE_SOCKET_STARTFD);
|
|
|
|
IPLITE_CODE_ISLOCKED_ASSERT();
|
|
|
|
msec = iplite_timeval_to_msec(timeout);
|
|
if (msec < -1)
|
|
SOCK_ERROUT(IP_ERRNO_EINVAL);
|
|
if (msec != 0)
|
|
{
|
|
if (ipcom_block_create(&select_event) != IPCOM_SUCCESS)
|
|
SOCK_ERROUT(IP_ERRNO_ENOMEM);
|
|
}
|
|
num = iplite_sock_select(IPLITE_SOCKET_STARTFD,
|
|
nfds,
|
|
readfds,
|
|
writefds,
|
|
select_event, msec);
|
|
|
|
if (select_event != IPCOM_BLOCK_INVALID)
|
|
(void)ipcom_block_delete(&select_event);
|
|
|
|
if (num < 0)
|
|
SOCK_ERROUT(-num);
|
|
|
|
return num;
|
|
|
|
errout:
|
|
return IP_SOCKERR;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* iplite_do_close
|
|
*===========================================================================
|
|
* Description: Closes the socket (tear down connections).
|
|
* Parameters: fd - A valid socket desriptor.
|
|
* Returns: 0 = success
|
|
*/
|
|
IP_GLOBAL int
|
|
iplite_do_close(Iplite_socket *sock)
|
|
{
|
|
ip_assert(sock != IP_NULL);
|
|
|
|
IPLITE_SOCK_ADD_REF(sock);
|
|
|
|
(void) iplite_do_shutdown(sock->ipcom.fd, IP_SHUT_RDWR);
|
|
#ifdef IPCOM_USE_TCP
|
|
if (sock->tcb != IP_NULL)
|
|
(void)iplite_tcp_close(sock);
|
|
#endif /* IPCOM_USE_TCP */
|
|
--sock->ref_count;
|
|
|
|
IPLITE_SOCK_DEL_REF(sock);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* iplite_sock_free
|
|
*===========================================================================
|
|
* Description: Frees all memory allocated by a socket.
|
|
* Parameters: sock - The socket to free.
|
|
* Returns:
|
|
*/
|
|
IP_PUBLIC void
|
|
iplite_sock_free(Iplite_socket *sock)
|
|
{
|
|
Ipcom_pkt *pkt;
|
|
|
|
ip_assert(sock != IP_NULL);
|
|
ip_assert(sock->ipcom.fd < IPLITE_CONF_MAX_SOCKETS);
|
|
ip_assert(sock->ipcom.fd >= IPLITE_SOCKET_STARTFD);
|
|
ip_assert(iplite.sockets[sock->ipcom.fd] == sock);
|
|
|
|
if (sock->ipcom.event_cb != IP_NULL)
|
|
(void)sock->ipcom.event_cb((Ipcom_socket *)sock, IP_NULL, IP_SOEVENT_CB_CLOSE);
|
|
|
|
iplite_sock_unbind(sock);
|
|
(void) iplite_sock_drop_all_multicast_memberships(sock, IP_NULL, IP_TRUE, IP_TRUE);
|
|
#ifdef IPCOM_USE_TCP
|
|
if (sock->tcb != IP_NULL)
|
|
iplite_tcp_sock_free(sock);
|
|
#endif /* IPCOM_USE_TCP */
|
|
|
|
/* Free any pending packets */
|
|
while (sock->rcv_head != IP_NULL)
|
|
{
|
|
pkt = sock->rcv_head;
|
|
sock->rcv_head = pkt->next;
|
|
ipcom_pkt_free(pkt);
|
|
}
|
|
|
|
#ifndef IPLITE_MEM_OPT
|
|
iplite.socket_last = IP_NULL;
|
|
#endif
|
|
iplite.sockets[sock->ipcom.fd] = IP_NULL;
|
|
|
|
#ifdef IPCOM_USE_PACKET
|
|
if (sock->ipcom.domain == IP_AF_PACKET)
|
|
iplite.num_packet_sock--;
|
|
#endif
|
|
|
|
iplite_kfree(sock);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* iplite_ip4_socklookup
|
|
*===========================================================================
|
|
* Description: Returns the IPv4 socket matching the parameters.
|
|
* Parameters: proto - The protocol the returned socket should be using.
|
|
* local_addr_ptr - The IPv4 address in network order of the
|
|
* local address to match or IP_NULL if any address should match.
|
|
* local_port - The source port in HOST byte order or 0 if any
|
|
* source port should match.
|
|
* peer_addr_n - The IPv4 address in network order of the
|
|
* peer address to match or IP_NULL if any address should match.
|
|
* peer_port - The destination port in HOST byte order or 0 if any
|
|
* destination port should match.
|
|
* Returns: A pointer to the matching socket or IP_NULL if no socket match.
|
|
*
|
|
*/
|
|
#ifdef IPCOM_USE_INET
|
|
IP_GLOBAL Iplite_socket *
|
|
iplite_ip4_socklookup(int proto, Ip_u32 *local_addr_ptr, Ip_u16 local_port,
|
|
Ip_u32 *peer_addr_ptr, Ip_u16 peer_port, int *next)
|
|
{
|
|
int i;
|
|
Ip_u32 local_addr_n = (local_addr_ptr == IP_NULL ? IP_INADDR_ANY : *local_addr_ptr);
|
|
Ip_u32 peer_addr_n = (peer_addr_ptr == IP_NULL ? IP_INADDR_ANY : *peer_addr_ptr);
|
|
Iplite_socket *sock;
|
|
|
|
#ifndef IPLITE_MEM_OPT
|
|
if (next == IP_NULL && iplite.socket_last != IP_NULL &&
|
|
iplite.socket_last->ipcom.domain == IP_AF_INET &&
|
|
iplite.socket_last->proto == proto &&
|
|
iplite.socket_last->sport == local_port &&
|
|
iplite.socket_last->dport == peer_port &&
|
|
local_addr_n == iplite.socket_last->d->ip4.saddr_n &&
|
|
peer_addr_n == iplite.socket_last->d->ip4.daddr_n)
|
|
{
|
|
/* The socket that matched the last time also matched this packet */
|
|
return iplite.socket_last;
|
|
}
|
|
#endif
|
|
|
|
for (i = (next == IP_NULL ? 0 : *next); i < IPLITE_CONF_MAX_SOCKETS; i++)
|
|
{
|
|
if (proto == IP_IPPROTO_TCP || proto == IP_IPPROTO_UDP)
|
|
sock = iplite.bound_sockets[i];
|
|
else
|
|
sock = iplite.sockets[i];
|
|
if (sock == IP_NULL)
|
|
continue;
|
|
if (sock->ipcom.domain != IP_AF_INET)
|
|
continue;
|
|
if (sock->proto && sock->proto != proto)
|
|
continue;
|
|
if (proto == IP_IPPROTO_TCP || proto == IP_IPPROTO_UDP)
|
|
{
|
|
if (local_port != 0 && sock->sport != local_port)
|
|
continue;
|
|
if (peer_port != 0 && sock->dport != 0 && sock->dport != peer_port)
|
|
continue;
|
|
if (local_addr_n != IP_INADDR_ANY
|
|
&& sock->d->ip4.saddr_n != IP_INADDR_ANY
|
|
&& local_addr_n != sock->d->ip4.saddr_n)
|
|
continue;
|
|
if (peer_addr_n != IP_INADDR_ANY
|
|
&& sock->d->ip4.daddr_n != IP_INADDR_ANY
|
|
&& peer_addr_n != sock->d->ip4.daddr_n)
|
|
continue;
|
|
}
|
|
#ifndef IPLITE_MEM_OPT
|
|
if (!(sock->flags & (IPLITE_SOCKET_FLAG_REUSEADDR | IPLITE_SOCKET_FLAG_REUSEPORT)))
|
|
iplite.socket_last = sock;
|
|
#endif
|
|
if (next != IP_NULL)
|
|
*next = i + 1;
|
|
return sock;
|
|
}
|
|
return IP_NULL;
|
|
}
|
|
#endif /* IPCOM_USE_INET */
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* iplite_ip6_socklookup
|
|
*===========================================================================
|
|
* Description: Returns the IPv6 socket matching the parameters. Source is
|
|
* always this host and the destination is the peer.
|
|
* Parameters: proto - The protocol the returned socket should be using.
|
|
* src_addr - The IPv6 source address in NETWORK byte order or
|
|
* the undefined address (all zeros) if all addresses should
|
|
* match. IP_NULL is will also be interpreted as the undefined
|
|
* address.
|
|
* local_port - The source port in HOST byte order or 0 if any
|
|
* source port should match.
|
|
* dst_addr - The IPv6 destination address in NETWORK byte order
|
|
* or the undefined address (all zeros) if all addresses should
|
|
* match. IP_NULL is will also be interpreted as the undefined
|
|
* address.
|
|
* peer_port - The destination port in HOST byte order or 0 if any
|
|
* destination port should match.
|
|
* next - Index of the next socket to test. Set to IP_NULL if
|
|
* only the first match is interesting.
|
|
* Returns: A pointer to the matching socket or IP_NULL if no socket match.
|
|
*
|
|
*/
|
|
#ifdef IPCOM_USE_INET6
|
|
IP_GLOBAL Iplite_socket*
|
|
iplite_ip6_socklookup(int proto, struct Ip_in6_addr *local_addr, Ip_u16 local_port,
|
|
struct Ip_in6_addr *peer_addr, Ip_u16 peer_port, int *next)
|
|
{
|
|
int i;
|
|
Iplite_socket *sock;
|
|
|
|
if (local_addr != IP_NULL && IP_IN6_IS_ADDR_UNSPECIFIED(local_addr))
|
|
local_addr = IP_NULL;
|
|
if (peer_addr != IP_NULL && IP_IN6_IS_ADDR_UNSPECIFIED(peer_addr))
|
|
peer_addr = IP_NULL;
|
|
|
|
#ifndef IPLITE_MEM_OPT
|
|
if (next == IP_NULL && iplite.socket_last != IP_NULL &&
|
|
iplite.socket_last->ipcom.domain == IP_AF_INET6 &&
|
|
iplite.socket_last->proto == proto &&
|
|
iplite.socket_last->sport == local_port &&
|
|
iplite.socket_last->dport == peer_port &&
|
|
local_addr != IP_NULL && IP_IN6_ARE_ADDR_EQUAL(local_addr, &iplite.socket_last->d->ip6.saddr) &&
|
|
peer_addr != IP_NULL && IP_IN6_ARE_ADDR_EQUAL(peer_addr, &iplite.socket_last->d->ip6.daddr))
|
|
{
|
|
/* The socket that matched the last time also matched this packet */
|
|
return iplite.socket_last;
|
|
}
|
|
#endif
|
|
|
|
for (i = (next == IP_NULL ? 0 : *next); i < IPLITE_CONF_MAX_SOCKETS; i++)
|
|
{
|
|
if (proto == IP_IPPROTO_TCP || proto == IP_IPPROTO_UDP)
|
|
sock = iplite.bound_sockets[i];
|
|
else
|
|
sock = iplite.sockets[i];
|
|
if (sock == IP_NULL)
|
|
continue;
|
|
if (sock->ipcom.domain != IP_AF_INET6)
|
|
continue;
|
|
if (sock->proto && sock->proto != proto)
|
|
continue;
|
|
if (proto == IP_IPPROTO_TCP || proto == IP_IPPROTO_UDP)
|
|
{
|
|
if (local_port != 0 && sock->sport != local_port)
|
|
continue;
|
|
if (peer_port != 0 && sock->dport != 0 && sock->dport != peer_port)
|
|
continue;
|
|
if (local_addr != IP_NULL &&
|
|
!IP_IN6_IS_ADDR_UNSPECIFIED(&sock->d->ip6.saddr) &&
|
|
!IP_IN6_ARE_ADDR_EQUAL(local_addr, &sock->d->ip6.saddr))
|
|
continue;
|
|
if (peer_addr != IP_NULL &&
|
|
!IP_IN6_IS_ADDR_UNSPECIFIED(&sock->d->ip6.daddr) &&
|
|
!IP_IN6_ARE_ADDR_EQUAL(peer_addr, &sock->d->ip6.daddr))
|
|
continue;
|
|
}
|
|
#ifndef IPLITE_MEM_OPT
|
|
if (!(sock->flags & (IPLITE_SOCKET_FLAG_REUSEADDR | IPLITE_SOCKET_FLAG_REUSEPORT)))
|
|
iplite.socket_last = sock;
|
|
#endif
|
|
if (next != IP_NULL)
|
|
*next = i + 1;
|
|
return sock;
|
|
}
|
|
return IP_NULL;
|
|
}
|
|
#endif /* IPCOM_USE_INET6 */
|
|
|
|
/*
|
|
*===========================================================================
|
|
* iplite_sock_unbind
|
|
*===========================================================================
|
|
* Description: Unbind the specific UDP or TCP socket.
|
|
* Parameters: sock - The socket to unbind.
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
iplite_sock_unbind(Iplite_socket *sock)
|
|
{
|
|
int r; /* The index of the socket to remove */
|
|
|
|
if (!IP_BIT_ISSET(sock->flags, IPLITE_SOCKET_FLAG_BOUND))
|
|
return;
|
|
|
|
/* Unbind the socket */
|
|
for (r = 0; r < IPLITE_CONF_MAX_SOCKETS && iplite.bound_sockets[r] != IP_NULL; r++)
|
|
{
|
|
if (iplite.bound_sockets[r] == sock)
|
|
{
|
|
int i;
|
|
|
|
for (i = r; i < IPLITE_CONF_MAX_SOCKETS && iplite.bound_sockets[i] != IP_NULL; i++)
|
|
{
|
|
if (i + 1 < IPLITE_CONF_MAX_SOCKETS)
|
|
iplite.bound_sockets[i] = iplite.bound_sockets[i + 1];
|
|
else
|
|
iplite.bound_sockets[i] = IP_NULL;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
ip_assert(r < IPLITE_CONF_MAX_SOCKETS);
|
|
sock->sport = 0;
|
|
|
|
IP_BIT_CLR(sock->flags, IPLITE_SOCKET_FLAG_BOUND);
|
|
}
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 11 PUBLIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipcom_socket
|
|
*===========================================================================
|
|
* Description: Creates a new socket.
|
|
* Parameters: domain - The address domain for this socket (IP_AF_xxx).
|
|
* type - The type of socket (IPLITE_SOCK_xxx).
|
|
* protocol - The protocol to use or 0 to select the default
|
|
* protocol for the selected socket type.
|
|
* Returns: >=0 the socket descriptor, -1 = error.
|
|
*
|
|
*/
|
|
IP_PUBLIC Ip_fd
|
|
ipcom_socket(int domain, int type, int protocol)
|
|
{
|
|
Ip_fd fd;
|
|
|
|
/* Block all ipcom_socket() calls until the stack is configured */
|
|
while (IP_BIT_ISFALSE(iplite_flags, IPLITE_FLAG_CONFIGURED))
|
|
ipcom_millisleep(10);
|
|
|
|
IPLITE_CODE_LOCK();
|
|
fd = iplite_do_socket(domain, type, protocol, IP_TRUE);
|
|
IPLITE_CODE_UNLOCK();
|
|
return fd;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipcom_shutdown
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_PUBLIC int
|
|
ipcom_shutdown(Ip_fd fd, int how)
|
|
{
|
|
int ret;
|
|
|
|
IPLITE_CODE_LOCK();
|
|
ret = iplite_do_shutdown(fd, how);
|
|
IPLITE_CODE_UNLOCK();
|
|
return ret;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipcom_socketclose
|
|
*===========================================================================
|
|
* Description: Closes a socket.
|
|
* Parameters: fd - The socket to close.
|
|
* Returns: 0= success, -1 = error
|
|
*
|
|
*/
|
|
IP_PUBLIC int
|
|
ipcom_socketclose(Ip_fd fd)
|
|
{
|
|
int ret;
|
|
Iplite_socket *sock;
|
|
|
|
ip_assert2(fd >= IPLITE_SOCKET_STARTFD);
|
|
ip_assert2(fd < IPLITE_CONF_MAX_SOCKETS);
|
|
ip_assert2(iplite.sockets[fd] != IP_NULL);
|
|
|
|
IPLITE_CODE_LOCK();
|
|
|
|
if (fd < IPLITE_SOCKET_STARTFD
|
|
|| fd >= IPLITE_CONF_MAX_SOCKETS
|
|
|| IP_NULL == (sock = iplite.sockets[fd])
|
|
|| IP_BIT_ISSET(sock->flags, IPLITE_SOCKET_FLAG_CLOSED))
|
|
{
|
|
ret = -IP_ERRNO_EBADF;
|
|
goto errout;
|
|
}
|
|
IP_BIT_SET(sock->flags, IPLITE_SOCKET_FLAG_CLOSED);
|
|
|
|
(void)iplite_do_close(sock);
|
|
|
|
IPLITE_CODE_UNLOCK();
|
|
return 0;
|
|
|
|
errout:
|
|
ip_assert(ret < 0);
|
|
(void)ipcom_errno_set(-ret);
|
|
IPLITE_CODE_UNLOCK();
|
|
return IP_SOCKERR;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipcom_socketselect
|
|
*===========================================================================
|
|
* Description: Checks if any of the sockets in a set is ready for reading,
|
|
* writing or have an exceptional condition.
|
|
* Parameters: ndfs - The first 'ndfs' descriptors are checked in each set
|
|
* i.e., the descriptors from 0 through nfds-1 in the descriptor
|
|
* sets are examined.
|
|
* readfds - The set of descriptors that should be checked for
|
|
* reading.
|
|
* writefds - The set of descriptors that should be checked for
|
|
* writing (sockets are always writeable)
|
|
* exceptfds - The set of descriptors that should be checked for
|
|
* exceptions (not supported, must be IP_NULL).
|
|
* Returns: The total number of ready descriptors in each set.
|
|
*
|
|
*/
|
|
IP_PUBLIC int
|
|
ipcom_socketselect(int nfds,
|
|
Ip_fd_set *readfds,
|
|
Ip_fd_set *writefds,
|
|
Ip_fd_set *exceptfds,
|
|
struct Ip_timeval *timeout)
|
|
{
|
|
int num;
|
|
|
|
IPLITE_CODE_LOCK();
|
|
num = iplite_do_socketselect(nfds, readfds, writefds, exceptfds, timeout);
|
|
IPLITE_CODE_UNLOCK();
|
|
return num;
|
|
}
|
|
|
|
|
|
#ifdef IPCOM_USE_TCP
|
|
/*
|
|
*===========================================================================
|
|
* ipcom_listen
|
|
*===========================================================================
|
|
* Description: Places a socket a state where it is listening for incoming
|
|
* connection(s).
|
|
* Parameters: fd - a bound, unconnected socket.
|
|
* backlog - The maximum length of the queue of pending
|
|
* connections. Use IPLITE_SOMAXCONN to get a maximum reasonable
|
|
* value
|
|
* Returns: 0 = success, -1 = error.
|
|
*
|
|
*/
|
|
IP_PUBLIC int
|
|
ipcom_listen(Ip_fd fd, int backlog)
|
|
{
|
|
Iplite_socket *sock;
|
|
int err;
|
|
|
|
ip_assert2(fd >= IPLITE_SOCKET_STARTFD);
|
|
ip_assert2(fd < IPLITE_CONF_MAX_SOCKETS);
|
|
ip_assert2(iplite.sockets[fd] != IP_NULL);
|
|
|
|
IPLITE_CODE_LOCK();
|
|
|
|
sock = iplite.sockets[fd];
|
|
if (sock == IP_NULL)
|
|
SOCK_ERROUT(IP_ERRNO_EBADF);
|
|
|
|
err = iplite_tcp_listen(sock, backlog);
|
|
if (err < 0)
|
|
SOCK_ERROUT(-err);
|
|
|
|
IPLITE_CODE_UNLOCK();
|
|
return err;
|
|
|
|
errout:
|
|
IPLITE_CODE_UNLOCK();
|
|
return IP_SOCKERR;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipcom_accept
|
|
*===========================================================================
|
|
* Description: Accepts an incoming connection attempt on a socket.
|
|
* Parameters: fd - A socket that is in listen state (ipcom_listen()) has
|
|
* been called.
|
|
* name - Will hold the address of the peer (set to IP_NULL if
|
|
* that information is not wanted).
|
|
* addrlen - Must be initialized to the length of the 'name'
|
|
* buffer, will hold the actual 'name' length upon return.
|
|
* Set to IP_NULL if 'name' is IP_NULL.
|
|
* Returns: 0>= the socket to use for communication (success), -1 = error.
|
|
*
|
|
*/
|
|
IP_PUBLIC int
|
|
ipcom_accept(Ip_fd fd, struct Ip_sockaddr *name, Ip_socklen_t *namelen)
|
|
{
|
|
Iplite_socket *sock;
|
|
Ip_fd new_fd;
|
|
|
|
ip_assert2(fd >= IPLITE_SOCKET_STARTFD);
|
|
ip_assert2(fd < IPLITE_CONF_MAX_SOCKETS);
|
|
ip_assert2(iplite.sockets[fd] != IP_NULL);
|
|
|
|
IPLITE_CODE_LOCK();
|
|
|
|
sock = iplite.sockets[fd];
|
|
if (sock == IP_NULL)
|
|
SOCK_ERROUT(IP_ERRNO_EBADF);
|
|
|
|
if (IP_BIT_ISFALSE(sock->flags, IPLITE_SOCKET_FLAG_NONBLOCKING))
|
|
{
|
|
Ip_fd_set rd_set;
|
|
|
|
IP_FD_ZERO(&rd_set);
|
|
IP_FD_SET(fd, &rd_set);
|
|
|
|
if (iplite_do_socketselect(fd + 1,
|
|
&rd_set,
|
|
IP_NULL,
|
|
IP_NULL,
|
|
IP_NULL) < 0)
|
|
/* errno already set */
|
|
goto errout;
|
|
}
|
|
|
|
new_fd = iplite_tcp_accept(sock, name, namelen);
|
|
if (new_fd < 0)
|
|
SOCK_ERROUT(-new_fd);
|
|
|
|
IPLITE_CODE_UNLOCK();
|
|
return new_fd;
|
|
|
|
errout:
|
|
IPLITE_CODE_UNLOCK();
|
|
return IP_SOCKERR;
|
|
}
|
|
#endif /* IPCOM_USE_TCP */
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipcom_bind
|
|
*===========================================================================
|
|
* Description: Assigns a name to a unnamed socket.
|
|
* Parameters: fd - The socket to name.
|
|
* name - The socket name.
|
|
* namelen - The length of the name buffer.
|
|
* Returns: 0 = success, -1 = error
|
|
*
|
|
*/
|
|
IP_PUBLIC int
|
|
ipcom_bind(Ip_fd fd, IP_CONST struct Ip_sockaddr *name, Ip_socklen_t namelen)
|
|
{
|
|
Iplite_socket *sock;
|
|
int err;
|
|
|
|
ip_assert2(fd >= IPLITE_SOCKET_STARTFD);
|
|
ip_assert2(fd < IPLITE_CONF_MAX_SOCKETS);
|
|
ip_assert2(iplite.sockets[fd] != IP_NULL);
|
|
ip_assert2(name != IP_NULL);
|
|
ip_assert2(namelen > 0);
|
|
|
|
IPLITE_CODE_LOCK();
|
|
|
|
sock = iplite.sockets[fd];
|
|
if (sock == IP_NULL)
|
|
SOCK_ERROUT(IP_ERRNO_EBADF);
|
|
|
|
#ifdef IPLITE_COMPAT_OLDSOCK
|
|
if (name->sa_family == 0 && name->sa_len < IP_AF_MAX)
|
|
((struct Ip_sockaddr *)name)->sa_family = name->sa_len;
|
|
((struct Ip_sockaddr *)name)->sa_len = (Ip_u8) namelen;
|
|
#endif
|
|
ip_assert(name->sa_len > 0);
|
|
|
|
if (name->sa_family != sock->ipcom.domain)
|
|
/* Wrong domain in socket name */
|
|
SOCK_ERROUT(IP_ERRNO_EINVAL);
|
|
|
|
if (IP_BIT_ISSET(sock->flags, IPLITE_SOCKET_FLAG_BOUND))
|
|
/* Socket already bound. */
|
|
SOCK_ERROUT(IP_ERRNO_EINVAL);
|
|
|
|
err = iplite_do_bind(sock, name, namelen, IP_TRUE);
|
|
if (err < 0)
|
|
SOCK_ERROUT(-err);
|
|
|
|
/* success. */
|
|
IPLITE_CODE_UNLOCK();
|
|
return 0;
|
|
|
|
errout:
|
|
IPLITE_CODE_UNLOCK();
|
|
return (int)IP_SOCKERR;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipcom_connect
|
|
*===========================================================================
|
|
* Description: Connects the socket to a specified peer.
|
|
* Parameters: fd - The socket to connect.
|
|
* to - The address of the peer.
|
|
* tolen - The length of the to buffer.
|
|
* Returns: 0= connection was successful, -1 = error.
|
|
*
|
|
*/
|
|
IP_PUBLIC int
|
|
ipcom_connect(Ip_fd fd, IP_CONST struct Ip_sockaddr *to, Ip_socklen_t tolen)
|
|
{
|
|
Iplite_socket *sock = IP_NULL;
|
|
int retval;
|
|
struct Ip_sockaddr *name = IP_NULL;
|
|
#ifdef IPCOM_USE_INET
|
|
struct Ip_sockaddr_in in_name;
|
|
#endif
|
|
#ifdef IPCOM_USE_INET6
|
|
struct Ip_sockaddr_in6 in6_name;
|
|
#endif
|
|
Iplite_netif *netif;
|
|
|
|
ip_assert2(fd >= IPLITE_SOCKET_STARTFD);
|
|
ip_assert2(fd < IPLITE_CONF_MAX_SOCKETS);
|
|
ip_assert2(iplite.sockets[fd] != IP_NULL);
|
|
|
|
IPLITE_CODE_LOCK();
|
|
|
|
if (to == IP_NULL)
|
|
SOCK_ERROUT(IP_ERRNO_EINVAL);
|
|
|
|
sock = iplite.sockets[fd];
|
|
if (sock == IP_NULL)
|
|
SOCK_ERROUT(IP_ERRNO_EBADF);
|
|
|
|
if (sock->ipcom.so_errno != 0)
|
|
SOCK_ERROUT(sock->ipcom.so_errno);
|
|
|
|
if (sock->ipcom.type == IP_SOCK_STREAM && IP_BIT_ISSET(sock->flags, IPLITE_SOCKET_FLAG_CONNECTED))
|
|
SOCK_ERROUT(IP_ERRNO_EISCONN);
|
|
|
|
IP_BIT_CLR(sock->flags, IPLITE_SOCKET_FLAG_CONNECTED);
|
|
|
|
#ifdef IPLITE_COMPAT_OLDSOCK
|
|
if (to->sa_family == 0 && to->sa_len < IP_AF_MAX && to->sa_len != tolen)
|
|
((struct Ip_sockaddr *)to)->sa_family = to->sa_len;
|
|
((struct Ip_sockaddr *)to)->sa_len = (Ip_u8) tolen;
|
|
#endif /* IPLITE_COMPAT_OLDSOCK */
|
|
|
|
if (to->sa_family != sock->ipcom.domain && to->sa_family != IP_AF_UNSPEC)
|
|
SOCK_ERROUT(IP_ERRNO_EAFNOSUPPORT);
|
|
|
|
/* Determine the destination address */
|
|
|
|
#ifdef IPCOM_USE_INET
|
|
if (to->sa_family == IP_AF_INET)
|
|
{
|
|
/* Setup the IPv4 destination (peer) address */
|
|
struct Ip_sockaddr_in *in_to;
|
|
struct Ip_in_addr src_addr;
|
|
|
|
if (tolen < sizeof(struct Ip_sockaddr_in))
|
|
SOCK_ERROUT(IP_ERRNO_EINVAL);
|
|
|
|
in_to = (struct Ip_sockaddr_in*) to;
|
|
if (in_to->sin_addr.s_addr == IP_INADDR_ANY)
|
|
goto disconnect;
|
|
|
|
sock->d->ip4.daddr_n = in_to->sin_addr.s_addr;
|
|
sock->dport = ip_ntohs(in_to->sin_port);
|
|
if (sock->dport == 0)
|
|
SOCK_ERROUT(IP_ERRNO_EINVAL);
|
|
|
|
netif = iplite_ip4_get_netif(in_to->sin_addr.s_addr, IP_NULL);
|
|
if (netif == IP_NULL)
|
|
SOCK_ERROUT(IP_ERRNO_EHOSTUNREACH);
|
|
|
|
if (IP_BIT_ISFALSE(sock->flags, IPLITE_SOCKET_FLAG_BOUND)
|
|
|| sock->d->ip4.saddr_n == IP_INADDR_ANY)
|
|
{
|
|
if (sock->d->ip4.saddr_n == IP_INADDR_ANY)
|
|
{
|
|
/* No address specified when the socket was bound, need to rebind */
|
|
in_name.sin_port = ip_htons(sock->sport);
|
|
iplite_sock_unbind(sock);
|
|
}
|
|
else
|
|
/* Not bound before, bind to an ephemeral port */
|
|
in_name.sin_port = 0;
|
|
|
|
in_name.sin_family = IP_AF_INET;
|
|
in_name.sin_len = sizeof(in_name);
|
|
|
|
src_addr.s_addr = iplite_ip4_get_src_addr(netif, in_to->sin_addr.s_addr);
|
|
if (src_addr.s_addr == 0)
|
|
SOCK_ERROUT(IP_ERRNO_EHOSTUNREACH);
|
|
in_name.sin_addr.s_addr = src_addr.s_addr;
|
|
name = (struct Ip_sockaddr *) &in_name;
|
|
|
|
}
|
|
/* else: already bound to an address != IP_INADDR_ANY */
|
|
}
|
|
else
|
|
#endif /* IPCOM_USE_INET */
|
|
#ifdef IPCOM_USE_INET6
|
|
if (to->sa_family == IP_AF_INET6)
|
|
{
|
|
/* Setup the IPv6 destination (peer) address */
|
|
struct Ip_sockaddr_in6 *in6_to;
|
|
IP_CONST struct Ip_in6_addr* src_addr;
|
|
Ip_u32 flowinfo = 0;
|
|
|
|
if (tolen < sizeof(struct Ip_sockaddr_in6))
|
|
SOCK_ERROUT(IP_ERRNO_EINVAL);
|
|
|
|
in6_to = (struct Ip_sockaddr_in6 *)to;
|
|
if (IP_IN6_IS_ADDR_UNSPECIFIED(&in6_to->sin6_addr))
|
|
goto disconnect;
|
|
flowinfo = in6_to->sin6_flowinfo;
|
|
if (ip_ntohl(flowinfo) & 0xff000000)
|
|
SOCK_ERROUT(IP_ERRNO_EINVAL);
|
|
netif = iplite_ip6_get_netif(in6_to->sin6_scope_id, &in6_to->sin6_addr, IP_NULL, IP_TRUE);
|
|
if (netif == IP_NULL)
|
|
SOCK_ERROUT(IP_ERRNO_EHOSTUNREACH);
|
|
|
|
sock->d->ip6.daddr = in6_to->sin6_addr;
|
|
sock->d->ip6.flowinfo_n = flowinfo;
|
|
sock->dport = ip_ntohs(in6_to->sin6_port);
|
|
sock->d->ip6.scope_id = in6_to->sin6_scope_id;
|
|
|
|
if (IP_BIT_ISFALSE(sock->flags, IPLITE_SOCKET_FLAG_BOUND)
|
|
|| IP_IN6_IS_ADDR_UNSPECIFIED(&sock->d->ip6.saddr))
|
|
{
|
|
if (IP_IN6_IS_ADDR_UNSPECIFIED(&sock->d->ip6.saddr))
|
|
{
|
|
/* No address specified when the socket was bound, need to rebind */
|
|
in6_name.sin6_port = ip_htons(sock->sport);
|
|
iplite_sock_unbind(sock);
|
|
}
|
|
else
|
|
/* Not bound before, bind to an ephemeral port */
|
|
in6_name.sin6_port = 0;
|
|
|
|
in6_name.sin6_family = IP_AF_INET6;
|
|
in6_name.sin6_len = sizeof(in6_name);
|
|
src_addr = iplite_ip6_get_src_addr(netif, &sock->d->ip6.daddr, 0);
|
|
if (src_addr == IP_NULL)
|
|
SOCK_ERROUT(IP_ERRNO_EHOSTUNREACH);
|
|
IPLITE_IP6_SET_ADDR(&in6_name.sin6_addr, src_addr);
|
|
in6_name.sin6_flowinfo = flowinfo;
|
|
in6_name.sin6_scope_id = in6_to->sin6_scope_id;
|
|
name = (struct Ip_sockaddr *) &in6_name;
|
|
}
|
|
/* else: already bound to an address != unspecified address */
|
|
}
|
|
else
|
|
#endif /* IPCOM_USE_INET6 */
|
|
if (to->sa_family == IP_AF_UNSPEC)
|
|
{
|
|
disconnect:
|
|
#ifdef IPCOM_USE_TCP
|
|
if (sock->tcb)
|
|
SOCK_ERROUT(IP_ERRNO_EAFNOSUPPORT);
|
|
#endif
|
|
#ifdef IPCOM_USE_INET
|
|
if (sock->ipcom.domain == IP_AF_INET)
|
|
sock->d->ip4.daddr_n = IP_INADDR_ANY;
|
|
#endif
|
|
#ifdef IPCOM_USE_INET6
|
|
if (sock->ipcom.domain == IP_AF_INET6)
|
|
sock->d->ip6.daddr = ip_in6addr_any;
|
|
#endif
|
|
IP_BIT_CLR(sock->flags, IPLITE_SOCKET_FLAG_CONNECTED);
|
|
sock->dport = 0;
|
|
goto done;
|
|
}
|
|
else
|
|
SOCK_ERROUT(IP_ERRNO_EAFNOSUPPORT);
|
|
|
|
/* Make sure that the socket is bound so packet sent from the peer
|
|
socket is accepted */
|
|
if (IP_BIT_ISFALSE(sock->flags, IPLITE_SOCKET_FLAG_BOUND))
|
|
{
|
|
retval = iplite_do_bind(sock, name, name->sa_len, IP_TRUE); /*lint !e644 */
|
|
if (retval < 0)
|
|
SOCK_ERROUT(-retval);
|
|
}
|
|
|
|
#ifdef IPCOM_USE_TCP
|
|
if (sock->tcb != IP_NULL)
|
|
{
|
|
/* The socket is a TCP socket, do the TCP connect */
|
|
if (IP_BIT_ISSET(sock->flags, IPLITE_SOCKET_FLAG_CONNECTING))
|
|
/* Asynchronous connect is still not finished */
|
|
SOCK_ERROUT(IP_ERRNO_EALREADY);
|
|
retval = iplite_tcp_connect(sock); /*lint !e644 */
|
|
if (retval < 0)
|
|
SOCK_ERROUT(-retval);
|
|
}
|
|
else
|
|
#endif /* IPCOM_USE_TCP */
|
|
{
|
|
IP_BIT_SET(sock->flags, IPLITE_SOCKET_FLAG_CONNECTED);
|
|
}
|
|
|
|
done:
|
|
/* success. */
|
|
IPLITE_CODE_UNLOCK();
|
|
return 0;
|
|
|
|
errout:
|
|
if (sock && (sock->ipcom.type != IP_SOCK_STREAM || ipcom_errno != IP_ERRNO_EISCONN))
|
|
IP_BIT_CLR(sock->flags, IPLITE_SOCKET_FLAG_CONNECTED);
|
|
IPLITE_CODE_UNLOCK();
|
|
return (int)IP_SOCKERR;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipcom_socketwrite
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_PUBLIC Ip_ssize_t
|
|
ipcom_socketwrite(Ip_fd sock, IP_CONST void *buf, Ip_size_t nbytes)
|
|
{
|
|
return ipcom_sendto(sock, buf, nbytes, 0, IP_NULL, 0);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipcom_send
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_PUBLIC Ip_ssize_t
|
|
ipcom_send(Ip_fd sock, IP_CONST void *msg, Ip_size_t len, int flags)
|
|
{
|
|
return ipcom_sendto(sock, msg, len, flags, IP_NULL, IP_NULL);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipcom_sendto
|
|
*===========================================================================
|
|
* Description: Sends a packet to the address to which the socket is connected
|
|
* or to the 'to_param' address if the socket is not connected.
|
|
* Parameters: fd - The descriptor for the socket to use.
|
|
* buf - The buffer to send.
|
|
* len - The length of the buffer in octets.
|
|
* flags - Unused by IPLITE.
|
|
* to - The destination for the data if the socket is
|
|
* unconnected, ignored for connected sockets.
|
|
* tolen - The size of the 'to_param' buffer in octets.
|
|
* Returns: >=0 = number of bytes sent, IP_SOCKERR = error code is
|
|
* retrivered by using ipcom_errno.
|
|
*
|
|
*/
|
|
IP_PUBLIC Ip_ssize_t
|
|
ipcom_sendto(Ip_fd fd, IP_CONST void *buf, Ip_size_t len, int flags,
|
|
IP_CONST struct Ip_sockaddr *to, Ip_socklen_t tolen)
|
|
{
|
|
return ipcom_sendto_pktinfo(fd, buf, len, flags, to, tolen, IP_NULL);
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipcom_sendto_pktinfo
|
|
*===========================================================================
|
|
* Description: Sends a packet to the address to which the socket is connected
|
|
* or to the 'to_param' address if the socket is not connected.
|
|
* Parameters: fd - The descriptor for the socket to use.
|
|
* buf - The buffer to send.
|
|
* len - The length of the buffer in octets.
|
|
* flags - Unused by IPLITE.
|
|
* to - The destination for the data if the socket is
|
|
* unconnected, ignored for connected sockets.
|
|
* tolen - The size of the 'to_param' buffer in octets.
|
|
* Returns: >=0 = number of bytes sent, IP_SOCKERR = error code is
|
|
* retrivered by using ipcom_errno.
|
|
*
|
|
*/
|
|
IP_PUBLIC Ip_ssize_t
|
|
ipcom_sendto_pktinfo(Ip_fd fd, IP_CONST void *buf, Ip_size_t len, int flags,
|
|
IP_CONST struct Ip_sockaddr *to, Ip_socklen_t tolen,
|
|
IP_CONST struct Ip_msghdr *msg)
|
|
{
|
|
|
|
Ipcom_pkt *pkt;
|
|
Iplite_socket *sock;
|
|
int ret;
|
|
Ip_bool non_blocking;
|
|
|
|
ip_assert2(fd >= IPLITE_SOCKET_STARTFD);
|
|
ip_assert2(fd < IPLITE_CONF_MAX_SOCKETS);
|
|
ip_assert2(iplite.sockets[fd] != IP_NULL);
|
|
ip_assert2(buf != IP_NULL);
|
|
|
|
IPLITE_STATS(sock_sendto++);
|
|
|
|
IPLITE_CODE_LOCK();
|
|
|
|
if (fd >= IPLITE_CONF_MAX_SOCKETS || iplite.sockets[fd] == IP_NULL)
|
|
{
|
|
IPLITE_STATS(sock_sendto_ebadf++);
|
|
sock = IP_NULL;
|
|
SOCK_ERROUT(IP_ERRNO_EBADF);
|
|
}
|
|
sock = iplite.sockets[fd];
|
|
ip_assert(sock != IP_NULL);
|
|
|
|
IPLITE_SOCK_ADD_REF(sock);
|
|
|
|
if (sock->ipcom.so_errno != 0)
|
|
{
|
|
ip_assert(sock->ipcom.so_errno > 0);
|
|
SOCK_ERROUT(sock->ipcom.so_errno);
|
|
}
|
|
|
|
if (IP_BIT_ISSET(sock->flags, IPLITE_SOCKET_FLAG_WRITE_CLOSED))
|
|
SOCK_ERROUT(IP_ERRNO_ESHUTDOWN);
|
|
|
|
#ifdef IPCOM_USE_TCP
|
|
if (sock->tcb != IP_NULL)
|
|
{
|
|
ret = iplite_tcp_usr_send(sock, buf, len, flags);
|
|
if (ret < 0)
|
|
{
|
|
IPLITE_STATS(sock_sendto_tcp_err++);
|
|
SOCK_ERROUT(-ret);
|
|
}
|
|
goto leave;
|
|
}
|
|
#endif /* IPCOM_USE_TCP */
|
|
|
|
/* Check if the packet is small enough to be sent
|
|
* (this value can be increased using IP_SO_SNDBUF socket option)
|
|
*/
|
|
|
|
if (len > (Ip_size_t) sock->snd_max_bytes)
|
|
{
|
|
IPLITE_STATS(sock_sendto_emsgsize++);
|
|
SOCK_ERROUT(IP_ERRNO_EMSGSIZE);
|
|
}
|
|
|
|
non_blocking = IP_BIT_ISSET(sock->flags, IPLITE_SOCKET_FLAG_NONBLOCKING)
|
|
|| IP_BIT_ISSET(flags, IP_MSG_DONTWAIT);
|
|
|
|
pkt = ipcom_pkt_malloc(len + sock->max_hdrspace,
|
|
IP_FLAG_FC_STACKCONTEXT | (non_blocking ? 0 : IP_FLAG_FC_BLOCKOK));
|
|
if (pkt == IP_NULL)
|
|
{
|
|
IPLITE_STATS(sock_sendto_nomem++);
|
|
|
|
if (non_blocking)
|
|
SOCK_ERROUT(IP_ERRNO_EWOULDBLOCK);
|
|
|
|
SOCK_ERROUT(IP_ERRNO_ENOMEM);
|
|
}
|
|
|
|
pkt->fd = sock->ipcom.fd;
|
|
pkt->start = ipcom_conf_max_link_hdr_size + sock->max_hdrspace;
|
|
#ifdef IPIPSEC2
|
|
if (sock->ipcom.domain == IP_AF_KEY)
|
|
{
|
|
while(((Ip_u32)&pkt->data[pkt->start] & 0x7) != 0)
|
|
pkt->start++;
|
|
}
|
|
#endif
|
|
|
|
#if defined(IPCOM_PKT_TX_ALIGN)
|
|
if (sock->ipcom.domain != IP_AF_KEY)
|
|
{
|
|
/* Optimize alignment for Ethernet header */
|
|
IPCOM_PKT_TX_ALIGN(pkt, sock->max_hdrspace + IP_ETH_HDR_SIZE, 1);
|
|
}
|
|
#endif /* IPCOM_PKT_TX_ALIGN */
|
|
|
|
/* Copy user data into pkt->data with enough space for anything. 0 bytes is valid. */
|
|
if (len > 0)
|
|
{
|
|
#if !defined(IPCOM_PKT_TX_ALIGN)
|
|
if (((int)&pkt->data[pkt->start] ^ (int)buf) & 0x3)
|
|
pkt->start += 2; /* Align user buffer with pkt buffer */
|
|
#endif /* IPCOM_PKT_TX_ALIGN */
|
|
|
|
#ifdef IPCOM_USE_ASM
|
|
if (IP_BIT_ISSET(sock->flags, IPLITE_SOCKET_FLAG_ADDCHECKSUM))
|
|
pkt->chk = ipcom_in_checksum_memcpy(&pkt->data[pkt->start], (void *)buf, len);
|
|
else
|
|
ipcom_memcpy(&pkt->data[pkt->start], buf, len);
|
|
#else
|
|
ipcom_memcpy(&pkt->data[pkt->start], buf, len);
|
|
if (IP_BIT_ISSET(sock->flags, IPLITE_SOCKET_FLAG_ADDCHECKSUM))
|
|
pkt->chk = ipcom_in_checksum_update(&pkt->data[pkt->start], len);
|
|
#endif
|
|
}
|
|
pkt->end = pkt->start + (int)len;
|
|
|
|
/* Send the data using UDP or Raw IP. */
|
|
if (non_blocking)
|
|
IP_BIT_SET(pkt->flags, IPCOM_PKT_FLAG_NONBLOCKING);
|
|
|
|
#ifdef IPLITE_COMPAT_OLDSOCK
|
|
if (to != IP_NULL)
|
|
{
|
|
if (to->sa_family == 0 && to->sa_len < IP_AF_MAX)
|
|
((struct Ip_sockaddr *)to)->sa_family = to->sa_len;
|
|
((struct Ip_sockaddr *)to)->sa_len = (Ip_u8) tolen;
|
|
}
|
|
#else
|
|
(void)tolen;
|
|
#endif
|
|
ip_assert(to == IP_NULL || to->sa_len > 0);
|
|
|
|
if (sock->ipcom.type == IP_SOCK_DGRAM
|
|
&& IP_BIT_ISFALSE(sock->flags, IPLITE_SOCKET_FLAG_BOUND))
|
|
{
|
|
union Ip_sockaddr_union name;
|
|
/* Do an implicit bind */
|
|
ipcom_memset(&name, 0, sizeof(name));
|
|
name.sa.sa_family = (Ip_sa_family_t)sock->ipcom.domain;
|
|
ret = iplite_do_bind(sock, &name.sa, sizeof(name), IP_TRUE);
|
|
if (ret < 0)
|
|
SOCK_ERROUT(-ret);
|
|
}
|
|
|
|
ip_assert(sock->transport_output != IP_NULL);
|
|
#if defined(IP_PORT_VXWORKS) && defined(IPCOM_USE_INET6)
|
|
if ((msg != IP_NULL)
|
|
&& (msg->msg_control != IP_NULL)
|
|
&& (msg->msg_controllen >= sizeof(struct Ip_in6_pktinfo)))
|
|
{
|
|
struct Ip_in6_pktinfo *info = (struct Ip_in6_pktinfo *)IP_CMSG_DATA(msg->msg_control);
|
|
struct Ip_in6_pktinfo *info_pkt = IP_NULL;
|
|
ip_assert(info != IP_NULL);
|
|
pkt->ifindex = info->ipi6_ifindex;
|
|
info_pkt = (struct Ip_in6_pktinfo *)ipcom_pkt_alloc_info(pkt,
|
|
IPLITE_PKT_INFO_PKTINFO, sizeof(struct Ip_in6_pktinfo));
|
|
if (info_pkt != IP_NULL)
|
|
{
|
|
ipcom_memcpy(info_pkt, info, sizeof(struct Ip_in6_pktinfo));
|
|
}
|
|
}
|
|
#else
|
|
(void)msg;
|
|
#endif
|
|
ret = sock->transport_output(sock, to, pkt);
|
|
if (ret == 0)
|
|
ret = (int)len;
|
|
else if (ret < 0)
|
|
SOCK_ERROUT(-ret);
|
|
|
|
leave:
|
|
if (sock)
|
|
IPLITE_SOCK_DEL_REF(sock);
|
|
IPLITE_CODE_UNLOCK();
|
|
return (Ip_ssize_t)ret;
|
|
|
|
errout:
|
|
/* EWOULDBLOCK can occur due to two reasons here. Out of packet memory
|
|
* or due to interface output queue full. In either case, the application
|
|
* will get a PKTAVAIL callback event to notify when it can retry send.
|
|
* Note: This behaviour is required for socket server to function!
|
|
*/
|
|
if (sock != IP_NULL && sock->ipcom.event_cb != IP_NULL && ipcom_errno == IP_ERRNO_EWOULDBLOCK)
|
|
{
|
|
IP_BIT_SET(iplite_flags, IPLITE_FLAG_PKTAVAIL_CB_PENDING);
|
|
IP_BIT_SET(sock->flags, IPLITE_SOCKET_FLAG_PKTAVAIL_CB_PENDING);
|
|
}
|
|
ret = IP_SOCKERR;
|
|
goto leave;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipcom_recv
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_PUBLIC Ip_ssize_t
|
|
ipcom_recv(Ip_fd sock, void *buf, Ip_size_t len, int flags)
|
|
{
|
|
return ipcom_recvfrom(sock, buf, len, flags, IP_NULL, IP_NULL);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipcom_socketread
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_PUBLIC Ip_ssize_t
|
|
ipcom_socketread(Ip_fd sock, void *buf, Ip_size_t nbytes)
|
|
{
|
|
return ipcom_recvfrom(sock, buf, nbytes, 0, IP_NULL, IP_NULL);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* iplite_recvfrom_waitall
|
|
*===========================================================================
|
|
* Description: IPLITE does not have the required features to implement
|
|
* the "low watermark" feature. This makes implementing
|
|
* MSG_WAITALL a bit awkward. This helper function implements
|
|
* the correct behavior of MSG_WAITALL, but with a far from
|
|
* optimal solution.
|
|
* Parameters: fd - a file descriptor
|
|
* buf - buffer where the data will be stored
|
|
* len - length of 'buf'
|
|
* flags - flags with MSG_WAITALL set
|
|
* from - buffer where the address of the sender should be
|
|
* stored or IP_NULL if that information is not relevant
|
|
* fromlen - initially the length of 'from', at return the
|
|
* number octets written to 'from'
|
|
* Returns: Number of octets received or negative error code.
|
|
*
|
|
*/
|
|
#ifndef IP_PORT_OSE5
|
|
IP_STATIC Ip_ssize_t
|
|
iplite_recvfrom_waitall(Ip_fd fd, void *buf, Ip_size_t len, int flags,
|
|
struct Ip_sockaddr *from, Ip_socklen_t *fromlen)
|
|
{
|
|
int is_nonblock = IP_BIT_ISSET(flags, IP_MSG_DONTWAIT);
|
|
int ret;
|
|
struct Ip_timeval now;
|
|
struct Ip_timeval end;
|
|
Ip_socklen_t tv_len = sizeof(end);
|
|
Ip_bool has_timeout = IP_FALSE;
|
|
|
|
if (ipcom_getsockopt(fd, IP_SOL_SOCKET, IP_SO_RCVTIMEO, &end, &tv_len) == 0
|
|
&& (end.tv_sec > 0 || end.tv_usec > 0))
|
|
{
|
|
/* Receive timeout != infinite */
|
|
ipcom_microtime(&now);
|
|
ip_timeval_add(&end, &now, &end);
|
|
has_timeout = IP_TRUE;
|
|
}
|
|
|
|
if (!is_nonblock)
|
|
ipcom_socketioctl(fd, IP_X_FIOGNBIO, &is_nonblock);
|
|
|
|
flags &= ~IP_MSG_WAITALL;
|
|
while (len > (ret = ipcom_recvfrom(fd,
|
|
buf,
|
|
len,
|
|
flags | IP_MSG_PEEK,
|
|
from,
|
|
fromlen)))
|
|
{
|
|
/*
|
|
* Not the best of solutions, but have to do for now...
|
|
*/
|
|
if (is_nonblock)
|
|
return ret;
|
|
|
|
if (has_timeout)
|
|
{
|
|
ipcom_microtime(&now);
|
|
if (ip_timeval_cmp(&now, &end, >))
|
|
return -IP_ERRNO_EWOULDBLOCK;
|
|
}
|
|
|
|
ipcom_millisleep(100);
|
|
}
|
|
|
|
if (IP_BIT_ISFALSE(flags, IP_MSG_PEEK))
|
|
return ipcom_recvfrom(fd, buf, len, flags, from, fromlen);
|
|
|
|
return ret;
|
|
}
|
|
#endif /* IP_PORT_OSE5 */
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipcom_recvfrom
|
|
*===========================================================================
|
|
* Description: Receives data from a socket.
|
|
* Parameters: fd - A socket descriptor.
|
|
* buf - A buffer to where the data should be copied.
|
|
* len - The length of buf buffer.
|
|
* flags - Currently unused (set to 0).
|
|
* from - The sender of the data.
|
|
* fromlen - The length of the from buffer, will be updated to
|
|
* contain the number of octets copied to the from buffer.
|
|
* Returns: >=0 = the number of bytes copied to buf, -1 = error.
|
|
*
|
|
*/
|
|
/*lint -efunc(429,ipcom_recvfrom) Custodial pointer 'ptr' (line X) has not been freed or returned*/
|
|
IP_PUBLIC Ip_ssize_t
|
|
ipcom_recvfrom(Ip_fd fd, void *buf, Ip_size_t len, int flags,
|
|
struct Ip_sockaddr *from, Ip_socklen_t *fromlen)
|
|
{
|
|
return ipcom_recvfrom_pktinfo(fd, buf, len, flags, from, fromlen, IP_NULL);
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipcom_recvfrom_pktinfo
|
|
*===========================================================================
|
|
* Description: Receives data from a socket, at the same time, return pkt info.
|
|
* Parameters: fd - A socket descriptor.
|
|
* buf - A buffer to where the data should be copied.
|
|
* len - The length of buf buffer.
|
|
* flags - Currently unused (set to 0).
|
|
* from - The sender of the data.
|
|
* fromlen - The length of the from buffer, will be updated to
|
|
* contain the number of octets copied to the from buffer.
|
|
* msg - Ip_msgdhr, used to get packet information
|
|
* Returns: >=0 = the number of bytes copied to buf, -1 = error.
|
|
*
|
|
*/
|
|
/*lint -efunc(429,ipcom_recvfrom) Custodial pointer 'ptr' (line X) has not been freed or returned*/
|
|
IP_PUBLIC Ip_ssize_t
|
|
ipcom_recvfrom_pktinfo(Ip_fd fd, void *buf, Ip_size_t len, int flags,
|
|
struct Ip_sockaddr *from, Ip_socklen_t *fromlen, struct Ip_msghdr *msg)
|
|
{
|
|
|
|
int read_bytes = -1;
|
|
Iplite_socket *sock = IP_NULL;
|
|
Ipcom_pkt *pkt;
|
|
|
|
#ifndef IP_PORT_OSE5
|
|
/* Note: OSE5 always read in non-blocking mode which will make below not work */
|
|
if (IP_BIT_ISSET(flags, IP_MSG_WAITALL))
|
|
{
|
|
read_bytes = iplite_recvfrom_waitall(fd, buf, len, flags, from, fromlen);
|
|
if (read_bytes >= 0)
|
|
return (Ip_ssize_t) read_bytes;
|
|
ipcom_errno_set(-read_bytes);
|
|
return IP_SOCKERR;
|
|
}
|
|
#endif /* IP_PORT_OSE5 */
|
|
|
|
IPLITE_CODE_LOCK();
|
|
|
|
if (fd >= IPLITE_CONF_MAX_SOCKETS || iplite.sockets[fd] == IP_NULL)
|
|
SOCK_ERROUT(IP_ERRNO_EBADF);
|
|
sock = iplite.sockets[fd];
|
|
ip_assert(sock != IP_NULL);
|
|
|
|
IPLITE_SOCK_ADD_REF(sock);
|
|
|
|
if (sock->ipcom.so_errno)
|
|
SOCK_ERROUT(sock->ipcom.so_errno);
|
|
|
|
if (IP_BIT_ISSET(sock->flags, IPLITE_SOCKET_FLAG_READ_CLOSED))
|
|
{
|
|
read_bytes = 0;
|
|
goto errout;
|
|
}
|
|
|
|
/* Check if in blocking mode an no bytes to read, wait for data to
|
|
arrive in that case */
|
|
if (sock->ipcom.rcv_bytes == 0
|
|
&& IP_BIT_ISFALSE(sock->flags, IPLITE_SOCKET_FLAG_NONBLOCKING)
|
|
&& IP_BIT_ISFALSE(flags, IP_MSG_DONTWAIT))
|
|
{
|
|
Ip_fd_set rd_set;
|
|
struct Ip_timeval start; /* Time */
|
|
struct Ip_timeval tv_buf;
|
|
struct Ip_timeval *tv = IP_NULL;
|
|
|
|
if (sock->rcv_timeout.tv_sec != 0
|
|
|| sock->rcv_timeout.tv_usec != 0)
|
|
{
|
|
/* Receive timeout != infinite */
|
|
ipcom_microtime(&start);
|
|
tv = &tv_buf;
|
|
*tv = sock->rcv_timeout;
|
|
}
|
|
|
|
IP_FD_ZERO(&rd_set);
|
|
|
|
for (;;)
|
|
{
|
|
IP_FD_SET(fd, &rd_set);
|
|
switch (iplite_do_socketselect(fd + 1,
|
|
&rd_set,
|
|
IP_NULL,
|
|
IP_NULL,
|
|
tv))
|
|
{
|
|
case 1: /* Socket ready */
|
|
break;
|
|
case 0: /* Timeout */
|
|
SOCK_ERROUT(IP_ERRNO_EWOULDBLOCK);
|
|
break;
|
|
default: /* Error */
|
|
/* errno has already been set */
|
|
goto errout;
|
|
}
|
|
|
|
if (iplite_sock_is_readable(sock))
|
|
break;
|
|
|
|
if (tv != IP_NULL)
|
|
{
|
|
struct Ip_timeval elapsed;
|
|
/* Another process grabbed the data before this
|
|
process got hold of the lock. */
|
|
ipcom_microtime(&elapsed);
|
|
ip_timeval_sub(&elapsed, &elapsed, &start);
|
|
*tv = sock->rcv_timeout;
|
|
if (ip_timeval_cmp(&elapsed, tv, <))
|
|
ip_timeval_sub(tv, tv, &elapsed);
|
|
else
|
|
{
|
|
tv->tv_sec = 0;
|
|
tv->tv_usec = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (sock->ipcom.rcv_bytes == 0
|
|
&& IP_UNLIKELY(IP_BIT_ISTRUE(sock->flags, IPLITE_SOCKET_FLAG_READ_CLOSED)))
|
|
{
|
|
/* the socket has been closed */
|
|
read_bytes = 0;
|
|
goto errout;
|
|
}
|
|
|
|
#ifdef IPCOM_USE_TCP
|
|
if (sock->tcb != IP_NULL)
|
|
{
|
|
#ifdef IP_PORT_VXWORKS
|
|
if (msg != IP_NULL)
|
|
{
|
|
msg->msg_controllen = 0;
|
|
}
|
|
#endif
|
|
read_bytes = iplite_tcp_usr_recv(sock, buf, len, flags);
|
|
if (read_bytes < 0)
|
|
{
|
|
IPLITE_STATS(sock_recvfrom_tcp_err++);
|
|
SOCK_ERROUT(-read_bytes);
|
|
}
|
|
}
|
|
else
|
|
#endif /* IPCOM_USE_TCP */
|
|
{
|
|
if (sock->ipcom.rcv_bytes == 0)
|
|
{
|
|
ip_assert(IP_BIT_ISTRUE(sock->flags, IPLITE_SOCKET_FLAG_NONBLOCKING)
|
|
|| IP_BIT_ISTRUE(flags, IP_MSG_DONTWAIT));
|
|
SOCK_ERROUT(IP_ERRNO_EWOULDBLOCK);
|
|
}
|
|
|
|
pkt = iplite_krecvfrom(sock, from, fromlen);
|
|
if (pkt == IP_NULL)
|
|
{
|
|
IPLITE_STATS(sock_recvfrom_err++);
|
|
SOCK_ERROUT(IP_ERRNO_EAGAIN);
|
|
}
|
|
|
|
read_bytes = IP_MIN((int)len, pkt->end - pkt->start);
|
|
if (read_bytes > 0)
|
|
ipcom_memcpy(buf, &pkt->data[pkt->start], read_bytes);
|
|
#if defined(IP_PORT_VXWORKS) && defined(IPCOM_USE_INET6)
|
|
if ((read_bytes > 0)
|
|
&& ((sock->flags & IPLITE_SOCKET_FLAG_RECVPKTINFO) != 0)
|
|
&& (msg != IP_NULL)
|
|
&& (msg->msg_control != IP_NULL)
|
|
&& (msg->msg_controllen > 0))
|
|
{
|
|
struct Ip_in6_pktinfo *pktinfo = IP_NULL;
|
|
Iplite_netif *netif = IP_NULL;
|
|
int cmsg_len = 0;
|
|
int pktinfo_len = 0;
|
|
struct Ip_cmsghdr *cmsg = (struct Ip_cmsghdr *)IP_CMSG_FIRSTHDR(msg);
|
|
|
|
pktinfo_len = sizeof(struct Ip_in6_pktinfo);
|
|
cmsg_len = IP_CMSG_SPACE(pktinfo_len);
|
|
if (cmsg_len <= msg->msg_controllen)
|
|
{
|
|
cmsg->cmsg_len = IP_CMSG_LEN(pktinfo_len);
|
|
cmsg->cmsg_level = IP_IPPROTO_IPV6;
|
|
cmsg->cmsg_type = IP_IPV6_PKTINFO;
|
|
|
|
pktinfo = (struct Ip_in6_pktinfo *)IP_CMSG_DATA(cmsg);
|
|
IPLITE_IP6_SET_ADDR(&pktinfo->ipi6_addr,
|
|
&((struct Ip_sockaddr_in6 *)from)->sin6_addr);
|
|
|
|
netif = iplite_if_indextonetif(pkt->ifindex);
|
|
if (netif != IP_NULL)
|
|
pktinfo->ipi6_ifindex = netif->ipcom.ifindex;
|
|
else
|
|
pktinfo->ipi6_ifindex = 0;
|
|
msg->msg_controllen = cmsg_len;
|
|
}
|
|
else
|
|
{
|
|
msg->msg_controllen = 0;
|
|
}
|
|
}
|
|
else if (msg != IP_NULL)
|
|
{
|
|
msg->msg_controllen = 0;
|
|
}
|
|
#else
|
|
if (msg != IP_NULL)
|
|
{
|
|
msg->msg_controllen = 0;
|
|
}
|
|
#endif
|
|
ipcom_pkt_free(pkt);
|
|
}
|
|
|
|
errout:
|
|
if (sock)
|
|
IPLITE_SOCK_DEL_REF(sock);
|
|
IPLITE_CODE_UNLOCK();
|
|
return (Ip_ssize_t) (read_bytes < 0 ? IP_SOCKERR : read_bytes);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* iplite_krecvfrom
|
|
*===========================================================================
|
|
* Description: Returns the first packet in the in queue of the socket.
|
|
* Parameters: sock - The socket on which the packet was queued.
|
|
* from - The address of the sender of the packet.
|
|
* fromlen - The length of the buffer pointed to by from.
|
|
* Returns: The oldest recieved packet.
|
|
*
|
|
*/
|
|
IP_STATIC Ipcom_pkt *
|
|
iplite_krecvfrom(Iplite_socket *sock, struct Ip_sockaddr *from, Ip_socklen_t *fromlen)
|
|
{
|
|
Ipcom_pkt *pkt;
|
|
|
|
ip_assert(sock != IP_NULL);
|
|
ip_assert(sock->rcv_head != IP_NULL);
|
|
IPLITE_STATS(sock_krecvfrom++);
|
|
|
|
/* Unlink the first packet from the queue head. */
|
|
pkt = sock->rcv_head;
|
|
sock->ipcom.rcv_bytes -= pkt->end - pkt->start;
|
|
sock->rcv_head = pkt->next;
|
|
if (sock->rcv_head == IP_NULL)
|
|
sock->rcv_tail = IP_NULL;
|
|
|
|
/* Copy of sender info. */
|
|
if (from != IP_NULL)
|
|
{
|
|
Ip_u16 sport_n = 0;
|
|
|
|
ip_assert2(fromlen != IP_NULL);
|
|
if (fromlen == IP_NULL)
|
|
SOCK_ERROUT(IP_ERRNO_EINVAL);
|
|
|
|
if (sock->proto == IP_IPPROTO_UDP)
|
|
{
|
|
Iplite_pkt_udp *udp;
|
|
|
|
udp = (Iplite_pkt_udp*) &pkt->data[pkt->start - IPLITE_UDP_HDR_SIZE];
|
|
sport_n = udp->sport;
|
|
}
|
|
|
|
switch(sock->ipcom.domain)
|
|
{
|
|
#ifdef IPCOM_USE_INET
|
|
case IP_AF_INET:
|
|
if (*fromlen >= sizeof(struct Ip_sockaddr_in))
|
|
{
|
|
Iplite_pkt_ip *ip4;
|
|
struct Ip_sockaddr_in *from_in = (struct Ip_sockaddr_in *)from;
|
|
|
|
ip4 = (Iplite_pkt_ip *) &pkt->data[pkt->ipstart];
|
|
from_in->sin_len = sizeof(struct Ip_sockaddr_in);
|
|
from_in->sin_family = IP_AF_INET;
|
|
ipcom_memcpy(&from_in->sin_addr.s_addr, ip4->src, sizeof(Ip_u32));
|
|
from_in->sin_port = sport_n;
|
|
*fromlen = sizeof(struct Ip_sockaddr_in);
|
|
}
|
|
break;
|
|
#endif /* IPCOM_USE_INET */
|
|
|
|
#ifdef IPCOM_USE_INET6
|
|
case IP_AF_INET6:
|
|
if (*fromlen >= sizeof(struct Ip_sockaddr_in6))
|
|
{
|
|
Iplite_pkt_ip6 *ip6;
|
|
struct Ip_sockaddr_in6 *from_in6 = (struct Ip_sockaddr_in6 *)from;
|
|
|
|
ip6 = (Iplite_pkt_ip6*) &pkt->data[pkt->ipstart];
|
|
from_in6->sin6_len = sizeof(struct Ip_sockaddr_in6);
|
|
from_in6->sin6_family = IP_AF_INET6;
|
|
IPLITE_IP6_SET_ADDR(&from_in6->sin6_addr, &ip6->src);
|
|
from_in6->sin6_flowinfo = ip_htonl(IPLITE_IP6_GET_FLOW(ip6));
|
|
from_in6->sin6_scope_id = pkt->ifindex;
|
|
from_in6->sin6_port = sport_n;
|
|
*fromlen = sizeof(struct Ip_sockaddr_in6);
|
|
}
|
|
break;
|
|
#endif /* IPCOM_USE_INET6 */
|
|
|
|
#ifdef IPCOM_USE_PACKET
|
|
case IP_AF_PACKET:
|
|
{
|
|
Iplite_netif *netif;
|
|
struct Ip_sockaddr_ll *from_ll = (struct Ip_sockaddr_ll *)from;
|
|
|
|
netif = iplite_if_indextonetif(pkt->ifindex);
|
|
ip_assert2(netif != IP_NULL);
|
|
if (netif != IP_NULL && *fromlen >= sizeof(*from_ll))
|
|
{
|
|
netif->link_get_frame_info(netif, pkt, &from_ll->sll_pkttype,
|
|
&from_ll->sll_protocol, from_ll->sll_addr, IP_NULL);
|
|
from_ll->sll_len = sizeof(*from_ll);
|
|
from_ll->sll_family = IP_AF_PACKET;
|
|
from_ll->sll_ifindex = netif->ipcom.ifindex;
|
|
from_ll->sll_hatype = netif->ipcom.type;
|
|
from_ll->sll_halen = (Ip_u8) netif->ipcom.link_addr_size;
|
|
*fromlen = sizeof(*from_ll);
|
|
}
|
|
}
|
|
break;
|
|
#endif /* IPCOM_USE_PACKET */
|
|
|
|
default:
|
|
/* Domain not implemented (bug if this point is reached) */
|
|
IP_PANIC();
|
|
break;
|
|
}
|
|
}
|
|
|
|
#ifdef IPCOM_USE_PACKET
|
|
if (sock->ipcom.domain == IP_AF_PACKET && sock->ipcom.type == IP_SOCK_DGRAM)
|
|
{
|
|
/* The link header should not be included when the type is IP_SOCK_DGRAM */
|
|
Iplite_netif *netif = iplite_if_indextonetif(pkt->ifindex);
|
|
if (netif != IP_NULL)
|
|
pkt->start += netif->ipcom.link_hdr_size;
|
|
}
|
|
#endif /* IPCOM_USE_PACKET */
|
|
|
|
return pkt;
|
|
|
|
errout:
|
|
return IP_NULL;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipcom_getsockname
|
|
*===========================================================================
|
|
* Description: Returns the name of the specified socket.
|
|
* Parameters: fd - A socket descriptor.
|
|
* name - A buffer that will receive the name of the socket.
|
|
* namelenp - A pointer to the length of name, will be updated
|
|
* to contain the actual number of octets copied to name.
|
|
* Returns: 0 = success, -1 = error
|
|
*
|
|
*/
|
|
IP_PUBLIC int
|
|
ipcom_getsockname(Ip_fd fd, struct Ip_sockaddr *name, Ip_socklen_t *namelenp)
|
|
{
|
|
int ret;
|
|
|
|
ip_assert2(name);
|
|
ip_assert2(namelenp);
|
|
|
|
IPLITE_CODE_LOCK();
|
|
ret = iplite_do_getname(fd, name, namelenp, IP_TRUE);
|
|
IPLITE_CODE_UNLOCK();
|
|
|
|
if (ret < 0)
|
|
SOCK_ERROUT(-ret);
|
|
return 0;
|
|
|
|
errout:
|
|
return (int)IP_SOCKERR;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipcom_getpeername
|
|
*===========================================================================
|
|
* Description: Returns the name of the peer connected to the specified socket.
|
|
* Parameters: fd - A socket descriptor.
|
|
* name - A buffer that will receive the name of the peer.
|
|
* namelenp - A pointer to the length of name, will be updated
|
|
* to contain the actual number of octets copied to name.
|
|
* Returns: 0 = success, -1 = error
|
|
*
|
|
*/
|
|
IP_PUBLIC int
|
|
ipcom_getpeername(Ip_fd fd, struct Ip_sockaddr *name, Ip_socklen_t *namelenp)
|
|
{
|
|
int ret;
|
|
|
|
ip_assert2(name);
|
|
ip_assert2(namelenp);
|
|
|
|
IPLITE_CODE_LOCK();
|
|
ret = iplite_do_getname(fd, name, namelenp, IP_FALSE);
|
|
IPLITE_CODE_UNLOCK();
|
|
|
|
if (ret < 0)
|
|
SOCK_ERROUT(-ret);
|
|
return 0;
|
|
|
|
errout:
|
|
return (int)IP_SOCKERR;
|
|
}
|
|
|
|
#endif /* !defined(IPLITE_ONE_FILE) || defined(IPLITE_C) */
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* END OF FILE
|
|
****************************************************************************
|
|
*/
|
|
|