diff -r 000000000000 -r d0f3a028347a loudmouth/src/lm-sock.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loudmouth/src/lm-sock.c Tue Feb 02 01:10:06 2010 +0200 @@ -0,0 +1,392 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2006 Imendio AB + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include +//#include +//#include + +#ifndef G_OS_WIN32 +//#include + +#include +#include +#include +#include +#include +#include +//#include +//#include +#include +#include +// hack - to compile without the error of n_long not defined +#define LM_SHUTDOWN SHUT_RDWR + +#else /* G_OS_WIN32 */ + +#include +#define LM_SHUTDOWN SD_BOTH + +#endif /* G_OS_WIN32 */ + +#include "lm-internals.h" +#include "lm-connection.h" +#include "lm-sock.h" +#include "lm-debug.h" + +#define IPV6_MAX_ADDRESS_LEN 46 /* 45 + '\0' */ + +#ifdef EMULATOR +#include "libloudmouth_wsd_solution.h" + +GET_GLOBAL_VAR_FROM_TLS(initialised,lm_sock,gboolean) + #define initialised (*GET_WSD_VAR_NAME(initialised,lm_sock,g)()) + +#else +static gboolean initialised = FALSE; +#endif +gboolean +_lm_sock_library_init (void) +{ +#ifdef G_OS_WIN32 + WORD version; + WSADATA data; + int error; +#endif /* G_OS_WIN32 */ + + if (initialised) { + return TRUE; + } + + lm_verbose ("Socket library initialising...\n"); + +#ifdef G_OS_WIN32 + lm_verbose ("Checking for winsock 2.0 or above...\n"); + + version = MAKEWORD (2, 0); + + error = WSAStartup (version, &data); + if (error != 0) { + g_printerr ("WSAStartup() failed, error:%d\n", error); + return FALSE; + } + + /* Confirm that the WinSock DLL supports 2.0. + * Note that if the DLL supports versions greater + * than 2.0 in addition to 2.0, it will still return + * 2.0 in wVersion since that is the version we + * requested. + */ + if (LOBYTE (data.wVersion) != 2 || + HIBYTE (data.wVersion) != 0) { + /* Tell the user that we could not find a usable + * WinSock DLL. + */ + g_printerr ("Socket library version is not sufficient!\n"); + WSACleanup (); + return FALSE; + } +#endif /* G_OS_WIN32 */ + + initialised = TRUE; + + return TRUE; +} + +void +_lm_sock_library_shutdown (void) +{ + if (!initialised) { + return; + } + + lm_verbose ("Socket library shutting down...\n"); + +#ifdef G_OS_WIN32 + WSACleanup (); +#endif /* G_OS_WIN32 */ + + initialised = FALSE; +} + +void +_lm_sock_set_blocking (LmSocketT sock, + gboolean block) +{ + int res; + +#ifndef G_OS_WIN32 + res = fcntl (sock, F_SETFL, block ? 0 : O_NONBLOCK); +#else /* G_OS_WIN32 */ + u_long mode = (block ? 0 : 1); + res = ioctlsocket (sock, FIONBIO, &mode); +#endif /* G_OS_WIN32 */ + + if (res != 0) { + // g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET, + // "Could not set connection to be %s\n", + // block ? "blocking" : "non-blocking"); + lm_verbose ("[_lm_sock_set_blocking]: Could not set connection to be %s\n", + block ? "blocking" : "non-blocking"); + } +} + +void +_lm_sock_shutdown (LmSocketT sock) +{ + shutdown (sock, LM_SHUTDOWN); +} + +void +_lm_sock_close (LmSocketT sock) +{ +#ifndef G_OS_WIN32 + close (sock); +#else /* G_OS_WIN32 */ + closesocket (sock); +#endif /* G_OS_WIN32 */ +} + +LmSocketT +_lm_sock_makesocket (int af, + int type, + int protocol) +{ + int optval = 1; + int sock_fd = -1; + unsigned int optlen = sizeof(optval); + sock_fd = socket (af, type, protocol); + setsockopt(sock_fd,SOL_SOCKET,SO_REUSEADDR|SO_REUSEPORT,&optval,optlen); + + return (LmSocketT)sock_fd; +} + +int +_lm_sock_connect (LmSocketT sock, + const struct sockaddr *name, + int namelen) +{ + return connect (sock, name, namelen); +} + +gboolean +_lm_sock_is_blocking_error (int err) +{ +#ifndef G_OS_WIN32 + return (err == _LM_SOCK_EINPROGRESS); +#else /* G_OS_WIN32 */ + return (err == _LM_SOCK_EINPROGRESS || + err == _LM_SOCK_EWOULDBLOCK || + err == _LM_SOCK_EINVAL); +#endif /* G_OS_WIN32 */ +} + +gboolean +_lm_sock_is_blocking_success (int err) +{ + //Bug fixed by MRT from week 50 devlong onwards + return (err == _LM_SOCK_EEXISTS); + //Error EEXIST = 17 is not expected here. But It should be mrt error 107 + //fix take later + //Before week 50 SDK + //return (err == _LM_SOCK_EALREADY || err == _LM_SOCK_EISCONN); +} + +int +_lm_sock_get_last_error (void) +{ +#ifndef G_OS_WIN32 + return errno; +#else /* G_OS_WIN32 */ + return WSAGetLastError (); +#endif /* G_OS_WIN32 */ +} + +void +_lm_sock_get_error (LmSocketT sock, + void *error, + socklen_t *len) +{ + getsockopt (sock, SOL_SOCKET, SO_ERROR, (void*) error, len); +} + +const gchar * +_lm_sock_get_error_str (int err) +{ +#ifndef G_OS_WIN32 + return strerror (err); +#else /* G_OS_WIN32 */ + switch (err) { + case WSAEINTR: return _("Connect interrupted and canceled"); + case WSAEACCES: return _("Permission denied"); + case WSAEFAULT: return _("Bad address"); + case WSAEINVAL: return _("Invalid argument"); + case WSAEMFILE: return _("Too many open sockets"); + case WSAEWOULDBLOCK: return _("Resource temporarily unavailable"); + case WSAEINPROGRESS: return _("Operation now in progress"); + case WSAEALREADY: return _("Operation already in progress"); + case WSAENOTSOCK: return _("Socket operation on nonsocket"); + case WSAEDESTADDRREQ: return _("Destination address required"); + case WSAEMSGSIZE: return _("Message too long"); + case WSAEPROTOTYPE: return _("Protocol wrong type for socket"); + case WSAENOPROTOOPT: return _("Bad protocol option"); + case WSAEPROTONOSUPPORT: return _("Protocol not supported"); + case WSAESOCKTNOSUPPORT: return _("Socket type not supported"); + case WSAEOPNOTSUPP: return _("Operation not supported"); + case WSAEPFNOSUPPORT: return _("Protocol family not supported"); + case WSAEAFNOSUPPORT: return _("Address family not supported by protocol family"); + case WSAEADDRINUSE: return _("Address already in use"); + case WSAEADDRNOTAVAIL: return _("Can not assign requested address"); + case WSAENETDOWN: return _("Network is down"); + case WSAENETUNREACH: return _("Network is unreachable"); + case WSAENETRESET: return _("Network dropped connection on reset"); + case WSAECONNABORTED: return _("Software caused connection abort"); + case WSAECONNRESET: return _("Connection reset by peer"); + case WSAENOBUFS: return _("No buffer space available"); + case WSAEISCONN: return _("Socket is already connected"); + case WSAENOTCONN: return _("Socket is not connected"); + case WSAESHUTDOWN: return _("Can not send after socket shutdown"); + case WSAETIMEDOUT: return _("Connection timed out"); + case WSAECONNREFUSED: return _("Connection refused"); + case WSAEHOSTDOWN: return _("Host is down"); + case WSAEHOSTUNREACH: return _("No route to host"); + case WSAEPROCLIM: return _("Too many processes"); + case WSASYSNOTREADY: return _("Network subsystem is unavailable"); + case WSAVERNOTSUPPORTED: return _("Winsock library version is out of range "); + case WSANOTINITIALISED: return _("Successful WSAStartup not yet performed"); + case WSAEDISCON: return _("Graceful shutdown in progress"); + case WSATYPE_NOT_FOUND: return _("Class type not found"); + case WSAHOST_NOT_FOUND: return _("Host not found"); + case WSATRY_AGAIN: return _("Nonauthoritative host not found"); + case WSANO_RECOVERY: return _("This is a nonrecoverable error"); + case WSANO_DATA: return _("Valid name, no data record of requested type"); + case WSA_INVALID_HANDLE: return _("Specified event object handle is invalid"); + case WSA_INVALID_PARAMETER: return _("One or more parameters are invalid"); + case WSA_IO_INCOMPLETE: return _("Overlapped I/O event object no in signaled state"); + case WSA_IO_PENDING: return _("Overlapped operations will complete later"); + case WSA_NOT_ENOUGH_MEMORY: return _("Insufficient memory available"); + case WSA_OPERATION_ABORTED: return _("Overlapped operation aborted"); + /* os dependent */ + case WSASYSCALLFAILURE: return _("System call failure"); + } + + return _("Unknown"); +#endif /* G_OS_WIN32 */ +} + +const gchar * +_lm_sock_addrinfo_get_error_str (int err) +{ + switch (err) { + case EAI_AGAIN: + return ("The nameserver failed to return an " + "address, try again later"); + case EAI_BADFLAGS: + return ("Internal error trying to obtain remote address"); + case EAI_FAIL: + return ("The nameserver encountered errors " + "looking up this address"); + /* EAI_NODATA is apparently missing on FreeBSD. On recent GNU libc, + * it requires _GNU_SOURCE to be defined; in the unlikely case that + * that GNU libc returns this value we'll return the default message */ +#ifdef EAI_NODATA + case EAI_NODATA: + return _("The remote host exists but no address " + "is available"); +#endif + case EAI_NONAME: + return ("The remote address is unknown"); + case EAI_FAMILY: + case EAI_SERVICE: + case EAI_SOCKTYPE: + return ("The remote address is not obtainable " + "for that socket type."); + default: + break; + } + + return ("The remote address could not be obtained "); +} + +#ifdef USE_TCP_KEEPALIVES +gboolean +_lm_sock_set_keepalive (LmSocketT sock, int delay) +{ + int opt; + + lm_verbose ("[_lm_sock_set_keepalive]: USE_TCP_KEEPALIVES Enabled\n"); + + opt = 1; + if (setsockopt (sock, SOL_SOCKET, SO_KEEPALIVE, &opt, sizeof (opt)) < 0) { + return FALSE; + } + + //opt = 3; /* 3 keepalives before considering connection dead */ + /*if (setsockopt (sock, IPPROTO_TCP, TCP_KEEPCNT, &opt, sizeof (opt)) < 0) { + return FALSE; + } + + opt = delay; + if (setsockopt (sock, IPPROTO_TCP, TCP_KEEPIDLE, &opt, sizeof (opt)) < 0) { + return FALSE; + } + + opt = delay; + if (setsockopt (sock, IPPROTO_TCP, TCP_KEEPINTVL, &opt, sizeof (opt)) < 0) { + return FALSE; + }*/ + UNUSED_FORMAL_PARAM(delay); + return TRUE; +} +#endif /* USE_TCP_KEEPALIVES */ + +gchar * +_lm_sock_get_local_host (LmSocketT sock) +{ + struct sockaddr addr_info; + void *sock_addr; + socklen_t namelen; + char addrbuf[IPV6_MAX_ADDRESS_LEN]; + const char *host; + + namelen = sizeof (struct sockaddr); + if (getsockname (sock, &addr_info, &namelen)) { + return NULL; + } + + switch (addr_info.sa_family) { + case AF_INET: + + sock_addr = & (((struct sockaddr_in *) &addr_info)->sin_addr); + break; + case AF_INET6: + sock_addr = & (((struct sockaddr_in6 *) &addr_info)->sin6_addr); + break; + default: + return NULL; + } + /* inet_ntoa has been obsoleted in favour of inet_ntop */ + host = inet_ntop (addr_info.sa_family, + sock_addr, + addrbuf, + IPV6_MAX_ADDRESS_LEN); + + return g_strdup (host); +} +