socket-unix.cxx 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590
  1. // Module: Log4CPLUS
  2. // File: socket-unix.cxx
  3. // Created: 4/2003
  4. // Author: Tad E. Smith
  5. //
  6. //
  7. // Copyright 2003-2013 Tad E. Smith
  8. //
  9. // Licensed under the Apache License, Version 2.0 (the "License");
  10. // you may not use this file except in compliance with the License.
  11. // You may obtain a copy of the License at
  12. //
  13. // http://www.apache.org/licenses/LICENSE-2.0
  14. //
  15. // Unless required by applicable law or agreed to in writing, software
  16. // distributed under the License is distributed on an "AS IS" BASIS,
  17. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  18. // See the License for the specific language governing permissions and
  19. // limitations under the License.
  20. #include <log4cplus/config.hxx>
  21. #if defined (LOG4CPLUS_USE_BSD_SOCKETS)
  22. #include <cstring>
  23. #include <vector>
  24. #include <algorithm>
  25. #include <cerrno>
  26. #include <log4cplus/internal/socket.h>
  27. #include <log4cplus/helpers/loglog.h>
  28. #include <log4cplus/thread/syncprims-pub-impl.h>
  29. #include <log4cplus/spi/loggingevent.h>
  30. #include <log4cplus/helpers/stringhelper.h>
  31. #ifdef LOG4CPLUS_HAVE_SYS_TYPES_H
  32. #include <sys/types.h>
  33. #endif
  34. #ifdef LOG4CPLUS_HAVE_SYS_SOCKET_H
  35. #include <sys/socket.h>
  36. #endif
  37. #if defined (LOG4CPLUS_HAVE_NETINET_IN_H)
  38. #include <netinet/in.h>
  39. #endif
  40. #if defined (LOG4CPLUS_HAVE_NETINET_TCP_H)
  41. #include <netinet/tcp.h>
  42. #endif
  43. #if defined (LOG4CPLUS_HAVE_ARPA_INET_H)
  44. #include <arpa/inet.h>
  45. #endif
  46. #if defined (LOG4CPLUS_HAVE_ERRNO_H)
  47. #include <errno.h>
  48. #endif
  49. #ifdef LOG4CPLUS_HAVE_NETDB_H
  50. #include <netdb.h>
  51. #endif
  52. #ifdef LOG4CPLUS_HAVE_FCNTL_H
  53. #include <fcntl.h>
  54. #endif
  55. #ifdef LOG4CPLUS_HAVE_UNISTD_H
  56. #include <unistd.h>
  57. #endif
  58. #ifdef LOG4CPLUS_HAVE_POLL_H
  59. #include <poll.h>
  60. #endif
  61. namespace log4cplus { namespace helpers {
  62. // from lockfile.cxx
  63. LOG4CPLUS_PRIVATE bool trySetCloseOnExec (int fd,
  64. helpers::LogLog & loglog = helpers::getLogLog ());
  65. namespace
  66. {
  67. #if ! defined (LOG4CPLUS_SINGLE_THREADED)
  68. // We need to use log4cplus::thread here to work around compilation
  69. // problem on AIX.
  70. static log4cplus::thread::Mutex ghbn_mutex;
  71. #endif
  72. static
  73. int
  74. get_host_by_name (char const * hostname, std::string * name,
  75. struct sockaddr_in * addr)
  76. {
  77. #if defined (LOG4CPLUS_HAVE_GETADDRINFO)
  78. struct addrinfo hints;
  79. std::memset (&hints, 0, sizeof (hints));
  80. hints.ai_family = AF_INET;
  81. hints.ai_socktype = SOCK_STREAM;
  82. hints.ai_protocol = IPPROTO_TCP;
  83. hints.ai_flags = AI_CANONNAME;
  84. if (inet_addr (hostname) != static_cast<in_addr_t>(-1))
  85. hints.ai_flags |= AI_NUMERICHOST;
  86. struct addrinfo * res = 0;
  87. int ret = getaddrinfo (hostname, 0, &hints, &res);
  88. if (ret != 0)
  89. return ret;
  90. struct addrinfo const & ai = *res;
  91. assert (ai.ai_family == AF_INET);
  92. if (name)
  93. *name = ai.ai_canonname;
  94. if (addr)
  95. std::memcpy (addr, ai.ai_addr, ai.ai_addrlen);
  96. freeaddrinfo (res);
  97. #else
  98. #if ! defined (LOG4CPLUS_SINGLE_THREADED)
  99. // We need to use log4cplus::thread here to work around
  100. // compilation problem on AIX.
  101. log4cplus::thread::MutexGuard guard (ghbn_mutex);
  102. #endif
  103. struct ::hostent * hp = gethostbyname (hostname);
  104. if (! hp)
  105. return 1;
  106. assert (hp->h_addrtype == AF_INET);
  107. if (name)
  108. *name = hp->h_name;
  109. if (addr)
  110. {
  111. assert (hp->h_length <= sizeof (addr->sin_addr));
  112. std::memcpy (&addr->sin_addr, hp->h_addr_list[0], hp->h_length);
  113. }
  114. #endif
  115. return 0;
  116. }
  117. } // namespace
  118. /////////////////////////////////////////////////////////////////////////////
  119. // Global Methods
  120. /////////////////////////////////////////////////////////////////////////////
  121. SOCKET_TYPE
  122. openSocket(unsigned short port, SocketState& state)
  123. {
  124. socket_holder sock_holder (::socket(AF_INET, SOCK_STREAM, 0));
  125. if(sock_holder.sock < 0) {
  126. return INVALID_SOCKET_VALUE;
  127. }
  128. struct sockaddr_in server = sockaddr_in ();
  129. server.sin_family = AF_INET;
  130. server.sin_addr.s_addr = INADDR_ANY;
  131. server.sin_port = htons(port);
  132. int optval = 1;
  133. socklen_t optlen = sizeof (optval);
  134. int ret = setsockopt (sock_holder.sock, SOL_SOCKET, SO_REUSEADDR, &optval,
  135. optlen);
  136. if (ret != 0)
  137. {
  138. int const eno = errno;
  139. helpers::getLogLog ().warn (LOG4CPLUS_TEXT ("setsockopt() failed: ")
  140. + helpers::convertIntegerToString (eno));
  141. }
  142. int retval = bind(sock_holder.sock,
  143. reinterpret_cast<struct sockaddr*>(&server), sizeof(server));
  144. if (retval < 0)
  145. return INVALID_SOCKET_VALUE;
  146. if (::listen(sock_holder.sock, 10))
  147. return INVALID_SOCKET_VALUE;
  148. state = ok;
  149. return to_log4cplus_socket (sock_holder.detach ());
  150. }
  151. SOCKET_TYPE
  152. connectSocket(const tstring& hostn, unsigned short port, bool udp, SocketState& state)
  153. {
  154. struct sockaddr_in server;
  155. int retval;
  156. std::memset (&server, 0, sizeof (server));
  157. retval = get_host_by_name (LOG4CPLUS_TSTRING_TO_STRING(hostn).c_str(),
  158. 0, &server);
  159. if (retval != 0)
  160. return INVALID_SOCKET_VALUE;
  161. server.sin_port = htons(port);
  162. server.sin_family = AF_INET;
  163. socket_holder sock_holder (
  164. ::socket(AF_INET, (udp ? SOCK_DGRAM : SOCK_STREAM), 0));
  165. if (sock_holder.sock < 0)
  166. return INVALID_SOCKET_VALUE;
  167. socklen_t namelen = sizeof (server);
  168. while (
  169. (retval = ::connect(sock_holder.sock,
  170. reinterpret_cast<struct sockaddr*>(&server), namelen))
  171. == -1
  172. && (errno == EINTR))
  173. ;
  174. if (retval == INVALID_OS_SOCKET_VALUE)
  175. return INVALID_SOCKET_VALUE;
  176. state = ok;
  177. return to_log4cplus_socket (sock_holder.detach ());
  178. }
  179. namespace
  180. {
  181. //! Helper for accept_wrap().
  182. template <typename T, typename U>
  183. struct socklen_var
  184. {
  185. typedef T type;
  186. };
  187. template <typename U>
  188. struct socklen_var<void, U>
  189. {
  190. typedef U type;
  191. };
  192. // Some systems like HP-UX have socklen_t but accept() does not use it
  193. // as type of its 3rd parameter. This wrapper works around this
  194. // incompatibility.
  195. template <typename accept_sockaddr_ptr_type, typename accept_socklen_type>
  196. static
  197. SOCKET_TYPE
  198. accept_wrap (
  199. int (* accept_func) (int, accept_sockaddr_ptr_type, accept_socklen_type *),
  200. SOCKET_TYPE sock, struct sockaddr * sa, socklen_t * len)
  201. {
  202. typedef typename socklen_var<accept_socklen_type, socklen_t>::type
  203. socklen_var_type;
  204. socklen_var_type l = static_cast<socklen_var_type>(*len);
  205. SOCKET_TYPE result
  206. = static_cast<SOCKET_TYPE>(
  207. accept_func (sock, sa,
  208. reinterpret_cast<accept_socklen_type *>(&l)));
  209. *len = static_cast<socklen_t>(l);
  210. return result;
  211. }
  212. } // namespace
  213. SOCKET_TYPE
  214. acceptSocket(SOCKET_TYPE sock, SocketState& state)
  215. {
  216. struct sockaddr_in net_client;
  217. socklen_t len = sizeof(struct sockaddr);
  218. int clientSock;
  219. while(
  220. (clientSock = accept_wrap (accept, to_os_socket (sock),
  221. reinterpret_cast<struct sockaddr*>(&net_client), &len))
  222. == -1
  223. && (errno == EINTR))
  224. ;
  225. if(clientSock != INVALID_OS_SOCKET_VALUE) {
  226. state = ok;
  227. }
  228. return to_log4cplus_socket (clientSock);
  229. }
  230. int
  231. closeSocket(SOCKET_TYPE sock)
  232. {
  233. return ::close(to_os_socket (sock));
  234. }
  235. int
  236. shutdownSocket(SOCKET_TYPE sock)
  237. {
  238. return ::shutdown(to_os_socket (sock), SHUT_RDWR);
  239. }
  240. long
  241. read(SOCKET_TYPE sock, SocketBuffer& buffer)
  242. {
  243. long res, readbytes = 0;
  244. do
  245. {
  246. res = ::read(to_os_socket (sock), buffer.getBuffer() + readbytes,
  247. buffer.getMaxSize() - readbytes);
  248. if( res <= 0 ) {
  249. return res;
  250. }
  251. readbytes += res;
  252. } while( readbytes < static_cast<long>(buffer.getMaxSize()) );
  253. return readbytes;
  254. }
  255. long
  256. write(SOCKET_TYPE sock, const SocketBuffer& buffer)
  257. {
  258. #if defined(MSG_NOSIGNAL)
  259. int flags = MSG_NOSIGNAL;
  260. #else
  261. int flags = 0;
  262. #endif
  263. return ::send( to_os_socket (sock), buffer.getBuffer(), buffer.getSize(),
  264. flags );
  265. }
  266. long
  267. write(SOCKET_TYPE sock, const std::string & buffer)
  268. {
  269. #if defined(MSG_NOSIGNAL)
  270. int flags = MSG_NOSIGNAL;
  271. #else
  272. int flags = 0;
  273. #endif
  274. return ::send (to_os_socket (sock), buffer.c_str (), buffer.size (),
  275. flags);
  276. }
  277. tstring
  278. getHostname (bool fqdn)
  279. {
  280. char const * hostname = "unknown";
  281. int ret;
  282. std::vector<char> hn (1024, 0);
  283. while (true)
  284. {
  285. ret = ::gethostname (&hn[0], static_cast<int>(hn.size ()) - 1);
  286. if (ret == 0)
  287. {
  288. hostname = &hn[0];
  289. break;
  290. }
  291. #if defined (LOG4CPLUS_HAVE_ENAMETOOLONG)
  292. else if (ret != 0 && errno == ENAMETOOLONG)
  293. // Out buffer was too short. Retry with buffer twice the size.
  294. hn.resize (hn.size () * 2, 0);
  295. #endif
  296. else
  297. break;
  298. }
  299. if (ret != 0 || (ret == 0 && ! fqdn))
  300. return LOG4CPLUS_STRING_TO_TSTRING (hostname);
  301. std::string full_hostname;
  302. ret = get_host_by_name (hostname, &full_hostname, 0);
  303. if (ret == 0)
  304. hostname = full_hostname.c_str ();
  305. return LOG4CPLUS_STRING_TO_TSTRING (hostname);
  306. }
  307. int
  308. setTCPNoDelay (SOCKET_TYPE sock, bool val)
  309. {
  310. #if (defined (SOL_TCP) || defined (IPPROTO_TCP)) && defined (TCP_NODELAY)
  311. #if defined (SOL_TCP)
  312. int level = SOL_TCP;
  313. #elif defined (IPPROTO_TCP)
  314. int level = IPPROTO_TCP;
  315. #endif
  316. int result;
  317. int enabled = static_cast<int>(val);
  318. if ((result = setsockopt(sock, level, TCP_NODELAY, &enabled,
  319. sizeof(enabled))) != 0)
  320. set_last_socket_error (errno);
  321. return result;
  322. #else
  323. // No recognizable TCP_NODELAY option.
  324. return 0;
  325. #endif
  326. }
  327. //
  328. // ServerSocket OS dependent stuff
  329. //
  330. ServerSocket::ServerSocket(unsigned short port)
  331. {
  332. int fds[2] = {-1, -1};
  333. int ret;
  334. sock = openSocket (port, state);
  335. if (sock == INVALID_SOCKET_VALUE)
  336. goto error;
  337. #if defined (LOG4CPLUS_HAVE_PIPE2) && defined (O_CLOEXEC)
  338. ret = pipe2 (fds, O_CLOEXEC);
  339. if (ret != 0)
  340. goto error;
  341. #elif defined (LOG4CPLUS_HAVE_PIPE)
  342. ret = pipe (fds);
  343. if (ret != 0)
  344. goto error;
  345. trySetCloseOnExec (fds[0]);
  346. trySetCloseOnExec (fds[1]);
  347. #else
  348. # error You are missing both pipe() or pipe2().
  349. #endif
  350. interruptHandles[0] = fds[0];
  351. interruptHandles[1] = fds[1];
  352. return;
  353. error:;
  354. err = get_last_socket_error ();
  355. state = not_opened;
  356. if (sock != INVALID_SOCKET_VALUE)
  357. closeSocket (sock);
  358. if (fds[0] != -1)
  359. ::close (fds[0]);
  360. if (fds[1] != -1)
  361. ::close (fds[1]);
  362. }
  363. Socket
  364. ServerSocket::accept ()
  365. {
  366. struct pollfd pollfds[2];
  367. struct pollfd & interrupt_pipe = pollfds[0];
  368. interrupt_pipe.fd = interruptHandles[0];
  369. interrupt_pipe.events = POLLIN;
  370. interrupt_pipe.revents = 0;
  371. struct pollfd & accept_fd = pollfds[1];
  372. accept_fd.fd = to_os_socket (sock);
  373. accept_fd.events = POLLIN;
  374. accept_fd.revents = 0;
  375. do
  376. {
  377. interrupt_pipe.revents = 0;
  378. accept_fd.revents = 0;
  379. int ret = poll (pollfds, 2, -1);
  380. switch (ret)
  381. {
  382. // Error.
  383. case -1:
  384. if (errno == EINTR)
  385. // Signal has interrupted the call. Just re-run it.
  386. continue;
  387. set_last_socket_error (errno);
  388. return Socket (INVALID_SOCKET_VALUE, not_opened, errno);
  389. // Timeout. This should not happen though.
  390. case 0:
  391. continue;
  392. default:
  393. // Some descriptor is ready.
  394. if ((interrupt_pipe.revents & POLLIN) == POLLIN)
  395. {
  396. // Read byte from interruption pipe.
  397. helpers::getLogLog ().debug (
  398. LOG4CPLUS_TEXT ("ServerSocket::accept- ")
  399. LOG4CPLUS_TEXT ("accept() interrupted by other thread"));
  400. char ch;
  401. ret = ::read (interrupt_pipe.fd, &ch, 1);
  402. if (ret == -1)
  403. {
  404. int const eno = errno;
  405. helpers::getLogLog ().warn (
  406. LOG4CPLUS_TEXT ("ServerSocket::accept- read() failed: ")
  407. + helpers::convertIntegerToString (eno));
  408. set_last_socket_error (eno);
  409. return Socket (INVALID_SOCKET_VALUE, not_opened, eno);
  410. }
  411. // Return Socket with state set to accept_interrupted.
  412. return Socket (INVALID_SOCKET_VALUE, accept_interrupted, 0);
  413. }
  414. else if ((accept_fd.revents & POLLIN) == POLLIN)
  415. {
  416. helpers::getLogLog ().debug (
  417. LOG4CPLUS_TEXT ("ServerSocket::accept- ")
  418. LOG4CPLUS_TEXT ("accepting connection"));
  419. SocketState st = not_opened;
  420. SOCKET_TYPE clientSock = acceptSocket (sock, st);
  421. int eno = 0;
  422. if (clientSock == INVALID_SOCKET_VALUE)
  423. eno = get_last_socket_error ();
  424. return Socket (clientSock, st, eno);
  425. }
  426. else
  427. return Socket (INVALID_SOCKET_VALUE, not_opened, 0);
  428. }
  429. }
  430. while (true);
  431. }
  432. void
  433. ServerSocket::interruptAccept ()
  434. {
  435. char ch = 'I';
  436. int ret;
  437. do
  438. {
  439. ret = ::write (interruptHandles[1], &ch, 1);
  440. }
  441. while (ret == -1 && errno == EINTR);
  442. if (ret == -1)
  443. {
  444. int const eno = errno;
  445. helpers::getLogLog ().warn (
  446. LOG4CPLUS_TEXT ("ServerSocket::interruptAccept- write() failed: ")
  447. + helpers::convertIntegerToString (eno));
  448. }
  449. }
  450. ServerSocket::~ServerSocket()
  451. {
  452. if (interruptHandles[0] != -1)
  453. ::close (interruptHandles[0]);
  454. if (interruptHandles[1] != -1)
  455. ::close (interruptHandles[1]);
  456. }
  457. } } // namespace log4cplus
  458. #endif // LOG4CPLUS_USE_BSD_SOCKETS