doubango/trunk/tinyNET/src/tnet_utils.c

1018 lines
23 KiB
C

/*
* Copyright (C) 2009 Mamadou Diop.
*
* Contact: Mamadou Diop <diopmamadou@yahoo.fr>
*
* This file is part of Open Source Doubango Framework.
*
* DOUBANGO is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* DOUBANGO is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with DOUBANGO.
*
*/
/**@file tnet_utils.c
* @brief Network utilities functions.
*
* @author Mamadou Diop <diopmamadou(at)yahoo.fr>
*
* @date Created: Sat Nov 8 16:54:58 2009 mdiop
*/
#include "tnet_utils.h"
#include "tsk_debug.h"
#include "tsk_string.h"
#include "tsk_memory.h"
#include "tnet_socket.h"
#include <string.h>
/**
* @fn void tnet_getlasterror(tnet_error_t *error)
*
* @brief Gets last network error description.
*
* @author Mamadou
* @date 12/12/2009
*
* @param [out] error The short description of the last network error.
**/
void tnet_getlasterror(tnet_error_t *error)
{
int err = tnet_geterrno();
memset(*error, 0, sizeof(*error));
#if TNET_UNDER_WINDOWS
{
#ifdef _WIN32_WCE
FormatMessage
#else
FormatMessageA
#endif
(
FORMAT_MESSAGE_FROM_SYSTEM,
0,
err,
0,
*error,
sizeof(*error)-1,
0);
}
#else
strerror_r(err, *error, sizeof(*error));
//sprintf(*error, "Network error (%d).", err);
#endif
}
int tnet_geterrno()
{
#if TNET_UNDER_WINDOWS
return WSAGetLastError();
#else
return errno;
#endif
}
/**
* @fn tnet_interfaces_L_t* tnet_get_interfaces()
*
* @brief Gets list of all network interfaces/adapters.
*
* @author Mamadou
* @date 1/25/2010
*
* @return List of interfaces.
* It is up to the caller to free the returned list using @ref TSK_OBJECT_SAFE_FREE.
*
**/
tnet_interfaces_L_t* tnet_get_interfaces()
{
tnet_interfaces_L_t * ifaces = TSK_LIST_CREATE();
#if TSK_UNDER_WINDOWS /*=== WINDOWS XP/VISTA/7/CE===*/
#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x))
#define FREE(x) HeapFree(GetProcessHeap(), 0, (x))
PIP_ADAPTER_INFO pAdapterInfo = NULL;
PIP_ADAPTER_INFO pAdapter = NULL;
DWORD dwRetVal = 0;
ULONG ulOutBufLen = sizeof (IP_ADAPTER_INFO);
pAdapterInfo = (IP_ADAPTER_INFO *) MALLOC(sizeof (IP_ADAPTER_INFO));
if(pAdapterInfo == NULL)
{
TSK_DEBUG_ERROR("Error allocating memory needed to call GetAdaptersinfo.");
goto bail;
}
// Make an initial call to GetAdaptersInfo to get the necessary size into the ulOutBufLen variable
if (GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) == ERROR_BUFFER_OVERFLOW)
{
FREE(pAdapterInfo);
pAdapterInfo = (IP_ADAPTER_INFO *) MALLOC(ulOutBufLen);
if(pAdapterInfo == NULL)
{
TSK_DEBUG_ERROR("Error allocating memory needed to call GetAdaptersinfo.");
goto bail;
}
}
if ((dwRetVal = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen)) == NO_ERROR)
{
pAdapter = pAdapterInfo;
while(pAdapter)
{
tnet_interface_t *iface;
if(pAdapter->Type == MIB_IF_TYPE_LOOPBACK){
continue;
}
iface = TNET_INTERFACE_CREATE(pAdapter->Description, pAdapter->Address, pAdapter->AddressLength);
iface->index = pAdapter->Index;
tsk_list_push_back_data(ifaces, &(iface));
pAdapter = pAdapter->Next;
}
}
if(pAdapterInfo)
{
FREE(pAdapterInfo);
}
#undef MALLOC
#undef FREE
#elif HAVE_IFADDRS /*=== Using getifaddrs ===*/
// see http://www.kernel.org/doc/man-pages/online/pages/man3/getifaddrs.3.html
struct ifaddrs *ifaddr = 0, *ifa = 0;
/* Get interfaces */
if(getifaddrs(&ifaddr) == -1)
{
TSK_DEBUG_ERROR("getifaddrs failed and errno= [%d]", tnet_geterrno());
goto bail;
}
for(ifa = ifaddr; ifa; ifa = ifa->ifa_next)
{
if(ifa->ifa_addr->sa_family != AF_LINK){
continue;
}
#if defined(__linux__)
{
struct ifreq ifr;
tnet_fd_t fd = TNET_INVALID_FD;
if((fd = socket(AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP)) < 0){
TSK_DEBUG_ERROR("Failed to create new DGRAM socket and errno= [%d]", tnet_geterrno());
goto next;
}
ifr.ifr_addr.sa_family = ifa->ifa_addr->sa_family;
strcpy(ifr.ifr_name, ifa.ifa_name);
if(tnet_ioctl(fd, SIOCGIFHWADDR, &ifr)<0){
TSK_DEBUG_ERROR("tnet_ioctl(SIOCGIFHWADDR)", tnet_geterrno());
goto next;
}
else{
//sockaddr_dl* sdl = (struct sockaddr_dl *)ifa->ifa_addr;
tnet_interface_t *iface = TNET_INTERFACE_CREATE(ifr->ifr_name, ifr->ifr_hwaddr.sa_data, 6);
tsk_list_push_back_data(ifaces, (void**)&(iface));
}
next:
tnet_sockfd_close(&fd);
}
#else
{
//struct sockaddr_dl* sdl = (struct sockaddr_dl*)ifa->ifa_addr;
tnet_interface_t *iface = TNET_INTERFACE_CREATE(ifa->ifa_name, ifa->ifa_addr, 6);
iface->index = if_nametoindex(ifa->ifa_name);
tsk_list_push_back_data(ifaces, (void**)&(iface));
}
#endif
}/* for */
freeifaddrs(ifaddr);
#else /*=== ANDROID,... --> Using SIOCGIFCONF and SIOCGIFHWADDR ===*/
tnet_fd_t fd = TNET_INVALID_FD;
char buffer[1024];
struct ifconf ifc;
struct sockaddr_in *sin;
struct ifreq *ifr;
if((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
{
TSK_DEBUG_ERROR("Failed to create new DGRAM socket and errno= [%d]", tnet_geterrno());
goto done;
}
ifc.ifc_len = sizeof(buffer);
ifc.ifc_buf = buffer;
if(ioctl(fd, SIOCGIFCONF, &ifc) < 0)
{
TSK_DEBUG_ERROR("ioctl(SIOCGIFCONF) failed and errno= [%d]", tnet_geterrno());
goto done;
}
for(ifr = ifc.ifc_req; ifr && !tsk_strempty(ifr->ifr_name); ifr++)
{
sin = (struct sockaddr_in *)&(ifr->ifr_addr);
// TODO: IPAddress if needed
if(/*ioctl(fd, SIOCGIFFLAGS, &ifr) == 0*/1)
{
if (!(ifr->ifr_flags & IFF_LOOPBACK))
{
if(/*ioctl(fd, SIOCGIFHWADDR, &ifr) == 0*/1)
{
tnet_interface_t *iface = TNET_INTERFACE_CREATE(ifr->ifr_name, ifr->ifr_hwaddr.sa_data, 6);
tsk_list_push_back_data(ifaces, (void**)&(iface));
//iface->index = if_nametoindex(ifr->ifr_name);
}
}
}
else
{
TSK_DEBUG_ERROR("ioctl(SIOCGIFFLAGS) failed and errno= [%d]", tnet_geterrno());
}
}
done:
tnet_sockfd_close(&fd);
#endif
bail:
return ifaces;
}
tnet_addresses_L_t* tnet_get_addresses(tnet_family_t family, unsigned unicast, unsigned anycast, unsigned multicast, unsigned dnsserver, long if_index)
{
tnet_addresses_L_t *addresses = TSK_LIST_CREATE();
tnet_ip_t ip;
#if TSK_UNDER_WINDOWS
#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x))
#define FREE(x) HeapFree(GetProcessHeap(), 0, (x))
/* Declare and initialize variables */
DWORD dwSize = 0;
DWORD dwRetVal = 0;
int i = 0;
// Set the flags to pass to GetAdaptersAddresses
ULONG flags = GAA_FLAG_INCLUDE_PREFIX;
LPVOID lpMsgBuf = NULL;
PIP_ADAPTER_ADDRESSES pAddresses = NULL;
ULONG outBufLen = 0;
PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL;
PIP_ADAPTER_UNICAST_ADDRESS pUnicast = NULL;
PIP_ADAPTER_ANYCAST_ADDRESS pAnycast = NULL;
PIP_ADAPTER_MULTICAST_ADDRESS pMulticast = NULL;
IP_ADAPTER_DNS_SERVER_ADDRESS *pDnServer = NULL;
IP_ADAPTER_PREFIX *pPrefix = NULL;
outBufLen = sizeof(IP_ADAPTER_ADDRESSES);
pAddresses = (IP_ADAPTER_ADDRESSES *) MALLOC(outBufLen);
// Make an initial call to GetAdaptersAddresses to get the
// size needed into the outBufLen variable
if(GetAdaptersAddresses(family, flags, NULL, pAddresses, &outBufLen) == ERROR_BUFFER_OVERFLOW)
{
FREE(pAddresses);
pAddresses = (IP_ADAPTER_ADDRESSES *) MALLOC(outBufLen);
}
if(pAddresses == NULL)
{
TSK_DEBUG_ERROR("Memory allocation failed for IP_ADAPTER_ADDRESSES struct.");
goto bail;
}
dwRetVal = GetAdaptersAddresses(family, flags, NULL, pAddresses, &outBufLen);
if(dwRetVal == NO_ERROR)
{
pCurrAddresses = pAddresses;
while (pCurrAddresses)
{
if((if_index != -1) && (pCurrAddresses->IfIndex != if_index && pCurrAddresses->Ipv6IfIndex != if_index)){
goto next;
}
/* UNICAST addresses
*/
pUnicast = pCurrAddresses->FirstUnicastAddress;
while(unicast && pUnicast)
{
//memset(ip, '\0', sizeof(ip));
tnet_get_sockip(pUnicast->Address.lpSockaddr, &ip);
{
tnet_address_t *address = TNET_ADDRESS_CREATE(ip);
address->family = pUnicast->Address.lpSockaddr->sa_family;
address->unicast = 1;
tsk_list_push_back_data(addresses, &address);
}
pUnicast = pUnicast->Next;
}
/* ANYCAST addresses
*/
pAnycast = pCurrAddresses->FirstAnycastAddress;
while(anycast && pAnycast)
{
//memset(ip, '\0', sizeof(ip));
tnet_get_sockip(pAnycast->Address.lpSockaddr, &ip);
{
tnet_address_t *address = TNET_ADDRESS_CREATE(ip);
address->family = pAnycast->Address.lpSockaddr->sa_family;
address->anycast = 1;
tsk_list_push_back_data(addresses, &address);
}
pAnycast = pAnycast->Next;
}
/* MULTYCAST addresses
*/
pMulticast = pCurrAddresses->FirstMulticastAddress;
while(multicast && pMulticast)
{
//memset(ip, '\0', sizeof(ip));
tnet_get_sockip(pMulticast->Address.lpSockaddr, &ip);
{
tnet_address_t *address = TNET_ADDRESS_CREATE(ip);
address->family = pMulticast->Address.lpSockaddr->sa_family;
address->multicast = 1;
tsk_list_push_back_data(addresses, &address);
}
pMulticast = pMulticast->Next;
}
/* DNS servers
*/
pDnServer = pCurrAddresses->FirstDnsServerAddress;
while(dnsserver && pDnServer)
{
//memset(ip, '\0', sizeof(ip));
tnet_get_sockip(pDnServer->Address.lpSockaddr, &ip);
{
tnet_address_t *address = TNET_ADDRESS_CREATE(ip);
address->family = pDnServer->Address.lpSockaddr->sa_family;
address->dnsserver = 1;
tsk_list_push_back_data(addresses, &address);
}
pDnServer = pDnServer->Next;
}
next:
pCurrAddresses = pCurrAddresses->Next;
}
}
if(pAddresses)
{
FREE(pAddresses);
}
#undef MALLOC
#undef FREE
#else /* !TSK_UNDER_WINDOWS */
#endif
bail:
return addresses;
}
int tnet_getbestsource(const char* destination, tnet_socket_type_t type, tnet_ip_t *source)
{
int ret = -1;
struct sockaddr_storage destAddr;
tnet_addresses_L_t* addresses = 0;
const tsk_list_item_t* item;
long dwBestIfIndex;
if(!destination || !source){
goto bail;
}
if((ret = tnet_sockaddr_init(destination, 0, type, &destAddr))){
goto bail;
}
#if TNET_UNDER_WINDOWS
if(GetBestInterfaceEx((struct sockaddr*)&destAddr, &dwBestIfIndex) != NO_ERROR){
ret = WSAGetLastError();
TNET_PRINT_LAST_ERROR("GetBestInterfaceEx failed.");
goto bail;
}
#endif
if(!(addresses = tnet_get_addresses(TNET_SOCKET_TYPE_IS_IPV6(type) ? AF_INET6 : AF_INET, 1, 0, 0, 0, dwBestIfIndex))){
ret = -2;
TSK_DEBUG_ERROR("Failed to retrieve addresses.");
goto bail;
}
tsk_list_foreach(item, addresses)
{
const tnet_address_t* address = item->data;
if(address && address->ip){
memset(*source, '\0', sizeof(*source));
memcpy(*source, address->ip, strlen(address->ip) > sizeof(*source) ? sizeof(*source) : strlen(address->ip));
ret = 0;
goto bail; // First is good for us.
}
}
bail:
TSK_OBJECT_SAFE_FREE(addresses);
return ret;
}
/**
* @fn int tnet_getaddrinfo(const char *node, const char *service,
* const struct addrinfo *hints, struct addrinfo **res)
*
* @brief converts human-readable text strings representing hostnames or IP addresses into a dynamically allocated linked list of struct addrinfo structures.
* You MUST call @ref tnet_freeaddrinfo() function to free the result.
*
* @author Mamadou
* @date 12/11/2009
*
* @param [in] node A pointer to a NULL-terminated ANSI string that contains a host (node) name or a numeric host address string. For the Internet protocol, the numeric host address string is a dotted-decimal IPv4 address or an IPv6 hex address..
* @param [in] service A pointer to a NULL-terminated ANSI string that contains either a service name or port number represented as a string.
* @param [in] hints A pointer to an addrinfo structure that provides hints about the type of socket the caller supports.
* @param [out] res A pointer to a linked list of one or more addrinfo structures that contains response information about the host.
*
* @return Success returns zero. Failure returns a nonzero error code.
**/
int tnet_getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res)
{
int ret;
if((ret = getaddrinfo(node, service, hints, res))){
TSK_DEBUG_ERROR("getaddrinfo failed: [%s]", tnet_gai_strerror(ret));
}
return ret;
}
/**
* @fn void tnet_freeaddrinfo(struct addrinfo *ai)
*
* @brief This function frees address information previously allocated using @ref tnet_getaddrinfo.
*
* @author Mamadou
* @date 12/11/2009
*
* @param [in] The address information to free.
**/
void tnet_freeaddrinfo(struct addrinfo *ai)
{
freeaddrinfo(ai);
}
int tnet_get_sockaddr(tnet_fd_t fd, struct sockaddr_storage *result)
{
if(fd >0)
{
socklen_t namelen = sizeof(*result);
return getsockname(fd, (struct sockaddr*)result, &namelen);
}
return -1;
}
tnet_socket_type_t tnet_get_socket_type(tnet_fd_t fd)
{
tnet_socket_type_t type = tnet_socket_type_invalid;
/*if(fd >0)
{
struct sockaddr_storage ss;
if(!tnet_get_sockaddr(fd, &ss))
{
if(((struct sockaddr *)&ss)->sa_family == AF_INET)
{
TNET_SOCKET_TYPE_AS_IPV4(type);
}
else if(((struct sockaddr *)&ss)->sa_family == AF_INET6)
{
TNET_SOCKET_TYPE_AS_IPV6(type);
}
}
}*/
return type;
}
int tnet_get_sockip_n_port(struct sockaddr *addr, tnet_ip_t *ip, tnet_port_t *port)
{
int status = -1;
if(addr->sa_family == AF_INET)
{
struct sockaddr_in *sin = (struct sockaddr_in *)addr;
if(port)
{
*port = ntohs(sin->sin_port);
status = 0;
}
if(ip)
{
if((status = tnet_getnameinfo((struct sockaddr*)sin, sizeof(*sin), *ip, sizeof(*ip), 0, 0, NI_NUMERICHOST)))
{
return status;
}
}
}
else if(addr->sa_family == AF_INET6)
{
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr;
#if TNET_UNDER_WINDOWS
int index;
#endif
if(port)
{
*port = ntohs(sin6->sin6_port);
status = 0;
}
if(ip)
{
if((status = tnet_getnameinfo((struct sockaddr*)sin6, sizeof(*sin6), *ip, sizeof(*ip), 0, 0, NI_NUMERICHOST)))
{
return status;
}
#if TNET_UNDER_WINDOWS
if((index = tsk_strindexOf(*ip, strlen(*ip), "%")) > 0){
*(*ip + index) = '\0';
}
#endif
}
}
else
{
TSK_DEBUG_ERROR("Unsupported address family.");
return -1;
}
return status;
}
int tnet_get_ip_n_port(tnet_fd_t fd, tnet_ip_t *ip, tnet_port_t *port)
{
if(port){
*port = 0;
}
if(fd > 0)
{
int status;
struct sockaddr_storage ss;
if((status = tnet_get_sockaddr(fd, &ss)))
{
TSK_DEBUG_ERROR("TNET_GET_SOCKADDR has failed with status code: %d", status);
return -1;
}
return tnet_get_sockip_n_port(((struct sockaddr *)&ss), ip, port);
}
TSK_DEBUG_ERROR("Could not use an invalid socket description.");
return -1;
}
int tnet_getnameinfo(const struct sockaddr *sa, socklen_t salen, char* node, socklen_t nodelen, char* service, socklen_t servicelen, int flags)
{
return getnameinfo(sa, salen, node, nodelen, service, servicelen, flags);
}
int tnet_gethostname(tnet_host_t* result)
{
return gethostname(*result, sizeof(*result));
}
int tnet_sockfd_joingroup6(tnet_fd_t fd, const char* multiaddr, unsigned iface_index)
{
int ret = -1;
//struct ipv6_mreq mreq6;
//struct sockaddr_storage ss;
//if((ret = tnet_sockaddr_init(multiaddr, 0, tnet_socket_type_udp_ipv6, &ss)))
//{
// return ret;
//}
//memcpy(&mreq6.ipv6mr_multiaddr, &((struct sockaddr_in6 *) &ss)->sin6_addr, sizeof(struct in6_addr));
//mreq6.ipv6mr_interface = iface_index;
//if((ret = setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, (const char*)&mreq6, sizeof(mreq6))))
//{
// TNET_PRINT_LAST_ERROR("Failed to join IPv6 multicast group.");
// return ret;
//}
return ret;
}
int tnet_sockfd_leavegroup6(tnet_fd_t fd, const char* multiaddr, unsigned iface_index)
{
//if(multiaddr)
{
}
return -1;
}
int tnet_sockaddrinfo_init(const char *host, tnet_port_t port, enum tnet_socket_type_e type, struct sockaddr_storage *ai_addr, int *ai_family, int *ai_socktype, int *ai_protocol)
{
int status = 0;
struct addrinfo *result = 0;
struct addrinfo *ptr = 0;
struct addrinfo hints;
tsk_istr_t p;
tsk_itoa(port, &p);
/* hints address info structure */
memset(&hints, 0, sizeof(hints));
hints.ai_family = TNET_SOCKET_TYPE_IS_IPV6(type) ? AF_INET6 : AF_INET;
hints.ai_socktype = TNET_SOCKET_TYPE_IS_STREAM(type) ? SOCK_STREAM : SOCK_DGRAM;
hints.ai_protocol = TNET_SOCKET_TYPE_IS_STREAM(type) ? IPPROTO_TCP : IPPROTO_UDP;
hints.ai_flags = AI_PASSIVE;
/* Performs getaddrinfo */
if((status = tnet_getaddrinfo(host, p, &hints, &result)))
{
TNET_PRINT_LAST_ERROR("getaddrinfo have failed.");
goto bail;
}
/* Find our address. */
for(ptr = result; ptr; ptr = ptr->ai_next)
{
if(ptr->ai_family == hints.ai_family && ptr->ai_socktype == hints.ai_socktype && ptr->ai_protocol == hints.ai_protocol)
{
/* duplicate addrinfo ==> Bad idea
*ai = tsk_calloc(1, sizeof (struct addrinfo));
memcpy (*ai, ptr, sizeof (struct addrinfo));
(*ai)->ai_addr = tsk_calloc(1, ptr->ai_addrlen);
memcpy((*ai)->ai_addr, ptr->ai_addr, ptr->ai_addrlen);
(*ai)->ai_addrlen = ptr->ai_addrlen;
(*ai)->ai_next = 0;
(*ai)->ai_canonname = 0;*/
if(ai_addr)memcpy(ai_addr, ptr->ai_addr, ptr->ai_addrlen);
if(ai_family) *ai_family = ptr->ai_family;
if(ai_socktype) *ai_socktype = ptr->ai_socktype;
if(ai_protocol) *ai_protocol = ptr->ai_protocol;
break;
}
}
bail:
tnet_freeaddrinfo(result);
return status;
}
int tnet_sockaddr_init(const char *host, tnet_port_t port, tnet_socket_type_t type, struct sockaddr_storage *addr)
{
int status;
struct sockaddr_storage ai_addr;
if((status = tnet_sockaddrinfo_init(host, port, type, &ai_addr, 0, 0, 0)))
{
return status;
}
memcpy(addr, &ai_addr, sizeof(ai_addr));
return status;
}
int tnet_sockfd_init(const char *host, tnet_port_t port, enum tnet_socket_type_e type, tnet_fd_t *fd)
{
int status = -1;
struct sockaddr_storage ai_addr;
int ai_family, ai_socktype, ai_protocol;
*fd = TNET_INVALID_SOCKET;
if((status = tnet_sockaddrinfo_init(host, port, type, &ai_addr, &ai_family, &ai_socktype, &ai_protocol)))
{
goto bail;
}
if((*fd = socket(ai_family, ai_socktype, ai_protocol)) == TNET_INVALID_SOCKET)
{
TNET_PRINT_LAST_ERROR("Failed to create new socket.");
goto bail;
}
#if TNET_USE_POLL /* For win32 WSA* function the socket is auto. set to nonblocking mode. */
if((status = tnet_sockfd_set_nonblocking(*fd)))
{
goto bail;
}
#endif
#if TNET_HAVE_SS_LEN
if((status = bind(*fd, (const struct sockaddr*)&ai_addr, ai_addr.ss_len)))
#else
if((status = bind(*fd, (const struct sockaddr*)&ai_addr, sizeof(ai_addr))))
#endif
{
TNET_PRINT_LAST_ERROR("bind have failed.");
tnet_sockfd_close(fd);
goto bail;
}
bail:
return (*fd == TNET_INVALID_SOCKET) ? status : 0;
}
int tnet_sockfd_set_mode(tnet_fd_t fd, int nonBlocking)
{
if(fd != TNET_INVALID_FD)
{
#if TNET_UNDER_WINDOWS
ULONG mode = nonBlocking;
if(ioctlsocket(fd, FIONBIO, &mode))
//if(WSAIoctl(fd, FIONBIO, &nonblocking, sizeof(nonblocking), NULL, 0, NULL, NULL, NULL) == SOCKET_ERROR)
{
TNET_PRINT_LAST_ERROR("ioctlsocket(FIONBIO) have failed.");
return -1;
}
#else
int flags;
if((flags = fcntl(fd, F_GETFL, 0)) < 0)
{
TNET_PRINT_LAST_ERROR("fcntl(F_GETFL) have failed.");
return -1;
}
if(fcntl(fd, F_SETFL, flags | (nonBlocking ? O_NONBLOCK : ~O_NONBLOCK)) < 0)
{
TNET_PRINT_LAST_ERROR("fcntl(O_NONBLOCK/O_NONBLOCK) have failed.");
return -1;
}
#endif
// int on = 1;
// ioctl(fd, FIONBIO, (char *)&on);
}
return 0;
}
int tnet_sockfd_sendto(tnet_fd_t fd, const struct sockaddr *to, const void* buf, size_t size)
{
if(fd == TNET_INVALID_FD)
{
TSK_DEBUG_ERROR("Using invalid FD to send data.");
return -1;
}
if(!buf || !size)
{
TSK_DEBUG_ERROR("Using invalid BUFFER.");
return -2;
}
#if TNET_HAVE_SA_LEN
return sendto(fd, buf, size, 0, to, to->sa_len);
#else
//return sendto(fd, buf, size, 0, to, sizeof(*to));
return sendto(fd, buf, size, 0, to,
to->sa_family == AF_INET6 ? sizeof(struct sockaddr_in6): (to->sa_family == AF_INET ? sizeof(struct sockaddr_in) : sizeof(*to))); //FIXME: why sizeof(*to) don't work for IPv6 on XP?
#endif
}
int tnet_sockfd_recvfrom(tnet_fd_t fd, void* buf, size_t size, int flags, struct sockaddr *from)
{
socklen_t fromlen;
if(fd == TNET_INVALID_FD)
{
TSK_DEBUG_ERROR("Using invalid FD to recv data.");
return -1;
}
#if TNET_HAVE_SA_LEN
fromlen = from->sa_len;
#else
fromlen = sizeof(*from);
#endif
return recvfrom(fd, buf, size, flags, from, &fromlen);
}
int tnet_sockfd_send(tnet_fd_t fd, void* buf, size_t size, int flags)
{
if(fd == TNET_INVALID_FD)
{
TSK_DEBUG_ERROR("Using invalid FD to send data.");
return -1;
}
return send(fd, buf, size, flags);
}
int tnet_sockfd_recv(tnet_fd_t fd, void* buf, size_t size, int flags)
{
if(fd == TNET_INVALID_FD)
{
TSK_DEBUG_ERROR("Using invalid FD to recv data.");
return -1;
}
return recv(fd, buf, size, flags);
}
int tnet_sockfd_close(tnet_fd_t *fd)
{
int ret;
#if TNET_UNDER_WINDOWS
ret = closesocket(*fd);
#else
ret = close(*fd);
#endif
*fd = TNET_INVALID_SOCKET;
return ret;
}
//=================================================================================================
// INTERFACE object definition
//
static void* tnet_interface_create(void * self, va_list * app)
{
tnet_interface_t *iface = self;
if(iface)
{
const char* description = va_arg(*app, const char*);
const uint8_t* mac_address = va_arg(*app, const uint8_t*);
size_t mac_address_length = va_arg(*app, size_t);
iface->description = tsk_strdup(description);
if((iface->mac_address = tsk_calloc(mac_address_length, sizeof(uint8_t)))){
memcpy(iface->mac_address, mac_address, mac_address_length);
}
iface->mac_address_length = mac_address_length;
}
return self;
}
static void* tnet_interface_destroy(void * self)
{
tnet_interface_t *iface = self;
if(iface)
{
TSK_FREE(iface->description);
TSK_FREE(iface->mac_address);
}
return self;
}
static int tnet_interface_cmp(const void *if1, const void *if2)
{
const tnet_interface_t *iface1 = if1;
const tnet_interface_t *iface2 = if2;
if(iface1 && iface2)
{
return tsk_stricmp(iface1->description, iface1->description);
}
else if(!iface1 && !iface2) return 0;
else return -1;
}
static const tsk_object_def_t tnet_interface_def_s =
{
sizeof(tnet_interface_t),
tnet_interface_create,
tnet_interface_destroy,
tnet_interface_cmp,
};
const void *tnet_interface_def_t = &tnet_interface_def_s;
//=================================================================================================
// ADDRESS object definition
//
static void* tnet_address_create(void * self, va_list * app)
{
tnet_address_t *address = self;
if(address)
{
address->ip = tsk_strdup(va_arg(*app, const char*));
}
return self;
}
static void* tnet_address_destroy(void * self)
{
tnet_address_t *address = self;
if(address)
{
TSK_FREE(address->ip);
}
return self;
}
static const tsk_object_def_t tnet_address_def_s =
{
sizeof(tnet_address_t),
tnet_address_create,
tnet_address_destroy,
0,
};
const void *tnet_address_def_t = &tnet_address_def_s;