SocketHandle.h 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501
  1. /*
  2. ** Copyright 2003-2009, Ernest Laurentin (http://www.ernzo.com/)
  3. **
  4. ** Licensed under the Apache License, Version 2.0 (the "License");
  5. ** you may not use this file except in compliance with the License.
  6. ** You may obtain a copy of the License at
  7. **
  8. ** http://www.apache.org/licenses/LICENSE-2.0
  9. **
  10. ** Unless required by applicable law or agreed to in writing, software
  11. ** distributed under the License is distributed on an "AS IS" BASIS,
  12. ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. ** See the License for the specific language governing permissions and
  14. ** limitations under the License.
  15. **
  16. ** File: SocketHandle.h
  17. ** Version: 1.4 - IPv6 support
  18. ** 1.3 - Update for Asynchronous mode / Linux port
  19. ** 1.2 - Update interface for TCP remote connection
  20. ** 1.1 - Added multicast support
  21. */
  22. #ifndef SOCKETHANDLE_H
  23. #define SOCKETHANDLE_H
  24. #pragma once
  25. #ifdef WIN32
  26. #include <winsock2.h>
  27. #include <ws2tcpip.h>
  28. #elif BSD_SOCKET
  29. #include "platform.h"
  30. #endif
  31. /**
  32. * @defgroup _SockHandle Socket Communication Classes
  33. * @{
  34. */
  35. /**
  36. * SockAddrIn structure
  37. * Encapsulate SOCKADDR_STORAGE (IPv4: SOCKADDR_IN, IPv6: SOCKADDR_IN6) structures
  38. */
  39. struct SockAddrIn : public sockaddr_storage {
  40. public:
  41. /**
  42. * Default constructor
  43. */
  44. SockAddrIn();
  45. /**
  46. * Copy constructor
  47. * @param sin reference object
  48. */
  49. SockAddrIn(const SockAddrIn& sin);
  50. /**
  51. * Destructor
  52. */
  53. ~SockAddrIn();
  54. /**
  55. * Copy function
  56. * @param sin reference object
  57. * @return reference of 'this' object
  58. */
  59. SockAddrIn& Copy(const SockAddrIn& sin);
  60. /**
  61. * Clear struct
  62. */
  63. void Clear();
  64. /**
  65. * Compare NetworkAddr object
  66. * @param sin reference object
  67. * @return true if equal, otherwise false
  68. */
  69. bool IsEqual(const SockAddrIn& sin) const;
  70. /**
  71. * Check if NULL
  72. * @return true if object is 'NULL' - not valid
  73. */
  74. bool IsNull() const { return IsEqual(NULLAddr); }
  75. /**
  76. * Get Socket address family
  77. * @return Socket address family (IPv4: AF_INET, IPv6: AF_INET6)
  78. */
  79. short GetFamily () const { return ss_family; }
  80. /**
  81. * Get IP address (IPv4)
  82. * @return IPv4 network address in network format
  83. */
  84. ULONG GetIPAddr() const { return ((SOCKADDR_IN*)this)->sin_addr.s_addr; }
  85. /**
  86. * Get Port
  87. * @return Port number in network format
  88. */
  89. short GetPort() const { return ((SOCKADDR_IN*)this)->sin_port; }
  90. /**
  91. * Create from string. Service is service name or port number.
  92. * @param pszAddr Hostname or IP address
  93. * @param pszService Service name or port
  94. * @param nFamily Socket address family (default: AF_INET, AF_INET6)
  95. * @return true if object is now valid
  96. */
  97. bool CreateFrom(LPCTSTR pszAddr, LPCTSTR pszService, int nFamily = AF_INET);
  98. /**
  99. * Create from number. Initialize object from host or network format values (IPv4 only).
  100. * @param lIPAddr IP Address
  101. * @param nPort Port number
  102. * @param nFamily Socket address family (default: AF_INET)
  103. * @param bFmtHost flag to indicate that IP address and port are in host (true) or network format (false)
  104. * @return true if object is now valid
  105. */
  106. bool CreateFrom(ULONG lIPAddr, USHORT nPort, int nFamily = AF_INET, bool bFmtHost = true);
  107. /**
  108. * Object copy operator
  109. * @param sin reference object to copy from
  110. * @return reference of 'this' object
  111. */
  112. SockAddrIn& operator=(const SockAddrIn& sin) { return Copy( sin ); }
  113. /**
  114. * Equality operator
  115. * @param sin reference object to test
  116. * @return true if object is equal
  117. */
  118. bool operator==(const SockAddrIn& sin) const { return IsEqual( sin ); }
  119. /**
  120. * Not Equal operator
  121. * @param sin reference object to test
  122. * @return true if object is different
  123. */
  124. bool operator!=(const SockAddrIn& sin) const { return !IsEqual( sin ); }
  125. /**
  126. * SOCKADDR conversion. Return SOCKADDR of this object.
  127. */
  128. operator LPSOCKADDR() { return reinterpret_cast<LPSOCKADDR>(this); }
  129. /**
  130. * PIN6_ADDR conversion. Return const PIN6_ADDR of this object.
  131. */
  132. operator const IN6_ADDR*() const { return reinterpret_cast<const IN6_ADDR*>(this); }
  133. /**
  134. * PIN6_ADDR conversion. Return PIN6_ADDR of this object.
  135. */
  136. operator PIN6_ADDR() { return reinterpret_cast<PIN6_ADDR>(this); }
  137. /**
  138. * Size of this struct (SOCKADDR_IN) or (SOCKADDR_STORAGE) depending on address family
  139. * @return size of this structure (SOCKADDR_IN) or (SOCKADDR_STORAGE)
  140. */
  141. size_t Size() const { return (ss_family == AF_INET) ? sizeof(sockaddr_in) : sizeof(sockaddr_storage); }
  142. /**
  143. * Initialize this object from SOCKADDR_IN struct.
  144. * @param psin SOCKADDR_IN object pointer
  145. */
  146. void SetAddr(const sockaddr_in* psin) { SetAddr(reinterpret_cast<const sockaddr_storage*>(psin)); }
  147. /**
  148. * Initialize this object from SOCKADDR_IN6 struct.
  149. * @param psin SOCKADDR_IN6 object pointer
  150. */
  151. void SetAddr(const sockaddr_in6* psin) { SetAddr(reinterpret_cast<const sockaddr_storage*>(psin)); }
  152. /**
  153. * Initialize this object from SOCKADDR_STORAGE struct.
  154. * @param pss SOCKADDR_STORAGE object pointer
  155. */
  156. void SetAddr(const sockaddr_storage* pss) { ss_family = pss->ss_family; memcpy(this, pss, Size()); }
  157. static SockAddrIn NULLAddr; ///< Null Address
  158. };
  159. #ifdef WIN32
  160. typedef LPWSAOVERLAPPED_COMPLETION_ROUTINE LPWSACOMPLETIONROUTINE;
  161. #endif
  162. #define SOCKET_SERVER_PORT 6432
  163. #define SOCKET_BUFFSIZE 1024 * 10 //注意, 这里单个包的大小不能超过该设置数值
  164. /**
  165. * CSocketHandle class
  166. * Socket communication class
  167. */
  168. class CSocketHandle
  169. {
  170. public:
  171. /**
  172. * Default constructor
  173. */
  174. CSocketHandle();
  175. /**
  176. * Destructor
  177. */
  178. ~CSocketHandle();
  179. /**
  180. * Check if socket is opened
  181. * @return true if this is opened (valid)
  182. */
  183. bool IsOpen() const;
  184. /**
  185. * Get SOCKET handle
  186. * @return SOCKET handle (handle is INVALID_SOCKET if object is closed)
  187. */
  188. SOCKET GetSocket() const;
  189. /**
  190. * Get SOCKET type
  191. * @return SOCKET type (-1 if not a valid socket)
  192. */
  193. int GetSocketType() const;
  194. /**
  195. * Attach a socket handle
  196. * This function may fail is socket handle is not valid or object already in used. Call Detach or Close to release object.
  197. * @param sock Socket handle to attach to this class
  198. * @return true if successful, otherwise false
  199. */
  200. bool Attach(SOCKET sock);
  201. /**
  202. * Detach a socket handle
  203. * @return previous socket handle or INVALID_SOCKET
  204. */
  205. SOCKET Detach();
  206. /**
  207. * Create a Socket - Server side.
  208. * @param pszHost hostname or IP address of adapter
  209. * @param pszServiceName Network service name or port number
  210. * @param nFamily address family to use (AF_INET, AF_INET6)
  211. * @param nType type of socket to create (SOCK_STREAM, SOCK_DGRAM)
  212. * @param uOptions Additional options (SO_BROADCAST, SO_REUSEADDR)
  213. * @return true if successful, otherwise false (call WSAGetLastError() to retrieve latest error)
  214. * @sa InitLibrary, ConnectTo, IsOpen
  215. */
  216. bool CreateSocket(LPCTSTR pszHost, LPCTSTR pszServiceName, int nFamily, int nType, UINT uOptions = 0);
  217. /**
  218. * Create a socket, connect to a server - Client side.
  219. * @param pszHostName Hostname or NIC address
  220. * @param pszRemote Remote network address
  221. * @param pszServiceName Network service name or port number
  222. * @param nFamily address family to use (AF_INET, AF_INET6)
  223. * @param nType type of socket to create (SOCK_STREAM, SOCK_DGRAM)
  224. * @return true if successful, otherwise false (call WSAGetLastError() to retrieve latest error)
  225. * @sa InitLibrary, CreateSocket, IsOpen
  226. */
  227. bool ConnectTo(LPCTSTR pszHostName, LPCTSTR pszRemote, LPCTSTR pszServiceName, int nFamily, int nType);
  228. /**
  229. * Close Socket
  230. * @sa InitLibrary, CreateSocket, ConnectTo, IsOpen
  231. */
  232. void Close();
  233. /**
  234. * Read from socket
  235. * @param lpBuffer Buffer to receive data
  236. * @param dwSize Size of buffer in bytes
  237. * @param lpAddrIn Peer address for UDP - this must be NULL for TCP
  238. * @param dwTimeout Read timeout in milliseconds
  239. * @return number of bytes read or (-1L) if fail
  240. * @sa InitLibrary, CreateSocket, ConnectTo, IsOpen, ReadEx, Write, WriteEx
  241. */
  242. DWORD Read(LPBYTE lpBuffer, DWORD dwSize, LPSOCKADDR lpAddrIn = NULL, DWORD dwTimeout = INFINITE);
  243. #ifdef WIN32
  244. /**
  245. * Read from socket (asynchronous mode).
  246. * @param lpBuffer Buffer to receive data
  247. * @param dwSize Size of buffer in bytes
  248. * @param lpAddrIn SockAddrIn for UDP - this must be NULL for TCP
  249. * @param lpOverlapped Windows Overlapped structure (required)
  250. * @param lpCompletionRoutine Winsock Completion routine (required)
  251. * @return number of bytes read, overlapped operation is pending or (-1L) if fail
  252. * @sa InitLibrary, CreateSocket, ConnectTo, IsOpen, Read, Write, WriteEx, IOControl, GetTransferOverlappedResult
  253. */
  254. DWORD ReadEx(LPBYTE lpBuffer, DWORD dwSize, LPSOCKADDR lpAddrIn,
  255. LPWSAOVERLAPPED lpOverlapped, LPWSACOMPLETIONROUTINE lpCompletionRoutine);
  256. #endif
  257. /**
  258. * Write to a destination socket
  259. * @param lpBuffer Buffer to send
  260. * @param dwCount Number of bytes to send
  261. * @param lpAddrIn Peer address for UDP - this must be NULL for TCP
  262. * @param dwTimeout Write timeout in milliseconds
  263. * @return number of bytes sent or (-1L) if fail
  264. * @sa InitLibrary, CreateSocket, ConnectTo, IsOpen, Read, ReadEx, WriteEx
  265. */
  266. DWORD Write(const LPBYTE lpBuffer, DWORD dwCount, const LPSOCKADDR lpAddrIn = NULL, DWORD dwTimeout = INFINITE);
  267. #ifdef WIN32
  268. /**
  269. * Write to a destination socket (asynchronous mode).
  270. * @param lpBuffer Buffer to send
  271. * @param dwCount Number of bytes to send
  272. * @param lpAddrIn SockAddrIn for UDP - this must be NULL for TCP
  273. * @param lpOverlapped Windows Overlapped structure (required)
  274. * @param lpCompletionRoutine Winsock Completion routine (required)
  275. * @return number of bytes read, overlapped operation is pending or (-1L) if fail
  276. * @sa InitLibrary, CreateSocket, ConnectTo, IsOpen, Read, ReadEx, Write, IOControl, GetTransferOverlappedResult
  277. */
  278. DWORD WriteEx(const LPBYTE lpBuffer, DWORD dwCount, const LPSOCKADDR lpAddrIn,
  279. LPWSAOVERLAPPED lpOverlapped, LPWSACOMPLETIONROUTINE lpCompletionRoutine);
  280. #endif
  281. #ifdef WIN32
  282. /**
  283. * Control the mode of a socket (asynchronous mode)
  284. * @param dwIoCode Control code of operation to perform
  285. * @param lpInBuffer Pointer to the input buffer
  286. * @param cbInBuffer Size of the input buffer, in bytes
  287. * @param lpOutBuffer Pointer to the output buffer
  288. * @param cbOutBuffer Size of the output buffer, in bytes
  289. * @param lpcbBytesReturned Pointer to actual number of bytes of output
  290. * @param lpOverlapped Winsock Overlapped structure
  291. * @param lpCompletionRoutine Winsock Completion routine
  292. * @return true if successful, otherwise false (call WSAGetLastError() to retrieve latest error)
  293. * @sa InitLibrary, CreateSocket, ConnectTo, IsOpen, ReadEx, WriteEx, GetTransferOverlappedResult
  294. */
  295. bool IOControl(DWORD dwIoCode, LPBYTE lpInBuffer, DWORD cbInBuffer,
  296. LPBYTE lpOutBuffer, DWORD cbOutBuffer,
  297. LPDWORD lpcbBytesReturned, LPWSAOVERLAPPED lpOverlapped,
  298. LPWSACOMPLETIONROUTINE lpCompletionRoutine);
  299. /**
  300. * Get Overlapped result (asynchronous mode)
  301. * @param lpOverlapped Windows Overlapped structure (required)
  302. * @param lpcbTransfer Pointer to get number of bytes transferred
  303. * @param bWait Force wait for overlapped operation to complete
  304. * @param lpdwFlags Optional flags (see MSDN on WSARecv API)
  305. * @sa InitLibrary, CreateSocket, ConnectTo, IsOpen, ReadEx, WriteEx, IOControl
  306. */
  307. bool GetTransferOverlappedResult(LPWSAOVERLAPPED lpOverlapped, LPDWORD lpcbTransfer, bool bWait = true, LPDWORD lpdwFlags = 0);
  308. #endif
  309. /**
  310. * Get Socket name - get local address
  311. * @param saddr_in current local address and port when connected
  312. * @return true if successful
  313. * @sa InitLibrary
  314. */
  315. bool GetSockName(SockAddrIn& saddr_in) const;
  316. /**
  317. * Get Peer Socket name - get peer address
  318. * @param saddr_in peer address and port (use only with TCP or client mode UDP)
  319. * @return true if successful
  320. * @sa InitLibrary
  321. */
  322. bool GetPeerName(SockAddrIn& saddr_in) const;
  323. /**
  324. * Register to multicast address
  325. * @param pszIPAddr multicast IP group
  326. * @param pszNIC interface IP address
  327. * @return true if successful
  328. * @sa InitLibrary
  329. */
  330. bool AddMembership(LPCTSTR pszIPAddr, LPCTSTR pszNIC);
  331. /**
  332. * Unregister from a multicast address
  333. * @param pszIPAddr multicast IP group
  334. * @param pszNIC interface IP address
  335. * @return true if successful
  336. * @sa InitLibrary
  337. */
  338. bool DropMembership(LPCTSTR pszIPAddr, LPCTSTR pszNIC);
  339. /**
  340. * Initialize Winsock library. This function calls WSAStartup.
  341. * @param wVersion Winsock version use MAKEWORD macro if possible (e.g.: MAKEWORD(2,2))
  342. * @return true if successful
  343. * @sa ReleaseLibrary
  344. */
  345. static bool InitLibrary(WORD wVersion);
  346. /**
  347. * Release Winsock library
  348. * @return true if successful
  349. * @sa InitLibrary
  350. */
  351. static bool ReleaseLibrary();
  352. /**
  353. * Wait for a new connection
  354. * @param sock A TCP socket handle. A new socket is return returned.
  355. * @return A new socket when a new client connects
  356. * @sa GetSocket, CreateSocket
  357. */
  358. static SOCKET WaitForConnection(SOCKET sock);
  359. /**
  360. * Shutdown a connection
  361. * @param sock Socket to shutdown communication
  362. * @return true if successful
  363. */
  364. static bool ShutdownConnection(SOCKET sock);
  365. /**
  366. * Check if IP address is unicast (network order).
  367. * @param ulAddr IP address (expected valid unicast address)
  368. * @return true if successful
  369. */
  370. static bool IsUnicastIP( ULONG ulAddr );
  371. /**
  372. * Check if IP address is multicast (network order).
  373. * @param ulAddr IP address (expected valid multicast address)
  374. * @return true if successful
  375. */
  376. static bool IsMulticastIP( ULONG ulAddr );
  377. /**
  378. * Format IP address to string
  379. * @param pszIPAddr Buffer to hold string
  380. * @param nSize Size of buffer in characters
  381. * @param ulAddr IP Address to format
  382. * @param bFmtHost Specify if address (ulAddr) is in host (true) or network format (false)
  383. * @return true if successful. Possible error could be INSUFFICIENT_BUFFER
  384. */
  385. static bool FormatIP(LPTSTR pszIPAddr, UINT nSize, ULONG ulAddr, bool bFmtHost);
  386. /**
  387. * Format IP address to string
  388. * @param pszIPAddr Buffer to hold string
  389. * @param nSize Size of buffer in characters
  390. * @param addrIn IP Address to format
  391. * @return true if successful. Possible error could be INSUFFICIENT_BUFFER
  392. */
  393. static bool FormatIP(LPTSTR pszIPAddr, UINT nSize, const SockAddrIn& addrIn);
  394. /**
  395. * Get service port number
  396. * @param pszServiceName Network service name (e.g.: "ftp", "telnet") or port number
  397. * @return port number
  398. */
  399. static USHORT GetPortNumber( LPCTSTR pszServiceName );
  400. /**
  401. * Get IP address of a host
  402. * @param pszHostName host name or IP address
  403. * @return Host IP address in host format
  404. * @sa GetAddressInfo
  405. */
  406. static ULONG GetIPAddress( LPCTSTR pszHostName );
  407. /**
  408. * Get current localname for this machine
  409. * @param pszName Buffer to receive host name
  410. * @param nSize Size of this buffer in character
  411. * @return true if successful
  412. */
  413. static bool GetLocalName(LPTSTR pszName, UINT nSize);
  414. /**
  415. * Get current (default) IP address for this machine
  416. * @param pszAddress Buffer to receive IP address (IPv4, IPv6 format)
  417. * @param nSize Size of this buffer in character
  418. * @param nFamily address family to use (AF_INET, AF_INET6)
  419. * @return true if successful
  420. */
  421. static bool GetLocalAddress(LPTSTR pszAddress, UINT nSize, int nFamily = AF_INET);
  422. /**
  423. * Get IP address info of a host (Supports: IPv4 and IPv6)
  424. * @param pszHostName host name or IP address
  425. * @param pszServiceName pszServiceName Network service name (e.g.: "ftp", "telnet") or port number
  426. * @param nFamily address family to use (AF_INET, AF_INET6)
  427. * @param sockAddr Socket address to fill in
  428. * @return true if successful
  429. */
  430. static bool GetAddressInfo( LPCTSTR pszHostName, LPCTSTR pszServiceName, int nFamily, SockAddrIn& sockAddr);
  431. // CSocketHandle - data
  432. protected:
  433. SOCKET m_hSocket; ///< socket handle
  434. public:
  435. char m_PendingBuffer[ SOCKET_BUFFSIZE ];
  436. int m_nPendingSize;
  437. CRITICAL_SECTION m_hClient2SrvSection;
  438. };
  439. /** @}*/
  440. #endif //SOCKETHANDLE_H