Skip to content

Instantly share code, notes, and snippets.

@kinichiro
Last active March 21, 2020 03:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kinichiro/facdfdfa311dabe1ab30e51acadc54d8 to your computer and use it in GitHub Desktop.
Save kinichiro/facdfdfa311dabe1ab30e51acadc54d8 to your computer and use it in GitHub Desktop.
investigation for detecting socket or fd (https://github.com/libressl-portable/portable/issues/266)
/*
* Public domain
*
* BSD socket emulation code for Winsock2
* File IO compatibility shims
* Brent Cook <bcook@openbsd.org>
* Kinichiro Inoguchi <inoguchi@openbsd.org>
*/
#define NO_REDEF_POSIX_FUNCTIONS
#include <windows.h>
#include <ws2tcpip.h>
#include <crtdbg.h>
#include <errno.h>
#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
void
posix_perror(const char *s)
{
fprintf(stderr, "%s: %s\n", s, strerror(errno));
}
FILE *
posix_fopen(const char *path, const char *mode)
{
if (strchr(mode, 'b') == NULL) {
char *bin_mode = NULL;
if (asprintf(&bin_mode, "%sb", mode) == -1)
return NULL;
FILE *f = fopen(path, bin_mode);
free(bin_mode);
return f;
}
return fopen(path, mode);
}
int
posix_open(const char *path, ...)
{
va_list ap;
int mode = 0;
int flags;
va_start(ap, path);
flags = va_arg(ap, int);
if (flags & O_CREAT)
mode = va_arg(ap, int);
va_end(ap);
flags |= O_BINARY;
if (flags & O_CLOEXEC) {
flags &= ~O_CLOEXEC;
flags |= O_NOINHERIT;
}
flags &= ~O_NONBLOCK;
return open(path, flags, mode);
}
char*
posix_fgets(char* s, int size, FILE* stream)
{
char* ret = fgets(s, size, stream);
if (ret != NULL) {
size_t end = strlen(ret);
if (end >= 2 && ret[end - 2] == '\r' && ret[end - 1] == '\n') {
ret[end - 2] = '\n';
ret[end - 1] = '\0';
}
}
return ret;
}
int
posix_rename(const char* oldpath, const char* newpath)
{
return MoveFileEx(oldpath, newpath, MOVEFILE_REPLACE_EXISTING) ? 0 : -1;
}
static int
wsa_errno(int err)
{
switch (err) {
case WSAENOBUFS:
errno = ENOMEM;
break;
case WSAEACCES:
errno = EACCES;
break;
case WSANOTINITIALISED:
errno = EPERM;
break;
case WSAEHOSTUNREACH:
case WSAENETDOWN:
errno = EIO;
break;
case WSAEFAULT:
errno = EFAULT;
break;
case WSAEINTR:
errno = EINTR;
break;
case WSAEINVAL:
errno = EINVAL;
break;
case WSAEINPROGRESS:
errno = EINPROGRESS;
break;
case WSAEWOULDBLOCK:
errno = EAGAIN;
break;
case WSAEOPNOTSUPP:
errno = ENOTSUP;
break;
case WSAEMSGSIZE:
errno = EFBIG;
break;
case WSAENOTSOCK:
errno = ENOTSOCK;
break;
case WSAENOPROTOOPT:
errno = ENOPROTOOPT;
break;
case WSAECONNREFUSED:
errno = ECONNREFUSED;
break;
case WSAEAFNOSUPPORT:
errno = EAFNOSUPPORT;
break;
case WSAEBADF:
errno = EBADF;
break;
case WSAENETRESET:
case WSAENOTCONN:
case WSAECONNABORTED:
case WSAECONNRESET:
case WSAESHUTDOWN:
case WSAETIMEDOUT:
errno = EPIPE;
break;
}
return -1;
}
static void noop_handler(const wchar_t *expression, const wchar_t *function,
const wchar_t *file, unsigned int line, uintptr_t pReserved)
{
return;
}
#define BEGIN_SUPPRESS_IPH \
{ \
_invalid_parameter_handler new_handler = noop_handler; \
_invalid_parameter_handler old_handler; \
old_handler = _set_thread_local_invalid_parameter_handler(new_handler); \
_CrtSetReportMode(_CRT_ASSERT, 0);
#define END_SUPPRESS_IPH \
_CrtSetReportMode(_CRTDBG_MODE_WNDW, 0); \
old_handler = _set_thread_local_invalid_parameter_handler(old_handler); \
}
static int
is_socket(int fd)
{
HANDLE hd;
BEGIN_SUPPRESS_IPH
hd = _get_osfhandle(fd);
END_SUPPRESS_IPH
if (hd == INVALID_HANDLE_VALUE) {
return (1); /* fd is not file descriptor */
}
return (0);
}
int
posix_connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
{
int rc = connect(sockfd, addr, addrlen);
if (rc == SOCKET_ERROR)
return wsa_errno(WSAGetLastError());
return rc;
}
int
posix_close(int fd)
{
if (closesocket(fd) == SOCKET_ERROR) {
int err = WSAGetLastError();
return (err == WSAENOTSOCK || err == WSAEBADF ||
err == WSANOTINITIALISED) ?
close(fd) : wsa_errno(err);
}
return 0;
}
ssize_t
posix_read(int fd, void *buf, size_t count)
{
ssize_t rc;
if (is_socket(fd)) {
if ((rc = recv(fd, buf, count, 0)) == SOCKET_ERROR) {
int err = WSAGetLastError();
return wsa_errno(err);
}
return rc;
} else {
return read(fd, buf, count);
}
}
ssize_t
posix_write(int fd, const void *buf, size_t count)
{
ssize_t rc;
if (is_socket(fd)) {
if ((rc = send(fd, buf, count, 0)) == SOCKET_ERROR) {
int err = WSAGetLastError();
return wsa_errno(err);
}
return rc;
} else {
return write(fd, buf, count);
}
}
int
posix_getsockopt(int sockfd, int level, int optname,
void *optval, socklen_t *optlen)
{
int rc = getsockopt(sockfd, level, optname, (char *)optval, optlen);
return rc == 0 ? 0 : wsa_errno(WSAGetLastError());
}
int
posix_setsockopt(int sockfd, int level, int optname,
const void *optval, socklen_t optlen)
{
int rc = setsockopt(sockfd, level, optname, (char *)optval, optlen);
return rc == 0 ? 0 : wsa_errno(WSAGetLastError());
}
uid_t getuid(void)
{
/* Windows fstat sets 0 as st_uid */
return 0;
}
#ifdef _MSC_VER
struct timezone;
int gettimeofday(struct timeval * tp, struct timezone * tzp)
{
/*
* Note: some broken versions only have 8 trailing zero's, the correct
* epoch has 9 trailing zero's
*/
static const uint64_t EPOCH = ((uint64_t) 116444736000000000ULL);
SYSTEMTIME system_time;
FILETIME file_time;
uint64_t time;
GetSystemTime(&system_time);
SystemTimeToFileTime(&system_time, &file_time);
time = ((uint64_t)file_time.dwLowDateTime);
time += ((uint64_t)file_time.dwHighDateTime) << 32;
tp->tv_sec = (long)((time - EPOCH) / 10000000L);
tp->tv_usec = (long)(system_time.wMilliseconds * 1000);
return 0;
}
unsigned int sleep(unsigned int seconds)
{
Sleep(seconds * 1000);
return seconds;
}
#endif
/*
* Public domain
*
* BSD socket emulation code for Winsock2
* File IO compatibility shims
* Brent Cook <bcook@openbsd.org>
* Kinichiro Inoguchi <inoguchi@openbsd.org>
*/
#define NO_REDEF_POSIX_FUNCTIONS
#include <windows.h>
#include <ws2tcpip.h>
#include <winternl.h>
#include <ntstatus.h>
#include <errno.h>
#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
void
posix_perror(const char *s)
{
fprintf(stderr, "%s: %s\n", s, strerror(errno));
}
FILE *
posix_fopen(const char *path, const char *mode)
{
if (strchr(mode, 'b') == NULL) {
char *bin_mode = NULL;
if (asprintf(&bin_mode, "%sb", mode) == -1)
return NULL;
FILE *f = fopen(path, bin_mode);
free(bin_mode);
return f;
}
return fopen(path, mode);
}
int
posix_open(const char *path, ...)
{
va_list ap;
int mode = 0;
int flags;
va_start(ap, path);
flags = va_arg(ap, int);
if (flags & O_CREAT)
mode = va_arg(ap, int);
va_end(ap);
flags |= O_BINARY;
if (flags & O_CLOEXEC) {
flags &= ~O_CLOEXEC;
flags |= O_NOINHERIT;
}
flags &= ~O_NONBLOCK;
return open(path, flags, mode);
}
char*
posix_fgets(char* s, int size, FILE* stream)
{
char* ret = fgets(s, size, stream);
if (ret != NULL) {
size_t end = strlen(ret);
if (end >= 2 && ret[end - 2] == '\r' && ret[end - 1] == '\n') {
ret[end - 2] = '\n';
ret[end - 1] = '\0';
}
}
return ret;
}
int
posix_rename(const char* oldpath, const char* newpath)
{
return MoveFileEx(oldpath, newpath, MOVEFILE_REPLACE_EXISTING) ? 0 : -1;
}
static int
wsa_errno(int err)
{
switch (err) {
case WSAENOBUFS:
errno = ENOMEM;
break;
case WSAEACCES:
errno = EACCES;
break;
case WSANOTINITIALISED:
errno = EPERM;
break;
case WSAEHOSTUNREACH:
case WSAENETDOWN:
errno = EIO;
break;
case WSAEFAULT:
errno = EFAULT;
break;
case WSAEINTR:
errno = EINTR;
break;
case WSAEINVAL:
errno = EINVAL;
break;
case WSAEINPROGRESS:
errno = EINPROGRESS;
break;
case WSAEWOULDBLOCK:
errno = EAGAIN;
break;
case WSAEOPNOTSUPP:
errno = ENOTSUP;
break;
case WSAEMSGSIZE:
errno = EFBIG;
break;
case WSAENOTSOCK:
errno = ENOTSOCK;
break;
case WSAENOPROTOOPT:
errno = ENOPROTOOPT;
break;
case WSAECONNREFUSED:
errno = ECONNREFUSED;
break;
case WSAEAFNOSUPPORT:
errno = EAFNOSUPPORT;
break;
case WSAEBADF:
errno = EBADF;
break;
case WSAENETRESET:
case WSAENOTCONN:
case WSAECONNABORTED:
case WSAECONNRESET:
case WSAESHUTDOWN:
case WSAETIMEDOUT:
errno = EPIPE;
break;
}
return -1;
}
static int
is_socket_by_NtQueryObject(int hd)
{
NTSTATUS st;
PPUBLIC_OBJECT_TYPE_INFORMATION info;
ULONG ret;
info = malloc(0x1000);
if ((st = NtQueryObject(hd, ObjectTypeInformation, info, 0x1000, &ret)) != STATUS_SUCCESS) {
switch (st) {
case STATUS_ACCESS_DENIED:
perror("STATUS_ACCESS_DENIED");
break;
case STATUS_INVALID_HANDLE:
perror("STATUS_INVALID_HANDLE");
break;
case STATUS_INFO_LENGTH_MISMATCH:
perror("STATUS_INFO_LENGTH_MISMATCH");
break;
default:
perror("other");
break;
}
return (0); /* hd is not handle */
}
return (1);
}
static int
is_socket_by_get_osfhandle(int fd)
{
HANDLE hd;
NTSTATUS st;
PPUBLIC_OBJECT_TYPE_INFORMATION info;
ULONG ret;
if ((hd = (HANDLE)_get_osfhandle(fd)) == INVALID_HANDLE_VALUE) {
return (1); /* fd is not file descriptor */
}
info = malloc(0x1000);
if ((st = NtQueryObject(hd, ObjectTypeInformation, info, 0x1000, &ret)) != STATUS_SUCCESS) {
switch (st) {
case STATUS_ACCESS_DENIED:
perror("STATUS_ACCESS_DENIED");
break;
case STATUS_INVALID_HANDLE:
perror("STATUS_INVALID_HANDLE");
break;
case STATUS_INFO_LENGTH_MISMATCH:
perror("STATUS_INFO_LENGTH_MISMATCH");
break;
default:
perror("other");
break;
}
}
return (0);
}
static int
is_socket_by_open_osfhandle(int hd)
{
int fd;
NTSTATUS st;
PPUBLIC_OBJECT_TYPE_INFORMATION info;
ULONG ret;
if ((fd = _open_osfhandle(hd, O_RDONLY)) == -1) {
return (0); /* hd is not file handle */
}
info = malloc(0x1000);
if ((st = NtQueryObject(hd, ObjectTypeInformation, info, 0x1000, &ret)) != STATUS_SUCCESS) {
perror("NtQueryObject");
}
return (1);
}
static int
is_socket_by_GetFileType(int hd)
{
DWORD type;
type = GetFileType(hd);
switch (type) {
case FILE_TYPE_DISK:
return (0);
case FILE_TYPE_PIPE:
return (1);
case FILE_TYPE_UNKNOWN:
perror("GetFileType");
return (0);
default:
perror("GetFileType");
return (0);
}
}
static int
is_socket_by_getsockopt(int sock)
{
int optval, optlen;
if (getsockopt(sock, SOL_SOCKET, SO_TYPE, (char*)&optval, &optlen) == SOCKET_ERROR) {
int err = WSAGetLastError();
if (err == WSAENOTSOCK)
return (0);
}
return (1);
}
int
posix_connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
{
int rc = connect(sockfd, addr, addrlen);
if (rc == SOCKET_ERROR)
return wsa_errno(WSAGetLastError());
return rc;
}
#define is_socket(x) is_socket_by_getsockopt(x)
int
posix_close(int fd)
{
if (closesocket(fd) == SOCKET_ERROR) {
int err = WSAGetLastError();
return (err == WSAENOTSOCK || err == WSAEBADF ||
err == WSANOTINITIALISED) ?
close(fd) : wsa_errno(err);
}
return 0;
}
ssize_t
posix_read(int fd, void *buf, size_t count)
{
ssize_t rc;
if (is_socket(fd)) {
if ((rc = recv(fd, buf, count, 0)) == SOCKET_ERROR) {
int err = WSAGetLastError();
return wsa_errno(err);
}
return rc;
} else {
return read(fd, buf, count);
}
}
ssize_t
posix_write(int fd, const void *buf, size_t count)
{
ssize_t rc;
if (is_socket(fd)) {
if ((rc = send(fd, buf, count, 0)) == SOCKET_ERROR) {
int err = WSAGetLastError();
return wsa_errno(err);
}
return rc;
} else {
return write(fd, buf, count);
}
}
int
posix_getsockopt(int sockfd, int level, int optname,
void *optval, socklen_t *optlen)
{
int rc = getsockopt(sockfd, level, optname, (char *)optval, optlen);
return rc == 0 ? 0 : wsa_errno(WSAGetLastError());
}
int
posix_setsockopt(int sockfd, int level, int optname,
const void *optval, socklen_t optlen)
{
int rc = setsockopt(sockfd, level, optname, (char *)optval, optlen);
return rc == 0 ? 0 : wsa_errno(WSAGetLastError());
}
uid_t getuid(void)
{
/* Windows fstat sets 0 as st_uid */
return 0;
}
#ifdef _MSC_VER
struct timezone;
int gettimeofday(struct timeval * tp, struct timezone * tzp)
{
/*
* Note: some broken versions only have 8 trailing zero's, the correct
* epoch has 9 trailing zero's
*/
static const uint64_t EPOCH = ((uint64_t) 116444736000000000ULL);
SYSTEMTIME system_time;
FILETIME file_time;
uint64_t time;
GetSystemTime(&system_time);
SystemTimeToFileTime(&system_time, &file_time);
time = ((uint64_t)file_time.dwLowDateTime);
time += ((uint64_t)file_time.dwHighDateTime) << 32;
tp->tv_sec = (long)((time - EPOCH) / 10000000L);
tp->tv_usec = (long)(system_time.wMilliseconds * 1000);
return 0;
}
unsigned int sleep(unsigned int seconds)
{
Sleep(seconds * 1000);
return seconds;
}
#endif
@kinichiro
Copy link
Author

To build with this posix_win.c, add ntdll after ws2_32 in CMakeLists.txt.

set(PLATFORM_LIBS ${PLATFORM_LIBS} ws2_32 ntdll)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment