/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ /* * Copyright 2013-2020 Couchbase, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * New-Style v2 plugin for Windows, Using IOCP. * This file contains various utility functions used by the plugin * @author Mark Nunberg */ #include "iocp_iops.h" #include #include #include #include "config.h" #include #if defined(__MINGW32__) && !defined(_ftime_s) #define _ftime_s _ftime /** Mingw doens't have the _s variant */ #endif int iocp_w32err_2errno(DWORD error) { return wsaerr_map_impl(error); } DWORD iocp_set_last_error(lcb_io_opt_t io, SOCKET sock) { int werr = GetLastError(); io->v.v2.error = iocp_w32err_2errno(werr); return werr; } lcb_uint32_t iocp_micros(void) { return (lcb_uint32_t)(gethrtime() / 1000); } LPFN_CONNECTEX iocp_initialize_connectex(SOCKET sock) { LPFN_CONNECTEX ret = NULL; DWORD dwBytes; GUID ce_guid = WSAID_CONNECTEX; WSAIoctl(sock, SIO_GET_EXTENSION_FUNCTION_POINTER, &ce_guid, sizeof(ce_guid), &ret, sizeof(&ret), &dwBytes, NULL, NULL); return ret; } int iocp_just_scheduled(iocp_t *io, iocp_overlapped_t *ol, int status) { DWORD err = GetLastError(); IOCP_LOG(IOCP_TRACE, "Pending count: %d", io->n_iopending); if ((status != 0 && err == WSA_IO_PENDING) || status == 0) { io->n_iopending++; ol->sd->refcount++; return 0; } /** * Otherwise, there's something wrong */ IOCP_LOG(IOCP_ERR, "Got non-harmless error for %p: %d", ol, (int)err); io->base.v.v2.error = iocp_w32err_2errno(err); return -1; } void iocp_socket_decref(iocp_t *io, iocp_sockdata_t *sd) { if (--sd->refcount) { return; } if (sd->sSocket != INVALID_SOCKET) { closesocket(sd->sSocket); } lcb_list_delete(&sd->list); (void)io; free(sd); } void iocp_on_dequeued(iocp_t *io, iocp_sockdata_t *sd, int action) { IOCP_LOG(IOCP_TRACE, "Dequeing. A=%d, Pending=%d", action, io->n_iopending); iocp_socket_decref(io, sd); } /**This following function was copied from libuv. * See http://github.com/joyent/libuv for more details */ int iocp_overlapped_status(OVERLAPPED *lpOverlapped) { NTSTATUS status = (NTSTATUS)lpOverlapped->Internal; switch (status) { case 0: return ERROR_SUCCESS; case STATUS_PENDING: return ERROR_IO_PENDING; case STATUS_INVALID_HANDLE: case STATUS_OBJECT_TYPE_MISMATCH: return WSAENOTSOCK; case STATUS_INSUFFICIENT_RESOURCES: case STATUS_PAGEFILE_QUOTA: case STATUS_COMMITMENT_LIMIT: case STATUS_WORKING_SET_QUOTA: case STATUS_NO_MEMORY: case STATUS_CONFLICTING_ADDRESSES: case STATUS_QUOTA_EXCEEDED: case STATUS_TOO_MANY_PAGING_FILES: case STATUS_REMOTE_RESOURCES: case STATUS_TOO_MANY_ADDRESSES: return WSAENOBUFS; case STATUS_SHARING_VIOLATION: case STATUS_ADDRESS_ALREADY_EXISTS: return WSAEADDRINUSE; case STATUS_LINK_TIMEOUT: case STATUS_IO_TIMEOUT: case STATUS_TIMEOUT: return WSAETIMEDOUT; case STATUS_GRACEFUL_DISCONNECT: return WSAEDISCON; case STATUS_REMOTE_DISCONNECT: case STATUS_CONNECTION_RESET: case STATUS_LINK_FAILED: case STATUS_CONNECTION_DISCONNECTED: case STATUS_PORT_UNREACHABLE: case STATUS_HOPLIMIT_EXCEEDED: return WSAECONNRESET; case STATUS_LOCAL_DISCONNECT: case STATUS_TRANSACTION_ABORTED: case STATUS_CONNECTION_ABORTED: return WSAECONNABORTED; case STATUS_BAD_NETWORK_PATH: case STATUS_NETWORK_UNREACHABLE: case STATUS_PROTOCOL_UNREACHABLE: return WSAENETUNREACH; case STATUS_HOST_UNREACHABLE: return WSAEHOSTUNREACH; case STATUS_CANCELLED: case STATUS_REQUEST_ABORTED: return WSAEINTR; case STATUS_BUFFER_OVERFLOW: case STATUS_INVALID_BUFFER_SIZE: return WSAEMSGSIZE; case STATUS_BUFFER_TOO_SMALL: case STATUS_ACCESS_VIOLATION: return WSAEFAULT; case STATUS_DEVICE_NOT_READY: case STATUS_REQUEST_NOT_ACCEPTED: return WSAEWOULDBLOCK; case STATUS_INVALID_NETWORK_RESPONSE: case STATUS_NETWORK_BUSY: case STATUS_NO_SUCH_DEVICE: case STATUS_NO_SUCH_FILE: case STATUS_OBJECT_PATH_NOT_FOUND: case STATUS_OBJECT_NAME_NOT_FOUND: case STATUS_UNEXPECTED_NETWORK_ERROR: return WSAENETDOWN; case STATUS_INVALID_CONNECTION: return WSAENOTCONN; case STATUS_REMOTE_NOT_LISTENING: case STATUS_CONNECTION_REFUSED: return WSAECONNREFUSED; case STATUS_PIPE_DISCONNECTED: return WSAESHUTDOWN; case STATUS_INVALID_ADDRESS: case STATUS_INVALID_ADDRESS_COMPONENT: return WSAEADDRNOTAVAIL; case STATUS_NOT_SUPPORTED: case STATUS_NOT_IMPLEMENTED: return WSAEOPNOTSUPP; case STATUS_ACCESS_DENIED: return WSAEACCES; default: if ((status & (FACILITY_NTWIN32 << 16)) == (FACILITY_NTWIN32 << 16) && (status & (ERROR_SEVERITY_ERROR | ERROR_SEVERITY_WARNING))) { /* It's a windows error that has been previously mapped to an */ /* ntstatus code. */ return (DWORD)(status & 0xffff); } else { /* The default fallback for unmappable ntstatus codes. */ return WSAEINVAL; } } }