blob: e5a32366ef5c62ee9fab3fa38446cd4d466105ab [file] [log] [blame]
/*
* Copyright (c) 2010 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "tctypes.h"
#include "rtp.h"
#include <stdio.h>
#include <ctype.h> //for tolower
#include <string.h>
#if defined(_WIN32_WCE) && defined(WIN32_PLATFORM_WFSP)
//INITGUID needs to be defined before DEFINE_GUID is defined
# define INITGUID
#endif
#include "vpx_network.h"
#if ENABLE_LOGGING
# ifndef vpx_NO_GLOBALS
static int module_loglevel = 0;
# else
# include "vpx_global_handling.h"
# define module_loglevel VPXGLOBALm(vpx_network,module_loglevel)
# endif
#endif
#ifndef INVALID_SOCKET
# define INVALID_SOCKET -1
#endif
#ifndef SOCKET_ERROR
# define SOCKET_ERROR -1
#endif
#if vpx_NET_SUPPORT_IPV6
# define supported_network_layer(n) ((n == vpx_IPv4) || (n == vpx_IPv6))
#else
# define supported_network_layer(n) (n == vpx_IPv4)
#endif
#define supported_transport_layer(t) ((t == vpx_TCP) || (t == vpx_UDP))
#if defined(__SYMBIAN32__)
# include <in_sock.h>
/*the prototype for bzero appears in symbian's headers, but bzero is
not in the libs (Series60 v2.1)*/
# define bzero(p,s) memset(p,0,s)
#endif
#if defined(_WIN32_WCE) && defined(WIN32_PLATFORM_WFSP)
# include <connmgr.h>
static HANDLE g_cxhandle = NULL; //data connection handle
#endif
enum
{
kInited = 0x01,
kBound = 0x02,
kConnected = 0x04,
kListening = 0x08
};
static TCRV socket_option(struct vpxsocket *vpx_sock, tc8 set, tc32 level,
tc32 option, void *value, tc32 optlen);
static tc32 set_nonblocking_io(struct vpxsocket *vpx_sock, tc32 on);
/*
*
* Exposed library functions
*
*/
/*
vpx_net_init()
Performs any necessary system dependent network initialization
Return: TC_OK on success, TC_ERROR otherwise
*/
TCRV vpx_net_init()
{
TCRV rv = TC_OK;
#if defined(WIN32) || defined(_WIN32_WCE)
WSADATA wsa_data;
#endif
//module_loglevel = VPXLOG_DEBUG;
vpxlog_dbg(LOG_PACKET,"vpx_network version: %s\n", vpx_network_version);
#if defined(WIN32) || defined(_WIN32_WCE)
//smartphone
# if defined(WIN32_PLATFORM_WFSP)
if (!g_cxhandle)
{
CONNMGR_CONNECTIONINFO ci = {0};
DWORD status;
HANDLE connection;
HRESULT hr;
ci.cbSize = sizeof(CONNMGR_CONNECTIONINFO);
ci.dwParams = CONNMGR_PARAM_GUIDDESTNET; //| CONNMGR_PARAM_MINRCVBW
#ifdef _X86_
/*the emulator has a proxy connection setup to access the internet;
w/o this flag set the call will fail*/
ci.dwFlags = CONNMGR_FLAG_PROXY_HTTP;
#else
ci.dwFlags = 0;
#endif
ci.dwPriority = CONNMGR_PRIORITY_USERINTERACTIVE;
ci.bExclusive = FALSE; //share connection among apps
ci.bDisabled = FALSE;
ci.guidDestNet = IID_DestNetCorp;
hr = ConnMgrEstablishConnectionSync(&ci, &connection, 50000, &status);
if (hr == E_FAIL && status == CONNMGR_STATUS_NOPATHTODESTINATION)
{
vpxlog_error("vpx_net_init: connection to IID_DestNetCorp failed."
" attempting DestNetInternet\n");
ci.guidDestNet = IID_DestNetInternet;
hr = ConnMgrEstablishConnectionSync(&ci, &connection, 50000, &status);
}
if (hr == S_OK && status == CONNMGR_STATUS_CONNECTED)
{
vpxlog_info("vpx_net_init: ConnMgrEstablishConnectionSync success\n");
}
else
{
rv = TC_ERROR;
vpxlog_error("vpx_net_init: ConnMgrEstablishConnectionSync failed,"
" hr:%u status:%u\n", hr, status);
}
}
# endif
/*
Initialize windows networking services
WINSOCK_VERSION is defined in winsock2.h
if the initialization fails or the returned version
is not equal to what we asked for, return an error
*/
if (WSAStartup(WINSOCK_VERSION, &wsa_data) ||
(LOBYTE(wsa_data.wVersion) != LOBYTE(WINSOCK_VERSION)) ||
(HIBYTE(wsa_data.wVersion) != HIBYTE(WINSOCK_VERSION)))
{
WSACleanup();
rv = TC_ERROR;
}
#endif
return rv;
}
/*
vpx_net_destroy()
Performs any necessary system dependent network deinitialization
*/
void vpx_net_destroy()
{
#if defined(WIN32) || defined(_WIN32_WCE)
# if defined(WIN32_PLATFORM_WFSP)
if (g_cxhandle)
{
//release our data connection immediately
ConnMgrReleaseConnection(g_cxhandle, 0);
g_cxhandle = NULL;
}
# endif
WSACleanup();
#endif
}
/*
vpx_net_open(struct vpxsocket* vpx_sock, enum network_layer net_layer,
enum transport_layer trans_layer)
vpx_sock - pointer to an vpxsocket structure that is to hold network info
net_layer - network layer of the socket to be created
trans_layer - transport layer of the socket to be created
Attempts to create a socket with the specified network
and transport layer. Read and send timeouts default to vpx_NET_NO_TIMEOUT.
Return:
TC_OK: on success
TC_INVALID_PARAMS: if vpx_sock is NULL or if the network/transport
layer is not supported.
TC_ERROR: if a socket could not be created.
*/
TCRV vpx_net_open(struct vpxsocket *vpx_sock,
enum network_layer net_layer,
enum transport_layer trans_layer)
{
TCRV rv = TC_INVALID_PARAMS;
if (vpx_sock && supported_transport_layer(trans_layer) &&
supported_network_layer(net_layer))
{
memset(vpx_sock, 0, sizeof(struct vpxsocket));
vpx_sock->nl = net_layer;
vpx_sock->tl = trans_layer;
switch (vpx_sock->nl)
{
case vpx_IPv4:
vpx_sock->sock = socket(PF_INET, trans_layer, 0);
break;
case vpx_IPv6:
#if vpx_NET_SUPPORT_IPV6
vpx_sock->sock = socket(PF_INET6, trans_layer, 0);
#endif
break;
}
if (vpx_sock->sock != INVALID_SOCKET)
{
rv = TC_OK;
vpx_sock->state = kInited;
vpx_sock->read_timeout_ms = vpx_NET_NO_TIMEOUT;
vpx_sock->send_timeout_ms = vpx_NET_NO_TIMEOUT;
}
else
rv = TC_ERROR;
}
return rv;
}
/*
vpx_net_close(struct vpxsocket* vpx_sock)
vpx_sock - pointer to an vpxsocket structure which
holds the socket to be closed
Attempts to close the socket associated with the vpx_sock structure
Return:
TC_OK: on success
TC_INVALID_PARAMS: if vpx_sock is NULL
TC_ERROR: if the socket could not be closed
*/
TCRV vpx_net_close(struct vpxsocket *vpx_sock)
{
TCRV rv = TC_INVALID_PARAMS;
if (vpx_sock && (vpx_sock->state & kInited))
{
#if defined(WIN32) || defined(_WIN32_WCE)
rv = closesocket(vpx_sock->sock) ? TC_ERROR : TC_OK;
#else
int ret;
ret = close(vpx_sock->sock);
rv = (ret) ? TC_ERROR : TC_OK;
vpxlog_dbg(LOG_PACKET, "vpx_net_close: fd=%d ret=%d eno=%d\n",
vpx_sock->sock, ret, errno);
#endif
vpx_sock->state = 0;
}
return rv;
}
/*
vpx_net_bind(struct vpxsocket* vpx_sock,
union vpx_sockaddr_x* vpx_sa_x,
tcu16 port)
vpx_sock - pointer to an vpxsocket structure that contains
the socket to be bound
vpx_sa_x - pointer to an vpx_sockaddr_x struct that contains the
interface to bind to or NULL if the user wants to
bind to any interface.
port - the port to bind the socket to
Attempts to bind vpx_sock to port on the interface specified in vpx_sa_x
or to any interface if vpx_sa_x is NULL. If provided vpx_sa_x should have
been filled out by vpx_net_get_addr_info.
Return:
TC_OK: on success
TC_INVALID_PARAMS: if vpx_sock is NULL or does not point to a structure
that was initialized via vpx_net_open
TC_ERROR: if vpx_sock could not be bound to the specified port
and interface
*/
TCRV vpx_net_bind(struct vpxsocket *vpx_sock,
union vpx_sockaddr_x *vpx_sa_x,
tcu16 port)
{
TCRV rv = TC_INVALID_PARAMS;
if (vpx_sock && (vpx_sock->state & kInited))
{
tc32 ret = SOCKET_ERROR;
switch (vpx_sock->nl)
{
case vpx_IPv4:
vpx_sock->local_addr.sa_in.sin_family = AF_INET;
vpx_sock->local_addr.sa_in.sin_addr.s_addr = vpx_sa_x ?
vpx_sa_x->sa_in.sin_addr.s_addr :
INADDR_ANY;
vpx_sock->local_addr.sa_in.sin_port = htons(port);
ret = bind(vpx_sock->sock, (struct sockaddr *)&vpx_sock->local_addr.sa_in,
sizeof(struct sockaddr_in));
break;
case vpx_IPv6:
#if vpx_NET_SUPPORT_IPV6
vpx_sock->local_addr.sa_in6.sin6_family = AF_INET6;
vpx_sock->local_addr.sa_in6.sin6_addr = vpx_sa_x ?
vpx_sa_x->sa_in6.sin6_addr :
in6addr_any;
vpx_sock->local_addr.sa_in6.sin6_port = htons(port);
ret = bind(vpx_sock->sock, (struct sockaddr *)&vpx_sock->local_addr.sa_in6,
sizeof(struct sockaddr_in6));
#endif
break;
}
if (ret != SOCKET_ERROR)
{
vpx_sock->state |= kBound;
rv = TC_OK;
}
else
rv = TC_ERROR;
}
return rv;
}
/*
vpx_net_listen(struct vpxsocket* vpx_sock, tc32 backlog)
vpx_sock - pointer to a properly initialized and bound vpxsocket
structure to be setup to listen for incoming connections
backlog - the maximum length the queue of pending connections can grow to.
If the value is less than 1, backlog will be set to the system's
maximum value.
Attempts to put vpx_sock into a state where it can accept incoming connections.
Return:
TC_OK: on success
TC_INVALID_PARAMS: if vpx_sock is NULL, not properly initialized and bound,
or if the transport layer does not support listening
TC_ERROR: if the vpx_sock could not be put into the listening state
*/
TCRV vpx_net_listen(struct vpxsocket *vpx_sock, tc32 backlog)
{
TCRV rv = TC_INVALID_PARAMS;
if (vpx_sock && (vpx_sock->state & kBound) && (vpx_sock->tl == vpx_TCP))
{
if (backlog < 1)
backlog = SOMAXCONN;
if (listen(vpx_sock->sock, backlog) != SOCKET_ERROR)
{
rv = TC_OK;
vpx_sock->state |= kListening;
}
else
rv = TC_ERROR;
}
return rv;
}
/*
vpx_net_accept(struct vpxsocket* vpx_sock, struct vpxsocket* vpx_sock_peer)
vpx_sock - pointer to a properly initialized, bound and listening
vpxsocket structure
vpx_sock_peer - result parameter; pointer to an vpxsocket structure that
will be filled out with the accepted connection's info
Attempts to have vpx_sock accept connections on the port it's currently
listening. If successful, vpx_sock_peer will be filled out with the
remote peer's info.
Return:
TC_OK: on success
TC_INVALID_PARAMS: if vpx_sock is NULL, was not put into the listening
state via vpx_net_listen or vpx_sock_peer is NULL
TC_ERROR: if there was an error accepting connections on vpx_sock
*/
TCRV vpx_net_accept(struct vpxsocket *vpx_sock, struct vpxsocket *vpx_sock_peer)
{
TCRV rv = TC_INVALID_PARAMS;
if (vpx_sock && (vpx_sock->state & kListening) && vpx_sock_peer)
{
unsigned int len;
switch (vpx_sock->nl)
{
case vpx_IPv4:
len = sizeof(struct sockaddr_in);
vpx_sock_peer->sock = accept(vpx_sock->sock,
(struct sockaddr *)&vpx_sock_peer->remote_addr.sa_in,
&len);
break;
case vpx_IPv6:
#if vpx_NET_SUPPORT_IPV6
len = sizeof(struct sockaddr_in6);
vpx_sock_peer->sock = accept(vpx_sock->sock,
(struct sockaddr *)&vpx_sock_peer->remote_addr.sa_in6,
&len);
#endif
break;
}
if (vpx_sock_peer->sock != INVALID_SOCKET)
{
vpx_sock_peer->nl = vpx_sock->nl;
vpx_sock_peer->tl = vpx_sock->tl;
vpx_sock_peer->state = kInited | kConnected;
vpx_sock_peer->read_timeout_ms = vpx_NET_NO_TIMEOUT;
vpx_sock_peer->send_timeout_ms = vpx_NET_NO_TIMEOUT;
rv = TC_OK;
}
else
rv = TC_ERROR;
}
return rv;
}
/*
vpx_net_connect(struct vpxsocket* vpx_sock, tc8* ip_addr, tcu16 port)
vpx_sock - pointer to an vpxsocket structure that is to be connencted
to the endpoint described by ip_addr and port
ip_addr - pointer to a character string that contains the address to
attempt to connect to
port - the port to attempt to connect to on ip_addr
Attempt to connect vpx_sock to port on ip_addr.
Return:
TC_OK: on success
TC_INVALID_PARAMS: if vpx_sock is NULL, not properly initialized or
if ip_addr is NULL
TC_ERROR: if information could not be obtained about the host or
if a connection could not be established
*/
TCRV vpx_net_connect(struct vpxsocket *vpx_sock, tc8 *ip_addr, tcu16 port)
{
TCRV rv = TC_INVALID_PARAMS;
if (vpx_sock && (vpx_sock->state & kInited))
{
rv = vpx_net_get_addr_info(ip_addr, port, vpx_sock->nl, vpx_sock->tl, &vpx_sock->remote_addr);
if (!rv)
{
tc32 ret = 0;
switch (vpx_sock->nl)
{
case vpx_IPv4:
ret = connect(vpx_sock->sock,
(struct sockaddr *)&vpx_sock->remote_addr.sa_in,
sizeof(struct sockaddr_in));
break;
case vpx_IPv6:
#if vpx_NET_SUPPORT_IPV6
ret = connect(vpx_sock->sock,
(struct sockaddr *)&vpx_sock->remote_addr.sa_in6,
sizeof(struct sockaddr_in6));
#endif
break;
}
if (!ret)
{
rv = TC_OK;
vpx_sock->state |= kConnected;
}
else
rv = TC_ERROR;
}
}
return rv;
}
/*
vpx_net_get_addr_info(tc8* ip_addr,
tcu16 port,
enum network_layer net_layer,
enum transport_layer trans_layer,
union vpx_sockaddr_x* vpx_sa_x)
ip_addr - address to resolve
port - port on ip_addr to obtain information for or 0 indicating any
net_layer - network layer desired on the host machine
trans_layer - the transport layer desired on the host machine
vpx_sa_x - pointer to an vpx_sockaddr_x union that will receive host
information if obtained
Attempts to acquire information about ip_addr that can be used in a
connection attempt. This information will be stored in vpx_sa_x which
can be used in subsequent vpx_net_ functions
Return:
TC_OK: on success
TC_INVALID_PARAMS: if ip_addr or vpx_sa_x are NULL or if the specified
network/transport layers are unsupported by this library
TC_ERROR: if no information could be obtained about the host
*/
TCRV vpx_net_get_addr_info(tc8 *ip_addr,
tcu16 port,
enum network_layer net_layer,
enum transport_layer trans_layer,
union vpx_sockaddr_x *vpx_sa_x)
{
TCRV rv = TC_INVALID_PARAMS;
if (ip_addr && vpx_sa_x &&
supported_network_layer(net_layer) &&
supported_transport_layer(trans_layer))
{
#if vpx_NET_SUPPORT_IPV6
char portstr[6];
struct addrinfo hints;
struct addrinfo *host = NULL;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_socktype = trans_layer;
switch (net_layer)
{
case vpx_IPv4:
hints.ai_family = PF_INET;
break;
case vpx_IPv6:
hints.ai_family = PF_INET6;
break;
}
sprintf(portstr, "%hu", port);
if (!getaddrinfo(ip_addr, portstr, &hints, &host))
{
memcpy(&vpx_sa_x->sa_in6, host->ai_addr, host->ai_addrlen);
freeaddrinfo(host);
rv = TC_OK;
}
else
rv = TC_ERROR;
#else
tc8 *p = ip_addr;
tc8 is_host_name = 0;
//IPv4, unfortunately gethostbyname will fail if given a dotted decimal ip,
//unlike getaddrinfo. So to avoid any delay's we check to see what
//representation of an ip we have,
//if there's a letter assume we have a hostname
while (*p && !(is_host_name = (tolower(*p) >= 'a' && tolower(*p) <= 'z'))) ++p;
if (is_host_name)
{
#if defined(__SYMBIAN32__) && !defined(__WINS__)
//vpxlog_dbg("Trying to get address by name %s:%d\n", ip_addr, port);
{
RSocketServ iSocketServ;
TNameEntry iNameEntry;
TNameRecord iNameRecord;
RHostResolver iResolver;
TRequestStatus iStatus;
User::LeaveIfError(iSocketServ.Connect());
User::LeaveIfError(iResolver.Open(iSocketServ, KAfInet, KProtocolInetUdp));
TPtrC8 ihostname8((const TUint8 *)ip_addr, strlen(ip_addr));
TBuf<256> ihostname;
ihostname.Copy(ihostname8);
//vpxlog_dbg("ihostname = %s\n", ihostname.Ptr());
iResolver.GetByName(ihostname, iNameEntry, iStatus);
User::WaitForRequest(iStatus);
if (iStatus == KErrNone)
{
iNameRecord = iNameEntry();
TInetAddr addr;
addr = TInetAddr::Cast(iNameRecord.iAddr);
bzero(&vpx_sa_x->sa_in, sizeof(struct sockaddr_in));
vpx_sa_x->sa_in.sin_addr.s_addr = ntohl(addr.Address());
vpx_sa_x->sa_in.sin_family = AF_INET;
vpx_sa_x->sa_in.sin_port = htons(port);
rv = TC_OK;
//vpxlog_dbg("I got an address of %x\n",vpx_sa_x->sa_in.sin_addr.s_addr);
}
else
{
rv = TC_ERROR;
//vpxlog_dbg("I got an error message %d\n",iStatus.Int() );
}
iResolver.Close();
iSocketServ.Close();
}
#else
#if defined(VXWORKS)
tc32 host;
/* The only way VxWorks will be able to resolve a host name
is if it's in its host table or if the image was built with
the resolvLib included */
if ((host = hostGetByName(ip_addr)) != ERROR)
{
vpx_sa_x->sa_in.sin_addr.s_addr = host;
#else
struct hostent *host;
if ((host = gethostbyname(ip_addr)))
{
memcpy(&vpx_sa_x->sa_in.sin_addr, host->h_addr_list[0], sizeof(struct in_addr));
#endif
vpx_sa_x->sa_in.sin_family = AF_INET;
vpx_sa_x->sa_in.sin_port = htons(port);
rv = TC_OK;
}
else
{
//could not resolve host name
rv = TC_ERROR;
}
//vpxlog_dbg("gethostbyname returned %d %x\n", rv, host);
#endif
}
else
{
#if defined(__SYMBIAN32__)
bzero(&vpx_sa_x->sa_in, sizeof(struct sockaddr_in));
if ((vpx_sa_x->sa_in.sin_addr.s_addr = inet_addr(ip_addr)) != INADDR_NONE)
{
#elif defined(WIN32) || defined(_WIN32_WCE)
if ((vpx_sa_x->sa_in.sin_addr.s_addr = inet_addr(ip_addr)) != INADDR_NONE)
{
#else
if ((vpx_sa_x->sa_in.sin_addr.s_addr = inet_addr(ip_addr)) > 0)
{
#endif
vpx_sa_x->sa_in.sin_family = AF_INET;
vpx_sa_x->sa_in.sin_port = htons(port);
rv = TC_OK;
}
else
{
vpxlog_dbg(ERRORS, "vpx_network: inet_addr() call returned INADDR_NONE\n");
rv = TC_ERROR;
}
}
#endif
}
return rv;
}
/*
vpx_net_read(struct vpxsocket* vpx_sock, tc8* buffer,
tc32 buf_len, tc32* bytes_read)
vpx_sock - pointer to a properly initialized vpxsocket structure
buffer - pointer to a character array where data is to be stored
buf_len - the max max amount of data to be read into buffer
bytes_read - pointer to an integer that will receive the actual amount
of data read or NULL
Attempts to read at most buf_len bytes off the socket into buffer. This
operation can only be done on a connected socket. If a read timeout has
been set to a non-zero value the operation will fail if it could not be
completed within the specified time. If the read timeout has been set to
0 the operation will fail if it could not be completed immediately.
Return:
TC_OK: on success
TC_INVALID_PARAMS: if vpx_sock is NULL, was not properly initialized
via vpx_net_open, was not connected via
vpx_net_connect, buffer is NULL or buf_len is <= 0
TC_TIMEDOUT: if a read timeout has been set to non-zero value and the
operation could not be completed in the specified time
TC_WOULDBLOCK: if the read timeout has been set to 0 and the operation
could not be completed immediately
TC_ERROR: if an error other than timed out or would block is encountered
trying to complete the operation, more information can be
obtained through calling vpx_net_get_error
*/
TCRV vpx_net_read(struct vpxsocket *vpx_sock, tc8 *buffer,
tc32 buf_len, tc32 *bytes_read)
{
TCRV rv = TC_INVALID_PARAMS;
if (vpx_sock && (vpx_sock->state & kConnected) && buffer && (buf_len > 0))
{
tc32 total_bytes_read = 0,
ret;
if (vpx_sock->read_timeout_ms)
{
struct timeval tv;
fd_set read_fds;
FD_ZERO(&read_fds);
FD_SET(vpx_sock->sock, &read_fds);
if (vpx_sock->read_timeout_ms != vpx_NET_NO_TIMEOUT)
{
tv.tv_sec = 0;
tv.tv_usec = vpx_sock->read_timeout_ms * 1000;
#if !defined(__SYMBIAN32__)
ret = select(vpx_sock->sock + 1, &read_fds, NULL, NULL, &tv);
#else
/*jwz 2005-10-04, symbian seems only to define a blocking select
via ioctl; as the client doesn't currently hit this path I
haven't looked for a replacement*/
ret = -1;
vpxassert(vpx_sock->read_timeout_ms == vpx_NET_NO_TIMEOUT);
#endif
}
else
{
#if !defined(__SYMBIAN32__)
ret = select(vpx_sock->sock + 1, &read_fds, NULL, NULL, NULL);
#else
/*jwz 2005-10-04, symbian seems only to define a blocking select
via ioctl; this select was unnecessary as the socket is set to
blocking.*/
ret = 1;
#endif
}
if (ret > 0)
{
tc32 n = 0;
#if defined(WIN32) || defined(_WIN32_WCE)
unsigned long recv_len = 0;
ioctlsocket(vpx_sock->sock, FIONREAD, &recv_len);
#elif defined(VXWORKS)
tcu32 recv_len = 0;
ioctl(vpx_sock->sock, FIONREAD, (tc32)&recv_len);
#elif defined(__SYMBIAN32__)
tcu32 recv_len = 0;
ioctl(vpx_sock->sock, E32IONREAD, &recv_len);
#else
tcu32 recv_len = 0;
ioctl(vpx_sock->sock, FIONREAD, &recv_len);
#endif
/* At this point select has said that the socket is readable.
We want to try to read once before checking the amount
available on the socket in case there is an error pending,
in which case recv_len would be 0. */
do
{
n = recv(vpx_sock->sock, buffer + total_bytes_read, buf_len, 0);
total_bytes_read += n;
buf_len -= n;
}
while (buf_len && ((tcu32)total_bytes_read < recv_len) && (n > 0));
rv = (n <= 0) ? TC_ERROR : TC_OK;
}
else if (ret < 0)
rv = TC_ERROR;
else
rv = TC_TIMEDOUT;
}
else
{
//set the socket to non-blocking...
if (!set_nonblocking_io(vpx_sock, 1))
{
#if defined(WIN32) || defined(_WIN32_WCE)
tc32 error = 0;
#endif
total_bytes_read = recv(vpx_sock->sock, buffer, buf_len, 0);
if (total_bytes_read < 0)
{
#if defined(LINUX) || defined(VXWORKS) || defined(__uClinux__) || defined(__SYMBIAN32__)
switch (errno)
{
case EAGAIN:
#if defined(EWOULDBLOCK) && EAGAIN != EWOULDBLOCK
case EWOULDBLOCK:
#endif
rv = TC_WOULDBLOCK;
break;
case EINTR:
case EFAULT:
rv = TC_ERROR;
break;
default:
/* default return is TC_INVALID_PARAMS and
covers EBADF, ENOTCONN, ENOTSOCK, EINVAL, etc */
break;
}
#elif defined(WIN32) || defined(_WIN32_WCE)
switch (error = WSAGetLastError())
{
case WSAEWOULDBLOCK:
rv = TC_WOULDBLOCK;
break;
case WSAEMSGSIZE:
rv = TC_MSG_TOO_LARGE;
break;
case WSAENETDOWN:
case WSAEFAULT:
case WSAEINTR:
case WSAEINPROGRESS:
case WSAENETRESET:
case WSAESHUTDOWN:
case WSAECONNABORTED:
case WSAETIMEDOUT:
case WSAECONNRESET:
rv = TC_ERROR;
break;
default:
/* defaults are approximately equal to those
described in the LINUX #if block */
break;
}
#endif
}
else
rv = TC_OK;
//reset the socket to blocking...
if (set_nonblocking_io(vpx_sock, 0))
rv = TC_ERROR;
#if defined(WIN32) || defined(_WIN32_WCE)
else
WSASetLastError(error);
#endif
}
}
if (bytes_read)
*bytes_read = (total_bytes_read > 0) ? total_bytes_read : 0;
}
return rv;
}
/*
vpx_net_recvfrom(struct vpxsocket* vpx_sock, tc8* buffer, tc32 buf_len,
tc32* bytes_read, union vpx_sockaddr_x* vpx_sa_x)
vpx_sock - pointer to a properly initialized vpxsocket structure
buffer - pointer to a character array where data is to be stored
buf_len - max amount of data to be read
bytes_read - pointer to an integer that will receive the actual amount
of data read or NULL
vpx_sa_from - pointer to a vpx_sockaddr_x union used to store the address
of the remote peer the data was received from or NULL
Attempts to read at most buf_len bytes off the socket into buffer. This
operation can be done on a connected or unconnected socket. If a
read timeout has been set to a non-zero value the operation will fail if
it could not be completed within the specified time. If the send timeout
has been set to 0 the operation will fail if it could not be completed
immediately. If data is received and vpx_sa_from is non-NULL the address
of the sender will be stored in it.
Return:
TC_OK: on success
TC_INVALID_PARAMS: if vpx_sock is NULL, was not properly initialized
via vpx_net_open, buffer is NULL or buf_len is <= 0
TC_TIMEDOUT: if a read timeout has been set to non-zero value and the
operation could not be completed in the specified time
TC_WOULDBLOCK: if the read timeout has been set to 0 and the operation
could not be completed immediately
TC_ERROR: if an error other than timed out or would block is encountered
trying to complete the operation, more information can be
obtained through calling vpx_net_get_error
*/
TCRV vpx_net_recvfrom(struct vpxsocket *vpx_sock, tc8 *buffer, tc32 buf_len,
tc32 *bytes_read, union vpx_sockaddr_x *vpx_sa_from)
{
TCRV rv = TC_INVALID_PARAMS;
if (vpx_sock && (vpx_sock->state & kInited) && buffer && (buf_len > 0))
{
tc32 n = -1;
unsigned int len;
if (vpx_sock->read_timeout_ms)
{
tc32 ret;
fd_set read_fds;
struct timeval tv;
FD_ZERO(&read_fds);
FD_SET(vpx_sock->sock, &read_fds);
if (vpx_sock->read_timeout_ms != vpx_NET_NO_TIMEOUT)
{
tv.tv_sec = 0;
tv.tv_usec = vpx_sock->read_timeout_ms * 1000;
#if !defined(__SYMBIAN32__)
ret = select(vpx_sock->sock + 1, &read_fds, NULL, NULL, &tv);
#else
/*jwz 2005-10-04, symbian seems only to define a blocking select
via ioctl; as the client doesn't currently hit this path I
haven't looked for a replacement*/
ret = -1;
vpxassert(vpx_sock->read_timeout_ms == vpx_NET_NO_TIMEOUT);
#endif
}
else
{
#if !defined(__SYMBIAN32__)
ret = select(vpx_sock->sock + 1, &read_fds, NULL, NULL, NULL);
#else
/*jwz 2005-10-04, symbian seems only to define a blocking select
via ioctl; this select was unnecessary as the socket is set to
blocking.*/
ret = 1;
#endif
}
if (ret > 0)
{
switch (vpx_sock->nl)
{
case vpx_IPv4:
len = sizeof(struct sockaddr_in);
n = recvfrom(vpx_sock->sock, buffer, buf_len, 0,
(struct sockaddr *)&vpx_sock->remote_addr.sa_in, &len);
#if defined(VXWORKS)
vpx_sock->remote_addr.sa_in.sin_family = AF_INET;
#endif
break;
case vpx_IPv6:
#if vpx_NET_SUPPORT_IPV6
len = sizeof(struct sockaddr_in6);
n = recvfrom(vpx_sock->sock, buffer, buf_len, 0,
(struct sockaddr *)&vpx_sock->remote_addr.sa_in6, &len);
#endif
break;
}
if (n == SOCKET_ERROR)
{
if (vpx_sock->tl == vpx_UDP)
{
#if defined(LINUX) || defined(VXWORKS) || defined(__uClinux__)
if (errno == EMSGSIZE)
//n = buf_len;
rv = TC_MSG_TOO_LARGE;
#elif defined(WIN32) || defined(_WIN32_WCE)
if (WSAGetLastError() == WSAEMSGSIZE)
//n = buf_len;
rv = TC_MSG_TOO_LARGE;
#elif defined(__SYMBIAN32__)
/*jwz 2005-10-04, symbian doesn't define EMSGSIZE. I
haven't looked for a replacement as the client
currently won't be using udp*/
if (errno == KErrTooBig) rv = TC_MSG_TOO_LARGE;
#endif
}
else
rv = TC_ERROR;
}
else
{
rv = TC_OK;
if (vpx_sa_from)
{
switch (vpx_sock->nl)
{
case vpx_IPv4:
memcpy(&vpx_sa_from->sa_in, &vpx_sock->remote_addr.sa_in,
sizeof(struct sockaddr_in));
break;
case vpx_IPv6:
#if vpx_NET_SUPPORT_IPV6
memcpy(&vpx_sa_from->sa_in6, &vpx_sock->remote_addr.sa_in6,
sizeof(struct sockaddr_in6));
#endif
break;
}
}
}
}
else if (ret < 0)
rv = TC_ERROR;
else
rv = TC_TIMEDOUT;
}
else
{
//set the socket to non-blocking...
if (!set_nonblocking_io(vpx_sock, 1))
{
#if defined(WIN32) || defined(_WIN32_WCE)
tc32 error = 0;
#endif
switch (vpx_sock->nl)
{
case vpx_IPv4:
len = sizeof(struct sockaddr_in);
n = recvfrom(vpx_sock->sock, buffer, buf_len, 0,
(struct sockaddr *)&vpx_sock->remote_addr.sa_in, &len);
#if defined(VXWORKS)
vpx_sock->remote_addr.sa_in.sin_family = AF_INET;
#endif
break;
case vpx_IPv6:
#if vpx_NET_SUPPORT_IPV6
len = sizeof(struct sockaddr_in6);
n = recvfrom(vpx_sock->sock, buffer, buf_len, 0,
(struct sockaddr *)&vpx_sock->remote_addr.sa_in6, &len);
#endif
break;
}
if (n < 0)
{
#if defined(LINUX) || defined(VXWORKS) || defined(__uClinux__) || defined(__SYMBIAN32__)
switch (errno)
{
case EAGAIN:
#if defined(EWOULDBLOCK) && EAGAIN != EWOULDBLOCK
case EWOULDBLOCK:
#endif
rv = TC_WOULDBLOCK;
break;
case EINTR:
case EFAULT:
rv = TC_ERROR;
break;
default:
/* default return is TC_INVALID_PARAMS and
covers EBADF, ENOTCONN, ENOTSOCK, EINVAL, etc */
break;
}
#elif defined(WIN32) || defined(_WIN32_WCE)
switch (error = WSAGetLastError())
{
case WSAEWOULDBLOCK:
rv = TC_WOULDBLOCK;
break;
case WSAEMSGSIZE:
rv = TC_MSG_TOO_LARGE;
break;
case WSAENETDOWN:
case WSAEFAULT:
case WSAEINTR:
case WSAEINPROGRESS:
case WSAENETRESET:
case WSAESHUTDOWN:
case WSAECONNABORTED:
case WSAETIMEDOUT:
case WSAECONNRESET:
rv = TC_ERROR;
break;
default:
/* defaults are approximately equal to those
described in the LINUX #if block */
break;
}
#endif
}
else
{
rv = TC_OK;
if (vpx_sa_from)
{
switch (vpx_sock->nl)
{
case vpx_IPv4:
memcpy(&vpx_sa_from->sa_in, &vpx_sock->remote_addr.sa_in,
sizeof(struct sockaddr_in));
break;
case vpx_IPv6:
#if vpx_SUPPORT_IPV6
memcpy(&vpx_sa_from->sa_in6, &vpx_sock->remote_addr.sa_in6,
sizeof(struct sockaddr_in6));
#endif
break;
}
}
}
//reset the socket to blocking...
if (set_nonblocking_io(vpx_sock, 0))
rv = TC_ERROR;
#if defined(WIN32) || defined(_WIN32_WCE)
else
WSASetLastError(error);
#endif
}
}
if (bytes_read)
*bytes_read = n;
}
return rv;
}
/*
vpx_net_send(struct vpxsocket* vpx_sock, tc8* buffer,
tc32 buf_len, tc32* bytes_sent)
vpx_sock - pointer to a properly initialized vpxsocket structure
buffer - pointer to a character array containing data to be sent
buf_len - the length of the data in buffer
bytes_sent - pointer to an integer that will receive the actual amount
of data sent or NULL
Attempts to send buffer to vpx_sock's connected peer. If a send timeout
has been set to a non-zero value the operation will fail if it could not
be completed within the specified time. If the send timeout has been set
to 0 the operation will fail if it could not be completed immediately.
Return:
TC_OK: on success
TC_INVALID_PARAMS: if vpx_sock is NULL, was not properly initialized
via vpx_net_open, was not connected via
vpx_net_connect, buffer is NULL or buf_len is <= 0
TC_TIMEDOUT: if a send timeout has been set to non-zero value and the
operation could not be completed in the specified time
TC_WOULDBLOCK: if the send timeout has been set to 0 and the operation
could not be completed immediately
TC_ERROR: if an error other than timed out or would block is encountered
trying to complete the operation, more information can be
obtained through calling vpx_net_get_error
*/
TCRV vpx_net_send(struct vpxsocket *vpx_sock, tc8 *buffer,
tc32 buf_len, tc32 *bytes_sent)
{
TCRV rv = TC_INVALID_PARAMS;
if (vpx_sock && (vpx_sock->state & kConnected) && buffer && (buf_len > 0))
{
tc32 n = 0;
if (vpx_sock->send_timeout_ms)
{
tc32 ret;
struct timeval tv;
fd_set write_fds;
FD_ZERO(&write_fds);
FD_SET(vpx_sock->sock, &write_fds);
if (vpx_sock->send_timeout_ms != vpx_NET_NO_TIMEOUT)
{
tv.tv_sec = 0;
tv.tv_usec = vpx_sock->send_timeout_ms * 1000;
#if !defined(__SYMBIAN32__)
ret = select(vpx_sock->sock + 1, NULL, &write_fds, NULL, &tv);
#else
/*jwz 2005-10-04, symbian seems only to define a blocking select
via ioctl; as the client doesn't currently hit this path I
haven't looked for a replacement*/
ret = -1;
vpxassert(vpx_sock->send_timeout_ms == vpx_NET_NO_TIMEOUT);
#endif
}
else
{
#if !defined(__SYMBIAN32__)
ret = select(vpx_sock->sock + 1, NULL, &write_fds, NULL, NULL);
#else
/*jwz 2005-10-04, symbian seems only to define a blocking select
via ioctl; this select was unnecessary as the socket is set to
blocking.*/
ret = 1;
#endif
}
if (ret > 0)
n = send(vpx_sock->sock, buffer, buf_len, 0);
else if (ret < 0)
rv = TC_ERROR;
else
rv = TC_TIMEDOUT;
rv = (n == SOCKET_ERROR) ? TC_ERROR : TC_OK;
}
else
{
//set the socket to non-blocking...
if (!set_nonblocking_io(vpx_sock, 1))
{
#if defined(WIN32) || defined(_WIN32_WCE)
tc32 error = 0;
#endif
n = send(vpx_sock->sock, buffer, buf_len, 0);
if (n < 0)
{
#if defined(LINUX) || defined(VXWORKS) || defined(__uClinux__) || defined(__SYMBIAN32__)
switch (errno)
{
case EAGAIN:
#if defined(EWOULDBLOCK) && EAGAIN != EWOULDBLOCK
case EWOULDBLOCK:
#endif
rv = TC_WOULDBLOCK;
break;
case EFAULT:
case EINTR:
#ifdef EMSGSIZE
case EMSGSIZE:
#endif
#ifdef ENOBUFS
case ENOBUFS:
#endif
case ENOMEM:
case EPIPE:
rv = TC_ERROR;
break;
default:
/* default return is TC_INVALID_PARAMS and
covers EBADF, ENOTSOCK, EINVAL, etc */
break;
}
#elif defined(WIN32) || defined(_WIN32_WCE)
switch (error = WSAGetLastError())
{
case WSAEWOULDBLOCK:
rv = TC_WOULDBLOCK;
break;
case WSAEMSGSIZE:
rv = TC_MSG_TOO_LARGE;
break;
case WSAENETDOWN:
case WSAEACCES:
case WSAEINTR:
case WSAEINPROGRESS:
case WSAEFAULT:
case WSAENETRESET:
case WSAENOBUFS:
case WSAESHUTDOWN:
case WSAEHOSTUNREACH:
case WSAECONNABORTED:
case WSAECONNRESET:
case WSAETIMEDOUT:
rv = TC_ERROR;
break;
default:
/* defaults are approximately equal to those
described in the LINUX #if block */
break;
}
#endif
}
else
rv = TC_OK;
//reset the socket to blocking...
if (set_nonblocking_io(vpx_sock, 0))
rv = TC_ERROR;
#if defined(WIN32) || defined(_WIN32_WCE)
else
WSASetLastError(error);
#endif
}
}
if (bytes_sent)
*bytes_sent = n;
}
return rv;
}
/*
vpx_net_sendto(struct vpxsocket* vpx_sock, tc8* buffer, tc32 buf_len,
tc32* bytes_sent, union vpx_sockaddr_x vpx_sa_to)
vpx_sock - pointer to a properly initialized vpxsocket structure
buffer - pointer to a character array containing data to be sent
buf_len - the length of the data in buffer
bytes_sent - pointer to an integer that will receive the actual amount
of data sent or NULL
vpx_sa_to - vpx_sockaddr_x containing the address of the target
Attempts to send buffer to vpx_sockaddr_to. This operation can be done on
connected and unconnected sockets. If a send timeout has been set
to a non-zero value the operation will fail if it could not be completed
within the specified time. If the send timeout has been set to 0 the
operation will fail if it could not be completed immediately.
Return:
TC_OK: on success
TC_INVALID_PARAMS: if vpx_sock is NULL, was not properly initialized
via vpx_net_open, buffer is NULL or buf_len is <= 0
TC_TIMEDOUT: if a send timeout has been set to non-zero value and the
operation could not be completed in the specified time
TC_WOULDBLOCK: if the send timeout has been set to 0 and the operation
could not be completed immediately
TC_ERROR: if an error other than timed out or would block is encountered
trying to complete the operation, more information can be
obtained through calling vpx_net_get_error
*/
TCRV vpx_net_sendto(struct vpxsocket *vpx_sock, tc8 *buffer, tc32 buf_len,
tc32 *bytes_sent, union vpx_sockaddr_x vpx_sa_to)
{
TCRV rv = TC_INVALID_PARAMS;
if (vpx_sock && (vpx_sock->state & kInited) && buffer && (buf_len > 0))
{
tc32 n = 0;
if (vpx_sock->send_timeout_ms)
{
tc32 ret;
fd_set write_fds;
struct timeval tv;
FD_ZERO(&write_fds);
FD_SET(vpx_sock->sock, &write_fds);
if (vpx_sock->send_timeout_ms != vpx_NET_NO_TIMEOUT)
{
tv.tv_sec = 0;
tv.tv_usec = vpx_sock->send_timeout_ms * 1000;
#if !defined(__SYMBIAN32__)
ret = select(vpx_sock->sock + 1, NULL, &write_fds, NULL, &tv);
#else
/*jwz 2005-10-04, symbian seems only to define a blocking select
via ioctl; as the client doesn't currently hit this path I
haven't looked for a replacement*/
ret = -1;
vpxassert(vpx_sock->send_timeout_ms == vpx_NET_NO_TIMEOUT);
#endif
}
else
{
#if !defined(__SYMBIAN32__)
ret = select(vpx_sock->sock + 1, NULL, &write_fds, NULL, NULL);
#else
/*jwz 2005-10-04, symbian seems only to define a blocking select
via ioctl; this select was unnecessary as the socket is set to
blocking.*/
ret = 1;
#endif
}
if (ret > 0)
{
switch (vpx_sock->nl)
{
case vpx_IPv4:
n = sendto(vpx_sock->sock, buffer, buf_len, 0,
(struct sockaddr *)&vpx_sa_to.sa_in,
sizeof(struct sockaddr_in));
break;
case vpx_IPv6:
#if vpx_SUPPORT_IPV6
n = sendto(vpx_sock->sock, buffer, buf_len, 0,
(struct sockaddr *)&vpx_sa_to.sa_in6,
sizeof(struct sockaddr_in6));
#endif
break;
}
rv = (n == SOCKET_ERROR) ? TC_ERROR : TC_OK;
}
else if (ret < 0)
{
rv = TC_ERROR;
}
else
rv = TC_TIMEDOUT;
}
else
{
//set the socket to non-blocking...
if (!set_nonblocking_io(vpx_sock, 1))
{
#if defined(WIN32) || defined(_WIN32_WCE)
tc32 error = 0;
#endif
switch (vpx_sock->nl)
{
case vpx_IPv4:
n = sendto(vpx_sock->sock, buffer, buf_len, 0,
(struct sockaddr *)&vpx_sa_to.sa_in,
sizeof(struct sockaddr_in));
break;
case vpx_IPv6:
#if vpx_SUPPORT_IPV6
n = sendto(vpx_sock->sock, buffer, buf_len, 0,
(struct sockaddr *)&vpx_sa_to.sa_in6,
sizeof(struct sockaddr_in6));
#endif
break;
}
if (n < 0)
{
#if defined(LINUX) || defined(VXWORKS) || defined(__uClinux__) || defined(__SYMBIAN32__)
switch (errno)
{
case EAGAIN:
#if defined(EWOULDBLOCK) && EAGAIN != EWOULDBLOCK
case EWOULDBLOCK:
#endif
rv = TC_WOULDBLOCK;
break;
case EFAULT:
case EINTR:
#ifdef EMSGSIZE
case EMSGSIZE:
#endif
#ifdef ENOBUFS
case ENOBUFS:
#endif
case ENOMEM:
case EPIPE:
rv = TC_ERROR;
break;
default:
/* default return is TC_INVALID_PARAMS and
covers EBADF, ENOTSOCK, EINVAL, etc */
break;
}
#elif defined(WIN32) || defined(_WIN32_WCE)
switch (error = WSAGetLastError())
{
case WSAEWOULDBLOCK:
rv = TC_WOULDBLOCK;
break;
case WSAEMSGSIZE:
rv = TC_MSG_TOO_LARGE;
break;
case WSAENETDOWN:
case WSAEACCES:
case WSAEINTR:
case WSAEINPROGRESS:
case WSAEFAULT:
case WSAENETRESET:
case WSAENOBUFS:
case WSAESHUTDOWN:
case WSAEHOSTUNREACH:
case WSAECONNABORTED:
case WSAECONNRESET:
case WSAETIMEDOUT:
rv = TC_ERROR;
break;
default:
/* defaults are approximately equal to those
described in the LINUX #if block */
break;
}
#endif
}
else
rv = TC_OK;
//reset the socket to blocking...
if (set_nonblocking_io(vpx_sock, 0))
rv = TC_ERROR;
#if defined(WIN32) || defined(_WIN32_WCE)
else
WSASetLastError(error);
#endif
}
}
if (bytes_sent)
*bytes_sent = n;
}
return rv;
}
/*
vpx_net_is_readable(struct vpxsocket* vpx_sock)
vpx_sock - pointer to a properly initialized vpxsocket structure to
be polled to see if data can be read from it
Return:
0: vpx_sock was NULL, did not point to a vpxsocket structure that was
initialized via vpx_net_open or the socket has no data that can be read
1: the socket has data that can be read
*/
tc32 vpx_net_is_readable(struct vpxsocket *vpx_sock)
{
tc32 is_readable = 0;
if (vpx_sock && (vpx_sock->state & kInited))
{
tc32 ret;
#ifndef __SYMBIAN32__
struct timeval tv = {0, 0};
fd_set read_fds;
FD_ZERO(&read_fds);
FD_SET(vpx_sock->sock, &read_fds);
ret = select(vpx_sock->sock + 1, &read_fds, NULL, NULL, &tv);
if ((ret > 0) && FD_ISSET(vpx_sock->sock, &read_fds))
is_readable = 1;
#else
/*jwz 2005-10-04, we do use this in the client to detect an error
condition. we'll have to see if this partial implementation is
enough; perhaps we'll have to write a wrapper for the RSocket class*/
/*jwz 2008-01-31, not sure whether this select workaround is necessary
now, but current builds have been using it w/no visible ill effects*/
char b;
ret = set_nonblocking_io(vpx_sock, 1);
vpxassert(!ret);
ret = (!ret) ? recv(vpx_sock->sock, &b, 1, MSG_PEEK) : ret;
if (ret > 0) is_readable = 1;
else if (errno != EAGAIN && errno != KErrWouldBlock/*-1000*/)
{
vpxlog_error("vpx_net_is_readable, ret=%d eno=%d\n", ret, errno);
is_readable = 1;
}
else is_readable = 0;
ret = set_nonblocking_io(vpx_sock, 0);
vpxassert(!ret);
#endif
}
return is_readable;
}
/*
vpx_net_amount_readable(struct vpxsocket* vpx_sock, TCRV* rv)
vpx_sock - pointer to a properly initialized vpxsocket structure to
be polled to see if data can be read from it
rv - TCRV pointer to receive the result of the function. This parameter
may be NULL. rv will be set to TC_OK on success and TC_ERROR
on error.
Return:
The amount of data in bytes able to be read off the socket
*/
tc32 vpx_net_amount_readable(struct vpxsocket *vpx_sock, TCRV *rv)
{
tc32 ret;
tc32 amount = 0;
if (vpx_sock && (vpx_sock->state & kInited))
{
#if defined(WIN32) || defined(_WIN32_WCE)
unsigned long amt;
ret = ioctlsocket(vpx_sock->sock, FIONREAD, &amt);
amount = (tc32)amt;
#elif defined(LINUX) || defined(__uClinux__)
ret = ioctl(vpx_sock->sock, FIONREAD, &amount);
#elif defined(VXWORKS)
ret = ioctl(vpx_sock->sock, FIONREAD, (tc32)&amount);
#elif defined(__SYMBIAN32__)
ret = ioctl(vpx_sock->sock, E32IONREAD, &amount);
#endif
if (rv)
*rv = (ret == SOCKET_ERROR) ? TC_ERROR : TC_OK;
}
return amount;
}
/*
vpx_net_is_writeable(struct vpxsocket* vpx_sock)
vpx_sock - pointer to a properly initialized vpxsocket structure to
be polled to see if data can be written to it
Return:
0: vpx_sock was NULL, did not point to a vpxsocket structure that was
initialized via vpx_net_open or the socket cannot be written to
without blocking
1: the socket can be written to without blocking
*/
tc32 vpx_net_is_writeable(struct vpxsocket *vpx_sock)
{
tc32 is_writeable = 0;
if (vpx_sock && (vpx_sock->state & kInited))
{
tc32 ret;
#if !defined(__SYMBIAN32__)
struct timeval tv = {0, 0};
#endif
fd_set write_fds;
FD_ZERO(&write_fds);
FD_SET(vpx_sock->sock, &write_fds);
#if !defined(__SYMBIAN32__)
ret = select(vpx_sock->sock + 1, NULL, &write_fds, NULL, &tv);
#else
ret = 0;
#endif
if ((ret > 0) &&
(FD_ISSET(vpx_sock->sock, &write_fds)))
is_writeable = 1;
}
return is_writeable;
}
/*
vpx_net_set_read_timeout(struct vpxsocket* vpx_sock, tcu32 read_timeout)
vpx_sock - pointer to a properly initialized vpxsocket structure
read_timeout - time to wait in milliseconds before giving up on a read
operation. 0 indicates that a non-blocking attempt to read
should be made. vpx_NET_NO_TIMEOUT - indicates the socket
should never timeout.
Return:
TC_OK: on success
TC_INVALID_PARAMS: if vpx_sock was NULL or did not point to an vpxsocket
that was initialized via vpx_net_open
*/
TCRV vpx_net_set_read_timeout(struct vpxsocket *vpx_sock, tcu32 read_timeout)
{
TCRV rv = TC_INVALID_PARAMS;
if (vpx_sock && (vpx_sock->state & kInited))
{
vpx_sock->read_timeout_ms = read_timeout;
rv = TC_OK;
}
return rv;
}
/*
vpx_net_set_send_timeout(struct vpxsocket* vpx_sock, tcu32 send_timeout)
vpx_sock - pointer to a properly initialized vpxsocket structure
read_timeout - time to wait in milliseconds before giving up on a send
operation. 0 indicates that a non-blocking attempt to send
should be made. vpx_NET_NO_TIMEOUT - indicates the socket
should never timeout.
Return:
TC_OK: on success
TC_INVALID_PARAMS: if vpx_sock was NULL or did not point to an vpxsocket
that was initialized via vpx_net_open
*/
TCRV vpx_net_set_send_timeout(struct vpxsocket *vpx_sock, tcu32 send_timeout)
{
TCRV rv = TC_INVALID_PARAMS;
if (vpx_sock && (vpx_sock->state & kInited))
{
vpx_sock->send_timeout_ms = send_timeout;
rv = TC_OK;
}
return rv;
}
/*
vpx_net_get_error(tc32* vpx_net_errno)
vpx_net_errno - pointer to a tc32 to store the last system network
error code or NULL if the user does not want it
Return:
A string representing the last system network error that occurred. This
string can only be used until the next call to vpx_net_get_error()
*/
tc8 *vpx_net_get_error(tc32 *vpx_net_errno)
{
#if defined(LINUX) || defined(__uClinux__) || defined(__SYMBIAN32__)
if (vpx_net_errno)
*vpx_net_errno = errno;
return strerror(errno);
#elif defined(VXWORKS)
tc32 error = errno;
tc8 *errStr = "No Error";
switch (error)
{
case ENOTSUP:
errStr = "ENOTSUP";
break;
case EMSGSIZE:
errStr = "EMSGSIZE";
break;
case EDESTADDRREQ:
errStr = "EDESTADDRREQ";
break;
case EPROTOTYPE:
errStr = "EPROTOTYPE";
break;
case ENOPROTOOPT:
errStr = "ENOPROTOOPT";
break;
case EPROTONOSUPPORT:
errStr = "EPROTONOSUPPORT";
break;
case ESOCKTNOSUPPORT:
errStr = "ESOCKTNOSUPPORT";
break;
case EOPNOTSUPP:
errStr = "EOPNOTSUPP";
break;
case EPFNOSUPPORT:
errStr = "EPFNOSUPPORT";
break;
case EAFNOSUPPORT:
errStr = "EAFNOSUPPORT";
break;
case EADDRINUSE:
errStr = "EADDRINUSE";
break;
case EADDRNOTAVAIL:
errStr = "EADDRNOTAVAIL";
break;
case ENOTSOCK:
errStr = "ENOTSOCK";
break;
case ENETUNREACH:
errStr = "ENETUNREACH";
break;
case ENETRESET:
errStr = "ENETRESET";
break;
case ECONNABORTED:
errStr = "ECONNABORTED";
break;
case ECONNRESET:
errStr = "ECONNRESET";
break;
case ENOBUFS:
errStr = "ENOBUFS";
break;
case EISCONN:
errStr = "EISCONN";
break;
case ENOTCONN:
errStr = "ENOTCONN";
break;
case ESHUTDOWN:
errStr = "ESHUTDOWN";
break;
case ETOOMANYREFS:
errStr = "ETOOMANYREFS";
break;
case ETIMEDOUT:
errStr = "ETIMEDOUT";
break;
case ECONNREFUSED:
errStr = "ECONNREFUSED";
break;
case ENETDOWN:
errStr = "ENETDOWN";
break;
case ETXTBSY:
errStr = "ETXTBSY";
break;
case ELOOP:
errStr = "ELOOP";
break;
case EHOSTUNREACH:
errStr = "EHOSTUNREACH";
break;
case ENOTBLK:
errStr = "ENOTBLK";
break;
case EHOSTDOWN:
errStr = "EHOSTDOWN";
break;
}
if (vpx_net_errno)
*vpx_net_errno = error;
return errStr;
#elif defined(WIN32) || defined(_WIN32_WCE)
tc8 *errstr = "No error";
tc32 error = WSAGetLastError();
/* there isn't much use in doing this, but it might give
enough info without having to use net helpmsg */
switch (error)
{
case WSAEWOULDBLOCK:
errstr = "WSAEWOULDBLOCK";
break;
case WSAEINPROGRESS:
errstr = "WSAEINPROGRESS";
break;
case WSAEALREADY:
errstr = "WSAEALREADY";
break;
case WSAENOTSOCK:
errstr = "WSAENOTSOCK";
break;
case WSAEDESTADDRREQ:
errstr = "WSAEDESTADDRREQ";
break;
case WSAEMSGSIZE:
errstr = "WSAEMSGSIZE";
break;
case WSAEPROTOTYPE:
errstr = "WSAEPROTOTYPE";
break;
case WSAENOPROTOOPT:
errstr = "WSAENOPROTOOPT";
break;
case WSAEPROTONOSUPPORT:
errstr = "WSAEPROTONOSUPPORT";
break;
case WSAESOCKTNOSUPPORT:
errstr = "WSAESOCKTNOSUPPORT";
break;
case WSAEOPNOTSUPP:
errstr = "WSAEOPNOTSUPP";
break;
case WSAEPFNOSUPPORT:
errstr = "WSAEPFNOSUPPORT";
break;
case WSAEAFNOSUPPORT:
errstr = "WSAEAFNOSUPPORT";
break;
case WSAEADDRINUSE:
errstr = "WSAEADDRINUSE";
break;
case WSAEADDRNOTAVAIL:
errstr = "WSAEADDRNOTAVAIL";
break;
case WSAENETDOWN:
errstr = "WSAENETDOWN";
break;
case WSAENETUNREACH:
errstr = "WSAENETUNREACH";
break;
case WSAENETRESET:
errstr = "WSAENETRESET";
break;
case WSAECONNABORTED:
errstr = "WSAECONNABORTED";
break;
case WSAECONNRESET:
errstr = "WSAECONNRESET";
break;
case WSAENOBUFS:
errstr = "WSAENOBUFS";
break;
case WSAEISCONN:
errstr = "WSAEISCONN";
break;
case WSAENOTCONN:
errstr = "WSAENOTCONN";
break;
case WSAESHUTDOWN:
errstr = "WSAESHUTDOWN";
break;
case WSAETOOMANYREFS:
errstr = "WSAETOOMANYREFS";
break;
case WSAETIMEDOUT:
errstr = "WSAETIMEDOUT";
break;
case WSAECONNREFUSED:
errstr = "WSAECONNREFUSED";
break;
case WSAELOOP:
errstr = "WSAELOOP";
break;
case WSAENAMETOOLONG:
errstr = "WSAENAMETOOLONG";
break;
case WSAEHOSTDOWN:
errstr = "WSAEHOSTDOWN";
break;
case WSAEHOSTUNREACH:
errstr = "WSAEHOSTUNREACH";
break;
case WSAENOTEMPTY:
errstr = "WSAENOTEMPTY";
break;
case WSAEPROCLIM:
errstr = "WSAEPROCLIM";
break;
case WSAEUSERS:
errstr = "WSAEUSERS";
break;
case WSAEDQUOT:
errstr = "WSAEDQUOT";
break;
case WSAESTALE:
errstr = "WSAESTALE";
break;
case WSAEREMOTE:
errstr = "WSAEREMOTE";
break;
case WSASYSNOTREADY:
errstr = "WSASYSNOTREADY";
break;
case WSAVERNOTSUPPORTED:
errstr = "WSAVERNOTSUPPORTED";
break;
case WSANOTINITIALISED:
errstr = "WSANOTINITIALISED";
break;
case WSAEDISCON:
errstr = "WSAEDISCON";
break;
case WSAENOMORE:
errstr = "WSAENOMORE";
break;
case WSAECANCELLED:
errstr = "WSAECANCELLED";
break;
case WSAEINVALIDPROCTABLE:
errstr = "WSAEINVALIDPROCTABLE";
break;
case WSAEINVALIDPROVIDER:
errstr = "WSAEINVALIDPROVIDER";
break;
case WSAEPROVIDERFAILEDINIT:
errstr = "WSAEPROVIDERFAILEDINIT";
break;
case WSASYSCALLFAILURE:
errstr = "WSASYSCALLFAILURE";
break;
case WSASERVICE_NOT_FOUND:
errstr = "WSASERVICE_NOT_FOUND";
break;
case WSATYPE_NOT_FOUND:
errstr = "WSATYPE_NOT_FOUND";
break;
case WSA_E_NO_MORE:
errstr = "WSA_E_NO_MORE";
break;
case WSA_E_CANCELLED:
errstr = "WSA_E_CANCELLED";
break;
case WSAEREFUSED:
errstr = "WSAEREFUSED";
break;
case WSAHOST_NOT_FOUND:
errstr = "WSAHOST_NOT_FOUND";
break;
}
if (vpx_net_errno)
*vpx_net_errno = error;
return errstr;
#endif
}
/*
vpx_net_recv_buf(struct vpxsocket* vpx_sock, tc8 set, tc32* value)
vpx_sock - a pointer to a properly initialized vpxsocket structure
set - Value indicating whether the option should be set or queried.
1 indicates the option should be set using the value stored
in value. 0 indicates the current value of the option should
be returned in value.
value - depending on the value of set, either contains the size
to set the socket's receive buffer to or will receive the
current size of the socket's receive buffer
Return:
TC_OK: on success
TC_INVALID_PARAMS: if vpx_sock is NULL, wasn't initialized via
vpx_net_open or value is NULL
TC_ERROR: if the option could not be queried/set
*/
TCRV vpx_net_recv_buf(struct vpxsocket *vpx_sock, tc8 set, tc32 *value)
{
tc32 optlen = sizeof(tc32);
return socket_option(vpx_sock, set, SOL_SOCKET, SO_RCVBUF, value, optlen);
}
/*
vpx_net_send_buf(struct vpxsocket* vpx_sock, tc8 set, tc32* value)
vpx_sock - a pointer to a properly initialized vpxsocket structure
set - Value indicating whether the option should be set or queried.
1 indicates the option should be set using the value stored
in value. 0 indicates the current value of the option should
be returned in value.
value - depending on the value of set, either contains the size
to set the socket's send buffer to or will receive the
current size of the socket's send buffer
Return:
TC_OK: on success
TC_INVALID_PARAMS: if vpx_sock is NULL, wasn't initialized via
vpx_net_open or value is NULL
TC_ERROR: if the option could not be queried/set
*/
TCRV vpx_net_send_buf(struct vpxsocket *vpx_sock, tc8 set, tc32 *value)
{
tc32 optlen = sizeof(tc32);
return socket_option(vpx_sock, set, SOL_SOCKET, SO_SNDBUF, value, optlen);
}
/*
vpx_net_reuse_addr(struct vpxsocket* vpx_sock, tc8 set, tc32* value)
vpx_sock - a pointer to a properly initialized vpxsocket structure
set - Value indicating whether the option should be set or queried.
1 indicates the option should be set using the value stored
in value. 0 indicates the current value of the option should
be returned in value.
value - depending on the value of set, either contains an integer
0/1 to indicate whether the socket's reuse address option
should be turned on or off or will receive the current setting
Return:
TC_OK: on success
TC_INVALID_PARAMS: if vpx_sock is NULL, wasn't initialized via
vpx_net_open or value is NULL
TC_ERROR: if the option could not be queried/set
*/
TCRV vpx_net_reuse_addr(struct vpxsocket *vpx_sock, tc8 set, tc32 *value)
{
tc32 optlen = sizeof(tc32);
return socket_option(vpx_sock, set, SOL_SOCKET, SO_REUSEADDR, value, optlen);
}
/*
vpx_net_linger(struct vpxsocket* vpx_sock, tc8 set, tcu16* on, tcu16* sec)
vpx_sock - a pointer to a properly initialized vpxsocket structure
set - Value indicating whether the option should be set or queried.
1 indicates the option should be set using the values stored in
on and sec. 0 indicates the current value of the option should
be returned in on and sec.
on - depending on the value of set indicates whether to turn on/off (1/0)
the linger option or will receive the current setting
sec - depending on the value of set indicates the amount of time in
seconds for the socket to linger or will receive the current value
Return:
TC_OK: on success
TC_INVALID_PARAMS: if vpx_sock is NULL, wasn't initialized via
vpx_net_open or on or sec are NULL
TC_ERROR: if the option could not be queried/set
*/
TCRV vpx_net_linger(struct vpxsocket *vpx_sock, tc8 set, tcu16 *on, tcu16 *sec)
{
TCRV rv = TC_INVALID_PARAMS;
/*on symbian SO_LINGER is defined but there's no linger struct*/
#if !defined(__SYMBIAN32__)
tc32 optlen = sizeof(struct linger);
struct linger l;
if (set && on && sec)
{
l.l_onoff = *on;
l.l_linger = *sec;
rv = socket_option(vpx_sock, set, SOL_SOCKET, SO_LINGER, &l, optlen);
}
else if (on && sec)
{
rv = socket_option(vpx_sock, set, SOL_SOCKET, SO_LINGER, &l, optlen);
*on = l.l_onoff;
*sec = l.l_linger;
}
#else
(void)vpx_sock;
(void)set;
(void)on;
(void)sec;
#endif
return rv;
}
/* udp only functions */
/*
vpx_net_multicast_ttl(struct vpxsocket* vpx_sock, tc8 set, tcu8* value)
vpx_sock - pointer to a properly initialized vpxsocket structure
set - flag indicating whether to set (non-zero value) or
query (0) the option
value - depending on the value of set, sets the ttl to the value stored
in value or receives the current value of ttl
Attempts to set/query the multicast ttl value of the socket
represented by vpx_sock
Return:
TC_OK: on success
TC_INVALID_PARAMS: if vpx_sock is NULL, was not initialized via
vpx_net_open, the socket is not a udp socket or
value is NULL
TC_ERROR: if the option could not be queried/set
*/
TCRV vpx_net_multicast_ttl(struct vpxsocket *vpx_sock, tc8 set, tcu8 *value)
{
TCRV rv = TC_INVALID_PARAMS;
tc32 optlen = sizeof(tcu8);
if (vpx_sock && (vpx_sock->state & kInited) && (vpx_sock->tl == vpx_UDP))
{
switch (vpx_sock->nl)
{
case vpx_IPv4:
rv = socket_option(vpx_sock, set, IPPROTO_IP, IP_MULTICAST_TTL, value, optlen);
break;
case vpx_IPv6:
#if vpx_NET_SUPPORT_IPV6
rv = socket_option(vpx_sock, set, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, value, optlen);
#endif
break;
}
}
return rv;
}
/*
vpx_net_join_multicast(struct vpxsocket* vpx_sock,
union vpx_sockaddr_x* remote_addr)
vpx_sock - pointer to a properly initialized vpxsocket structure
local_addr - an vpx_sockaddr_x structure containing the address of the
local interface to use for the multicast session or NULL
indicating any interface can be used. (Currently ignored
for IPv6).
remote_addr - an vpx_sockaddr_x structure containing the multicast address
Attempts to add vpx_sock to the multicast session indicated by remote_addr.
On success the reuse_addr option will be set on vpx_sock so others may
join the session and vpx_sock will be added to the session.
Return:
TC_OK: on success
TC_INVALID_PARAMS: if vpx_sock is NULL, was not properly initialized via
vpx_net_open, vpx_sock does not represent a UDP socket,
or remote_addr is NULL
TC_ERROR: if the reuse_addr option could not be set or the socket could
not be added to the multicast session
*/
TCRV vpx_net_join_multicast(struct vpxsocket *vpx_sock,
union vpx_sockaddr_x *local_addr,
union vpx_sockaddr_x *remote_addr)
{
TCRV rv = TC_INVALID_PARAMS;
if (vpx_sock && (vpx_sock->state & kInited) &&
(vpx_sock->tl == vpx_UDP) && remote_addr)
{
switch (vpx_sock->nl)
{
case vpx_IPv4:
{
tc32 on = 1;
struct ip_mreq mreq;
//allow others to bind to the same multicast port
rv = vpx_net_reuse_addr(vpx_sock, 1, &on);
if (!rv)
{
mreq.imr_interface.s_addr = local_addr ?
local_addr->sa_in.sin_addr.s_addr :
INADDR_ANY;
mreq.imr_multiaddr.s_addr = remote_addr->sa_in.sin_addr.s_addr;
memset(&vpx_sock->local_addr.sa_in, 0, sizeof(struct sockaddr_in));
memset(&vpx_sock->remote_addr.sa_in, 0, sizeof(struct sockaddr_in));
vpx_sock->local_addr.sa_in.sin_addr.s_addr = mreq.imr_interface.s_addr;
vpx_sock->remote_addr.sa_in.sin_addr.s_addr = mreq.imr_multiaddr.s_addr;
rv = socket_option(vpx_sock, 1, IPPROTO_IP, IP_ADD_MEMBERSHIP,
&mreq, sizeof(struct ip_mreq));
}
}
break;
case vpx_IPv6:
#if vpx_NET_SUPPORT_IPV6
{
tc32 on = 1;
struct ipv6_mreq mreq;
//allow others to bind to the same multicast port
rv = vpx_net_reuse_addr(vpx_sock, 1, &on);
if (!rv)
{
struct in6_addr in6 = in6addr_any;
mreq.ipv6mr_interface = 0;
memset(&vpx_sock->local_addr.sa_in6, 0, sizeof(struct sockaddr_in6));
memset(&vpx_sock->remote_addr.sa_in6, 0, sizeof(struct sockaddr_in6));
memcpy(&mreq.ipv6mr_multiaddr, &remote_addr->sa_in6.sin6_addr,
sizeof(struct in6_addr));
memcpy(&vpx_sock->local_addr.sa_in6.sin6_addr,
&in6, sizeof(struct in6_addr));
memcpy(&vpx_sock->remote_addr.sa_in6.sin6_addr,
&mreq.ipv6mr_multiaddr, sizeof(struct in6_addr));
rv = socket_option(vpx_sock, 1, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP,
&mreq, sizeof(struct ipv6_mreq));
}
}
#endif
break;
}
}
return rv;
}
/*
vpx_net_join_multicast_addr(struct vpxsocket* vpx_sock
, tc8* ip_addr
, tcu16 port)
vpx_sock - pointer to an vpxsocket structure that is to be connencted
to the endpoint described by ip_addr and port
ip_addr - pointer to a character string that contains the multicast
address to attempt to join
port - the port to attempt to join on ip_addr
Attempt to join vpx_sock to port on ip_addr.
Return:
TC_OK: on success
TC_INVALID_PARAMS: if vpx_sock is NULL, was not properly initialized via
vpx_net_open, vpx_sock does not represent a UDP socket,
or remote_addr is NULL
TC_ERROR: if the reuse_addr option could not be set or the socket could
not be added to the multicast session
*/
TCRV vpx_net_join_multicast_addr(struct vpxsocket *vpx_sock
, tc8 *ip_addr
, tcu16 port)
{
TCRV rv = TC_INVALID_PARAMS;
if (vpx_sock && (vpx_sock->state & kInited) &&
(vpx_sock->tl == vpx_UDP) && ip_addr)
{
rv = vpx_net_get_addr_info(ip_addr, port, vpx_sock->nl,
vpx_sock->tl, &vpx_sock->remote_addr);
if (!rv)
{
tc32 ret = 0;
ret = vpx_net_bind(vpx_sock,
NULL,
port);
if (!ret)
{
ret = vpx_net_join_multicast(vpx_sock,
NULL,
&vpx_sock->remote_addr);
if (!ret)
{
rv = TC_OK;
vpx_sock->state |= kConnected;
}
else
rv = TC_ERROR;
}
else
{
rv = TC_ERROR;
}
}
}
return rv;
}
/*
vpx_net_leave_multicast(struct vpxsocket* vpx_sock)
vpx_sock - pointer to a properly initialized vpxsocket structure to be
removed from the multicast session
Attempts to remove vpx_sock from the multicast session it was previously
added to via vpx_net_join_multicast
Return:
TC_OK: on success
TC_INVALID_PARAMS: if vpx_sock is NULL, was not properly initialized via
vpx_net_open or the socket is not a UDP socket
TC_ERROR: if the socket could not be removed from the session
*/
TCRV vpx_net_leave_multicast(struct vpxsocket *vpx_sock)
{
TCRV rv = TC_INVALID_PARAMS;
if (vpx_sock && (vpx_sock->state & kInited) && (vpx_sock->tl == vpx_UDP))
{
switch (vpx_sock->nl)
{
case vpx_IPv4:
{
struct ip_mreq mreq;
mreq.imr_interface.s_addr = vpx_sock->local_addr.sa_in.sin_addr.s_addr;
mreq.imr_multiaddr.s_addr = vpx_sock->remote_addr.sa_in.sin_addr.s_addr;
rv = socket_option(vpx_sock, 1, IPPROTO_IP, IP_DROP_MEMBERSHIP,
&mreq, sizeof(struct ip_mreq));
}
break;
case vpx_IPv6:
#if vpx_NET_SUPPORT_IPV6
{
struct ipv6_mreq mreq;
mreq.ipv6mr_interface = 0;
memcpy(&mreq.ipv6mr_multiaddr, &vpx_sock->remote_addr.sa_in6.sin6_addr,
sizeof(struct in6_addr));
rv = socket_option(vpx_sock, 1, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP,
&mreq, sizeof(struct ipv6_mreq));
}
#endif
break;
}
}
return rv;
}
/* END - udp only functions */
/*
*
* END - Exposed library functions
*
*/
/*
*
* Internal library functions
*
*/
/*
socket_option(struct vpxsocket* vpx_sock, tc8 set, tc32 level,
tc32 option, void* value, tc32 optlen)
Generic function used to wrap set/getsockopt. Used by exposed library
functions to set/get socket options
*/
static TCRV socket_option(struct vpxsocket *vpx_sock, tc8 set, tc32 level,
tc32 option, void *value, tc32 optlen)
{
TCRV rv = TC_INVALID_PARAMS;
tc32 ret;
if (vpx_sock && (vpx_sock->state & kInited) && value)
{
if (set)
ret = setsockopt(vpx_sock->sock, level, option, value, optlen);
else
ret = getsockopt(vpx_sock->sock, level, option, value, (tcu32 *)&optlen);
rv = (ret == SOCKET_ERROR) ? TC_ERROR : TC_OK;
}
return rv;
}
/*
set_nonblocking_io(struct vpxsocket* vpx_sock, tc32 on)
vpx_sock - pointer to an vpxsocket structure
on - turn non-blocking io on (non-zero value) / off (0)
Internal library function used to turn non-blocking io
on/off for the specified socket
*/
static tc32 set_nonblocking_io(struct vpxsocket *vpx_sock, tc32 on)
{
#if defined(WIN32) || defined(_WIN32_WCE)
return ioctlsocket(vpx_sock->sock, FIONBIO, &((unsigned long)on));
#elif defined(VXWORKS)
return ioctl(vpx_sock->sock, FIONBIO, (tc32)&on);
#elif defined(__SYMBIAN32__)
/*jwz 2005-10-04, FIONBIO is undefined on symbian and I haven't looked for
a replacement. For now this is acceptable as the only use of
non-blocking io in the client is rtp(udp)*/
//(void)vpx_sock; (void)on;
//return -1;
//const int dbg_on=on;
int ret;
if (on) ret = setsockopt(vpx_sock->sock, SOL_SOCKET, KSONonBlockingIO, &on, sizeof(on));
else ret = setsockopt(vpx_sock->sock, SOL_SOCKET, KSOBlockingIO, (on = 1, &on), sizeof(on));
//vpxlog_dbg("set_nbio(%d): ret:%d eno:%d\n",dbg_on,ret,eno);
return ret;
#else
return ioctl(vpx_sock->sock, FIONBIO, &on);
#endif
}