Last active
March 21, 2020 03:03
-
-
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)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Public domain | |
* | |
* BSD socket emulation code for Winsock2 | |
* File IO compatibility shims | |
* Brent Cook <[email protected]> | |
* Kinichiro Inoguchi <[email protected]> | |
*/ | |
#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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Public domain | |
* | |
* BSD socket emulation code for Winsock2 | |
* File IO compatibility shims | |
* Brent Cook <[email protected]> | |
* Kinichiro Inoguchi <[email protected]> | |
*/ | |
#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 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
To build with this posix_win.c, add
ntdll
afterws2_32
inCMakeLists.txt
.