winio-0.1: cbits/HsWinIO.c
// Copyright 2007-2008 Felix Martini.
//
// See LICENSE for license terms.
#ifdef _WIN32
#define _WIN32_WINNT 0x0500
#define DllExport __declspec(dllexport)
#include <winsock2.h>
#include <windows.h>
DllExport
BOOL HsGetFileSize(HANDLE fileHandle, INT64 *fileSize)
{
LARGE_INTEGER size;
BOOL res;
res = GetFileSizeEx(fileHandle, &size);
*fileSize = size.QuadPart;
return res;
}
DllExport
BOOL HsGetFilePointer(HANDLE fileHandle, INT64 *filePointer)
{
LARGE_INTEGER zero;
LARGE_INTEGER pointer;
BOOL res;
zero.QuadPart = 0;
res = SetFilePointerEx(fileHandle, zero, &pointer, FILE_CURRENT);
*filePointer = pointer.QuadPart;
return res;
}
DllExport
BOOL HsSetFilePointer(HANDLE fileHandle, INT64 offset, DWORD moveMethod)
{
LARGE_INTEGER distToMove;
distToMove.QuadPart = offset;
return SetFilePointerEx(fileHandle, distToMove, NULL, moveMethod);
}
DllExport
HANDLE HsNewCompletionPort(DWORD numThreads)
{
return CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0,
numThreads);
}
DllExport
BOOL HsAssociateHandleWithPort(HANDLE handle, HANDLE port)
{
HANDLE h;
h = CreateIoCompletionPort(handle, port, 0, 0);
return (h == port);
}
DllExport
BOOL HsAssociateSocketWithPort(SOCKET socket, HANDLE port)
{
HANDLE h;
h = CreateIoCompletionPort((HANDLE)socket, port, 0, 0);
return (h == port);
}
typedef struct _PER_IO_DATA {
OVERLAPPED Overlapped;
void *UserData;
} PER_IO_DATA;
DllExport
BOOL HsGetCompletion(HANDLE port, DWORD *numBytes, void **userData,
DWORD timeout)
{
OVERLAPPED *overlappedPtr = NULL;
ULONG_PTR completionKey;
BOOL res;
res = GetQueuedCompletionStatus(port, numBytes, &completionKey,
&overlappedPtr, timeout);
if (overlappedPtr != NULL) {
PER_IO_DATA *perIoDataPtr;
perIoDataPtr =
CONTAINING_RECORD(overlappedPtr, PER_IO_DATA, Overlapped);
*userData = perIoDataPtr->UserData;
HeapFree(GetProcessHeap(), 0, perIoDataPtr);
} else {
*userData = NULL;
}
return res;
}
// HsAsyncRead returns the number of bytes read if the operation is completed
// synchronously or -1 if an error occurs.
// N.B. Operations that are successfully initiated asynchronously will report
// the error ERROR_IO_PENDING and a completion event will be send to the
// completion port when the operation is finished.
DllExport
int HsAsyncRead(HANDLE handle, UINT64 pos, void *buf, int size,
void *userData)
{
PER_IO_DATA *perIoDataPtr;
DWORD numBytesRead;
BOOL res;
perIoDataPtr =
HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PER_IO_DATA));
if (perIoDataPtr == NULL) {
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return -1;
} else {
perIoDataPtr->Overlapped.Offset = (DWORD) pos;
perIoDataPtr->Overlapped.OffsetHigh = (DWORD) (pos >> 32);
perIoDataPtr->UserData = userData;
res = ReadFile(handle, buf, size, &numBytesRead,
&(perIoDataPtr->Overlapped));
if (!res) {
DWORD error;
error = GetLastError();
if (error != ERROR_IO_PENDING) {
HeapFree(GetProcessHeap(), 0, perIoDataPtr);
}
return -1;
} else {
// We report a pending operation even if it has completed
// synchronously because Windows still posts a completion event
// to the port. TODO: Vista and later operating systems support a
// function named SetFileCompletionNotificationModes which can
// prevent that.
SetLastError(ERROR_IO_PENDING);
return -1;
}
}
}
DllExport
int HsAsyncWrite(HANDLE handle, UINT64 pos, void *buf, int size,
void *userData)
{
PER_IO_DATA *perIoDataPtr;
DWORD numBytesWritten;
BOOL res;
perIoDataPtr =
HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PER_IO_DATA));
if (perIoDataPtr == NULL) {
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return -1;
} else {
perIoDataPtr->Overlapped.Offset = (DWORD) pos;
perIoDataPtr->Overlapped.OffsetHigh = (DWORD) (pos >> 32);
perIoDataPtr->UserData = userData;
res = WriteFile(handle, buf, size, &numBytesWritten,
&(perIoDataPtr->Overlapped));
if (!res) {
DWORD error;
error = GetLastError();
if (error != ERROR_IO_PENDING) {
HeapFree(GetProcessHeap(), 0, perIoDataPtr);
}
return -1;
} else {
SetLastError(ERROR_IO_PENDING);
return -1;
}
}
}
DllExport
int HsAsyncRecv(SOCKET socket, void *buf, int size, void *userData)
{
WSABUF dataBuf;
DWORD flags;
PER_IO_DATA *perIoDataPtr;
DWORD numBytesRecvd;
int res;
dataBuf.buf = (char *)buf;
dataBuf.len = size;
flags = 0;
perIoDataPtr =
HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PER_IO_DATA));
if (perIoDataPtr == NULL) {
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return -1;
} else {
perIoDataPtr->UserData = userData;
res = WSARecv(socket, &dataBuf, 1, &numBytesRecvd, &flags,
&(perIoDataPtr->Overlapped), NULL);
if (res != 0) {
DWORD error;
error = WSAGetLastError();
if (error != WSA_IO_PENDING) {
HeapFree(GetProcessHeap(), 0, perIoDataPtr);
}
return -1;
} else {
SetLastError(ERROR_IO_PENDING);
return -1;
}
}
}
DllExport
int HsAsyncRecvFrom(SOCKET socket, void *buf, int size,
struct sockaddr *fromPtr, int *fromLenPtr, void *userData)
{
WSABUF dataBuf;
DWORD flags;
PER_IO_DATA *perIoDataPtr;
DWORD numBytesRecvd;
int res;
dataBuf.buf = (char *)buf;
dataBuf.len = size;
flags = 0;
perIoDataPtr =
HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PER_IO_DATA));
if (perIoDataPtr == NULL) {
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return -1;
} else {
perIoDataPtr->UserData = userData;
res = WSARecvFrom(socket, &dataBuf, 1, &numBytesRecvd, &flags,
fromPtr, fromLenPtr, &(perIoDataPtr->Overlapped), NULL);
if (res != 0) {
DWORD error;
error = WSAGetLastError();
if (error != WSA_IO_PENDING) {
HeapFree(GetProcessHeap(), 0, perIoDataPtr);
}
return -1;
} else {
SetLastError(ERROR_IO_PENDING);
return -1;
}
}
}
DllExport
int HsAsyncSend(SOCKET socket, void *buf, int size, void *userData)
{
WSABUF dataBuf;
DWORD flags;
PER_IO_DATA *perIoDataPtr;
DWORD numBytesSend;
int res;
dataBuf.buf = (char *)buf;
dataBuf.len = size;
flags = 0;
perIoDataPtr =
HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PER_IO_DATA));
if (perIoDataPtr == NULL) {
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return -1;
} else {
perIoDataPtr->UserData = userData;
res = WSASend(socket, &dataBuf, 1, &numBytesSend, flags,
&(perIoDataPtr->Overlapped), NULL);
if (res != 0) {
DWORD error;
error = WSAGetLastError();
if (error != WSA_IO_PENDING) {
HeapFree(GetProcessHeap(), 0, perIoDataPtr);
}
return -1;
} else {
SetLastError(ERROR_IO_PENDING);
return -1;
}
}
}
DllExport
int HsAsyncSendTo(SOCKET socket, void *buf, int size,
struct sockaddr *toPtr, int toLen, void *userData)
{
WSABUF dataBuf;
DWORD flags;
PER_IO_DATA *perIoDataPtr;
DWORD numBytesSend;
int res;
dataBuf.buf = (char *)buf;
dataBuf.len = size;
flags = 0;
perIoDataPtr =
HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PER_IO_DATA));
if (perIoDataPtr == NULL) {
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return -1;
} else {
perIoDataPtr->UserData = userData;
res = WSASendTo(socket, &dataBuf, 1, &numBytesSend, flags,
toPtr, toLen, &(perIoDataPtr->Overlapped), NULL);
if (res != 0) {
DWORD error;
error = WSAGetLastError();
if (error != WSA_IO_PENDING) {
HeapFree(GetProcessHeap(), 0, perIoDataPtr);
}
return -1;
} else {
SetLastError(ERROR_IO_PENDING);
return -1;
}
}
}
#endif // _WIN32