summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPixel <pixel@nobis-crew.org>2011-10-17 23:06:29 -0700
committerPixel <pixel@nobis-crew.org>2011-10-17 23:06:57 -0700
commitea271d967c52892a61f2b2db754780912e0f7cef (patch)
tree9cc70e5adfb75699291471ff4a5a6e9532c0002c
parent58f4ba6c8a4f9662dad9f5ddb3106c2e2c34daa6 (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.h8
-rw-r--r--includes/Socket.h9
-rw-r--r--mingw32-config.h2
-rw-r--r--src/Socket.cc165
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);