ECChannelClient.cpp 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. /*
  2. * Copyright 2005 - 2016 Zarafa and its licensors
  3. *
  4. * This program is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU Affero General Public License, version 3,
  6. * as published by the Free Software Foundation.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU Affero General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU Affero General Public License
  14. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. *
  16. */
  17. #include <kopano/platform.h>
  18. #include <new>
  19. #include <mapidefs.h>
  20. #include <mapiutil.h>
  21. #include <mapix.h>
  22. #include <netdb.h>
  23. #include <arpa/inet.h>
  24. #include <netinet/in.h>
  25. #include <sys/un.h>
  26. #include <sys/socket.h>
  27. #include <kopano/ECChannel.h>
  28. #include <kopano/ECDefs.h>
  29. #include <kopano/stringutil.h>
  30. #include "ECChannelClient.h"
  31. namespace KC {
  32. ECChannelClient::ECChannelClient(const char *szPath, const char *szTokenizer)
  33. {
  34. m_strTokenizer = szTokenizer;
  35. m_strPath = GetServerNameFromPath(szPath);
  36. if (strncmp(szPath, "file", 4) == 0 || szPath[0] == PATH_SEPARATOR) {
  37. m_bSocket = true;
  38. m_ulPort = 0;
  39. return;
  40. }
  41. m_bSocket = false;
  42. m_ulPort = atoi(GetServerPortFromPath(szPath).c_str());
  43. }
  44. ECChannelClient::~ECChannelClient()
  45. {
  46. delete m_lpChannel;
  47. }
  48. ECRESULT ECChannelClient::DoCmd(const std::string &strCommand, std::vector<std::string> &lstResponse)
  49. {
  50. ECRESULT er;
  51. std::string strResponse;
  52. er = Connect();
  53. if (er != erSuccess)
  54. return er;
  55. er = m_lpChannel->HrWriteLine(strCommand);
  56. if (er != erSuccess)
  57. return er;
  58. er = m_lpChannel->HrSelect(m_ulTimeout);
  59. if (er != erSuccess)
  60. return er;
  61. // @todo, should be able to read more than 4MB of results
  62. er = m_lpChannel->HrReadLine(&strResponse, 4*1024*1024);
  63. if (er != erSuccess)
  64. return er;
  65. lstResponse = tokenize(strResponse, m_strTokenizer);
  66. if (!lstResponse.empty() && lstResponse.front() == "OK")
  67. lstResponse.erase(lstResponse.begin());
  68. else
  69. return KCERR_CALL_FAILED;
  70. return erSuccess;
  71. }
  72. ECRESULT ECChannelClient::Connect()
  73. {
  74. ECRESULT er = erSuccess;
  75. if (!m_lpChannel) {
  76. if (m_bSocket)
  77. er = ConnectSocket();
  78. else
  79. er = ConnectHttp();
  80. }
  81. return er;
  82. }
  83. ECRESULT ECChannelClient::ConnectSocket()
  84. {
  85. ECRESULT er = erSuccess;
  86. int fd = -1;
  87. struct sockaddr_un saddr;
  88. memset(&saddr, 0, sizeof(saddr));
  89. saddr.sun_family = AF_UNIX;
  90. if (m_strPath.size() >= sizeof(saddr.sun_path)) {
  91. ec_log_warn("%s: path %s too long", __PRETTY_FUNCTION__,
  92. m_strPath.c_str());
  93. return KCERR_INVALID_PARAMETER;
  94. }
  95. kc_strlcpy(saddr.sun_path, m_strPath.c_str(), sizeof(saddr.sun_path));
  96. if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
  97. er = KCERR_INVALID_PARAMETER;
  98. goto exit;
  99. }
  100. if (connect(fd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
  101. er = KCERR_NETWORK_ERROR;
  102. goto exit;
  103. }
  104. m_lpChannel = new(std::nothrow) ECChannel(fd);
  105. if (!m_lpChannel) {
  106. er = KCERR_NOT_ENOUGH_MEMORY;
  107. goto exit;
  108. }
  109. exit:
  110. if (er != erSuccess && fd != -1)
  111. close(fd);
  112. return er;
  113. }
  114. ECRESULT ECChannelClient::ConnectHttp()
  115. {
  116. ECRESULT er = erSuccess;
  117. int fd = -1, ret;
  118. struct addrinfo *sock_res, sock_hints;
  119. const struct addrinfo *sock_addr;
  120. char port_string[sizeof("65536")];
  121. snprintf(port_string, sizeof(port_string), "%u", m_ulPort);
  122. memset(&sock_hints, 0, sizeof(sock_hints));
  123. sock_hints.ai_socktype = SOCK_STREAM;
  124. ret = getaddrinfo(m_strPath.c_str(), port_string, &sock_hints,
  125. &sock_res);
  126. if (ret != 0) {
  127. er = KCERR_NETWORK_ERROR;
  128. goto exit;
  129. }
  130. for (sock_addr = sock_res; sock_addr != NULL;
  131. sock_addr = sock_addr->ai_next)
  132. {
  133. fd = socket(sock_addr->ai_family, sock_addr->ai_socktype,
  134. sock_addr->ai_protocol);
  135. if (fd < 0)
  136. /* Socket type could not be created */
  137. continue;
  138. if (connect(fd, sock_addr->ai_addr,
  139. sock_addr->ai_addrlen) < 0) {
  140. /* No route */
  141. int saved_errno = errno;
  142. close(fd);
  143. fd = -1;
  144. errno = saved_errno;
  145. continue;
  146. }
  147. /* Good connected socket, use it */
  148. break;
  149. }
  150. if (fd < 0) {
  151. er = KCERR_NETWORK_ERROR;
  152. goto exit;
  153. }
  154. m_lpChannel = new(std::nothrow) ECChannel(fd);
  155. if (!m_lpChannel) {
  156. er = KCERR_NOT_ENOUGH_MEMORY;
  157. goto exit;
  158. }
  159. exit:
  160. if (sock_res != NULL)
  161. freeaddrinfo(sock_res);
  162. if (er != erSuccess && fd != -1)
  163. close(fd);
  164. return er;
  165. }
  166. } /* namespace */