PageRenderTime 57ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 0ms

/include/kNet/Socket.h

https://bitbucket.org/clb/knet
C Header | 342 lines | 151 code | 62 blank | 129 comment | 8 complexity | 692135134a11ea6dd06a95a623219993 MD5 | raw file
Possible License(s): Apache-2.0
  1. /* Copyright The kNet Project.
  2. Licensed under the Apache License, Version 2.0 (the "License");
  3. you may not use this file except in compliance with the License.
  4. You may obtain a copy of the License at
  5. http://www.apache.org/licenses/LICENSE-2.0
  6. Unless required by applicable law or agreed to in writing, software
  7. distributed under the License is distributed on an "AS IS" BASIS,
  8. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  9. See the License for the specific language governing permissions and
  10. limitations under the License. */
  11. #pragma once
  12. /** @file Socket.h
  13. @brief The Socket class. */
  14. #ifdef WIN32
  15. #include "kNetBuildConfig.h"
  16. #include "win32/WS2Include.h"
  17. #define KNET_EWOULDBLOCK WSAEWOULDBLOCK
  18. #define KNET_SOCKET_ERROR SOCKET_ERROR
  19. #define KNET_ACCEPT_FAILURE SOCKET_ERROR
  20. namespace kNet
  21. {
  22. typedef int socklen_t;
  23. }
  24. #elif defined(UNIX) || defined(ANDROID)
  25. #include <sys/types.h>
  26. #include <sys/socket.h>
  27. #include <netinet/in.h>
  28. #include <netdb.h>
  29. #include <errno.h>
  30. #define INVALID_SOCKET (0)
  31. #define KNET_SOCKET_ERROR (-1)
  32. #define KNET_ACCEPT_FAILURE (-1)
  33. #define KNET_EWOULDBLOCK EWOULDBLOCK
  34. #define closesocket close
  35. #define TIMEVAL timeval
  36. #define SD_SEND SHUT_WR
  37. #define SD_BOTH SHUT_RDWR
  38. #define _stricmp strcasecmp
  39. namespace kNet
  40. {
  41. typedef unsigned int SOCKET;
  42. }
  43. #endif
  44. #include <vector>
  45. #include <list>
  46. #include "SharedPtr.h"
  47. #include "EndPoint.h"
  48. #include "WaitFreeQueue.h"
  49. #include "Event.h"
  50. namespace kNet
  51. {
  52. /// Identifiers for the possible bottom-level tranport layers.
  53. enum SocketTransportLayer
  54. {
  55. InvalidTransportLayer = 0, ///< A default invalid value for uninitialized sockets.
  56. SocketOverUDP,
  57. SocketOverTCP
  58. };
  59. std::string SocketTransportLayerToString(SocketTransportLayer transport);
  60. /// Converts the given string (case-insensitive parsing) to the corresponding SocketTransportLayer enum.
  61. /// "tcp" & "socketovertcp" -> SocketOverTCP.
  62. /// "udp" & "socketoverudp" -> SocketOverUDP.
  63. /// Other strings -> InvalidTransportLayer.
  64. SocketTransportLayer StringToSocketTransportLayer(const char *str);
  65. enum SocketType
  66. {
  67. InvalidSocketType = 0, ///< A default invalid value for uninitialized sockets.
  68. ServerListenSocket, ///< For TCP: a listen socket. For UDP: the single master socket handle that is used to send & receive all data.
  69. ServerClientSocket, ///< For TCP: a client data socket. For UDP: a slave-mode Socket object that shares the underlying socket handle with the UDP master Socket.
  70. ClientSocket ///< A client-side socket.
  71. };
  72. std::string SocketTypeToString(SocketType type);
  73. typedef int OverlappedTransferTag;
  74. #ifdef WIN32
  75. typedef WSABUF kNetBuffer;
  76. #else
  77. struct kNetBuffer
  78. {
  79. /// Specifies the number of bytes allocated to buf. This is the maximum amount of bytes that can
  80. /// be written to buf.
  81. unsigned long len;
  82. char *buf;
  83. };
  84. #endif
  85. struct OverlappedTransferBuffer
  86. {
  87. kNetBuffer buffer;
  88. #ifdef WIN32
  89. WSAOVERLAPPED overlapped;
  90. #endif
  91. /// Specifies the number of bytes buffer.buf actually contains.
  92. int bytesContains;
  93. sockaddr_in from;
  94. socklen_t fromLen;
  95. };
  96. /// Represents a low-level network socket.
  97. class Socket : public RefCountable
  98. {
  99. public:
  100. Socket();
  101. Socket(SOCKET connection, const EndPoint &localEndPoint, const char *localHostName,
  102. const EndPoint &remoteEndPoint, const char *remoteHostName,
  103. SocketTransportLayer transport, SocketType type, size_t maxSendSize);
  104. Socket(const Socket &);
  105. ~Socket();
  106. Socket &operator=(const Socket &);
  107. /// Sets the underlying socket send buffer (SO_SNDBUF) size.
  108. void SetSendBufferSize(int bytes);
  109. /// Sets the underlying socket receive buffer (SO_RCVBUF) size.
  110. void SetReceiveBufferSize(int bytes);
  111. /// Returns the current value for the send buffer of this socket.
  112. int SendBufferSize() const;
  113. /// Returns the current value for the receive buffer of this socket.
  114. int ReceiveBufferSize() const;
  115. /// Returns true if the connection is both write-open AND read-open.
  116. bool Connected() const;
  117. /// Returns true if the connection is open for reading from. This does not mean that there necessarily is new data
  118. /// to be immediately read - it only means that the socket is open for receiving data.
  119. bool IsReadOpen() const { return IsOverlappedReceiveReady() || readOpen; }
  120. /// Returns true if the connection is open for writing to.
  121. bool IsWriteOpen() const { return writeOpen; }
  122. /// Forces this socket to be treated as if it has been read-closed.
  123. void MarkReadClosed() { readOpen = false; }
  124. /// Forces this socket to be treated as if it has been write-closed.
  125. void MarkWriteClosed() { writeOpen = false; }
  126. /// If this function returns true, this socket represents a UDP server socket instance. For a UDP server,
  127. /// the data for all clients is received through this same socket, and there are no individual sockets created for
  128. /// each new connection, like is done with TCP.
  129. bool IsUDPServerSocket() const { return transport == SocketOverUDP && type == ServerListenSocket; }
  130. /// Returns whether this socket is a UDP slave socket. [worker thread]
  131. bool IsUDPSlaveSocket() const { return transport == SocketOverUDP && type == ServerClientSocket; }
  132. /// Performs a write close operation on the socket, signalling the other end that no more data will be sent. Any data
  133. /// currently left in the send buffers will be sent over to the other side, but no new data can be sent. The connection
  134. /// will remain half-open for reading, and Receive() calls may still be made to the socket. When a read returns 0, the
  135. /// connection will be transitioned to bidirectionally closed state (Connected() will return false).
  136. void Disconnect();
  137. /// Performs an immediate write and read close on the socket, without waiting for the connection to gracefully shut down.
  138. void Close();
  139. /// Sends the given data through the socket. This function may only be called if Socket::IsWriteOpen() returns true. If
  140. /// the socket is not write-open, calls to this function will fail.
  141. /// This function is an orthogonal API to the overlapped IO Send routines. Do not mix these API calls when doing
  142. /// networking, but instead choose one preferred method and consistently use it.
  143. bool Send(const char *data, size_t numBytes);
  144. /// Waits until the Socket is ready for sending. Returns true if the socket transitioned to write-ready state in the given
  145. /// time period, or false if the wait timed out or if some other error occurred.
  146. /// This function is an orthogonal API to the overlapped IO Send routines. Do not mix these API calls when doing
  147. /// networking, but instead choose one preferred method and consistently use it.
  148. bool WaitForSendReady(int msecs);
  149. /// Starts the sending of new data. After having filled the data to send to the OverlappedTransferBuffer that is
  150. /// returned here, commit the send by calling EndSend. If you have called BeginSend, but decide not to send any data,
  151. /// call AbortSend instead (otherwise memory will leak).
  152. /// @return A transfer buffer where the data to send is to be filled in. If no new data can be sent at this time,
  153. /// this function returns 0.
  154. OverlappedTransferBuffer *BeginSend();
  155. /// Finishes and queues up the given transfer that was created with a call to BeginSend.
  156. /// @return True if send succeeded, false otherwise. In either case, the ownership of the passed buffer send
  157. /// is taken by this Socket and may not be accessed anymore. Discard the pointer after calling this function.
  158. bool EndSend(OverlappedTransferBuffer *send);
  159. /// Cancels the sending of data. Call this function if you first call BeginSend, but decide you don't want to send the data.
  160. /// This frees the given buffer, do not dereference it after calling this function.
  161. void AbortSend(OverlappedTransferBuffer *send);
  162. #ifdef WIN32
  163. /// Returns the number of sends in the send queue.
  164. int NumOverlappedSendsInProgress() const { return queuedSendBuffers.Size(); }
  165. /// Returns the maximum number of sends that can be queued up simultaneously.
  166. int MaxOverlappedSendsInProgress() const { return queuedSendBuffers.Capacity(); }
  167. #endif
  168. /// Returns true if it is possible to send out new data. In this case, a call to BeginSend will succeed.
  169. bool IsOverlappedSendReady();
  170. /// Returns the event object that should be waited on to receive a notification when it is possible to send out new data.
  171. Event GetOverlappedSendEvent();
  172. /// Waits for the max given amount of time for new data to be received from the socket.
  173. /// @return True if new data was received, false if the timeout period elapsed.
  174. // bool WaitForData(int msecs); // this will be removed completely.
  175. /// Reads in data from the socket. If there is no data available, this function will not block, but will immediately
  176. /// return 0.
  177. /// This function issues an immediate recv() call to the socket and is not compatible with the Overlapped Transfer API
  178. /// above. Do not mix the use of these two APIs, but pick one method to use and stay with it.
  179. /// @param endPoint [out] If the socket is an UDP socket that is not bound to an address, this will contain the source address.
  180. /// @return The number of bytes that were successfully read.
  181. size_t Receive(char *dst, size_t maxBytes, EndPoint *endPoint = 0);
  182. /// Call to receive new data from the socket.
  183. /// @return A buffer that contains the data, or 0 if no new data was available. When you are finished reading the buffer, call
  184. /// EndReceive to free up the buffer, or memory will leak.
  185. OverlappedTransferBuffer *BeginReceive();
  186. /// Finishes a read operation on the socket. Frees the given buffer to be re-queued for a future socket read operation.
  187. void EndReceive(OverlappedTransferBuffer *buffer);
  188. #ifdef WIN32
  189. /// Returns the number of receive buffers that have been queued for the socket.
  190. int NumOverlappedReceivesInProgress() const { return queuedReceiveBuffers.Size(); }
  191. /// Returns the maximum number of receive buffers that can be queued for the socket.
  192. int MaxOverlappedReceivesInProgress() const { return queuedReceiveBuffers.Capacity(); }
  193. #endif
  194. /// Returns true if there is new data to be read in. In that case, BeginReceive() will not return 0.
  195. bool IsOverlappedReceiveReady() const;
  196. /// Returns the event object that will be notified whenever data is available to be read from the socket.
  197. Event GetOverlappedReceiveEvent(); // [worker thread]
  198. /// Returns which transport layer the connection is using. This value is either SocketOverUDP or SocketOverTCP.
  199. SocketTransportLayer TransportLayer() const { return transport; }
  200. /// Returns the type of this socket object.
  201. SocketType Type() const { return type; }
  202. /// Returns the maximum amount of bytes that can be sent through to the network in one call. If you try sending
  203. /// more data than specified by this value, the result is undefined.
  204. size_t MaxSendSize() const { return maxSendSize; }
  205. /// Returns the local EndPoint this socket is bound to.
  206. const EndPoint &LocalEndPoint() const { return localEndPoint; }
  207. /// Returns the local address (local hostname) of the local end point this socket is bound to.
  208. const char *LocalAddress() const { return localHostName.c_str(); }
  209. /// Returns the local port that this socket is bound to.
  210. unsigned short LocalPort() const { return localEndPoint.port; }
  211. /// Returns the remote EndPoint this socket is connected to.
  212. /// If SocketType == ServerListenSocket, this socket is not bound
  213. /// to any remote end point, and so the returned struct is uninitialized (filled with zeroes).
  214. const EndPoint &RemoteEndPoint() const { return remoteEndPoint; }
  215. /// Returns the destination address (destination hostname) of the remote end point this socket is connected to.
  216. /// If SocketType == ServerListenSocket, returns an empty string.
  217. const char *DestinationAddress() const { return remoteHostName.c_str(); }
  218. /// Returns the destination port of the remote end point this socket is connected to.
  219. /// If SocketType == ServerListenSocket, returns 0.
  220. unsigned short DestinationPort() const { return remoteEndPoint.port; }
  221. /// Returns a human-readable representation of this socket, specifying the peer address and port this socket is
  222. /// connected to.
  223. std::string ToString() const;
  224. /// Sets the socket to blocking or nonblocking state.
  225. void SetBlocking(bool isBlocking);
  226. SOCKET &GetSocketHandle() { return connectSocket; }
  227. /// Enables or disables the use of Nagle's algorithm (TCP_NODELAY) for this socket.
  228. /// Nagle's algorithm reduces the bandwidth consumption of the channel, but can increase latency.
  229. /// Conversely, disabling Nagle's algorithm improves the latency, but increases the number of IP packets sent to the network.
  230. /// By default, Nagle's algorithm is enabled.
  231. /// Read more about Nagle's algorithm here: http://msdn.microsoft.com/en-us/library/ms817942.aspx
  232. void SetNaglesAlgorithmEnabled(bool enabled);
  233. private:
  234. /// Stores the handle to the underlying BSD socket object. Has the value INVALID_SOCKET if uninitialized.
  235. SOCKET connectSocket;
  236. /// Specifies the local system end point (IP and port) this socket is bound to.
  237. EndPoint localEndPoint;
  238. /// Specifies the network host name of the local end point (the local system).
  239. /// If the local end point does not have a hostname, this field is the string representation of the
  240. /// system IP address (one of them, there may be multiple IPs).
  241. std::string localHostName;
  242. /// Specifies the remote system end point (IP and port) this socket is bound to (== the "peer" address).
  243. /// If SocketType == ServerListenSocket or transport == SocketOverUDP, this socket is not bound
  244. /// to any remote end point, and so this struct is uninitialized (filled with zeroes).
  245. EndPoint remoteEndPoint;
  246. /// If this socket is a UDP socket, the remoteEndPoint variable is copied (cached) to the variable
  247. /// udpPeerAddress to avoid having to reconstruct it at each Socket::Send() call (this is an optimization).
  248. /// This field is only used if this socket is a UDP socket.
  249. sockaddr_in udpPeerAddress;
  250. /// Specifies the network host name of the remote end point (== the remote system == the "peer").
  251. /// If the remote end point does not have a known hostname, this field is the string representation of the
  252. /// remote IP address. If SocketType == ServerListenSocket, this field is empty.
  253. std::string remoteHostName;
  254. /// Specifies the underlying transport protocol that this Socket is using (TCP or UDP).
  255. SocketTransportLayer transport;
  256. /// Specifies the type of this SOCKET object.
  257. /// UDP server sockets are never bound to a remote, since the same socket is used to send and receive data to and
  258. /// from all client addresses. UDP client sockets and TCP sockets on the other hand are always bound to a peer.
  259. /// UDP client sockets are shared slave copies of the single UDP server socket. In this case, this field is used
  260. /// to remember that this Socket object is not authoritative over the OS socket object and should not close it
  261. /// when tearing down this socket.
  262. SocketType type;
  263. /// Specifies the maximum amount of data that can be sent to the socket at one call to send().
  264. size_t maxSendSize;
  265. /// Tracks whether data can be sent through this socket.
  266. bool writeOpen;
  267. /// Tracks whether the socket is open for receiving data (doesn't mean that there necessarily exists new data to be read).
  268. bool readOpen;
  269. #ifdef WIN32
  270. WaitFreeQueue<OverlappedTransferBuffer*> queuedReceiveBuffers;
  271. WaitFreeQueue<OverlappedTransferBuffer*> queuedSendBuffers;
  272. /// Frees all allocated data in the queuedReceiveBuffers and queuedSendBuffers queues.
  273. void FreeOverlappedTransferBuffers();
  274. void EnqueueNewReceiveBuffer(OverlappedTransferBuffer *buffer = 0);
  275. #endif
  276. };
  277. } // ~kNet