Guest User

Untitled

a guest
Mar 27th, 2018
90
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.42 KB | None | 0 0
  1. Class:
  2. ==========
  3. MySQLStream: PackageStream
  4.  
  5. Interface:
  6. ==========
  7. PackageStream
  8.  
  9. #ifndef THORS_ANVIL_MYSQL_PACKAGE_STREAM_H
  10. #define THORS_ANVIL_MYSQL_PACKAGE_STREAM_H
  11.  
  12. #include <string>
  13. #include <cstddef>
  14.  
  15. namespace ThorsAnvil
  16. {
  17. namespace MySQL
  18. {
  19.  
  20. class PackageStream
  21. {
  22. public:
  23. virtual ~PackageStream() = 0;
  24. virtual void read(char* buffer, std::size_t len) = 0;
  25. virtual void write(char const* buffer, std::size_t len) = 0;
  26. virtual void startNewConversation() = 0;
  27. virtual void flush() = 0;
  28. virtual void reset() = 0;
  29. virtual void drop() = 0;
  30. virtual bool isEmpty() = 0;
  31. virtual std::string readRemainingData() = 0;
  32. };
  33.  
  34. }
  35. }
  36.  
  37. #endif
  38.  
  39. #ifndef THORS_ANVIL_MYSQL_MY_SQL_STREAM_H
  40. #define THORS_ANVIL_MYSQL_MY_SQL_STREAM_H
  41.  
  42. #include "PackageStream.h"
  43. #include <string>
  44. #include <cstddef>
  45.  
  46. namespace ThorsAnvil
  47. {
  48. namespace MySQL
  49. {
  50.  
  51. class MySQLStream: public PackageStream
  52. {
  53. static std::size_t constexpr ErrorResult = static_cast<std::size_t>(-1);
  54.  
  55. int socket;
  56. public:
  57. MySQLStream(std::string const& host, int port);
  58. MySQLStream(int socket);
  59. ~MySQLStream();
  60. virtual void read(char* buffer, std::size_t len) override;
  61. virtual void write(char const* buffer, std::size_t len) override;
  62. virtual void startNewConversation() override {}
  63. virtual void flush() override {}
  64. virtual void reset() override {}
  65. virtual void drop() override {}
  66. virtual bool isEmpty() override {return true;}
  67. virtual std::string readRemainingData() override {return "";}
  68. };
  69.  
  70. }
  71. }
  72.  
  73. #endif
  74.  
  75. #include "MySQLStream.h"
  76. #include "ThorSQL/SQLUtil.h"
  77. #include <stdexcept>
  78. #include <sys/socket.h>
  79. #include <sys/types.h>
  80. #include <sys/uio.h>
  81. #include <netdb.h>
  82. #include <unistd.h>
  83. #include <errno.h>
  84.  
  85. using namespace ThorsAnvil::MySQL;
  86.  
  87. MySQLStream::MySQLStream(int socket)
  88. : socket(socket)
  89. {}
  90. MySQLStream::MySQLStream(std::string const& host, int port)
  91. {
  92. port = port ? port : 3306;
  93.  
  94. sockaddr_in serv_addr;
  95. memset(&serv_addr, '0', sizeof(serv_addr));
  96. serv_addr.sin_family = AF_INET;
  97. serv_addr.sin_port = htons(port);
  98.  
  99. hostent* serv = ::gethostbyname(host.c_str());
  100. if (serv == NULL)
  101. {
  102. throw std::runtime_error(
  103. errorMsg("ThorsAnvil::MySQL::MySQLStream::MySQLStream: ",
  104. "::gethostbyname() Failed: ", strerror(errno)
  105. ));
  106. }
  107. bcopy((char *)serv->h_addr, (char *)&serv_addr.sin_addr.s_addr, serv->h_length);
  108.  
  109. if ((socket = ::socket(AF_INET, SOCK_STREAM, 0)) < 0)
  110. {
  111. throw std::runtime_error(
  112. errorMsg("ThrosAnvil::MySQL::MySQLStream::MySQLStream: ",
  113. "::socket() Failed: ", strerror(errno)
  114. ));
  115. }
  116.  
  117. using SockAddr = struct sockaddr;
  118. if (::connect(socket, reinterpret_cast<SockAddr*>(&serv_addr), sizeof(serv_addr)) < 0)
  119. {
  120. ::close(socket);
  121. throw std::runtime_error(
  122. errorMsg("ThorsAnvil::MySQL::MySQLStream::MySQLStream: ",
  123. "::connect() Failed: ", strerror(errno)
  124. ));
  125. }
  126. }
  127. MySQLStream::~MySQLStream()
  128. {
  129. ::close(socket);
  130. }
  131.  
  132.  
  133. void MySQLStream::read(char* buffer, std::size_t len)
  134. {
  135. std::size_t readSoFar = 0;
  136. while (readSoFar != len)
  137. {
  138. std::size_t read = ::read(socket, buffer + readSoFar, len - readSoFar);
  139. if ((read == ErrorResult) && (errno == EAGAIN || errno == EINTR))
  140. {
  141. /* Recoverable error. Try again. */
  142. continue;
  143. }
  144. else if (read == 0)
  145. {
  146. throw std::runtime_error(
  147. errorMsg("ThorsAnvil::MySQL::MySQLStream::read: "
  148. "::read() Failed: ",
  149. "Tried to read ", len, "bytes but only found ", readSoFar, " before EOF"
  150. ));
  151. }
  152. else if (read == ErrorResult)
  153. {
  154. throw std::runtime_error(
  155. errorMsg("ThorsAnvil::MySQL::MySQLStream::read: ",
  156. "::read() Failed: ",
  157. "errno=", errno, " Message=", strerror(errno)
  158. ));
  159. }
  160.  
  161. readSoFar += read;
  162. }
  163. }
  164. void MySQLStream::write(char const* buffer, std::size_t len)
  165. {
  166. std::size_t writenSoFar = 0;
  167. while (writenSoFar != len)
  168. {
  169. std::size_t writen = ::write(socket, buffer + writenSoFar, len - writenSoFar);
  170. if ((writen == ErrorResult) && (errno == EAGAIN || errno == EINTR))
  171. {
  172. /* Recoverable error. Try again. */
  173. continue;
  174. }
  175. else if (writen == 0)
  176. {
  177. throw std::runtime_error(
  178. errorMsg("ThorsAnvil::MySQL::MySQLStream::write: ",
  179. "::write() Failed: ",
  180. "Tried to write ", len, "bytes but only found ", writenSoFar, " before EOF"
  181. ));
  182. }
  183. else if (writen == ErrorResult)
  184. {
  185. throw std::runtime_error(
  186. errorMsg("ThorsAnvil::MySQL::MySQLStream::write: ",
  187. "::write() Failed: ",
  188. "errno=", errno, " Message=", strerror(errno)
  189. ));
  190. }
  191.  
  192. writenSoFar += writen;
  193. }
  194. }
  195.  
  196. #include <sstream>
  197. #include <stdexcept>
  198.  
  199. class MockStream: public ThorsAnvil::MySQL::PackageStream
  200. {
  201. char const* input;
  202. unsigned char*output;
  203. std::size_t len;
  204. std::size_t readSoFar;
  205. std::size_t writSoFar;
  206. public:
  207. MockStream(char const* data, std::size_t len, unsigned char* output = nullptr)
  208. : input(data)
  209. , output(output)
  210. , len(len)
  211. , readSoFar(0)
  212. , writSoFar(0)
  213. {
  214. }
  215. virtual void read(char* buffer, std::size_t size) override {if (readSoFar + size > len) {
  216. std::stringstream msg;
  217. msg << "Read too much: readSoFar(" << readSoFar << ") Size(" << size << ") Len(" << len << ")";
  218. throw std::runtime_error(msg.str());
  219. }
  220. std::copy(input + readSoFar, input + readSoFar + size, buffer);readSoFar += size;
  221. }
  222. virtual void write(char const* buffer, std::size_t len) override {std::copy(buffer, buffer + len, output + writSoFar); writSoFar += len;}
  223. virtual void startNewConversation() override {}
  224. virtual void flush() override {}
  225. virtual void drop() override {readSoFar = len;}
  226. virtual void reset() override {}
  227. virtual bool isEmpty() override {return len == readSoFar;}
  228. virtual std::string readRemainingData() override {return std::string(input + readSoFar, input + readSoFar + len);}
  229.  
  230.  
  231. std::size_t readLen() const {return readSoFar;}
  232. std::size_t writLen() const {return writSoFar;}
  233. };
  234.  
  235. class MySQLStream: public PackageStream {
  236. //...
  237. virtual void startNewConversation() override {}
  238. virtual void flush() override {}
  239. virtual void reset() override {}
  240. virtual void drop() override {}
  241. virtual bool isEmpty() override {return true;}
  242. virtual std::string readRemainingData() override {return "";}
  243. //...
  244. };
Add Comment
Please, Sign In to add comment