From 8612bacf0adffdbc1a33e2e30dd109be3506b03c Mon Sep 17 00:00:00 2001 From: hniksic Date: Sun, 6 Mar 2005 08:36:45 -0800 Subject: [PATCH] [svn] Store errors for Winsock calls in errno. Provide a version of strerror that handles Winsock errors. --- src/ChangeLog | 9 ++++ src/mswindows.c | 122 ++++++++++++++++++++++++++++++++++++++++++++++-- src/mswindows.h | 36 +++++++++++++- 3 files changed, 163 insertions(+), 4 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index 9547bd7e..39af0663 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,12 @@ +2005-03-06 Hrvoje Niksic + + * mswindows.c: Provide wrappers to Winsock functions that set + errno to WSAGetLastError() in case of failure. Also provide a + Windows-specific version of strerror. + + * mswindows.h: Wrap calls to socket, bind, connect, recv, send, + select, getsockname, getpeername, and setsockopt. + 2005-03-06 Hrvoje Niksic * url.c (url_parse): Reject port numbers larger than 65535. We diff --git a/src/mswindows.c b/src/mswindows.c index 22605a95..15518a00 100644 --- a/src/mswindows.c +++ b/src/mswindows.c @@ -48,6 +48,8 @@ so, delete this exception statement from your version. */ # endif #endif +#define INHIBIT_WRAP /* avoid wrapping of socket, bind, ... */ + #include "wget.h" #include "utils.h" #include "url.h" @@ -210,7 +212,7 @@ str_to_int64 (const char *nptr, char **endptr, int base) #endif /* !defined(__BORLANDC__) && (!defined(_MSC_VER) || _MSC_VER >= 1300) */ void -windows_main_junk (int *argc, char **argv, char **exec_name) +windows_main (int *argc, char **argv, char **exec_name) { char *p; @@ -335,7 +337,7 @@ fake_fork (void) char *name; BOOL rv; - event = section = pi.hProcess = pi.hThread = NULL; + section = pi.hProcess = pi.hThread = NULL; /* Get the fully qualified name of our executable. This is more reliable than using argv[0]. */ @@ -694,7 +696,7 @@ run_with_timeout (double seconds, void (*fun) (void *), void *arg) static HANDLE thread_hnd = NULL; struct thread_data thread_arg; DWORD thread_id; - int rc = 0; + int rc; DEBUGP (("seconds %.2f, ", seconds)); @@ -738,3 +740,117 @@ run_with_timeout (double seconds, void (*fun) (void *), void *arg) thread_hnd = NULL; return rc; } + +/* Wget expects network calls such as bind, connect, etc., to set errno. + To achieve that, we place Winsock calls in wrapper functions that, in + case of error, sets errno to the value of GetLastError(). In addition, + we provide a wrapper around strerror, which recognizes Winsock errors + and prints the appropriate error message. */ + +/* Define a macro that creates a function definition that wraps FUN into + a function that sets errno the way the rest of the code expects. */ + +#define WRAP(fun, decl, call) int wrap_##fun decl { \ + int retval = fun call; \ + if (retval < 0) \ + errno = WSAGetLastError (); \ + return retval; \ +} + +WRAP (socket, (int domain, int type, int protocol), (domain, type, protocol)) +WRAP (bind, (int s, struct sockaddr *a, int alen), (s, a, alen)) +WRAP (connect, (int s, const struct sockaddr *a, int alen), (s, a, alen)) +WRAP (recv, (int s, void *buf, int len, int flags), (s, buf, len, flags)) +WRAP (send, (int s, const void *buf, int len, int flags), (s, buf, len, flags)) +WRAP (select, (int n, fd_set *r, fd_set *w, fd_set *e, const struct timeval *tm), + (n, r, w, e, tm)) +WRAP (getsockname, (int s, struct sockaddr *n, int *nlen), (s, n, nlen)) +WRAP (getpeername, (int s, struct sockaddr *n, int *nlen), (s, n, nlen)) +WRAP (setsockopt, (int s, int level, int opt, const void *val, int len), + (s, level, opt, val, len)) + +/* Return the text of the error message for Winsock error WSERR. */ + +static const char * +get_winsock_error (int wserr) +{ + switch (wserr) { + case WSAEINTR: return "Interrupted system call"; + case WSAEBADF: return "Bad file number"; + case WSAEACCES: return "Permission denied"; + case WSAEFAULT: return "Bad address"; + case WSAEINVAL: return "Invalid argument"; + case WSAEMFILE: return "Too many open files"; + 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 "Cannot 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 "Cannot send after socket shutdown"; + case WSAETOOMANYREFS: return "Too many references"; + case WSAETIMEDOUT: return "Connection timed out"; + case WSAECONNREFUSED: return "Connection refused"; + case WSAELOOP: return "Too many levels of symbolic links"; + case WSAENAMETOOLONG: return "File name too long"; + case WSAEHOSTDOWN: return "Host is down"; + case WSAEHOSTUNREACH: return "No route to host"; + case WSAENOTEMPTY: return "Not empty"; + case WSAEPROCLIM: return "Too many processes"; + case WSAEUSERS: return "Too many users"; + case WSAEDQUOT: return "Bad quota"; + case WSAESTALE: return "Something is stale"; + case WSAEREMOTE: return "Remote error"; + case WSAEDISCON: return "Disconnected"; + + /* Extended Winsock errors */ + case WSASYSNOTREADY: return "Winsock library is not ready"; + case WSANOTINITIALISED: return "Winsock library not initalised"; + case WSAVERNOTSUPPORTED: return "Winsock version not supported"; + + case WSAHOST_NOT_FOUND: return "Host not found"; + case WSATRY_AGAIN: return "Host not found, try again"; + case WSANO_RECOVERY: return "Unrecoverable error in call to nameserver"; + case WSANO_DATA: return "No data record of requested type"; + + default: + return NULL; + } +} + +/* Return the error message corresponding to ERR. This is different + from Windows libc strerror() in that it handles Winsock errors + correctly. */ + +const char * +windows_strerror (int err) +{ + const char *p; + if (err >= 0 && err < sys_nerr) + return strerror (err); + else if ((p = get_winsock_error (err)) != NULL) + return p; + else + { + static char buf[32]; + snprintf (buf, sizeof (buf), "Unknown error %d (%#x)", err, err); + return buf; + } +} diff --git a/src/mswindows.h b/src/mswindows.h index 08f0c84d..8691d94c 100644 --- a/src/mswindows.h +++ b/src/mswindows.h @@ -130,6 +130,40 @@ __int64 str_to_int64 (const char *, char **, int); # define mkdir(a, b) mkdir(a) #endif /* __BORLANDC__ */ +#ifndef INHIBIT_WRAP + +/* Winsock functions don't set errno, so we provide wrappers + that do. */ + +#define socket wrap_socket +#define bind wrap_bind +#define connect wrap_connect +#define recv wrap_recv +#define send wrap_send +#define select wrap_select +#define getsockname wrap_getsockname +#define getpeername wrap_getpeername +#define setsockopt wrap_setsockopt + +#endif /* not INHIBIT_WRAP */ + +int wrap_socket (int, int, int); +int wrap_bind (int, struct sockaddr *, int); +int wrap_connect (int, const struct sockaddr *, int); +int wrap_recv (int, void *, int, int); +int wrap_send (int, const void *, int, int); +int wrap_select (int, fd_set *, fd_set *, fd_set *, const struct timeval *); +int wrap_getsockname (int, struct sockaddr *, int *); +int wrap_getpeername (int, struct sockaddr *, int *); +int wrap_setsockopt (int, int, int, const void *, int); + +/* Finally, provide a private version of strerror that does the + right thing with Winsock errors. */ +#ifndef INHIBIT_WRAP +# define strerror windows_strerror +#endif +const char *windows_strerror (int); + /* Declarations of various socket errors: */ #define EWOULDBLOCK WSAEWOULDBLOCK @@ -181,7 +215,7 @@ void ws_startup (void); void ws_changetitle (const char *); void ws_percenttitle (double); char *ws_mypath (void); -void windows_main_junk (int *, char **, char **); +void windows_main (int *, char **, char **); /* Things needed for IPv6; missing in . */ #ifdef ENABLE_IPV6 -- 2.39.2