PageRenderTime 59ms CodeModel.GetById 29ms RepoModel.GetById 0ms app.codeStats 0ms

/include/ulib/net/socket.h

https://github.com/alepharchives/ULib
C Header | 688 lines | 350 code | 164 blank | 174 comment | 11 complexity | aea2ca19ff2ad481c3a1fc5da3e01544 MD5 | raw file
Possible License(s): GPL-2.0, AGPL-1.0
  1. // ============================================================================
  2. //
  3. // = LIBRARY
  4. // ulib - c++ library
  5. //
  6. // = FILENAME
  7. // socket.h
  8. //
  9. // = AUTHOR
  10. // Stefano Casazza
  11. //
  12. // ============================================================================
  13. #ifndef ULIB_SOCKET_H
  14. #define ULIB_SOCKET_H 1
  15. #include <ulib/net/ipaddress.h>
  16. #ifdef HAVE_SYS_SENDFILE_H
  17. # ifndef HAVE_SENDFILE64
  18. # undef __USE_FILE_OFFSET64
  19. # endif
  20. # include <sys/sendfile.h>
  21. # ifndef HAVE_SENDFILE64
  22. # define __USE_FILE_OFFSET64
  23. # endif
  24. #endif
  25. #ifdef __MINGW32__
  26. # include <ws2tcpip.h>
  27. # define CAST(a) (char*)a
  28. #else
  29. # define CAST(a) a
  30. # include <netinet/tcp.h>
  31. #endif
  32. #include <errno.h>
  33. #if !defined(ENABLE_IPV6) && !defined(AF_INET6)
  34. # define AF_INET6 AF_INET
  35. #endif
  36. #ifndef SOL_TCP
  37. #define SOL_TCP IPPROTO_TCP
  38. #endif
  39. /* Atomically mark descriptor(s) as non-blocking */
  40. #ifndef SOCK_NONBLOCK
  41. #define SOCK_NONBLOCK 04000
  42. #endif
  43. /* Atomically set close-on-exec flag for the new descriptor(s) */
  44. #ifndef SOCK_CLOEXEC
  45. #define SOCK_CLOEXEC 02000000
  46. #endif
  47. /**
  48. @class USocket
  49. @brief basic IP socket functionality
  50. This class is used to provide basic IP socket functionality within a C++ class environment.
  51. The socket descriptor is stored as a member variable within the socket class.
  52. The member methods are simple wrappers to the standard socket library function calls except
  53. they use class UIPAddress instances and port numbers rather than sockaddr structures
  54. */
  55. class UHTTP;
  56. class UFile;
  57. class UNotifier;
  58. class USocketExt;
  59. class USSHSocket;
  60. class USSLSocket;
  61. class UTCPSocket;
  62. class UUnixSocket;
  63. class USmtpClient;
  64. class UImapClient;
  65. class UPop3Client;
  66. class UClient_Base;
  67. class UServer_Base;
  68. class SocketAddress;
  69. class UClientImage_Base;
  70. #define U_socket_IPv6(obj) (obj)->USocket::flag[0]
  71. #define U_socket_LocalSet(obj) (obj)->USocket::flag[1]
  72. #define U_socket_unused1(obj) (obj)->USocket::flag[2]
  73. #define U_socket_unused2(obj) (obj)->USocket::flag[3]
  74. class U_EXPORT USocket {
  75. public:
  76. // Check for memory error
  77. U_MEMORY_TEST
  78. // Allocator e Deallocator
  79. U_MEMORY_ALLOCATOR
  80. U_MEMORY_DEALLOCATOR
  81. static const UString* str_host;
  82. static const UString* str_range;
  83. static const UString* str_close;
  84. static const UString* str_cookie;
  85. static const UString* str_setcookie;
  86. static const UString* str_starttls;
  87. static const UString* str_location;
  88. static const UString* str_refresh;
  89. static const UString* str_connection;
  90. static const UString* str_user_agent;
  91. static const UString* str_authorization;
  92. static const UString* str_content_type;
  93. static const UString* str_content_length;
  94. static const UString* str_content_disposition;
  95. static const UString* str_accept;
  96. static const UString* str_accept_language;
  97. static const UString* str_accept_encoding;
  98. static const UString* str_if_range;
  99. static const UString* str_if_none_match;
  100. static const UString* str_if_modified_since;
  101. static const UString* str_if_unmodified_since;
  102. static const UString* str_referer;
  103. static const UString* str_X_Real_IP;
  104. static const UString* str_X_Forwarded_For;
  105. static const UString* str_Transfer_Encoding;
  106. static const UString* str_X_Progress_ID;
  107. static const UString* str_expect_100_continue;
  108. static const UString* str_chunked;
  109. static void str_allocate();
  110. // COSTRUTTORI
  111. static int accept4_flags; // If flags is 0, then accept4() is the same as accept()
  112. enum State {
  113. CLOSE = 0x000,
  114. TIMEOUT = 0x001,
  115. BROKEN = 0x002,
  116. EPOLLERROR = 0x004,
  117. CONNECT = 0x008,
  118. LOGIN = 0x010
  119. };
  120. USocket(bool bSocketIsIPv6 = false);
  121. virtual ~USocket();
  122. #ifdef __MINGW32__
  123. int getFd() const { return fh; }
  124. #else
  125. int getFd() const { return iSockDesc; }
  126. #endif
  127. bool isOpen() const { return (iSockDesc > 0); }
  128. bool isLogin() const { return (iState == LOGIN); }
  129. bool isClosed() const { return (iSockDesc <= 0); }
  130. bool isBroken() const { return ((iState & BROKEN) != 0); }
  131. bool isTimeout() const { return ((iState & TIMEOUT) != 0); }
  132. bool isEpollErr() const { return ((iState & EPOLLERROR) != 0); }
  133. bool isSysError() const { return (iState < CLOSE); }
  134. bool isConnected() const { return (iState >= CONNECT); }
  135. /**
  136. This method is called after read block of data of remote connection
  137. */
  138. void checkErrno();
  139. bool checkTime(long time_limit, long& timeout);
  140. /**
  141. This method is called after send block of data to remote connection
  142. */
  143. bool checkIO(int iBytesTransferred)
  144. {
  145. U_TRACE(0, "USocket::checkIO(%d)", iBytesTransferred)
  146. if (iBytesTransferred <= 0)
  147. {
  148. if (iBytesTransferred < 0) checkErrno();
  149. U_RETURN(false);
  150. }
  151. U_RETURN(true);
  152. }
  153. /**
  154. The socket() function is called to create the socket of the specified type.
  155. The parameters indicate whether the socket will use IPv6 or IPv4 and the type of socket
  156. (the default being SOCK_STREAM or TCP). The returned descriptor is stored in iSockDesc
  157. */
  158. static int socket(int domain, int type, int protocol)
  159. {
  160. U_TRACE(1, "USocket::socket(%d,%d,%d)", domain, type, protocol)
  161. int fd = U_SYSCALL(socket, "%d,%d,%d", domain, type, protocol);
  162. U_RETURN(fd);
  163. }
  164. bool socket(int iSocketType, int protocol = 0);
  165. void close()
  166. {
  167. U_TRACE(0, "USocket::close()")
  168. closesocket();
  169. iState = CLOSE;
  170. }
  171. /**
  172. The getsockopt() function is called with the provided parameters to obtain the desired value
  173. */
  174. bool getSockOpt(int iCodeLevel, int iOptionName, void* pOptionData, uint32_t& iDataLength)
  175. {
  176. U_TRACE(1, "USocket::getSockOpt(%d,%d,%p,%p)", iCodeLevel, iOptionName, pOptionData, iDataLength)
  177. U_CHECK_MEMORY
  178. U_INTERNAL_ASSERT(isOpen())
  179. bool result = (U_SYSCALL(getsockopt, "%d,%d,%d,%p,%p", getFd(), iCodeLevel, iOptionName, CAST(pOptionData), (socklen_t*)&iDataLength) == 0);
  180. U_RETURN(result);
  181. }
  182. /**
  183. The setsockopt() function is called with the provided parameters to obtain the desired value
  184. */
  185. bool setSockOpt(int iCodeLevel, int iOptionName, const void* pOptionData, uint32_t iDataLength)
  186. {
  187. U_TRACE(1, "USocket::setSockOpt(%d,%d,%p,%u)", iCodeLevel, iOptionName, pOptionData, iDataLength)
  188. U_CHECK_MEMORY
  189. U_INTERNAL_ASSERT(isOpen())
  190. bool result = (U_SYSCALL(setsockopt, "%d,%d,%d,%p,%u", getFd(), iCodeLevel, iOptionName, CAST(pOptionData), iDataLength) == 0);
  191. U_RETURN(result);
  192. }
  193. /**
  194. Actual state is blocking...?
  195. */
  196. bool isBlocking()
  197. {
  198. U_TRACE(0, "USocket::isBlocking()")
  199. U_CHECK_MEMORY
  200. U_INTERNAL_ASSERT(isOpen())
  201. U_INTERNAL_DUMP("O_NONBLOCK = %B, flags = %B", O_NONBLOCK, flags)
  202. bool blocking = ((flags & O_NONBLOCK) != O_NONBLOCK);
  203. U_RETURN(blocking);
  204. }
  205. /**
  206. Connect the socket to the specified server IP Address and port number
  207. */
  208. bool connectServer(const UIPAddress& cAddr, int iServPort);
  209. /**
  210. The method is called with a local IP address and port number to bind the socket to.
  211. A default port number of zero is a wildcard and lets the OS choose the port number
  212. */
  213. bool bind( int iLocalPort = 0);
  214. bool bind(UIPAddress& cLocalAddr, int iLocalPort = 0);
  215. /**
  216. The iBackLog parameter indicates the number of unconnected sockets that can be pending in the socket queue
  217. */
  218. void listen(int iBackLog = 5)
  219. {
  220. U_TRACE(1, "USocket::listen(%d)", iBackLog)
  221. U_CHECK_MEMORY
  222. U_INTERNAL_ASSERT(isOpen())
  223. (void) U_SYSCALL(listen, "%d,%d", getFd(), iBackLog);
  224. }
  225. /**
  226. Get details of the IP address and port number bound to the local socket
  227. */
  228. UIPAddress& localIPAddress() __pure;
  229. int localPortNumber() __pure;
  230. const char* getLocalInfo()
  231. {
  232. U_TRACE(0, "USocket::getLocalInfo()")
  233. U_CHECK_MEMORY
  234. U_INTERNAL_ASSERT(isLocalSet())
  235. const char* address = cLocalAddress.getAddressString();
  236. U_RETURN(address);
  237. }
  238. /**
  239. This method is called when the local socket address is valid.
  240. It sets the LocalSet flag, obtains details of the local address and stores them in the internal member variables
  241. */
  242. void setLocal();
  243. void setLocal(const UIPAddress& addr)
  244. {
  245. U_TRACE(0, "USocket::setLocal(%p)", &addr)
  246. cLocalAddress = addr;
  247. U_socket_LocalSet(this) = true;
  248. }
  249. bool isLocalSet() const { return U_socket_LocalSet(this); }
  250. /**
  251. Get details of the IP address and port number bound to the remote socket
  252. */
  253. int remotePortNumber()
  254. {
  255. U_TRACE(0, "USocket::remotePortNumber()")
  256. U_CHECK_MEMORY
  257. U_RETURN(iRemotePort);
  258. }
  259. UIPAddress& remoteIPAddress()
  260. {
  261. U_TRACE(0, "USocket::remoteIPAddress()")
  262. U_CHECK_MEMORY
  263. return cRemoteAddress;
  264. }
  265. /**
  266. This method manage the buffer of the socket connection
  267. */
  268. uint32_t getBufferRCV()
  269. {
  270. U_TRACE(1, "USocket::getBufferRCV()")
  271. uint32_t size = U_NOT_FOUND, tmp = sizeof(uint32_t);
  272. (void) getSockOpt(SOL_SOCKET, SO_RCVBUF, (void*)&size, tmp);
  273. U_RETURN(size);
  274. }
  275. uint32_t getBufferSND()
  276. {
  277. U_TRACE(1, "USocket::getBufferSND()")
  278. uint32_t size = U_NOT_FOUND, tmp = sizeof(uint32_t);
  279. (void) getSockOpt(SOL_SOCKET, SO_SNDBUF, (void*)&size, tmp);
  280. U_RETURN(size);
  281. }
  282. bool setBufferRCV(uint32_t size)
  283. {
  284. U_TRACE(1, "USocket::setBufferRCV(%u)", size)
  285. bool result = setSockOpt(SOL_SOCKET, SO_RCVBUF, (const void*)&size, sizeof(uint32_t));
  286. U_RETURN(result);
  287. }
  288. bool setBufferSND(uint32_t size)
  289. {
  290. U_TRACE(1, "USocket::setBufferSND(%u)", size)
  291. bool result = setSockOpt(SOL_SOCKET, SO_SNDBUF, (const void*)&size, sizeof(uint32_t));
  292. U_RETURN(result);
  293. }
  294. /* The shutdown() tells the receiver the server is done sending data. No
  295. * more data is going to be send. More importantly, it doesn't close the
  296. * socket. At the socket layer, this sends a TCP/IP FIN packet to the receiver
  297. */
  298. bool shutdown(int how = SHUT_WR)
  299. {
  300. U_TRACE(1, "USocket::shutdown(%d)", how)
  301. U_CHECK_MEMORY
  302. U_INTERNAL_ASSERT(isOpen())
  303. bool result = (U_SYSCALL(shutdown, "%d,%d", getFd(), how) == 0);
  304. U_RETURN(result);
  305. }
  306. /**
  307. * Stick a TCP cork in the socket. It's not clear that this will help performance, but it might.
  308. *
  309. * TCP_CORK: If set, don't send out partial frames. All queued partial frames are sent when the option is cleared again. This is useful
  310. * for prepending headers before calling sendfile(), or for throughput optimization. As currently implemented, there is a 200
  311. * millisecond ceiling on the time for which output is corked by TCP_CORK. If this ceiling is reached, then queued data is
  312. * automatically transmitted.
  313. *
  314. * This is a no-op if we don't think this platform has corks.
  315. ***/
  316. void setTcpCork(uint32_t corked)
  317. {
  318. U_TRACE(0, "USocket::setTcpCork(%u)", corked)
  319. # ifdef TCP_CORK
  320. (void) setSockOpt(SOL_TCP, TCP_CORK, (const void*)&corked, sizeof(uint32_t));
  321. # endif
  322. }
  323. /**
  324. * Ask for the server not to be awakened until some data has arrived on the socket. Takes an integer value (seconds), this can bound the
  325. * maximum number of attempts TCP will make to complete the connection. This works for RPC protocol because the client sends a request immediately
  326. * after connection without waiting for anything from the server.
  327. ***/
  328. void setTcpDeferAccept(uint32_t value)
  329. {
  330. U_TRACE(0, "USocket::setTcpDeferAccept(%u)", value)
  331. # ifdef TCP_DEFER_ACCEPT
  332. (void) setSockOpt(SOL_TCP, TCP_DEFER_ACCEPT, (const void*)&value, sizeof(uint32_t));
  333. # endif
  334. }
  335. void setTcpQuickAck(uint32_t value)
  336. {
  337. U_TRACE(0, "USocket::setTcpQuickAck(%u)", value)
  338. # ifdef TCP_QUICKACK
  339. (void) setSockOpt(SOL_TCP, TCP_QUICKACK, (const void*)&value, sizeof(uint32_t));
  340. # endif
  341. }
  342. void setTcpNoDelay(uint32_t value)
  343. {
  344. U_TRACE(0, "USocket::setTcpNoDelay(%u)", value)
  345. # ifdef TCP_NODELAY
  346. (void) setSockOpt(SOL_TCP, TCP_NODELAY, (const void*)&value, sizeof(uint32_t));
  347. # endif
  348. }
  349. void setTcpFastOpen(uint32_t value)
  350. {
  351. U_TRACE(0, "USocket::setTcpFastOpen(%u)", value)
  352. # ifdef TCP_FASTOPEN
  353. (void) setSockOpt(SOL_TCP, TCP_FASTOPEN, (const void*)&value, sizeof(uint32_t));
  354. # endif
  355. }
  356. void setTcpCongestion(const char* value)
  357. {
  358. U_TRACE(0, "USocket::setTcpCongestion(%S)", value)
  359. # ifdef TCP_CONGESTION
  360. (void) setSockOpt(IPPROTO_TCP, TCP_CONGESTION, (const void*)&value, u__strlen(value, __PRETTY_FUNCTION__) + 1);
  361. # endif
  362. }
  363. /**
  364. Enables/disables the @c SO_TIMEOUT pseudo option
  365. @c SO_TIMEOUT is not one of the options defined for Berkeley sockets, but was actually introduced
  366. as part of the Java API. For client sockets it has the same meaning as the @c SO_RCVTIMEO option,
  367. which specifies the maximum number of milliseconds that a blocking @c read() call will wait for
  368. data to arrive on the socket. Timeouts only have effect for system calls that perform socket I/O
  369. (e.g., read(2), recvmsg(2), send(2), sendmsg(2));
  370. @param timeoutMS the specified timeout value, in milliseconds. A zero value indicates no timeout, i.e. an infinite wait
  371. */
  372. bool setTimeoutRCV(uint32_t timeoutMS = U_TIMEOUT_MS);
  373. bool setTimeoutSND(uint32_t timeoutMS = U_TIMEOUT_MS);
  374. /**
  375. The recvfrom() function is called with the proper parameters, params is placed for obtaining
  376. the source address information. The number of bytes read is returned
  377. */
  378. int recvFrom(void* pBuffer, uint32_t iBufLength, uint32_t uiFlags, UIPAddress& cSourceIP, int& iSourcePortNumber);
  379. /**
  380. The socket transmits the data to the remote socket.
  381. */
  382. int sendTo(void* pPayload, uint32_t iPayloadLength, uint32_t uiFlags, UIPAddress& cDestinationIP, int iDestinationPortNumber);
  383. /**
  384. This method is called to receive a block of data on the connected socket.
  385. The parameters signify the payload receiving buffer and its size.
  386. If the socket is not connected, then we failed on assertion, otherwise we call
  387. the recv() system call to receive the data, returning the number of bytes actually readden
  388. */
  389. static int recv(int fd, void* buf, uint32_t len, int recv_flags);
  390. /**
  391. This method is called to read a 16-bit binary value from the remote connection.
  392. We loop - calling recv() - until the required number of bytes are read, if recv()
  393. returns a smaller number of bytes due to the remaining values not yet arriving, we go back into a loop.
  394. Once the value is read into uiNetOrder, we convert it to host byte order and return the read value
  395. */
  396. int recvBinary16Bits();
  397. /**
  398. This method is called to read a 32-bit binary value from the remote connection.
  399. We loop - calling recv() - until the required number of bytes are read, if recv()
  400. returns a smaller number of bytes due to the remaining values not yet arriving, we go back into a loop.
  401. Once the value is read into uiNetOrder, we convert it to host byte order and return the read value
  402. */
  403. uint32_t recvBinary32Bits();
  404. /**
  405. This method is called to send a 16-bit binary value to the remote connection.
  406. We convert the parameter to network byte order and call the send() method to send it.
  407. If two bytes are not sent (the returned value is not two), return false
  408. */
  409. bool sendBinary16Bits(uint16_t iData);
  410. /**
  411. This method is called to send a 32-bit binary value to the remote connection.
  412. We convert the parameter to network byte order and call the send() method to send it.
  413. If four bytes are not sent (the returned value is not four), return false
  414. */
  415. bool sendBinary32Bits(uint32_t lData);
  416. // -----------------------------------------------------------------------------------------------------------
  417. // VIRTUAL METHOD
  418. // -----------------------------------------------------------------------------------------------------------
  419. virtual bool isSSL() const
  420. {
  421. U_TRACE(0, "USocket::isSSL()")
  422. U_RETURN(false);
  423. }
  424. virtual bool isIPC() const
  425. {
  426. U_TRACE(0, "USocket::isIPC()")
  427. U_RETURN(false);
  428. }
  429. #ifdef closesocket
  430. #undef closesocket
  431. #endif
  432. virtual void closesocket() { _closesocket(); }
  433. virtual const char* getMsgError(char* buffer, uint32_t buffer_size);
  434. /**
  435. This method is called to connect the socket to a server TCP socket that is specified
  436. by the provided IP Address and port number. We call the connect() method to perform the connection
  437. */
  438. virtual bool connectServer(const UString& server, int iServPort);
  439. /**
  440. The default local port number is automatically allocated, the default back logged queue length is 5.
  441. We then try to bind the USocket to the specified port number and any local IP Address using the bind() method.
  442. Following this, we call the listen() method to cause the socket to begin listening for new connections
  443. */
  444. virtual bool setServer( int port, int iBackLog);
  445. virtual bool setServer(const UString& cLocalAddr, int port, int iBackLog);
  446. /**
  447. This method is called to accept a new pending connection on the server socket.
  448. The USocket pointed to by the provided parameter is modified to refer to the
  449. newly connected socket. The remote IP Address and port number are also set.
  450. */
  451. virtual bool acceptClient(USocket* pcConnection);
  452. /**
  453. This method is called to receive a block of data on the connected socket.
  454. The parameters signify the payload receiving buffer and its size.
  455. If the socket is not connected, then we failed on assertion, otherwise we call
  456. the recv() method to receive the data, returning the number of bytes actually readden
  457. */
  458. int recv(void* pBuffer, uint32_t iBufLength, int timeoutMS);
  459. virtual int recv(void* pBuffer, uint32_t iBufLength);
  460. /**
  461. This method is called to send a block of data to the remote connection.
  462. The parameters signify the Data Payload and its size.
  463. If the socket is not connected, then we failed on assertion, otherwise we call
  464. the send() method to send the data, returning the number of bytes actually sent
  465. */
  466. virtual int send(const char* pPayload, uint32_t iPayloadLength);
  467. int send(const void* pPayload, uint32_t iPayloadLength, int timeoutMS);
  468. // write data into multiple buffers
  469. virtual int writev(const struct iovec* iov, int iovcnt);
  470. int writev(const struct iovec* iov, int iovcnt, int timeoutMS);
  471. // -----------------------------------------------------------------------------------------------------------
  472. /*
  473. sendfile() copies data between one file descriptor and another. Either or both of these file descriptors may refer to a socket.
  474. OUT_FD should be a descriptor opened for writing. POFFSET is a pointer to a variable holding the input file pointer position from
  475. which sendfile() will start reading data. When sendfile() returns, this variable will be set to the offset of the byte following
  476. the last byte that was read. COUNT is the number of bytes to copy between file descriptors. Because this copying is done within
  477. the kernel, sendfile() does not need to spend time transferring data to and from user space.
  478. */
  479. bool sendfile(int in_fd, off_t* poffset, uint32_t count, int timeoutMS);
  480. // DEBUG
  481. #ifdef DEBUG
  482. const char* dump(bool reset) const;
  483. #endif
  484. protected:
  485. UIPAddress cLocalAddress, cRemoteAddress;
  486. int iSockDesc, iState, iLocalPort, iRemotePort, flags;
  487. unsigned char flag[4];
  488. #ifdef __MINGW32__
  489. SOCKET fh;
  490. #endif
  491. bool connect();
  492. void setRemote();
  493. void _closesocket();
  494. bool bind(SocketAddress& cLocal);
  495. int _writev(const struct iovec* iov, int iovcnt);
  496. bool setServer(SocketAddress& cLocal, int iBackLog);
  497. private:
  498. USocket(const USocket&) {}
  499. USocket& operator=(const USocket&) { return *this; }
  500. friend class UHTTP;
  501. friend class UFile;
  502. friend class UNotifier;
  503. friend class USocketExt;
  504. friend class USSHSocket;
  505. friend class UTCPSocket;
  506. friend class USSLSocket;
  507. friend class UUnixSocket;
  508. friend class UFtpClient;
  509. friend class USmtpClient;
  510. friend class UImapClient;
  511. friend class UPop3Client;
  512. friend class UClient_Base;
  513. friend class UServer_Base;
  514. friend class UClientImage_Base;
  515. friend class UStreamPlugIn;
  516. friend class UWebSocketPlugIn;
  517. template <class T> friend class UServer;
  518. template <class T> friend class UClientImage;
  519. };
  520. #endif