loudmouth/src/lm-sock.c
changeset 10 59927b2d3b75
parent 0 d0f3a028347a
equal deleted inserted replaced
0:d0f3a028347a 10:59927b2d3b75
     1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
       
     2 /*
       
     3  * Copyright (C) 2006 Imendio AB
       
     4  *
       
     5  * This program is free software; you can redistribute it and/or
       
     6  * modify it under the terms of the GNU Lesser General Public License as
       
     7  * published by the Free Software Foundation; either version 2 of the
       
     8  * License, or (at your option) any later version.
       
     9  *
       
    10  * This program is distributed in the hope that it will be useful,
       
    11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    13  * Lesser General Public License for more details.
       
    14  *
       
    15  * You should have received a copy of the GNU Lesser General Public
       
    16  * License along with this program; if not, write to the
       
    17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
       
    18  * Boston, MA 02111-1307, USA.
       
    19  */
       
    20 
       
    21 #include <config.h>
       
    22 //#include <glib.h>
       
    23 //#include <glib/gi18n.h>
       
    24 
       
    25 #ifndef G_OS_WIN32
       
    26 //#include <libc/netinet/net_types.h>
       
    27 
       
    28 #include <errno.h>
       
    29 #include <string.h>
       
    30 #include <unistd.h>
       
    31 #include <sys/socket.h>
       
    32 #include <fcntl.h>
       
    33 #include <netinet/in.h>
       
    34 //#include <libc/netinet/ip.h>
       
    35 //#include <libc/netinet/tcp.h>
       
    36 #include <arpa/inet.h>
       
    37 #include <netdb.h>
       
    38 // hack - to compile without the error of n_long not defined
       
    39 #define LM_SHUTDOWN SHUT_RDWR
       
    40 
       
    41 #else  /* G_OS_WIN32 */
       
    42 
       
    43 #include <winsock2.h>
       
    44 #define LM_SHUTDOWN SD_BOTH
       
    45 
       
    46 #endif /* G_OS_WIN32 */
       
    47 
       
    48 #include "lm-internals.h"
       
    49 #include "lm-connection.h"
       
    50 #include "lm-sock.h"
       
    51 #include "lm-debug.h"
       
    52 
       
    53 #define IPV6_MAX_ADDRESS_LEN 46 /* 45 + '\0' */
       
    54 
       
    55 #ifdef EMULATOR
       
    56 #include "libloudmouth_wsd_solution.h"
       
    57 
       
    58 GET_GLOBAL_VAR_FROM_TLS(initialised,lm_sock,gboolean)
       
    59 	#define initialised (*GET_WSD_VAR_NAME(initialised,lm_sock,g)())
       
    60 
       
    61 #else
       
    62 static gboolean initialised = FALSE;
       
    63 #endif
       
    64 gboolean
       
    65 _lm_sock_library_init (void)
       
    66 {
       
    67 #ifdef G_OS_WIN32
       
    68 	WORD    version;
       
    69 	WSADATA data;
       
    70 	int     error;
       
    71 #endif /* G_OS_WIN32 */
       
    72 	
       
    73 	if (initialised) {
       
    74 		return TRUE;
       
    75 	}
       
    76 
       
    77 	lm_verbose ("Socket library initialising...\n");
       
    78 	
       
    79 #ifdef G_OS_WIN32
       
    80 	lm_verbose ("Checking for winsock 2.0 or above...\n");
       
    81 	
       
    82 	version = MAKEWORD (2, 0);
       
    83 		
       
    84 	error = WSAStartup (version, &data);
       
    85 	if (error != 0) {
       
    86 		g_printerr ("WSAStartup() failed, error:%d\n", error);
       
    87 		return FALSE;
       
    88 	}
       
    89 	
       
    90 	/* Confirm that the WinSock DLL supports 2.0.
       
    91 	 * Note that if the DLL supports versions greater  
       
    92 	 * than 2.0 in addition to 2.0, it will still return 
       
    93 	 * 2.0 in wVersion since that is the version we      
       
    94 	 * requested.                                        
       
    95 	 */
       
    96 	if (LOBYTE (data.wVersion) != 2 ||
       
    97 	    HIBYTE (data.wVersion) != 0) {
       
    98 		/* Tell the user that we could not find a usable
       
    99 		 * WinSock DLL.                                  
       
   100 		 */
       
   101 		g_printerr ("Socket library version is not sufficient!\n");
       
   102 		WSACleanup ();
       
   103 		return FALSE;
       
   104 	}
       
   105 #endif /* G_OS_WIN32 */
       
   106 
       
   107 	initialised = TRUE;
       
   108 	
       
   109 	return TRUE;
       
   110 }
       
   111 
       
   112 void
       
   113 _lm_sock_library_shutdown (void)
       
   114 {
       
   115 	if (!initialised) {
       
   116 		return;
       
   117 	}
       
   118 
       
   119 	lm_verbose ("Socket library shutting down...\n");
       
   120 
       
   121 #ifdef G_OS_WIN32
       
   122 	WSACleanup ();
       
   123 #endif /* G_OS_WIN32 */
       
   124 
       
   125 	initialised = FALSE;
       
   126 }
       
   127 
       
   128 void
       
   129 _lm_sock_set_blocking (LmSocketT sock, 
       
   130 		       gboolean block)
       
   131 {
       
   132 	int res;
       
   133 
       
   134 #ifndef G_OS_WIN32
       
   135 	res = fcntl (sock, F_SETFL, block ? 0 : O_NONBLOCK);
       
   136 #else  /* G_OS_WIN32 */
       
   137 	u_long mode = (block ? 0 : 1);
       
   138 	res = ioctlsocket (sock, FIONBIO, &mode);
       
   139 #endif /* G_OS_WIN32 */
       
   140 
       
   141 	if (res != 0) {
       
   142 	//	g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET,
       
   143 	//	       "Could not set connection to be %s\n",
       
   144 	//	       block ? "blocking" : "non-blocking");
       
   145 		lm_verbose ("[_lm_sock_set_blocking]: Could not set connection to be %s\n",
       
   146 		       block ? "blocking" : "non-blocking");
       
   147 	}
       
   148 }
       
   149 
       
   150 void
       
   151 _lm_sock_shutdown (LmSocketT sock)
       
   152 {
       
   153 	shutdown (sock, LM_SHUTDOWN);
       
   154 }
       
   155 
       
   156 void
       
   157 _lm_sock_close (LmSocketT sock)
       
   158 {
       
   159 #ifndef G_OS_WIN32
       
   160 	close (sock);
       
   161 #else  /* G_OS_WIN32 */
       
   162 	closesocket (sock);
       
   163 #endif /* G_OS_WIN32 */
       
   164 }
       
   165 
       
   166 LmSocketT
       
   167 _lm_sock_makesocket (int af,
       
   168 		     int type, 
       
   169 		     int protocol)
       
   170 {
       
   171 	int optval = 1;
       
   172 	int sock_fd = -1;
       
   173     unsigned int optlen = sizeof(optval);
       
   174     sock_fd = socket (af, type, protocol);
       
   175     setsockopt(sock_fd,SOL_SOCKET,SO_REUSEADDR|SO_REUSEPORT,&optval,optlen);
       
   176 	
       
   177 	return (LmSocketT)sock_fd;
       
   178 }
       
   179 
       
   180 int 
       
   181 _lm_sock_connect (LmSocketT               sock, 
       
   182 		  const struct sockaddr *name, 
       
   183 		  int                    namelen)
       
   184 {
       
   185 	return connect (sock, name, namelen);
       
   186 }
       
   187 
       
   188 gboolean
       
   189 _lm_sock_is_blocking_error (int err)
       
   190 {
       
   191 #ifndef G_OS_WIN32
       
   192 	return (err == _LM_SOCK_EINPROGRESS);
       
   193 #else  /* G_OS_WIN32 */
       
   194 	return (err == _LM_SOCK_EINPROGRESS || 
       
   195 		err == _LM_SOCK_EWOULDBLOCK || 
       
   196 		err == _LM_SOCK_EINVAL);
       
   197 #endif /* G_OS_WIN32 */
       
   198 }
       
   199 
       
   200 gboolean
       
   201 _lm_sock_is_blocking_success (int err)
       
   202 {
       
   203 	//Bug fixed by MRT from week 50 devlong onwards
       
   204 	return (err == _LM_SOCK_EEXISTS);
       
   205 	//Error EEXIST = 17 is not expected here. But It should be mrt error 107
       
   206 	//fix take later
       
   207 	//Before week 50 SDK
       
   208 	//return (err == _LM_SOCK_EALREADY || err == _LM_SOCK_EISCONN);
       
   209 }
       
   210 
       
   211 int 
       
   212 _lm_sock_get_last_error (void)
       
   213 {
       
   214 #ifndef G_OS_WIN32
       
   215 	return errno;
       
   216 #else  /* G_OS_WIN32 */
       
   217 	return WSAGetLastError ();
       
   218 #endif /* G_OS_WIN32 */
       
   219 }
       
   220 
       
   221 void 
       
   222 _lm_sock_get_error (LmSocketT   sock, 
       
   223 		    void      *error, 
       
   224 		    socklen_t *len)
       
   225 {
       
   226 	getsockopt (sock, SOL_SOCKET, SO_ERROR, (void*) error, len);
       
   227 }
       
   228 
       
   229 const gchar *
       
   230 _lm_sock_get_error_str (int err)
       
   231 {
       
   232 #ifndef G_OS_WIN32
       
   233 	return strerror (err);
       
   234 #else  /* G_OS_WIN32 */
       
   235 	switch (err) {
       
   236 	case WSAEINTR:              return _("Connect interrupted and canceled");
       
   237 	case WSAEACCES:             return _("Permission denied"); 
       
   238 	case WSAEFAULT:             return _("Bad address");
       
   239 	case WSAEINVAL:             return _("Invalid argument");
       
   240 	case WSAEMFILE:             return _("Too many open sockets");
       
   241 	case WSAEWOULDBLOCK:        return _("Resource temporarily unavailable");
       
   242 	case WSAEINPROGRESS:        return _("Operation now in progress");
       
   243 	case WSAEALREADY:           return _("Operation already in progress");
       
   244 	case WSAENOTSOCK:           return _("Socket operation on nonsocket");
       
   245 	case WSAEDESTADDRREQ:       return _("Destination address required");
       
   246 	case WSAEMSGSIZE:           return _("Message too long");
       
   247 	case WSAEPROTOTYPE:         return _("Protocol wrong type for socket");
       
   248 	case WSAENOPROTOOPT:        return _("Bad protocol option");
       
   249 	case WSAEPROTONOSUPPORT:    return _("Protocol not supported");
       
   250 	case WSAESOCKTNOSUPPORT:    return _("Socket type not supported");
       
   251 	case WSAEOPNOTSUPP:         return _("Operation not supported");
       
   252 	case WSAEPFNOSUPPORT:       return _("Protocol family not supported");
       
   253 	case WSAEAFNOSUPPORT:       return _("Address family not supported by protocol family");
       
   254 	case WSAEADDRINUSE:         return _("Address already in use");
       
   255 	case WSAEADDRNOTAVAIL:      return _("Can not assign requested address");
       
   256 	case WSAENETDOWN:           return _("Network is down");
       
   257 	case WSAENETUNREACH:        return _("Network is unreachable");
       
   258 	case WSAENETRESET:          return _("Network dropped connection on reset");
       
   259 	case WSAECONNABORTED:       return _("Software caused connection abort");
       
   260 	case WSAECONNRESET:         return _("Connection reset by peer");
       
   261 	case WSAENOBUFS:            return _("No buffer space available");
       
   262 	case WSAEISCONN:            return _("Socket is already connected");
       
   263 	case WSAENOTCONN:           return _("Socket is not connected");
       
   264 	case WSAESHUTDOWN:          return _("Can not send after socket shutdown");
       
   265 	case WSAETIMEDOUT:          return _("Connection timed out");
       
   266 	case WSAECONNREFUSED:       return _("Connection refused");
       
   267 	case WSAEHOSTDOWN:          return _("Host is down");
       
   268 	case WSAEHOSTUNREACH:       return _("No route to host");
       
   269 	case WSAEPROCLIM:           return _("Too many processes");
       
   270 	case WSASYSNOTREADY:        return _("Network subsystem is unavailable");
       
   271 	case WSAVERNOTSUPPORTED:    return _("Winsock library version is out of range ");
       
   272 	case WSANOTINITIALISED:     return _("Successful WSAStartup not yet performed");
       
   273 	case WSAEDISCON:            return _("Graceful shutdown in progress");
       
   274 	case WSATYPE_NOT_FOUND:     return _("Class type not found");
       
   275 	case WSAHOST_NOT_FOUND:     return _("Host not found");
       
   276 	case WSATRY_AGAIN:          return _("Nonauthoritative host not found");
       
   277 	case WSANO_RECOVERY:        return _("This is a nonrecoverable error");
       
   278 	case WSANO_DATA:            return _("Valid name, no data record of requested type");
       
   279 	case WSA_INVALID_HANDLE:    return _("Specified event object handle is invalid");
       
   280 	case WSA_INVALID_PARAMETER: return _("One or more parameters are invalid");
       
   281 	case WSA_IO_INCOMPLETE:     return _("Overlapped I/O event object no in signaled state");
       
   282 	case WSA_IO_PENDING:        return _("Overlapped operations will complete later");
       
   283 	case WSA_NOT_ENOUGH_MEMORY: return _("Insufficient memory available");
       
   284 	case WSA_OPERATION_ABORTED: return _("Overlapped operation aborted");
       
   285 		/* os dependent */
       
   286 	case WSASYSCALLFAILURE:     return _("System call failure");
       
   287 	}
       
   288 	
       
   289 	return _("Unknown");
       
   290 #endif /* G_OS_WIN32 */
       
   291 }
       
   292 
       
   293 const gchar *
       
   294 _lm_sock_addrinfo_get_error_str (int err)
       
   295 {
       
   296 	switch (err) {
       
   297 	case EAI_AGAIN:    
       
   298 		return ("The nameserver failed to return an "
       
   299 			 "address, try again later");
       
   300 	case EAI_BADFLAGS: 
       
   301 		return ("Internal error trying to obtain remote address");
       
   302 	case EAI_FAIL:     
       
   303 		return ("The nameserver encountered errors "
       
   304 			 "looking up this address");
       
   305 	/* EAI_NODATA is apparently missing on FreeBSD. On recent GNU libc,
       
   306 	 * it requires _GNU_SOURCE to be defined; in the unlikely case that
       
   307 	 * that GNU libc returns this value we'll return the default message */
       
   308 #ifdef EAI_NODATA
       
   309 	case EAI_NODATA:   
       
   310 		return _("The remote host exists but no address "
       
   311 			 "is available");
       
   312 #endif
       
   313 	case EAI_NONAME:   
       
   314 		return ("The remote address is unknown");
       
   315 	case EAI_FAMILY:
       
   316 	case EAI_SERVICE:
       
   317 	case EAI_SOCKTYPE:
       
   318 		return ("The remote address is not obtainable "
       
   319 			 "for that socket type.");
       
   320 	default:
       
   321 		break;
       
   322 	}
       
   323 
       
   324 	return ("The remote address could not be obtained ");
       
   325 }
       
   326 
       
   327 #ifdef USE_TCP_KEEPALIVES
       
   328 gboolean
       
   329 _lm_sock_set_keepalive (LmSocketT sock, int delay)
       
   330 {
       
   331 	int opt;
       
   332 
       
   333 	lm_verbose ("[_lm_sock_set_keepalive]: USE_TCP_KEEPALIVES Enabled\n");
       
   334 		       
       
   335 	opt = 1;
       
   336 	if (setsockopt (sock, SOL_SOCKET, SO_KEEPALIVE, &opt, sizeof (opt)) < 0) {
       
   337 		return FALSE;
       
   338 	}
       
   339 
       
   340 	//opt = 3; /* 3 keepalives before considering connection dead */
       
   341 	/*if (setsockopt (sock, IPPROTO_TCP, TCP_KEEPCNT, &opt, sizeof (opt)) < 0) {
       
   342 		return FALSE;
       
   343 	}
       
   344 
       
   345 	opt = delay;
       
   346 	if (setsockopt (sock, IPPROTO_TCP, TCP_KEEPIDLE, &opt, sizeof (opt)) < 0) {
       
   347 		return FALSE;
       
   348 	}
       
   349 
       
   350 	opt = delay; 
       
   351 	if (setsockopt (sock, IPPROTO_TCP, TCP_KEEPINTVL, &opt, sizeof (opt)) < 0) {
       
   352 		return FALSE;
       
   353 	}*/
       
   354 	UNUSED_FORMAL_PARAM(delay);
       
   355 	return TRUE;
       
   356 }
       
   357 #endif /* USE_TCP_KEEPALIVES */
       
   358 
       
   359 gchar *
       
   360 _lm_sock_get_local_host (LmSocketT sock)
       
   361 {
       
   362 	struct sockaddr      addr_info;
       
   363 	void                *sock_addr;
       
   364 	socklen_t            namelen;
       
   365 	char                 addrbuf[IPV6_MAX_ADDRESS_LEN];
       
   366 	const char          *host;
       
   367 
       
   368 	namelen = sizeof (struct sockaddr);
       
   369 	if (getsockname (sock, &addr_info, &namelen)) {
       
   370 		return NULL;
       
   371 	}
       
   372 
       
   373 	switch (addr_info.sa_family) {
       
   374 		case AF_INET: 
       
   375 			
       
   376 			sock_addr = & (((struct sockaddr_in *) &addr_info)->sin_addr);
       
   377 			break;
       
   378 		case AF_INET6:
       
   379 			sock_addr = & (((struct sockaddr_in6 *) &addr_info)->sin6_addr);
       
   380 			break;
       
   381 		default:
       
   382 			return NULL;
       
   383 	}
       
   384 	/* inet_ntoa has been obsoleted in favour of inet_ntop */
       
   385 	host = inet_ntop (addr_info.sa_family,
       
   386 			  sock_addr,
       
   387 			  addrbuf,
       
   388 			  IPV6_MAX_ADDRESS_LEN);
       
   389 
       
   390 	return g_strdup (host);
       
   391 }
       
   392