UnixSocketServer.cpp 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. /*
  2. This file is part of cpp-ethereum.
  3. cpp-ethereum is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation, either version 3 of the License, or
  6. (at your option) any later version.
  7. cpp-ethereum is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
  13. */
  14. /** @file UnixSocketServer.cpp
  15. * @authors:
  16. * Arkadiy Paronyan <arkadiy@ethdev.com>
  17. * @date 2015
  18. */
  19. #ifndef WIN32
  20. #include "UnixSocketServer.h"
  21. #include <cstdlib>
  22. #include <sys/socket.h>
  23. #include <cstdio>
  24. #include <fcntl.h>
  25. #include <unistd.h>
  26. #include <string>
  27. #include <libdevcore/Guards.h>
  28. #include <libdevcore/FileSystem.h>
  29. // "Mac OS X does not support the flag MSG_NOSIGNAL but we have an equivalent."
  30. // See http://lists.apple.com/archives/macnetworkprog/2002/Dec/msg00091.html
  31. #if defined(__APPLE__)
  32. #if !defined(MSG_NOSIGNAL)
  33. #define MSG_NOSIGNAL SO_NOSIGPIPE
  34. #endif
  35. #endif
  36. using namespace std;
  37. using namespace jsonrpc;
  38. using namespace dev;
  39. int const c_pathMaxSize = sizeof(sockaddr_un::sun_path)/sizeof(sockaddr_un::sun_path[0]);
  40. string ipcSocketPath()
  41. {
  42. #ifdef __APPLE__
  43. // A bit hacky, but backwards compatible: If we did not change the default data dir,
  44. // put the socket in ~/Library/Ethereum, otherwise in the set data dir.
  45. string path = getIpcPath();
  46. if (path == getDefaultDataDir())
  47. return getenv("HOME") + string("/Library/Ethereum");
  48. else
  49. return path;
  50. #else
  51. return getIpcPath();
  52. #endif
  53. }
  54. UnixDomainSocketServer::UnixDomainSocketServer(string const& _appId):
  55. IpcServerBase(string(getIpcPath() + "/" + _appId + ".ipc").substr(0, c_pathMaxSize))
  56. {
  57. }
  58. UnixDomainSocketServer::~UnixDomainSocketServer()
  59. {
  60. StopListening();
  61. }
  62. bool UnixDomainSocketServer::StartListening()
  63. {
  64. if (!m_running)
  65. {
  66. if (access(m_path.c_str(), F_OK) != -1)
  67. unlink(m_path.c_str());
  68. if (access(m_path.c_str(), F_OK) != -1)
  69. return false;
  70. m_socket = socket(PF_UNIX, SOCK_STREAM, 0);
  71. memset(&(m_address), 0, sizeof(sockaddr_un));
  72. m_address.sun_family = AF_UNIX;
  73. #ifdef __APPLE__
  74. m_address.sun_len = m_path.size() + 1;
  75. #endif
  76. strncpy(m_address.sun_path, m_path.c_str(), c_pathMaxSize);
  77. ::bind(m_socket, reinterpret_cast<sockaddr*>(&m_address), sizeof(sockaddr_un));
  78. listen(m_socket, 128);
  79. }
  80. return IpcServerBase::StartListening();
  81. }
  82. bool UnixDomainSocketServer::StopListening()
  83. {
  84. shutdown(m_socket, SHUT_RDWR);
  85. close(m_socket);
  86. m_socket = -1;
  87. if (IpcServerBase::StopListening())
  88. {
  89. unlink(m_path.c_str());
  90. return true;
  91. }
  92. return false;
  93. }
  94. void UnixDomainSocketServer::Listen()
  95. {
  96. socklen_t addressLen = sizeof(m_address);
  97. while (m_running)
  98. {
  99. int connection = accept(m_socket, (sockaddr*) &(m_address), &addressLen);
  100. if (connection > 0)
  101. {
  102. DEV_GUARDED(x_sockets)
  103. m_sockets.insert(connection);
  104. std::thread handler([this, connection](){ GenerateResponse(connection); });
  105. handler.detach();
  106. }
  107. }
  108. }
  109. void UnixDomainSocketServer::CloseConnection(int _socket)
  110. {
  111. close(_socket);
  112. }
  113. size_t UnixDomainSocketServer::Write(int _connection, string const& _data)
  114. {
  115. int r = send(_connection, _data.data(), _data.size(), MSG_NOSIGNAL);
  116. if (r > 0)
  117. return r;
  118. return 0;
  119. }
  120. size_t UnixDomainSocketServer::Read(int _connection, void* _data, size_t _size)
  121. {
  122. int r = read(_connection, _data, _size);
  123. if (r > 0)
  124. return r;
  125. return 0;
  126. }
  127. #endif