267 lines
5.0 KiB
C
267 lines
5.0 KiB
C
/*
|
|
* 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 <http://www.fsf.org/copyleft/gpl.txt>.
|
|
*
|
|
* 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 "utils.h"
|
|
|
|
#include <errno.h>
|
|
|
|
/**
|
|
* See header
|
|
*/
|
|
void windows_init()
|
|
{
|
|
WSADATA wsad;
|
|
|
|
/* initialize winsock2 */
|
|
WSAStartup(MAKEWORD(2, 2), &wsad);
|
|
}
|
|
|
|
/**
|
|
* See header
|
|
*/
|
|
void windows_deinit()
|
|
{
|
|
WSACleanup();
|
|
}
|
|
|
|
/**
|
|
* See header
|
|
*/
|
|
int socketpair(int domain, int type, int protocol, int sv[2])
|
|
{
|
|
struct sockaddr_in addr = {
|
|
.sin_family = AF_INET,
|
|
.sin_addr.s_addr = htonl(INADDR_LOOPBACK),
|
|
};
|
|
socklen_t len = sizeof(addr);
|
|
int s, c, sc;
|
|
BOOL on;
|
|
|
|
/* We don't check domain for AF_INET, as we use it as replacement for
|
|
* AF_UNIX. */
|
|
if (type != SOCK_STREAM)
|
|
{
|
|
errno = EINVAL;
|
|
return -1;
|
|
}
|
|
if (protocol != 0 && protocol != IPPROTO_TCP)
|
|
{
|
|
errno = EINVAL;
|
|
return -1;
|
|
}
|
|
s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
|
if (s == -1)
|
|
{
|
|
return -1;
|
|
}
|
|
c = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
|
if (c == -1)
|
|
{
|
|
closesocket(c);
|
|
return -1;
|
|
}
|
|
if (bind(s, (struct sockaddr*)&addr, sizeof(addr)) == 0 &&
|
|
getsockname(s,(struct sockaddr*)&addr, &len) == 0 &&
|
|
listen(s, 0) == 0 &&
|
|
connect(c, (struct sockaddr*)&addr, sizeof(addr)) == 0)
|
|
{
|
|
sc = accept(s, NULL, NULL);
|
|
if (sc > 0)
|
|
{
|
|
closesocket(s);
|
|
s = sc;
|
|
if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY,
|
|
(void*)&on, sizeof(on)) == 0 &&
|
|
setsockopt(c, IPPROTO_TCP, TCP_NODELAY,
|
|
(void*)&on, sizeof(on)) == 0)
|
|
{
|
|
sv[0] = s;
|
|
sv[1] = c;
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
closesocket(s);
|
|
closesocket(c);
|
|
return -1;
|
|
}
|
|
|
|
/**
|
|
* Set errno for a function setting WSA error on failure
|
|
*/
|
|
static int wserr(int retval)
|
|
{
|
|
if (retval < 0)
|
|
{
|
|
switch (WSAGetLastError())
|
|
{
|
|
case WSANOTINITIALISED:
|
|
errno = EBADF;
|
|
break;
|
|
case WSAENETDOWN:
|
|
case WSAENETRESET:
|
|
case WSAESHUTDOWN:
|
|
errno = EPIPE;
|
|
break;
|
|
case WSAEACCES:
|
|
errno = EACCES;
|
|
break;
|
|
case WSAEINTR:
|
|
errno = EINTR;
|
|
break;
|
|
case WSAEINPROGRESS:
|
|
errno = EBUSY;
|
|
break;
|
|
case WSAEFAULT:
|
|
errno = EFAULT;
|
|
break;
|
|
case WSAENOBUFS:
|
|
errno = ENOMEM;
|
|
break;
|
|
case WSAENOTSOCK:
|
|
errno = EINVAL;
|
|
break;
|
|
case WSAEOPNOTSUPP:
|
|
errno = ENOSYS;
|
|
break;
|
|
case WSAEWOULDBLOCK:
|
|
errno = EWOULDBLOCK;
|
|
break;
|
|
case WSAEMSGSIZE:
|
|
errno = ENOSPC;
|
|
break;
|
|
case WSAEINVAL:
|
|
errno = EINVAL;
|
|
break;
|
|
case WSAENOTCONN:
|
|
case WSAEHOSTUNREACH:
|
|
case WSAECONNABORTED:
|
|
case WSAECONNRESET:
|
|
errno = EIO;
|
|
break;
|
|
case WSAETIMEDOUT:
|
|
errno = ESRCH;
|
|
break;
|
|
default:
|
|
errno = ENOENT;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
errno = 0;
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
/**
|
|
* Check and clear the dontwait flag
|
|
*/
|
|
static bool check_dontwait(int *flags)
|
|
{
|
|
if (*flags & MSG_DONTWAIT)
|
|
{
|
|
*flags &= ~MSG_DONTWAIT;
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
* See header
|
|
*/
|
|
#undef recv
|
|
ssize_t windows_recv(int sockfd, void *buf, size_t len, int flags)
|
|
{
|
|
u_long on = 1, off = 0;
|
|
ssize_t outlen = -1;
|
|
|
|
if (!check_dontwait(&flags))
|
|
{
|
|
return wserr(recv(sockfd, buf, len, flags));
|
|
}
|
|
if (wserr(ioctlsocket(sockfd, FIONBIO, &on) == 0))
|
|
{
|
|
outlen = wserr(recv(sockfd, buf, len, flags));
|
|
ioctlsocket(sockfd, FIONBIO, &off);
|
|
}
|
|
return outlen;
|
|
}
|
|
|
|
/**
|
|
* See header
|
|
*/
|
|
#undef recvfrom
|
|
ssize_t windows_recvfrom(int sockfd, void *buf, size_t len, int flags,
|
|
struct sockaddr *src_addr, socklen_t *addrlen)
|
|
{
|
|
u_long on = 1, off = 0;
|
|
ssize_t outlen = -1;
|
|
|
|
if (!check_dontwait(&flags))
|
|
{
|
|
return wserr(recvfrom(sockfd, buf, len, flags, src_addr, addrlen));
|
|
}
|
|
if (wserr(ioctlsocket(sockfd, FIONBIO, &on)) == 0)
|
|
{
|
|
outlen = wserr(recvfrom(sockfd, buf, len, flags, src_addr, addrlen));
|
|
ioctlsocket(sockfd, FIONBIO, &off);
|
|
}
|
|
return outlen;
|
|
}
|
|
|
|
/**
|
|
* See header
|
|
*/
|
|
#undef send
|
|
ssize_t windows_send(int sockfd, const void *buf, size_t len, int flags)
|
|
{
|
|
u_long on = 1, off = 0;
|
|
ssize_t outlen = -1;
|
|
|
|
if (!check_dontwait(&flags))
|
|
{
|
|
return wserr(send(sockfd, buf, len, flags));
|
|
}
|
|
if (wserr(ioctlsocket(sockfd, FIONBIO, &on)) == 0)
|
|
{
|
|
outlen = wserr(send(sockfd, buf, len, flags));
|
|
ioctlsocket(sockfd, FIONBIO, &off);
|
|
}
|
|
return outlen;
|
|
}
|
|
|
|
/**
|
|
* See header
|
|
*/
|
|
#undef sendto
|
|
ssize_t windows_sendto(int sockfd, const void *buf, size_t len, int flags,
|
|
const struct sockaddr *dest_addr, socklen_t addrlen)
|
|
{
|
|
u_long on = 1, off = 0;
|
|
ssize_t outlen = -1;
|
|
|
|
if (!check_dontwait(&flags))
|
|
{
|
|
return wserr(sendto(sockfd, buf, len, flags, dest_addr, addrlen));
|
|
}
|
|
if (wserr(ioctlsocket(sockfd, FIONBIO, &on)) == 0)
|
|
{
|
|
outlen = wserr(sendto(sockfd, buf, len, flags, dest_addr, addrlen));
|
|
ioctlsocket(sockfd, FIONBIO, &off);
|
|
}
|
|
return outlen;
|
|
}
|