Baselib_Socket.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. #pragma once
  2. // Baselib Socket
  3. //
  4. // This is a socket platform abstraction api heavily influenced by non-blocking Berkeley Sockets.
  5. // Berkeley Sockets look like they behave in similar fashion on all platforms, but there are a lot of small differences.
  6. // Compared to Berkeley Sockets this API is somewhat more high level and doesn't provide as fine grained control.
  7. #include "Baselib_ErrorState.h"
  8. #include "Baselib_NetworkAddress.h"
  9. #include "Internal/Baselib_EnumSizeCheck.h"
  10. #ifdef __cplusplus
  11. BASELIB_C_INTERFACE
  12. {
  13. #endif
  14. // Socket Handle, a handle to a specific socket.
  15. typedef struct Baselib_Socket_Handle { intptr_t handle; } Baselib_Socket_Handle;
  16. static const Baselib_Socket_Handle Baselib_Socket_Handle_Invalid = { -1 };
  17. // Socket protocol.
  18. typedef enum Baselib_Socket_Protocol
  19. {
  20. Baselib_Socket_Protocol_UDP = 1,
  21. Baselib_Socket_Protocol_TCP = 2,
  22. } Baselib_Socket_Protocol;
  23. BASELIB_ENUM_ENSURE_ABI_COMPATIBILITY(Baselib_Socket_Protocol);
  24. // Socket message. Used to send or receive data in message based protocols such as UDP.
  25. typedef struct Baselib_Socket_Message
  26. {
  27. Baselib_NetworkAddress* address;
  28. void* data;
  29. uint32_t dataLen;
  30. } Baselib_Socket_Message;
  31. // Create a socket.
  32. //
  33. // Possible error codes:
  34. // - Baselib_ErrorCode_InvalidArgument: if context, family or protocol is invalid or unknown.
  35. // - Baselib_ErrorCode_AddressFamilyNotSupported: if the requested address family is not available.
  36. BASELIB_API Baselib_Socket_Handle Baselib_Socket_Create(
  37. Baselib_NetworkAddress_Family family,
  38. Baselib_Socket_Protocol protocol,
  39. Baselib_ErrorState* errorState
  40. );
  41. // Bind socket to a local address and port.
  42. //
  43. // Bind can only be called once per socket.
  44. // Address can either be a specific interface ip address.
  45. // In case if encoded ip is nullptr / "0.0.0.0" / "::" (same as INADDR_ANY) will bind to all interfaces.
  46. //
  47. // \param addressReuse A set of sockets can be bound to the same address port combination if all
  48. // sockets are bound with this flag set to AddressReuse_Allow, similar to
  49. // SO_REUSEADDR+SO_REUSEPORT.
  50. // Please note that setting this flag to false doesn't mean anyone is forbidden
  51. // to binding to the same ip/port combo, or in other words it does NOT use
  52. // SO_EXCLUSIVEADDRUSE where it's available.
  53. //
  54. // Possible error codes:
  55. // - Baselib_ErrorCode_InvalidArgument: Socket does not represent a valid open socket. Address pointer is null or incompatible.
  56. // - Baselib_ErrorCode_AddressInUse: Address or port is already bound by another socket, or the system is out of ephemeral ports.
  57. // - Baselib_ErrorCode_AddressUnreachable: Address doesn't map to any known interface.
  58. BASELIB_API void Baselib_Socket_Bind(
  59. Baselib_Socket_Handle socket,
  60. const Baselib_NetworkAddress* address,
  61. Baselib_NetworkAddress_AddressReuse addressReuse,
  62. Baselib_ErrorState* errorState
  63. );
  64. // Connect a socket to a remote address.
  65. //
  66. // Note that this function initiates an asynchronous connection. You must call
  67. // Baselib_Socket_Poll with Baselib_Socket_PollEvents.requestedEvents =
  68. // Baselib_Socket_PollEvents_Connected to wait for the connection to finish.
  69. //
  70. // Possible error codes:
  71. // - Baselib_ErrorCode_InvalidArgument: Socket does not represent a valid socket, or socket is not a TCP socket. Address pointer is null or incompatible.
  72. // - Baselib_ErrorCode_AddressUnreachable: Unable to establish a connection with peer.
  73. BASELIB_API void Baselib_Socket_TCP_Connect(
  74. Baselib_Socket_Handle socket,
  75. const Baselib_NetworkAddress* address,
  76. Baselib_NetworkAddress_AddressReuse addressReuse,
  77. Baselib_ErrorState* errorState
  78. );
  79. // Bitmask of events to be used in Baselib_Socket_Poll
  80. typedef enum Baselib_Socket_PollEvents
  81. {
  82. Baselib_Socket_PollEvents_Readable = 1,
  83. Baselib_Socket_PollEvents_Writable = 2,
  84. // Note: Connected cannot be set at the same time as Readable and Writable.
  85. Baselib_Socket_PollEvents_Connected = 4,
  86. } Baselib_Socket_PollEvents;
  87. BASELIB_ENUM_ENSURE_ABI_COMPATIBILITY(Baselib_Socket_PollEvents);
  88. // Socket entry to be passed into Baselib_Socket_Poll.
  89. //
  90. // Note that the name `Fd` does not refer to the fact that these are file
  91. // descriptors (they are sockets), but rather the fact that nearly every socket
  92. // API calls this struct "pollfd".
  93. typedef struct Baselib_Socket_PollFd
  94. {
  95. Baselib_Socket_Handle handle;
  96. Baselib_Socket_PollEvents requestedEvents;
  97. Baselib_Socket_PollEvents resultEvents;
  98. Baselib_ErrorState* errorState;
  99. } Baselib_Socket_PollFd;
  100. // Helper method to construct a Baselib_Socket_PollFd. Use of this method is not
  101. // necessary, you may fill out the struct yourself if desired.
  102. static inline Baselib_Socket_PollFd Baselib_Socket_PollFd_New(Baselib_Socket_Handle handle, Baselib_Socket_PollEvents events, Baselib_ErrorState* errorState)
  103. {
  104. Baselib_Socket_PollFd result;
  105. result.handle = handle;
  106. result.requestedEvents = events;
  107. result.resultEvents = (Baselib_Socket_PollEvents)0;
  108. result.errorState = errorState;
  109. return result;
  110. }
  111. // Wait for a socket being readable, writable, or an error occurs. Specific
  112. // events that occurred will be set in sockets[i].resultEvents. Errors
  113. // associated with particular sockets will be reported in sockets[i].errorState.
  114. //
  115. // It is valid to have sockets[i].errorState to point to the same ErrorState as
  116. // the outer parameter errorState - or, more generally, you may alias whatever
  117. // error states within sockets[i].errorState and the parameter errorState.
  118. //
  119. // If timeoutInMilliseconds==0, Poll() will not block. There is no option to
  120. // wait indefinitely.
  121. //
  122. // Possible error codes on the outer parameter errorState:
  123. // - Baselib_ErrorCode_InvalidArgument: Sockets list is null. An individual socket handle is invalid.
  124. //
  125. // Possible error codes on sockets[i].errorState:
  126. // - Baselib_ErrorCode_AddressUnreachable: Asynchronous Connect() failed.
  127. // - Baselib_ErrorCode_Disconnected: Socket has been disconnected, or asynchronous Connect() failed (apple devices).
  128. BASELIB_API void Baselib_Socket_Poll(
  129. Baselib_Socket_PollFd* sockets,
  130. uint32_t socketsCount,
  131. uint32_t timeoutInMilliseconds,
  132. Baselib_ErrorState* errorState
  133. );
  134. // Get address of locally bound socket.
  135. //
  136. // Possible error codes:
  137. // - Baselib_ErrorCode_InvalidArgument: Socket does not represent a valid bound socket. Address pointer is null.
  138. BASELIB_API void Baselib_Socket_GetAddress(
  139. Baselib_Socket_Handle socket,
  140. Baselib_NetworkAddress* address,
  141. Baselib_ErrorState* errorState
  142. );
  143. // Configure a TCP server socket to begin listening for incoming connections.
  144. // The maximum queue size is used for each platform.
  145. //
  146. // Possible error codes:
  147. // - Baselib_ErrorCode_InvalidArgument: Socket does not represent a valid socket, or socket is not a TCP socket.
  148. // - Baselib_ErrorCode_AddressInUse: Another socket is already listening on the same port, or the system is out of ephemeral ports.
  149. BASELIB_API void Baselib_Socket_TCP_Listen(
  150. Baselib_Socket_Handle socket,
  151. Baselib_ErrorState* errorState
  152. );
  153. // Accept an incoming TCP connection to this server socket. When there are no
  154. // incoming connections, this returns Baselib_Socket_Handle_Invalid and does not
  155. // raise an error.
  156. //
  157. // Possible error codes:
  158. // - Baselib_ErrorCode_InvalidArgument: Socket does not represent a valid socket, or socket is not a TCP socket.
  159. BASELIB_API Baselib_Socket_Handle Baselib_Socket_TCP_Accept(
  160. Baselib_Socket_Handle socket,
  161. Baselib_ErrorState* errorState
  162. );
  163. // Send messages to unconnected destinations.
  164. //
  165. // Socket does not need to be bound before calling SendMessages.
  166. // When sending multiple messages an error may be raised after some of the messages were submitted.
  167. //
  168. // If the socket is not already bound to a port SendMessages will implicitly bind the socket before issuing the send operation.
  169. //
  170. // Warning: This function may not fail when called with a TCP socket, as it may
  171. // simply ignore the address parameter, and send to whatever the socket is
  172. // connected to. However, as there is no way to retreive the actual number of
  173. // bytes sent with this API, its use in this manner is strongly discouraged.
  174. //
  175. // Known issues (behavior may change in the future):
  176. // Some platforms do not support sending zero sized UDP packets.
  177. //
  178. // Possible error codes:
  179. // - Baselib_ErrorCode_AddressUnreachable: Message destination is known to not be reachable from this machine.
  180. // - Baselib_ErrorCode_InvalidArgument: Socket does not represent a valid socket. Messages is `NULL` or a message has an invalid or incompatible destination.
  181. // - Baselib_ErrorCode_InvalidBufferSize: Message payload exceeds max message size.
  182. //
  183. // \returns The number of messages successfully sent. This number may be lower than messageCount if send buffer is full or an error was raised. Reported error will be about last message tried to send.
  184. BASELIB_API uint32_t Baselib_Socket_UDP_Send(
  185. Baselib_Socket_Handle socket,
  186. Baselib_Socket_Message messages[],
  187. uint32_t messagesCount,
  188. Baselib_ErrorState* errorState
  189. );
  190. // Send a message to the connected peer.
  191. //
  192. // \returns The possibly-zero length of the message actually sent, which may be less than `dataLen`.
  193. //
  194. // Possible error codes:
  195. // - Baselib_ErrorCode_InvalidArgument: Socket does not represent a valid socket, or socket is not a TCP socket. Socket validity is not checked if dataLen==0.
  196. // - Baselib_ErrorCode_Disconnected: Socket has been disconnected.
  197. BASELIB_API uint32_t Baselib_Socket_TCP_Send(
  198. Baselib_Socket_Handle socket,
  199. void* data,
  200. uint32_t dataLen,
  201. Baselib_ErrorState* errorState
  202. );
  203. // Receive messages from unconnected sources.
  204. //
  205. // UDP message data that doesn't fit a message buffer is silently discarded.
  206. //
  207. // Warning: This function may not fail when called with a TCP socket, as it may
  208. // simply ignore the address parameter, and receive from whatever the socket is
  209. // connected to. However, as there is no way to retreive the actual number of
  210. // bytes received with this API, its use in this manner is strongly discouraged.
  211. //
  212. // Known issues (behavior may change in the future):
  213. // If the socket is not bound to a port RecvMessages will return zero without raising an error.
  214. // Some platforms does not support receiveing zero sized UDP packets.
  215. //
  216. // Possible error codes:
  217. // - Baselib_ErrorCode_InvalidArgument: Socket does not represent a valid socket. Or messages is `NULL`.
  218. //
  219. // \returns The number of messages successfully received. This number may be lower than messageCount if recv buffer is empty or an error was raised. Reported error will be about last message tried to receive.
  220. BASELIB_API uint32_t Baselib_Socket_UDP_Recv(
  221. Baselib_Socket_Handle socket,
  222. Baselib_Socket_Message messages[],
  223. uint32_t messagesCount,
  224. Baselib_ErrorState* errorState
  225. );
  226. // Receive a message from a connected source. Note that this method differs from
  227. // traditional socket APIs in that it is valid to return 0, this means that no
  228. // data were received. Disconnection is detected by errorState being
  229. // Baselib_ErrorCode_Disconnected.
  230. //
  231. // This function may or may not work when passed a UDP socket. Graceful error
  232. // handling of this case is omitted due to performance reasons.
  233. //
  234. // \returns The length of the message actually received, which may be less than `dataLen` or even zero.
  235. //
  236. // Possible error codes:
  237. // - Baselib_ErrorCode_InvalidArgument: Socket does not represent a valid socket.
  238. // - Baselib_ErrorCode_Disconnected: Socket has been disconnected.
  239. BASELIB_API uint32_t Baselib_Socket_TCP_Recv(
  240. Baselib_Socket_Handle socket,
  241. void* data,
  242. uint32_t dataLen,
  243. Baselib_ErrorState* errorState
  244. );
  245. // Close socket.
  246. //
  247. // Closing an already closed socket results in a no-op.
  248. BASELIB_API void Baselib_Socket_Close(
  249. Baselib_Socket_Handle socket
  250. );
  251. #ifdef __cplusplus
  252. }
  253. #endif