diff options
author | Pixel <pixel@nobis-crew.org> | 2011-10-17 23:06:29 -0700 |
---|---|---|
committer | Pixel <pixel@nobis-crew.org> | 2011-10-17 23:06:57 -0700 |
commit | ea271d967c52892a61f2b2db754780912e0f7cef (patch) | |
tree | 9cc70e5adfb75699291471ff4a5a6e9532c0002c | |
parent | 58f4ba6c8a4f9662dad9f5ddb3106c2e2c34daa6 (diff) |
Making some adjustments to get the Socket code compiling under mingw32. Doesn't work though; I'm guessing IPv6 isn't really mingw32 thing. At least, it's not WinXP's. Will try later to make something that switches between IPv4 and IPv6 intelligently.
-rw-r--r-- | includes/Printer.h | 8 | ||||
-rw-r--r-- | includes/Socket.h | 9 | ||||
-rw-r--r-- | mingw32-config.h | 2 | ||||
-rw-r--r-- | src/Socket.cc | 165 |
4 files changed, 180 insertions, 4 deletions
diff --git a/includes/Printer.h b/includes/Printer.h index cd24059..e8d9a03 100644 --- a/includes/Printer.h +++ b/includes/Printer.h @@ -20,6 +20,14 @@ enum { M_MAX = M_ENGINE_DEBUG, }; +#undef E_STRING +#undef E_TASK +#undef E_EVENT +#undef E_HANDLE +#undef E_INPUT +#undef E_SOCKET +#undef E_THREAD + enum { E_STRING = 1, E_TASK = 2, diff --git a/includes/Socket.h b/includes/Socket.h index 1f20fbb..b762d9b 100644 --- a/includes/Socket.h +++ b/includes/Socket.h @@ -1,6 +1,12 @@ #pragma once +#ifdef _WIN32 +#include <windows.h> +#include <winsock2.h> +#include <ws2tcpip.h> +#else #include <netdb.h> +#endif #include <Handle.h> #include <Task.h> #include <Printer.h> @@ -53,7 +59,8 @@ class Listener : public Task { public: Listener(int port, const char * local = NULL) : m_stop(false) { m_listener.setLocal(local, port); - m_listener.listen(); + bool r = m_listener.listen(); + Assert(r); m_name = String(ClassName(this).c_str()) + " - " + m_listener.getName(); Printer::elog(E_SOCKET, "Created a listener task at %p", this); } diff --git a/mingw32-config.h b/mingw32-config.h index 4910388..fb5a4e8 100644 --- a/mingw32-config.h +++ b/mingw32-config.h @@ -1,3 +1,5 @@ +#define _WIN32_WINNT 0x501 + #define HAVE_PROPER_ICONV 1 #define __CLEANUP_C 1 diff --git a/src/Socket.cc b/src/Socket.cc index 762aae3..65991a9 100644 --- a/src/Socket.cc +++ b/src/Socket.cc @@ -1,9 +1,12 @@ +#ifndef _WIN32 #include <arpa/inet.h> -#include <sys/types.h> #include <sys/socket.h> -#include <netdb.h> +#endif +#include <sys/types.h> #include <unistd.h> #include <fcntl.h> +#include <sys/stat.h> +#include <stdio.h> #include <errno.h> #include "Socket.h" #include "Threads.h" @@ -35,6 +38,139 @@ struct DNSRequest { int error; }; +static Balau::String getErrorMessage() { + Balau::String msg; +#ifdef _WIN32 + char * lpMsgBuf; + if (FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + WSAGetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + (LPTSTR) &lpMsgBuf, + 0, + NULL)) { + char * eol = strrchr(lpMsgBuf, '\n'); + if (eol) + *eol = 0; + msg = lpMsgBuf; + } else { + msg = "FormatMessage failed"; + } + LocalFree(lpMsgBuf); +#else + msg = strerror(errno); +#endif + return msg; +} + +#if defined(_WIN32) && !defined(AI_V4MAPPED) +// mingw32 is retarded. +#define AI_NUMERICSERV 0x00000008L +#define AI_ALL 0x00000100L +#define AI_ADDRCONFIG 0x00000400L +#define AI_V4MAPPED 0x00000800L +#define AI_NON_AUTHORITATIVE 0x00004000L +#define AI_SECURE 0x00008000L +#define AI_RETURN_PREFERRED_NAMES 0x00010000L +#define AI_FQDN 0x00020000L +#define AI_FILESERVER 0x00040000L + +// and winXP is stupid + +static const char * inet_ntop4(const unsigned char * src, char * dst, socklen_t size) { + char out[INET_ADDRSTRLEN]; + + int len = sprintf(out, "%u.%u.%u.%u", src[0], src[1], src[2], src[3]); + if (len < 0) { + return NULL; + } else if (len > size) { + errno = ENOSPC; + return NULL; + } + return strcpy(dst, out); +} + +static const char * inet_ntop6(const unsigned char * src, char * dst, socklen_t size) { + char tmp[INET6_ADDRSTRLEN], *tp; + struct { int base, len; } best, cur; + unsigned int words[8]; + int i; + + memset(words, 0, sizeof(words)); + for (i = 0; i < 16; i += 2) + words[i / 2] = (src[i] << 8) | src[i + 1]; + best.base = -1; + cur.base = -1; + for (i = 0; i < 8; i++) { + if (words[i] == 0) { + if (cur.base == -1) + cur.base = i, cur.len = 1; + else + cur.len++; + } else { + if (cur.base != -1) { + if (best.base == -1 || cur.len > best.len) + best = cur; + cur.base = -1; + } + } + } + if (cur.base != -1) { + if (best.base == -1 || cur.len > best.len) + best = cur; + } + if (best.base != -1 && best.len < 2) + best.base = -1; + + tp = tmp; + for (i = 0; i < 8; i++) { + if (best.base != -1 && i >= best.base && i < (best.base + best.len)) { + if (i == best.base) + *tp++ = ':'; + continue; + } + if (i != 0) + *tp++ = ':'; + if (i == 6 && best.base == 0 && (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) { + if (!inet_ntop4 (src + 12, tp, sizeof tmp - (tp - tmp))) + return NULL; + tp += strlen (tp); + break; + } + + int len = sprintf (tp, "%x", words[i]); + if (len < 0) + return NULL; + tp += len; + } + if (best.base != -1 && (best.base + best.len) == 8) + *tp++ = ':'; + *tp++ = '\0'; + + if ((socklen_t) (tp - tmp) > size) { + errno = ENOSPC; + return NULL; + } + + return strcpy(dst, tmp); +} + +static const char * inet_ntop(int af, const void * src, char * dst, socklen_t size) { + switch (af) { + case AF_INET: + return inet_ntop4((const unsigned char *) src, dst, size); + case AF_INET6: + return inet_ntop6((const unsigned char *) src, dst, size); + default: + errno = WSAEAFNOSUPPORT; + WSASetLastError(errno); + return NULL; + } +} + +#endif + #if 0 // TODO: use getaddrinfo_a, if available. #else @@ -100,7 +236,12 @@ Balau::Socket::Socket() throw (GeneralException) : m_fd(socket(AF_INET6, SOCK_ST Assert(m_fd >= 0); m_evtR = new SocketEvent(m_fd, EV_READ); m_evtW = new SocketEvent(m_fd, EV_WRITE); +#ifdef _WIN32 + u_long iMode = 1; + ioctlsocket(m_fd, FIONBIO, &iMode); +#else fcntl(m_fd, F_SETFL, O_NONBLOCK); +#endif memset(&m_localAddr, 0, sizeof(m_localAddr)); memset(&m_remoteAddr, 0, sizeof(m_remoteAddr)); Printer::elog(E_SOCKET, "Creating a socket at %p", this); @@ -127,7 +268,12 @@ Balau::Socket::Socket(int fd) : m_fd(fd), m_connected(true), m_connecting(false) m_evtR = new SocketEvent(m_fd, EV_READ); m_evtW = new SocketEvent(m_fd, EV_WRITE); +#ifdef _WIN32 + u_long iMode = 1; + ioctlsocket(m_fd, FIONBIO, &iMode); +#else fcntl(m_fd, F_SETFL, O_NONBLOCK); +#endif m_name.set("Socket(Connected - [%s]:%i <- [%s]:%i)", rLocal, htons(m_localAddr.sin6_port), rRemote, htons(m_remoteAddr.sin6_port)); Printer::elog(E_SOCKET, "Created a new socket from listener at %p; %s", this, m_name.to_charp()); @@ -136,6 +282,7 @@ Balau::Socket::Socket(int fd) : m_fd(fd), m_connected(true), m_connecting(false) void Balau::Socket::close() throw (GeneralException) { #ifdef _WIN32 closesocket(m_fd); + WSACleanup(); #else ::close(m_fd); #endif @@ -314,11 +461,21 @@ bool Balau::Socket::listen() { Assert(rLocal); m_name.set("Socket(Listener - [%s]:%i)", rLocal, htons(m_localAddr.sin6_port)); + Printer::elog(E_SOCKET, "Socket %i started to listen: %s", m_fd, m_name.to_charp()); + } else { + String msg = getErrorMessage(); + Printer::elog(E_SOCKET, "listen() failed with error #i (%s)", errno, msg.to_charp()); } return m_listening; } +#ifdef _WIN32 +#ifndef EWOULDBLOCK +#define EWOULDBLOCK EAGAIN +#endif +#endif + Balau::IO<Balau::Socket> Balau::Socket::accept() throw (GeneralException) { Assert(m_listening); Assert(m_fd >= 0); @@ -326,13 +483,15 @@ Balau::IO<Balau::Socket> Balau::Socket::accept() throw (GeneralException) { while(true) { sockaddr_in6 remoteAddr; socklen_t len; + Printer::elog(E_SOCKET, "Socket %i (%s) is going to accept()", m_fd, m_name.to_charp()); int s = ::accept(m_fd, (sockaddr *) &remoteAddr, &len); if (s < 0) { if ((errno == EAGAIN) || (errno == EINTR) || (errno == EWOULDBLOCK)) { Task::yield(m_evtR, true); } else { - throw GeneralException(String("Unexpected error accepting a connection: #") + errno + "(" + strerror(errno) + ")"); + String msg = getErrorMessage(); + throw GeneralException(String("Unexpected error accepting a connection: #") + errno + "(" + msg + ")"); } } else { Printer::elog(E_SOCKET, "Listener at %p got a new connection", this); |