From fb0b5390845213665a2557fabb86d6df14b73913 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 30 Oct 2013 18:01:18 +0100 Subject: [PATCH] socket-win: Implement a Windows socket plugin using Winsock2 --- configure.ac | 4 + src/libcharon/Makefile.am | 7 + src/libcharon/plugins/socket_win/Makefile.am | 21 + .../plugins/socket_win/socket_win_plugin.c | 75 +++ .../plugins/socket_win/socket_win_plugin.h | 42 ++ .../plugins/socket_win/socket_win_socket.c | 508 ++++++++++++++++++ .../plugins/socket_win/socket_win_socket.h | 44 ++ 7 files changed, 701 insertions(+) create mode 100644 src/libcharon/plugins/socket_win/Makefile.am create mode 100644 src/libcharon/plugins/socket_win/socket_win_plugin.c create mode 100644 src/libcharon/plugins/socket_win/socket_win_plugin.h create mode 100644 src/libcharon/plugins/socket_win/socket_win_socket.c create mode 100644 src/libcharon/plugins/socket_win/socket_win_socket.h diff --git a/configure.ac b/configure.ac index d069a168d..2085ae1b3 100644 --- a/configure.ac +++ b/configure.ac @@ -206,6 +206,7 @@ ARG_ENABL_SET([kernel-klips], [enable the KLIPS kernel interface.]) ARG_ENABL_SET([kernel-libipsec],[enable the libipsec kernel interface.]) ARG_DISBL_SET([socket-default], [disable default socket implementation for charon.]) ARG_ENABL_SET([socket-dynamic], [enable dynamic socket implementation for charon]) +ARG_ENABL_SET([socket-win], [enable Winsock2 based socket implementation for charon]) # configuration/control plugins ARG_DISBL_SET([stroke], [disable charons stroke configuration backend.]) ARG_ENABL_SET([smp], [enable SMP configuration and control interface. Requires libxml.]) @@ -1215,6 +1216,7 @@ ADD_PLUGIN([kernel-netlink], [h charon starter nm cmd]) ADD_PLUGIN([resolve], [h charon cmd]) ADD_PLUGIN([socket-default], [c charon nm cmd]) ADD_PLUGIN([socket-dynamic], [c charon cmd]) +ADD_PLUGIN([socket-win], [c charon]) ADD_PLUGIN([farp], [c charon]) ADD_PLUGIN([stroke], [c charon]) ADD_PLUGIN([vici], [c charon]) @@ -1417,6 +1419,7 @@ AM_CONDITIONAL(USE_IMC_SWID, test x$imc_swid = xtrue) AM_CONDITIONAL(USE_IMV_SWID, test x$imv_swid = xtrue) AM_CONDITIONAL(USE_SOCKET_DEFAULT, test x$socket_default = xtrue) AM_CONDITIONAL(USE_SOCKET_DYNAMIC, test x$socket_dynamic = xtrue) +AM_CONDITIONAL(USE_SOCKET_WIN, test x$socket_win = xtrue) AM_CONDITIONAL(USE_FARP, test x$farp = xtrue) AM_CONDITIONAL(USE_ADDRBLOCK, test x$addrblock = xtrue) AM_CONDITIONAL(USE_UNITY, test x$unity = xtrue) @@ -1646,6 +1649,7 @@ AC_CONFIG_FILES([ src/libcharon/plugins/tnc_pdp/Makefile src/libcharon/plugins/socket_default/Makefile src/libcharon/plugins/socket_dynamic/Makefile + src/libcharon/plugins/socket_win/Makefile src/libcharon/plugins/farp/Makefile src/libcharon/plugins/smp/Makefile src/libcharon/plugins/sql/Makefile diff --git a/src/libcharon/Makefile.am b/src/libcharon/Makefile.am index 8513af86b..52d20b315 100644 --- a/src/libcharon/Makefile.am +++ b/src/libcharon/Makefile.am @@ -195,6 +195,13 @@ if MONOLITHIC endif endif +if USE_SOCKET_WIN + SUBDIRS += plugins/socket_win +if MONOLITHIC + libcharon_la_LIBADD += plugins/socket_win/libstrongswan-socket-win.la +endif +endif + if USE_FARP SUBDIRS += plugins/farp if MONOLITHIC diff --git a/src/libcharon/plugins/socket_win/Makefile.am b/src/libcharon/plugins/socket_win/Makefile.am new file mode 100644 index 000000000..f01178fcc --- /dev/null +++ b/src/libcharon/plugins/socket_win/Makefile.am @@ -0,0 +1,21 @@ +AM_CPPFLAGS = \ + -I${linux_headers} \ + -I$(top_srcdir)/src/libstrongswan \ + -I$(top_srcdir)/src/libhydra \ + -I$(top_srcdir)/src/libcharon + +AM_CFLAGS = \ + $(PLUGIN_CFLAGS) + +if MONOLITHIC +noinst_LTLIBRARIES = libstrongswan-socket-win.la +else +plugin_LTLIBRARIES = libstrongswan-socket-win.la +endif + +libstrongswan_socket_win_la_SOURCES = \ + socket_win_socket.h socket_win_socket.c \ + socket_win_plugin.h socket_win_plugin.c + +libstrongswan_socket_win_la_LDFLAGS = -module -avoid-version +libstrongswan_socket_win_la_LIBADD = -lws2_32 diff --git a/src/libcharon/plugins/socket_win/socket_win_plugin.c b/src/libcharon/plugins/socket_win/socket_win_plugin.c new file mode 100644 index 000000000..4c5ffe03c --- /dev/null +++ b/src/libcharon/plugins/socket_win/socket_win_plugin.c @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2013 Martin Willi + * Copyright (C) 2013 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "socket_win_plugin.h" +#include "socket_win_socket.h" + +#include + +typedef struct private_socket_win_plugin_t private_socket_win_plugin_t; + +/** + * Private data of socket plugin + */ +struct private_socket_win_plugin_t { + + /** + * Implements plugin interface + */ + socket_win_plugin_t public; +}; + +METHOD(plugin_t, get_name, char*, + private_socket_win_plugin_t *this) +{ + return "socket-win"; +} + +METHOD(plugin_t, destroy, void, + private_socket_win_plugin_t *this) +{ + free(this); +} + +METHOD(plugin_t, get_features, int, + private_socket_win_plugin_t *this, plugin_feature_t *features[]) +{ + static plugin_feature_t f[] = { + PLUGIN_CALLBACK(socket_register, socket_win_socket_create), + PLUGIN_PROVIDE(CUSTOM, "socket"), + }; + *features = f; + return countof(f); +} + +/** + * Create instance of socket-win plugin + */ +plugin_t *socket_win_plugin_create() +{ + private_socket_win_plugin_t *this; + + INIT(this, + .public = { + .plugin = { + .get_name = _get_name, + .get_features = _get_features, + .destroy = _destroy, + }, + }, + ); + + return &this->public.plugin; +} diff --git a/src/libcharon/plugins/socket_win/socket_win_plugin.h b/src/libcharon/plugins/socket_win/socket_win_plugin.h new file mode 100644 index 000000000..c4873ce61 --- /dev/null +++ b/src/libcharon/plugins/socket_win/socket_win_plugin.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2013 Martin Willi + * Copyright (C) 2013 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup socket_win socket_win + * @ingroup cplugins + * + * @defgroup socket_win_plugin socket_win_plugin + * @{ @ingroup socket_win + */ + +#ifndef SOCKET_WIN_PLUGIN_H_ +#define SOCKET_WIN_PLUGIN_H_ + +#include + +typedef struct socket_win_plugin_t socket_win_plugin_t; + +/** + * Winsock2 based socket implementation plugin. + */ +struct socket_win_plugin_t { + + /** + * implements plugin interface + */ + plugin_t plugin; +}; + +#endif /** SOCKET_WIN_PLUGIN_H_ @}*/ diff --git a/src/libcharon/plugins/socket_win/socket_win_socket.c b/src/libcharon/plugins/socket_win/socket_win_socket.c new file mode 100644 index 000000000..473b05313 --- /dev/null +++ b/src/libcharon/plugins/socket_win/socket_win_socket.c @@ -0,0 +1,508 @@ +/* + * Copyright (C) 2013 Martin Willi + * Copyright (C) 2013 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/* for WSAID_WSASENDMSG, Windows 7 */ +#define _WIN32_WINNT 0x0601 + +#include "socket_win_socket.h" + +#include +#include +#include + +#include + +/* Maximum size of a packet */ +#define MAX_PACKET 10000 + +/* number of sockets in use */ +#define SOCKET_COUNT 2 + +/* missing on MinGW */ +#ifndef IPV6_V6ONLY +# define IPV6_V6ONLY 27 +#endif + +/* GUIDS to lookup WSASend/RecvMsg */ +static GUID WSARecvMsgGUID = WSAID_WSARECVMSG; +static GUID WSASendMsgGUID = WSAID_WSASENDMSG; + +typedef struct private_socket_win_socket_t private_socket_win_socket_t; + +/** + * Private data of an socket_t object + */ +struct private_socket_win_socket_t { + + /** + * public functions + */ + socket_win_socket_t public; + + /** + * Port for each socket + */ + u_int16_t ports[SOCKET_COUNT]; + + /** + * IPv4/IPv6 dual-use sockets + */ + SOCKET socks[SOCKET_COUNT]; + + /** + * Events to wait for socket data + */ + HANDLE events[SOCKET_COUNT]; + + /** + * Maximum packet size to receive + */ + int max_packet; + + /** + * WSASendMsg function + */ + int (*WSASendMsg)(SOCKET, LPWSAMSG, DWORD, LPDWORD, + LPWSAOVERLAPPED, LPWSAOVERLAPPED_COMPLETION_ROUTINE); + + /** + * WSARecvMsg function + */ + int (*WSARecvMsg)(SOCKET, LPWSAMSG, LPDWORD, + LPWSAOVERLAPPED, LPWSAOVERLAPPED_COMPLETION_ROUTINE); +}; + +METHOD(socket_t, receiver, status_t, + private_socket_win_socket_t *this, packet_t **out) +{ + WSAOVERLAPPED overlapped[SOCKET_COUNT] = {}; + char buf[this->max_packet], cbuf[128]; + bool old; + DWORD i, len, flags, err; + WSAMSG msg; + WSABUF data; + WSACMSGHDR *cmsg; + SOCKADDR_IN6 addr; + host_t *src = NULL, *dst = NULL; + packet_t *pkt; + + data.buf = buf; + data.len = sizeof(buf); + + memset(&msg, 0, sizeof(msg)); + msg.name = (struct sockaddr*)&addr; + msg.namelen = sizeof(addr); + msg.lpBuffers = &data; + msg.dwBufferCount = 1; + msg.Control.buf = cbuf; + msg.Control.len = sizeof(cbuf); + + for (i = 0; i < SOCKET_COUNT; i++) + { + overlapped[i].hEvent = this->events[i]; + + if (this->socks[i] != INVALID_SOCKET) + { + if (this->WSARecvMsg(this->socks[i], &msg, NULL, + &overlapped[i], NULL) == SOCKET_ERROR) + { + err = WSAGetLastError(); + if (err != WSA_IO_PENDING) + { + DBG1(DBG_NET, "reading from socket failed: %d", err); + return FAILED; + } + } + } + } + + old = thread_cancelability(TRUE); + i = WSAWaitForMultipleEvents(SOCKET_COUNT, this->events, + FALSE, INFINITE, TRUE); + thread_cancelability(old); + if (i < WSA_WAIT_EVENT_0 || i >= WSA_WAIT_EVENT_0 + SOCKET_COUNT) + { + DBG1(DBG_NET, "waiting on sockets failed: %d", WSAGetLastError()); + return FAILED; + } + i -= WSA_WAIT_EVENT_0; + + /* WSAEvents must be reset manually */ + WSAResetEvent(this->events[i]); + + if (!WSAGetOverlappedResult(this->socks[i], &overlapped[i], + &len, FALSE, &flags)) + { + err = WSAGetLastError(); + /* ignore WSAECONNRESET; this is returned for any ICMP port unreachable, + * for a packet we sent, but is most likely not related to the packet + * we try to receive. */ + if (err != WSAECONNRESET) + { + DBG1(DBG_NET, "getting socket result failed: %d", err); + } + return FAILED; + } + + if (len >= sizeof(buf)) + { + DBG1(DBG_NET, "receive buffer too small, packet discarded"); + return FAILED; + } + DBG3(DBG_NET, "received packet %b", buf, (int)len); + + for (cmsg = WSA_CMSG_FIRSTHDR(&msg); dst == NULL && cmsg != NULL; + cmsg = WSA_CMSG_NXTHDR(&msg, cmsg)) + { + if (cmsg->cmsg_level == IPPROTO_IP && + cmsg->cmsg_type == IP_PKTINFO) + { + struct in_pktinfo *pktinfo; + struct sockaddr_in sin = { + .sin_family = AF_INET, + }; + + pktinfo = (struct in_pktinfo*)WSA_CMSG_DATA(cmsg); + sin.sin_addr = pktinfo->ipi_addr; + sin.sin_port = htons(this->ports[i]); + dst = host_create_from_sockaddr((struct sockaddr*)&sin); + } + if (cmsg->cmsg_level == IPPROTO_IPV6 && + cmsg->cmsg_type == IPV6_PKTINFO) + { + struct in6_pktinfo *pktinfo; + struct sockaddr_in6 sin = { + .sin6_family = AF_INET6, + }; + + pktinfo = (struct in6_pktinfo*)WSA_CMSG_DATA(cmsg); + sin.sin6_addr = pktinfo->ipi6_addr; + sin.sin6_port = htons(this->ports[i]); + dst = host_create_from_sockaddr((struct sockaddr*)&sin); + } + } + + if (!dst) + { + DBG1(DBG_NET, "receiving IP destination address failed"); + return FAILED; + } + + switch (dst->get_family(dst)) + { + case AF_INET6: + src = host_create_from_sockaddr((struct sockaddr*)&addr); + break; + case AF_INET: + /* extract v4 address from mapped v6 */ + src = host_create_from_chunk(AF_INET, + chunk_create(addr.sin6_addr.u.Byte + 12, 4), + ntohs(addr.sin6_port)); + break; + } + if (!src) + { + DBG1(DBG_NET, "receiving IP source address failed"); + dst->destroy(dst); + return FAILED; + } + + pkt = packet_create(); + pkt->set_source(pkt, src); + pkt->set_destination(pkt, dst); + DBG2(DBG_NET, "received packet: from %#H to %#H", src, dst); + pkt->set_data(pkt, chunk_clone(chunk_create(buf, len))); + + *out = pkt; + return SUCCESS; +} + +METHOD(socket_t, sender, status_t, + private_socket_win_socket_t *this, packet_t *packet) +{ + u_int16_t port; + int i = -1, j; + host_t *src, *dst; + WSAMSG msg; + DWORD len; + WSABUF data; + WSACMSGHDR *cmsg; + SOCKADDR_IN6 addr = { + .sin6_family = AF_INET6, + .sin6_addr = { + .u = { + .Byte = { + /* v6-mapped-v4 by default */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00, + }, + }, + }, + }; + char buf[WSA_CMSG_SPACE(max(sizeof(struct in6_pktinfo), + sizeof(struct in_pktinfo)))]; + + src = packet->get_source(packet); + dst = packet->get_destination(packet); + data.len = packet->get_data(packet).len; + data.buf = packet->get_data(packet).ptr; + + DBG2(DBG_NET, "sending packet: from %#H to %#H", src, dst); + + DBG3(DBG_NET, "sending packet %b", data.buf, (int)data.len); + + port = src->get_port(src); + for (j = 0; j < SOCKET_COUNT; j++) + { + if (!port || this->ports[j] == port) + { + i = j; + break; + } + } + if (i == -1) + { + DBG1(DBG_NET, "no socket found to send packet from port %u", port); + return FAILED; + } + + /* copy destination IPv6, or last 32 bits of mapped IPv4 address */ + len = dst->get_address(dst).len; + if (len > sizeof(addr.sin6_addr)) + { + return FAILED; + } + memcpy(addr.sin6_addr.u.Byte + sizeof(addr.sin6_addr) - len, + dst->get_address(dst).ptr, len); + addr.sin6_port = htons(dst->get_port(dst)); + + memset(&msg, 0, sizeof(msg)); + msg.name = (struct sockaddr*)&addr; + msg.namelen = sizeof(addr); + msg.lpBuffers = &data; + msg.dwBufferCount = 1; + + if (!src->is_anyaddr(src)) + { + memset(buf, 0, sizeof(buf)); + msg.Control.buf = buf; + + switch (src->get_family(src)) + { + case AF_INET: + { + struct in_pktinfo *pktinfo; + SOCKADDR_IN *sin; + + msg.Control.len = WSA_CMSG_SPACE(sizeof(*pktinfo)); + cmsg = WSA_CMSG_FIRSTHDR(&msg); + cmsg->cmsg_level = IPPROTO_IP; + cmsg->cmsg_type = IP_PKTINFO; + cmsg->cmsg_len = WSA_CMSG_LEN(sizeof(*pktinfo)); + pktinfo = (struct in_pktinfo*)WSA_CMSG_DATA(cmsg); + sin = (SOCKADDR_IN*)src->get_sockaddr(src); + pktinfo->ipi_addr = sin->sin_addr; + break; + } + case AF_INET6: + { + struct in6_pktinfo *pktinfo; + SOCKADDR_IN6 *sin; + + msg.Control.len = WSA_CMSG_SPACE(sizeof(*pktinfo)); + cmsg = WSA_CMSG_FIRSTHDR(&msg); + cmsg->cmsg_level = IPPROTO_IPV6; + cmsg->cmsg_type = IPV6_PKTINFO; + cmsg->cmsg_len = WSA_CMSG_LEN(sizeof(*pktinfo)); + pktinfo = (struct in6_pktinfo*)WSA_CMSG_DATA(cmsg); + sin = (SOCKADDR_IN6*)src->get_sockaddr(src); + pktinfo->ipi6_addr = sin->sin6_addr; + break; + } + } + } + + if (this->WSASendMsg(this->socks[i], &msg, 0, &len, + NULL, NULL) == SOCKET_ERROR) + { + DBG1(DBG_NET, "sending packet failed: %d", WSAGetLastError()); + return FAILED; + } + return SUCCESS; +} + +METHOD(socket_t, get_port, u_int16_t, + private_socket_win_socket_t *this, bool nat) +{ + return this->ports[nat != 0]; +} + +METHOD(socket_t, supported_families, socket_family_t, + private_socket_win_socket_t *this) +{ + return SOCKET_FAMILY_IPV4 | SOCKET_FAMILY_IPV6; +} + +/** + * Open an IPv4/IPv6 dual-use socket to send and receive packets + */ +static SOCKET open_socket(private_socket_win_socket_t *this, int i) +{ + SOCKADDR_IN6 addr = { + .sin6_family = AF_INET6, + .sin6_port = htons(this->ports[i]), + }; + int addrlen = sizeof(addr); + BOOL on = TRUE, off = FALSE; + DWORD dwon = TRUE; + SOCKET s; + + s = WSASocket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP, + NULL, 0, WSA_FLAG_OVERLAPPED); + if (s == INVALID_SOCKET) + { + DBG1(DBG_NET, "creating socket failed: %d", WSAGetLastError()); + return INVALID_SOCKET; + } + /* enable IPv4 on IPv6 socket */ + if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, + (const char*)&off, sizeof(off)) == SOCKET_ERROR) + { + DBG1(DBG_NET, "using dual-mode socket failed: %d", WSAGetLastError()); + closesocket(s); + return INVALID_SOCKET; + } + if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, + (const char*)&on, sizeof(on)) == SOCKET_ERROR) + { + DBG1(DBG_NET, "enabling SO_REUSEADDR failed: %d", WSAGetLastError()); + closesocket(s); + return INVALID_SOCKET; + } + if (bind(s, (const struct sockaddr*)&addr, addrlen) == SOCKET_ERROR) + { + DBG1(DBG_NET, "unable to bind socket: %d", WSAGetLastError()); + closesocket(s); + return INVALID_SOCKET; + } + /* retrieve randomly allocated port if needed */ + if (this->ports[i] == 0) + { + if (getsockname(s, (struct sockaddr*)&addr, + &addrlen) == SOCKET_ERROR) + { + DBG1(DBG_NET, "unable to determine port: %d", WSAGetLastError()); + closesocket(s); + return INVALID_SOCKET; + } + this->ports[i] = ntohs(addr.sin6_port); + } + /* PKTINFO is required for both protocol families */ + if (setsockopt(s, IPPROTO_IP, IP_PKTINFO, + (char*)&dwon, sizeof(dwon)) == SOCKET_ERROR) + { + DBG1(DBG_NET, "unable to set IP_PKTINFO: %d", WSAGetLastError()); + closesocket(s); + return INVALID_SOCKET; + } + if (setsockopt(s, IPPROTO_IPV6, IPV6_PKTINFO, + (char*)&dwon, sizeof(dwon)) == SOCKET_ERROR) + { + DBG1(DBG_NET, "unable to set IP6_PKTINFO: %d", WSAGetLastError()); + closesocket(s); + return INVALID_SOCKET; + } + return s; +} + +METHOD(socket_t, destroy, void, + private_socket_win_socket_t *this) +{ + int i; + + for (i = 0; i < SOCKET_COUNT; i++) + { + if (this->socks[i] != INVALID_SOCKET) + { + closesocket(this->socks[i]); + } + if (this->events[i] != WSA_INVALID_EVENT) + { + WSACloseEvent(this->events[i]); + } + } + free(this); +} + +/* + * See header for description + */ +socket_win_socket_t *socket_win_socket_create() +{ + private_socket_win_socket_t *this; + DWORD len; + int i; + + INIT(this, + .public = { + .socket = { + .send = _sender, + .receive = _receiver, + .get_port = _get_port, + .supported_families = _supported_families, + .destroy = _destroy, + }, + }, + .ports = { + lib->settings->get_int(lib->settings, + "%s.port", CHARON_UDP_PORT, lib->ns), + lib->settings->get_int(lib->settings, + "%s.port_nat_t", CHARON_NATT_PORT, lib->ns), + }, + .max_packet = lib->settings->get_int(lib->settings, + "%s.max_packet", MAX_PACKET, lib->ns), + ); + + for (i = 0; i < SOCKET_COUNT; i++) + { + this->socks[i] = open_socket(this, i); + this->events[i] = WSACreateEvent(); + } + + for (i = 0; i < SOCKET_COUNT; i++) + { + if (this->events[i] == WSA_INVALID_EVENT || + this->socks[i] == INVALID_SOCKET) + { + DBG1(DBG_NET, "creating socket failed: %d", WSAGetLastError()); + destroy(this); + return NULL; + } + } + + if (WSAIoctl(this->socks[0], SIO_GET_EXTENSION_FUNCTION_POINTER, + &WSASendMsgGUID, sizeof(WSASendMsgGUID), &this->WSASendMsg, + sizeof(this->WSASendMsg), &len, NULL, NULL) != 0 || + WSAIoctl(this->socks[0], SIO_GET_EXTENSION_FUNCTION_POINTER, + &WSARecvMsgGUID, sizeof(WSARecvMsgGUID), &this->WSARecvMsg, + sizeof(this->WSARecvMsg), &len, NULL, NULL) != 0) + { + DBG1(DBG_NET, "send/recvmsg() lookup failed: %d", WSAGetLastError()); + destroy(this); + return NULL; + } + + return &this->public; +} diff --git a/src/libcharon/plugins/socket_win/socket_win_socket.h b/src/libcharon/plugins/socket_win/socket_win_socket.h new file mode 100644 index 000000000..21699c330 --- /dev/null +++ b/src/libcharon/plugins/socket_win/socket_win_socket.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2013 Martin Willi + * Copyright (C) 2013 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup socket_win_socket socket_win_socket + * @{ @ingroup socket_win + */ + +#ifndef SOCKET_WIN_SOCKET_H_ +#define SOCKET_WIN_SOCKET_H_ + +typedef struct socket_win_socket_t socket_win_socket_t; + +#include + +/** + * Winsock2 based socket implementation. + */ +struct socket_win_socket_t { + + /** + * Implements the socket_t interface. + */ + socket_t socket; +}; + +/** + * Create a socket_win_socket instance. + */ +socket_win_socket_t *socket_win_socket_create(); + +#endif /** SOCKET_WIN_SOCKET_H_ @}*/