CX Framework
Cross-platform C utility framework
Loading...
Searching...
No Matches
win_net.h
1#pragma once
2
3#include <cx/net/net_private.h>
4#include <cx/platform/win.h>
5
6#include <cx/buffer/buffer.h>
7
8#include <limits.h>
9#include <ws2tcpip.h>
10#include <mswsock.h> // WSAID_WSARECVMSG / WSAID_WSASENDMSG, which are extensions, not exports
11
12// Map a raw winsock error code to a NetErrorCode. For codes that do not come from the thread-local
13// WSAGetLastError() value: getsockopt(SO_ERROR) results, and the IOCP backend's completion errors
14// (which route through its own mapper first, since a failed overlapped op reports Win32/NTSTATUS-
15// derived codes that only partially overlap the WSAE* space).
16NetErrorCode _netMapWsaError(int e);
17
18bool netAddrToSockaddr(_In_ const NetAddr* addr, _Out_ struct sockaddr_storage* sa,
19 _Out_ int* sasz);
20
26bool netAddrFromSockaddr(_Out_ NetAddr* addr, _In_ const struct sockaddr* sa);
27
28// Cancel every outstanding overlapped operation on a socket handle, whichever thread posted them,
29// and report whether that can be done at all on this host.
30//
31// The call behind this is CancelIoEx, which arrived with Vista. An XP-compatible build cannot
32// import it -- the executable would fail to load on XP with a missing kernel32 entry point -- so it
33// is resolved at runtime. XP's plain CancelIo is no substitute: it only reaches operations the
34// calling thread itself posted, and the IOCP backend posts everything from its completion threads.
35bool _netHaveCancelIoEx(void);
36void _netCancelSockIo(NetSockHandle h);
37
38// WSARecvMsg and WSASendMsg are the only Winsock calls that carry control messages. Where the SDK
39// is too old to name the message structure or the packet-info option, this whole path compiles out
40// and everything ancillary falls back to plain recvfrom/sendto and reports nothing, which is the
41// same answer a path that strips ECN gives.
42#if defined(WSA_CMSG_FIRSTHDR) && defined(IP_PKTINFO)
43#define NET_HAVE_WSAMSG 1
44#endif
45
46// An XP-targeted build (_WIN32_WINNT < 0x0600) gets the message structure and every option, but not
47// the identifier for WSASendMsg, which the SDK hides behind the same version check that hides the
48// Vista-only WSASendMsg import declaration. Only the identifier is needed here -- the call itself
49// is reached through a pointer WSAIoctl hands out, and on a host that has no WSASendMsg that ioctl
50// simply fails and the send falls back. So name it rather than lose the send path on every Windows
51// version an XP-compatible binary runs on.
52#if defined(NET_HAVE_WSAMSG) && !defined(WSAID_WSASENDMSG)
53#define WSAID_WSASENDMSG /* a441e712-754f-43ca-84a7-0dee44cf606d */ \
54 { 0xa441e712, 0x754f, 0x43ca, { 0x84, 0xa7, 0x0d, 0xee, 0x44, 0xcf, 0x60, 0x6d } }
55#endif
56
57#if defined(NET_HAVE_WSAMSG)
58
59// Enough room for the control messages one datagram carries in either direction, in either address
60// family: a packet info structure and a traffic class byte.
61#define NET_CMSG_SPACE 128
62
63typedef INT(WSAAPI* NetRecvMsgFn)(SOCKET, LPWSAMSG, LPDWORD, LPWSAOVERLAPPED,
64 LPWSAOVERLAPPED_COMPLETION_ROUTINE);
65
66typedef INT(WSAAPI* NetSendMsgFn)(SOCKET, LPWSAMSG, DWORD, LPDWORD, LPWSAOVERLAPPED,
67 LPWSAOVERLAPPED_COMPLETION_ROUTINE);
68
69// The WSARecvMsg / WSASendMsg extensions, or NULL if they could not be loaded. Fetched once from a
70// throwaway socket; the pointers are good for every socket in the process.
71NetRecvMsgFn _netRecvMsgFn(void);
72NetSendMsgFn _netSendMsgFn(void);
73
74// Writes the control messages that ask for a local address and an ECN mark into a message whose
75// Control field already points at a buffer of at least NET_CMSG_SPACE bytes. Control.len is left
76// holding what was actually used, which is zero when the platform can express neither -- and a
77// message with a control buffer but nothing in it is not the same as one with no control buffer,
78// so a caller must clear Control entirely in that case.
79//
80// Returns true if anything was written.
81bool _netPktInfoToCmsg(_Inout_ WSAMSG* mh, _In_ const NetPktInfo* info, int family);
82
83// Reads the local address and ECN mark out of a received message's control data, and clears what
84// was not there.
85void _netCmsgToPktInfo(_Inout_ WSAMSG* mh, _Out_ NetPktInfo* info);
86
87#endif
88
93typedef WSABUF NetPlatIov;
94
95// NET_MAX_IOV (the shared scatter/gather bound) is defined in net_private.h so the portable gather in
96// socket.c and this platform translation agree on the array size.
97
117_meta_inline size_t netIovToPlatform(_Out_writes_(count) NetPlatIov* out,
118 _In_reads_(count) const BufIov* iov, size_t count)
119{
120 for (size_t i = 0; i < count; ++i) {
121 // WSABUF counts bytes in a ULONG, which is 32 bits even on 64-bit Windows. A segment
122 // that large should be impossible, but truncating silently would send the wrong length.
123 devAssertMsg(iov[i].len <= ULONG_MAX, "iov entry too large for WSABUF");
124 out[i].buf = (CHAR*)iov[i].data;
125 out[i].len = (ULONG)iov[i].len;
126 }
127 return count;
128}
Simple buffer management.
#define devAssertMsg(expr, msg)
Definition assert.h:148
intptr NetSockHandle
Platform-neutral OS socket handle: a Windows SOCKET or a Unix file descriptor.
Definition net_shared.h:17
NetErrorCode
Network error codes.
Definition net_shared.h:243
Per-datagram information the IP layer carries alongside the payload.
Definition net_shared.h:328