1 /* Copyright 2003-2004 Roger Dingledine; Copyright 2004 Nick Mathewson */
2 /* See LICENSE for licensing information */
4 const char compat_c_id
[] = "$Id$";
6 /* This is required on rh7 to make strptime not complain.
17 #include <sys/utsname.h>
19 #ifdef HAVE_SYS_TIME_H
25 #ifdef HAVE_SYS_FCNTL_H
26 #include <sys/fcntl.h>
37 #ifdef HAVE_SYS_RESOURCE_H
38 #include <sys/resource.h>
43 #ifdef HAVE_NETINET_IN_H
44 #include <netinet/in.h>
46 #ifdef HAVE_ARPA_INET_H
47 #include <arpa/inet.h>
49 #ifndef HAVE_GETTIMEOFDAY
51 #include <sys/timeb.h>
54 #ifdef HAVE_SYS_SOCKET_H
55 #include <sys/socket.h>
60 #ifdef HAVE_SYS_PARAM_H
61 #include <sys/param.h> /* FreeBSD needs this to know what version it is */
75 /* Inline the strl functions if the platform doesn't have them. */
83 /* used by inet_addr, not defined on solaris anywhere!? */
85 #define INADDR_NONE ((unsigned long) -1)
88 /** Replacement for snprintf. Differs from platform snprintf in two
89 * ways: First, always NUL-terminates its output. Second, always
90 * returns -1 if the result is truncated. (Note that this return
91 * behavior does <i>not</i> conform to C99; it just happens to be the
92 * easiest to emulate "return -1" with conformant implementations than
93 * it is to emulate "return number that would be written" with
94 * non-conformant implementations.) */
95 int tor_snprintf(char *str
, size_t size
, const char *format
, ...)
100 r
= tor_vsnprintf(str
,size
,format
,ap
);
105 /** Replacement for vsnprintf; behavior differs as tor_snprintf differs from
108 int tor_vsnprintf(char *str
, size_t size
, const char *format
, va_list args
)
112 return -1; /* no place for the NUL */
113 if (size
> SIZE_T_CEILING
)
116 r
= _vsnprintf(str
, size
, format
, args
);
118 r
= vsnprintf(str
, size
, format
, args
);
121 if (r
< 0 || ((size_t)r
) >= size
)
126 /** Take a filename and return a pointer to its final element. This
127 * function is called on __FILE__ to fix a MSVC nit where __FILE__
128 * contains the full path to the file. This is bad, because it
129 * confuses users to find the home directory of the person who
130 * compiled the binary in their warrning messages.
133 _tor_fix_source_file(const char *fname
)
135 const char *cp1
, *cp2
, *r
;
136 cp1
= strrchr(fname
, '/');
137 cp2
= strrchr(fname
, '\\');
139 r
= (cp1
<cp2
)?(cp2
+1):(cp1
+1);
150 #ifndef UNALIGNED_INT_ACCESS_OK
152 * Read a 16-bit value beginning at <b>cp</b>. Equivalent to
153 * *(uint16_t*)(cp), but will not cause segfaults on platforms that forbid
154 * unaligned memory access.
156 uint16_t get_uint16(const char *cp
)
163 * Read a 32-bit value beginning at <b>cp</b>. Equivalent to
164 * *(uint32_t*)(cp), but will not cause segfaults on platforms that forbid
165 * unaligned memory access.
167 uint32_t get_uint32(const char *cp
)
174 * Set a 16-bit value beginning at <b>cp</b> to <b>v</b>. Equivalent to
175 * *(uint16_t)(cp) = v, but will not cause segfaults on platforms that forbid
176 * unaligned memory access. */
177 void set_uint16(char *cp
, uint16_t v
)
182 * Set a 32-bit value beginning at <b>cp</b> to <b>v</b>. Equivalent to
183 * *(uint32_t)(cp) = v, but will not cause segfaults on platforms that forbid
184 * unaligned memory access. */
185 void set_uint32(char *cp
, uint32_t v
)
192 * Rename the file 'from' to the file 'to'. On unix, this is the same as
193 * rename(2). On windows, this removes 'to' first if it already exists.
194 * Returns 0 on success. Returns -1 and sets errno on failure.
196 int replace_file(const char *from
, const char *to
)
199 return rename(from
,to
);
201 switch (file_status(to
))
206 if (unlink(to
)) return -1;
214 return rename(from
,to
);
218 /** Turn <b>socket</b> into a nonblocking socket.
220 void set_socket_nonblocking(int socket
)
224 ioctlsocket(socket
, FIONBIO
, (unsigned long*) &nonblocking
);
226 fcntl(socket
, F_SETFL
, O_NONBLOCK
);
231 * Allocate a pair of connected sockets. (Like socketpair(family,
232 * type,protocol,fd), but works on systems that don't have
235 * Currently, only (AF_UNIX, SOCK_STREAM, 0 ) sockets are supported.
237 * Note that on systems without socketpair, this call will fail if
238 * localhost is inaccessible (for example, if the networking
239 * stack is down). And even if it succeeds, the socket pair will not
240 * be able to read while localhost is down later (the socket pair may
241 * even close, depending on OS-specific timeouts).
244 tor_socketpair(int family
, int type
, int protocol
, int fd
[2])
246 #ifdef HAVE_SOCKETPAIR
247 return socketpair(family
, type
, protocol
, fd
);
249 /* This socketpair does not work when localhost is down. So
250 * it's really not the same thing at all. But it's close enough
251 * for now, and really, when localhost is down sometimes, we
252 * have other problems too.
257 struct sockaddr_in listen_addr
;
258 struct sockaddr_in connect_addr
;
267 errno
= WSAEAFNOSUPPORT
;
269 errno
= EAFNOSUPPORT
;
278 listener
= socket(AF_INET
, type
, 0);
281 if (!SOCKET_IS_POLLABLE(listener
)) {
282 log_fn(LOG_WARN
, "Too many connections; can't open socketpair");
283 tor_close_socket(listener
);
286 memset(&listen_addr
, 0, sizeof(listen_addr
));
287 listen_addr
.sin_family
= AF_INET
;
288 listen_addr
.sin_addr
.s_addr
= htonl(INADDR_LOOPBACK
);
289 listen_addr
.sin_port
= 0; /* kernel chooses port. */
290 if (bind(listener
, (struct sockaddr
*) &listen_addr
, sizeof (listen_addr
))
292 goto tidy_up_and_fail
;
293 if (listen(listener
, 1) == -1)
294 goto tidy_up_and_fail
;
296 connector
= socket(AF_INET
, type
, 0);
298 goto tidy_up_and_fail
;
299 if (!SOCKET_IS_POLLABLE(connector
)) {
300 log_fn(LOG_WARN
, "Too many connections; can't open socketpair");
301 goto tidy_up_and_fail
;
303 /* We want to find out the port number to connect to. */
304 size
= sizeof(connect_addr
);
305 if (getsockname(listener
, (struct sockaddr
*) &connect_addr
, &size
) == -1)
306 goto tidy_up_and_fail
;
307 if (size
!= sizeof (connect_addr
))
308 goto abort_tidy_up_and_fail
;
309 if (connect(connector
, (struct sockaddr
*) &connect_addr
,
310 sizeof(connect_addr
)) == -1)
311 goto tidy_up_and_fail
;
313 size
= sizeof(listen_addr
);
314 acceptor
= accept(listener
, (struct sockaddr
*) &listen_addr
, &size
);
316 goto tidy_up_and_fail
;
317 if (!SOCKET_IS_POLLABLE(acceptor
)) {
318 log_fn(LOG_WARN
, "Too many connections; can't open socketpair");
319 goto tidy_up_and_fail
;
321 if (size
!= sizeof(listen_addr
))
322 goto abort_tidy_up_and_fail
;
323 tor_close_socket(listener
);
324 /* Now check we are talking to ourself by matching port and host on the
326 if (getsockname(connector
, (struct sockaddr
*) &connect_addr
, &size
) == -1)
327 goto tidy_up_and_fail
;
328 if (size
!= sizeof (connect_addr
)
329 || listen_addr
.sin_family
!= connect_addr
.sin_family
330 || listen_addr
.sin_addr
.s_addr
!= connect_addr
.sin_addr
.s_addr
331 || listen_addr
.sin_port
!= connect_addr
.sin_port
) {
332 goto abort_tidy_up_and_fail
;
339 abort_tidy_up_and_fail
:
341 errno
= WSAECONNABORTED
;
343 errno
= ECONNABORTED
; /* I hope this is portable and appropriate. */
347 int save_errno
= errno
;
349 tor_close_socket(listener
);
351 tor_close_socket(connector
);
353 tor_close_socket(acceptor
);
360 /** Get the maximum allowed number of file descriptors. (Some systems
361 * have a low soft limit.) Make sure we set it to at least
362 * <b>required_min</b>. Return 0 if we can, or -1 if we fail. */
363 int set_max_file_descriptors(unsigned int required_min
) {
364 #ifndef HAVE_GETRLIMIT
365 log_fn(LOG_INFO
,"This platform is missing getrlimit(). Proceeding.");
366 return 0; /* hope we'll be ok */
370 if (getrlimit(RLIMIT_NOFILE
, &rlim
) != 0) {
371 log_fn(LOG_WARN
, "Could not get maximum number of file descriptors: %s",
375 if (required_min
> rlim
.rlim_max
) {
376 log_fn(LOG_WARN
,"We need %u file descriptors available, and we're limited to %lu. Please change your ulimit.", required_min
, (unsigned long int)rlim
.rlim_max
);
379 if (required_min
> rlim
.rlim_cur
) {
380 log_fn(LOG_INFO
,"Raising max file descriptors from %lu to %lu.",
381 (unsigned long int)rlim
.rlim_cur
, (unsigned long int)rlim
.rlim_max
);
383 rlim
.rlim_cur
= rlim
.rlim_max
;
384 if (setrlimit(RLIMIT_NOFILE
, &rlim
) != 0) {
385 log_fn(LOG_WARN
, "Could not set maximum number of file descriptors: %s",
393 /** Call setuid and setgid to run as <b>user</b>:<b>group</b>. Return 0 on
394 * success. On failure, log and return -1.
396 int switch_id(char *user
, char *group
) {
398 struct passwd
*pw
= NULL
;
399 struct group
*gr
= NULL
;
404 log_fn(LOG_ERR
,"User '%s' not found.", user
);
409 /* switch the group first, while we still have the privileges to do so */
411 gr
= getgrnam(group
);
413 log_fn(LOG_ERR
,"Group '%s' not found.", group
);
417 if (setgid(gr
->gr_gid
) != 0) {
418 log_fn(LOG_ERR
,"Error setting GID: %s", strerror(errno
));
422 if (setgid(pw
->pw_gid
) != 0) {
423 log_fn(LOG_ERR
,"Error setting GID: %s", strerror(errno
));
428 /* now that the group is switched, we can switch users and lose
431 if (setuid(pw
->pw_uid
) != 0) {
432 log_fn(LOG_ERR
,"Error setting UID: %s", strerror(errno
));
441 "User or group specified, but switching users is not supported.");
447 /** Allocate and return a string containing the home directory for the
448 * user <b>username</b>. Only works on posix-like systems */
450 get_user_homedir(const char *username
)
453 tor_assert(username
);
455 if (!(pw
= getpwnam(username
))) {
456 log_fn(LOG_ERR
,"User '%s' not found.", username
);
459 return tor_strdup(pw
->pw_dir
);
463 /** Set *addr to the IP address (in dotted-quad notation) stored in c.
464 * Return 1 on success, 0 if c is badly formatted. (Like inet_aton(c,addr),
465 * but works on Windows and Solaris.)
467 int tor_inet_aton(const char *c
, struct in_addr
* addr
)
469 #ifdef HAVE_INET_ATON
470 return inet_aton(c
, addr
);
475 if (strcmp(c
, "255.255.255.255") == 0) {
476 addr
->s_addr
= 0xFFFFFFFFu
;
480 if (r
== INADDR_NONE
)
487 /** Similar behavior to Unix gethostbyname: resolve <b>name</b>, and set
488 * *addr to the proper IP address, in network byte order. Returns 0
489 * on success, -1 on failure; 1 on transient failure.
491 * (This function exists because standard windows gethostbyname
492 * doesn't treat raw IP addresses properly.)
494 int tor_lookup_hostname(const char *name
, uint32_t *addr
)
496 /* Perhaps eventually this should be replaced by a tor_getaddrinfo or
499 struct in_addr iaddr
;
502 /* Empty address is an error. */
504 } else if (tor_inet_aton(name
, &iaddr
)) {
506 memcpy(addr
, &iaddr
.s_addr
, 4);
509 #ifdef HAVE_GETADDRINFO
511 struct addrinfo
*res
, *res_p
;
512 struct addrinfo hints
;
513 memset(&hints
, 0, sizeof(hints
));
514 hints
.ai_family
= PF_INET
;
515 hints
.ai_socktype
= SOCK_STREAM
;
516 err
= getaddrinfo(name
, NULL
, NULL
, &res
);
518 for (res_p
= res
; res_p
; res_p
= res_p
->ai_next
) {
519 if (res_p
->ai_family
== AF_INET
) {
520 struct sockaddr_in
*sin
= (struct sockaddr_in
*)res_p
->ai_addr
;
521 memcpy(addr
, &sin
->sin_addr
, 4);
530 return (err
== EAI_AGAIN
) ? 1 : -1;
533 #ifdef HAVE_GETHOSTBYNAME_R
534 ent
= gethostbyname_r(name
);
539 /* break to remind us if we move away from IPv4 */
540 tor_assert(ent
->h_length
== 4);
541 memcpy(addr
, ent
->h_addr
, 4);
546 return (WSAGetLastError() == WSATRY_AGAIN
) ? 1 : -1;
548 return (h_errno
== TRY_AGAIN
) ? 1 : -1;
554 /* Hold the result of our call to <b>uname</b>. */
555 static char uname_result
[256];
556 /* True iff uname_result is set. */
557 static int uname_result_is_set
= 0;
559 /* Return a pointer to a description of our platform.
567 if (!uname_result_is_set
) {
569 if (uname(&u
) != -1) {
570 /* (linux says 0 is success, solaris says 1 is success) */
571 tor_snprintf(uname_result
, sizeof(uname_result
), "%s %s %s",
572 u
.sysname
, u
.nodename
, u
.machine
);
579 const char *plat
= NULL
;
581 int major
; int minor
; const char *version
;
582 } win_version_table
[] = {
583 { 5, 2, "Windows Server 2003" },
584 { 5, 1, "Windows XP" },
585 { 5, 0, "Windows 2000" },
586 /* { 4, 0, "Windows NT 4.0" }, */
587 { 4, 90, "Windows Me" },
588 { 4, 10, "Windows 98" },
589 /* { 4, 0, "Windows 95" } */
590 { 3, 51, "Windows NT 3.51" },
593 info
.dwOSVersionInfoSize
= sizeof(info
);
595 if (info
.dwMajorVersion
== 4 && info
.dwMinorVersion
== 0) {
596 if (info
.dwPlatformId
== VER_PLATFORM_WIN32_NT
)
597 plat
= "Windows NT 4.0";
601 for (i
=0; win_version_table
[i
].major
>=0; ++i
) {
602 if (win_version_table
[i
].major
== info
.dwMajorVersion
&&
603 win_version_table
[i
].minor
== info
.dwMinorVersion
) {
604 plat
= win_version_table
[i
].version
;
610 strlcpy(uname_result
, plat
, sizeof(uname_result
));
612 if (info
.dwMajorVersion
> 5 ||
613 (info
.dwMajorVersion
==5 && info
.dwMinorVersion
>2))
614 tor_snprintf(uname_result
, sizeof(uname_result
),
615 "Very recent version of Windows [major=%d,minor=%d]",
616 (int)info
.dwMajorVersion
,(int)info
.dwMinorVersion
);
618 tor_snprintf(uname_result
, sizeof(uname_result
),
619 "Unrecognized version of Windows [major=%d,minor=%d]",
620 (int)info
.dwMajorVersion
,(int)info
.dwMinorVersion
);
623 strlcpy(uname_result
, "Unknown platform", sizeof(uname_result
));
626 uname_result_is_set
= 1;
635 #if defined(USE_PTHREADS)
636 struct tor_pthread_data_t
{
641 tor_pthread_helper_fn(void *_data
)
643 struct tor_pthread_data_t
*data
= _data
;
654 /** Minimalist interface to run a void function in the background. On
655 * unix calls fork, on win32 calls beginthread. Returns -1 on failure.
656 * func should not return, but rather should call spawn_exit.
658 * NOTE: if <b>data</b> is used, it should not be allocated on the stack,
659 * since in a multithreaded environment, there is no way to be sure that
660 * the caller's stack will still be around when the called function is
664 spawn_func(int (*func
)(void *), void *data
)
666 #if defined(USE_WIN32_THREADS)
668 rv
= _beginthread(func
, 0, data
);
669 if (rv
== (unsigned long) -1)
672 #elif defined(USE_PTHREADS)
674 struct tor_pthread_data_t
*d
;
675 d
= tor_malloc(sizeof(struct tor_pthread_data_t
));
678 if (pthread_create(&thread
,NULL
,tor_pthread_helper_fn
,d
))
680 if (pthread_detach(thread
))
691 tor_assert(0); /* Should never reach here. */
692 return 0; /* suppress "control-reaches-end-of-non-void" warning. */
700 /** End the current thread/process.
704 #if defined(USE_WIN32_THREADS)
706 #elif defined(USE_PTHREADS)
709 /* http://www.erlenstar.demon.co.uk/unix/faq_2.html says we should
710 * call _exit, not exit, from child processes. */
715 /** Set *timeval to the current time of day. On error, log and terminate.
716 * (Same as gettimeofday(timeval,NULL), but never returns -1.)
718 void tor_gettimeofday(struct timeval
*timeval
) {
719 #ifdef HAVE_GETTIMEOFDAY
720 if (gettimeofday(timeval
, NULL
)) {
721 log_fn(LOG_ERR
, "gettimeofday failed.");
722 /* If gettimeofday dies, we have either given a bad timezone (we didn't),
726 #elif defined(HAVE_FTIME)
729 timeval
->tv_sec
= tb
.time
;
730 timeval
->tv_usec
= tb
.millitm
* 1000;
732 #error "No way to get time."
737 #ifdef USE_WIN32_THREADS
741 tor_mutex_t
*tor_mutex_new(void)
744 m
= tor_malloc_zero(sizeof(tor_mutex_t
));
745 m
->handle
= CreateMutex(NULL
, FALSE
, NULL
);
746 tor_assert(m
->handle
!= NULL
);
749 void tor_mutex_free(tor_mutex_t
*m
)
751 CloseHandle(m
->handle
);
754 void tor_mutex_acquire(tor_mutex_t
*m
)
757 r
= WaitForSingleObject(m
->handle
, INFINITE
);
759 case WAIT_ABANDONED
: /* holding thread exited. */
760 case WAIT_OBJECT_0
: /* we got the mutex normally. */
762 case WAIT_TIMEOUT
: /* Should never happen. */
766 log_fn(LOG_WARN
, "Failed to acquire mutex: %d", GetLastError());
769 void tor_mutex_release(tor_mutex_t
*m
)
772 r
= ReleaseMutex(m
->handle
);
774 log_fn(LOG_WARN
, "Failed to release mutex: %d", GetLastError());
777 #elif defined(USE_PTHREADS)
779 pthread_mutex_t mutex
;
781 tor_mutex_t
*tor_mutex_new(void)
783 tor_mutex_t
*mutex
= tor_malloc_zero(sizeof(tor_mutex_t
));
784 pthread_mutex_init(&mutex
->mutex
, NULL
);
787 void tor_mutex_acquire(tor_mutex_t
*m
)
790 pthread_mutex_lock(&m
->mutex
);
792 void tor_mutex_release(tor_mutex_t
*m
)
795 pthread_mutex_unlock(&m
->mutex
);
797 void tor_mutex_free(tor_mutex_t
*m
)
800 pthread_mutex_destroy(&m
->mutex
);
807 tor_mutex_t
*tor_mutex_new(void) { return NULL
; }
808 void tor_mutex_acquire(tor_mutex_t
*m
) { }
809 void tor_mutex_release(tor_mutex_t
*m
) { }
810 void tor_mutex_free(tor_mutex_t
*m
) { }
814 * On Windows, WSAEWOULDBLOCK is not always correct: when you see it,
815 * you need to ask the socket for its actual errno. Also, you need to
816 * get your errors from WSAGetLastError, not errno. (If you supply a
817 * socket of -1, we check WSAGetLastError, but don't correct
820 * The upshot of all of this is that when a socket call fails, you
821 * should call tor_socket_errno <em>at most once</em> on the failing
822 * socket to get the error.
825 int tor_socket_errno(int sock
)
827 int optval
, optvallen
=sizeof(optval
);
828 int err
= WSAGetLastError();
829 if (err
== WSAEWOULDBLOCK
&& sock
>= 0) {
830 if (getsockopt(sock
, SOL_SOCKET
, SO_ERROR
, (void*)&optval
, &optvallen
))
840 #define E(code, s) { code, (s " [" #code " ]") }
841 struct { int code
; const char *msg
; } windows_socket_errors
[] = {
842 E(WSAEINTR
, "Interrupted function call"),
843 E(WSAEACCES
, "Permission denied"),
844 E(WSAEFAULT
, "Bad address"),
845 E(WSAEINVAL
, "Invalid argument"),
846 E(WSAEMFILE
, "Too many open files"),
847 E(WSAEWOULDBLOCK
, "Resource temporarily unavailable"),
848 E(WSAEINPROGRESS
, "Operation now in progress"),
849 E(WSAEALREADY
, "Operation already in progress"),
850 E(WSAENOTSOCK
, "Socket operation on nonsocket"),
851 E(WSAEDESTADDRREQ
, "Destination address required"),
852 E(WSAEMSGSIZE
, "Message too long"),
853 E(WSAEPROTOTYPE
, "Protocol wrong for socket"),
854 E(WSAENOPROTOOPT
, "Bad protocol option"),
855 E(WSAEPROTONOSUPPORT
, "Protocol not supported"),
856 E(WSAESOCKTNOSUPPORT
, "Socket type not supported"),
857 /* What's the difference between NOTSUPP and NOSUPPORT? :) */
858 E(WSAEOPNOTSUPP
, "Operation not supported"),
859 E(WSAEPFNOSUPPORT
, "Protocol family not supported"),
860 E(WSAEAFNOSUPPORT
, "Address family not supported by protocol family"),
861 E(WSAEADDRINUSE
, "Address already in use"),
862 E(WSAEADDRNOTAVAIL
, "Cannot assign requested address"),
863 E(WSAENETDOWN
, "Network is down"),
864 E(WSAENETUNREACH
, "Network is unreachable"),
865 E(WSAENETRESET
, "Network dropped connection on reset"),
866 E(WSAECONNABORTED
, "Software caused connection abort"),
867 E(WSAECONNRESET
, "Connection reset by peer"),
868 E(WSAENOBUFS
, "No buffer space available"),
869 E(WSAEISCONN
, "Socket is already connected"),
870 E(WSAENOTCONN
, "Socket is not connected"),
871 E(WSAESHUTDOWN
, "Cannot send after socket shutdown"),
872 E(WSAETIMEDOUT
, "Connection timed out"),
873 E(WSAECONNREFUSED
, "Connection refused"),
874 E(WSAEHOSTDOWN
, "Host is down"),
875 E(WSAEHOSTUNREACH
, "No route to host"),
876 E(WSAEPROCLIM
, "Too many processes"),
877 /* Yes, some of these start with WSA, not WSAE. No, I don't know why. */
878 E(WSASYSNOTREADY
, "Network subsystem is unavailable"),
879 E(WSAVERNOTSUPPORTED
, "Winsock.dll out of range"),
880 E(WSANOTINITIALISED
, "Successful WSAStartup not yet performed"),
881 E(WSAEDISCON
, "Graceful shutdown now in progress"),
882 #ifdef WSATYPE_NOT_FOUND
883 E(WSATYPE_NOT_FOUND
, "Class type not found"),
885 E(WSAHOST_NOT_FOUND
, "Host not found"),
886 E(WSATRY_AGAIN
, "Nonauthoritative host not found"),
887 E(WSANO_RECOVERY
, "This is a nonrecoverable error"),
888 E(WSANO_DATA
, "Valid name, no data record of requested type)"),
890 /* There are some more error codes whose numeric values are marked
891 * <b>OS dependent</b>. They start with WSA_, apparently for the same
892 * reason that practitioners of some craft traditions deliberately
893 * introduce imperfections into their baskets and rugs "to allow the
894 * evil spirits to escape." If we catch them, then our binaries
895 * might not report consistent results across versions of Windows.
896 * Thus, I'm going to let them all fall through.
900 /** There does not seem to be a strerror equivalent for winsock errors.
901 * Naturally, we have to roll our own.
903 const char *tor_socket_strerror(int e
)
906 for (i
=0; windows_socket_errors
[i
].code
>= 0; ++i
) {
907 if (e
== windows_socket_errors
[i
].code
)
908 return windows_socket_errors
[i
].msg
;
914 /** Called before we make any calls to network-related functions.
915 * (Some operating systems require their network libraries to be
917 int network_init(void)
920 /* This silly exercise is necessary before windows will allow gethostbyname to work.
924 r
= WSAStartup(0x101,&WSAData
);
926 log_fn(LOG_WARN
,"Error initializing windows network layer: code was %d",r
);