SAM.h 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. #ifndef SAM_H__
  2. #define SAM_H__
  3. #include <inttypes.h>
  4. #include <string>
  5. #include <map>
  6. #include <list>
  7. #include <thread>
  8. #include <mutex>
  9. #include <memory>
  10. #include <boost/asio.hpp>
  11. #include "Identity.h"
  12. #include "LeaseSet.h"
  13. #include "Streaming.h"
  14. #include "Destination.h"
  15. namespace i2p
  16. {
  17. namespace client
  18. {
  19. const size_t SAM_SOCKET_BUFFER_SIZE = 8192;
  20. const int SAM_SOCKET_CONNECTION_MAX_IDLE = 3600; // in seconds
  21. const int SAM_SESSION_READINESS_CHECK_INTERVAL = 20; // in seconds
  22. const char SAM_HANDSHAKE[] = "HELLO VERSION";
  23. const char SAM_HANDSHAKE_REPLY[] = "HELLO REPLY RESULT=OK VERSION=%s\n";
  24. const char SAM_HANDSHAKE_NOVERSION[] = "HELLO REPLY RESULT=NOVERSION\n";
  25. const char SAM_HANDSHAKE_I2P_ERROR[] = "HELLO REPLY RESULT=I2P_ERROR\n";
  26. const char SAM_SESSION_CREATE[] = "SESSION CREATE";
  27. const char SAM_SESSION_CREATE_REPLY_OK[] = "SESSION STATUS RESULT=OK DESTINATION=%s\n";
  28. const char SAM_SESSION_CREATE_DUPLICATED_ID[] = "SESSION STATUS RESULT=DUPLICATED_ID\n";
  29. const char SAM_SESSION_CREATE_DUPLICATED_DEST[] = "SESSION STATUS RESULT=DUPLICATED_DEST\n";
  30. const char SAM_SESSION_CREATE_INVALID_ID[] = "SESSION STATUS RESULT=INVALID_ID\n";
  31. const char SAM_SESSION_STATUS_INVALID_KEY[] = "SESSION STATUS RESULT=INVALID_KEY\n";
  32. const char SAM_SESSION_STATUS_I2P_ERROR[] = "SESSION STATUS RESULT=I2P_ERROR MESSAGE=%s\n";
  33. const char SAM_STREAM_CONNECT[] = "STREAM CONNECT";
  34. const char SAM_STREAM_STATUS_OK[] = "STREAM STATUS RESULT=OK\n";
  35. const char SAM_STREAM_STATUS_INVALID_ID[] = "STREAM STATUS RESULT=INVALID_ID\n";
  36. const char SAM_STREAM_STATUS_INVALID_KEY[] = "STREAM STATUS RESULT=INVALID_KEY\n";
  37. const char SAM_STREAM_STATUS_CANT_REACH_PEER[] = "STREAM STATUS RESULT=CANT_REACH_PEER\n";
  38. const char SAM_STREAM_STATUS_I2P_ERROR[] = "STREAM STATUS RESULT=I2P_ERROR\n";
  39. const char SAM_STREAM_ACCEPT[] = "STREAM ACCEPT";
  40. const char SAM_DATAGRAM_SEND[] = "DATAGRAM SEND";
  41. const char SAM_RAW_SEND[] = "RAW SEND";
  42. const char SAM_DEST_GENERATE[] = "DEST GENERATE";
  43. const char SAM_DEST_REPLY[] = "DEST REPLY PUB=%s PRIV=%s\n";
  44. const char SAM_DEST_REPLY_I2P_ERROR[] = "DEST REPLY RESULT=I2P_ERROR\n";
  45. const char SAM_NAMING_LOOKUP[] = "NAMING LOOKUP";
  46. const char SAM_NAMING_REPLY[] = "NAMING REPLY RESULT=OK NAME=ME VALUE=%s\n";
  47. const char SAM_DATAGRAM_RECEIVED[] = "DATAGRAM RECEIVED DESTINATION=%s SIZE=%lu\n";
  48. const char SAM_RAW_RECEIVED[] = "RAW RECEIVED SIZE=%lu\n";
  49. const char SAM_NAMING_REPLY_INVALID_KEY[] = "NAMING REPLY RESULT=INVALID_KEY NAME=%s\n";
  50. const char SAM_NAMING_REPLY_KEY_NOT_FOUND[] = "NAMING REPLY RESULT=KEY_NOT_FOUND NAME=%s\n";
  51. const char SAM_PARAM_MIN[] = "MIN";
  52. const char SAM_PARAM_MAX[] = "MAX";
  53. const char SAM_PARAM_STYLE[] = "STYLE";
  54. const char SAM_PARAM_ID[] = "ID";
  55. const char SAM_PARAM_SILENT[] = "SILENT";
  56. const char SAM_PARAM_DESTINATION[] = "DESTINATION";
  57. const char SAM_PARAM_NAME[] = "NAME";
  58. const char SAM_PARAM_SIGNATURE_TYPE[] = "SIGNATURE_TYPE";
  59. const char SAM_PARAM_CRYPTO_TYPE[] = "CRYPTO_TYPE";
  60. const char SAM_PARAM_SIZE[] = "SIZE";
  61. const char SAM_VALUE_TRANSIENT[] = "TRANSIENT";
  62. const char SAM_VALUE_STREAM[] = "STREAM";
  63. const char SAM_VALUE_DATAGRAM[] = "DATAGRAM";
  64. const char SAM_VALUE_RAW[] = "RAW";
  65. const char SAM_VALUE_TRUE[] = "true";
  66. const char SAM_VALUE_FALSE[] = "false";
  67. const char SAM_VALUE_HOST[] = "HOST";
  68. const char SAM_VALUE_PORT[] = "PORT";
  69. enum SAMSocketType
  70. {
  71. eSAMSocketTypeUnknown,
  72. eSAMSocketTypeSession,
  73. eSAMSocketTypeStream,
  74. eSAMSocketTypeAcceptor,
  75. eSAMSocketTypeTerminated
  76. };
  77. class SAMBridge;
  78. struct SAMSession;
  79. class SAMSocket: public std::enable_shared_from_this<SAMSocket>
  80. {
  81. public:
  82. typedef boost::asio::ip::tcp::socket Socket_t;
  83. SAMSocket (SAMBridge& owner);
  84. ~SAMSocket ();
  85. Socket_t& GetSocket () { return m_Socket; };
  86. void ReceiveHandshake ();
  87. void SetSocketType (SAMSocketType socketType) { m_SocketType = socketType; };
  88. SAMSocketType GetSocketType () const { return m_SocketType; };
  89. void Terminate (const char* reason);
  90. bool IsSession(const std::string & id) const;
  91. private:
  92. void TerminateClose() { Terminate(nullptr); }
  93. void HandleHandshakeReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred);
  94. void HandleHandshakeReplySent (const boost::system::error_code& ecode, std::size_t bytes_transferred);
  95. void HandleMessage (const boost::system::error_code& ecode, std::size_t bytes_transferred);
  96. void SendMessageReply (const char * msg, size_t len, bool close);
  97. void HandleMessageReplySent (const boost::system::error_code& ecode, std::size_t bytes_transferred, bool close);
  98. void Receive ();
  99. void HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred);
  100. void I2PReceive ();
  101. void HandleI2PReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred);
  102. void HandleI2PAccept (std::shared_ptr<i2p::stream::Stream> stream);
  103. void HandleWriteI2PData (const boost::system::error_code& ecode, size_t sz);
  104. void HandleI2PDatagramReceive (const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len);
  105. void HandleI2PRawDatagramReceive (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len);
  106. void ProcessSessionCreate (char * buf, size_t len);
  107. void ProcessStreamConnect (char * buf, size_t len, size_t rem);
  108. void ProcessStreamAccept (char * buf, size_t len);
  109. void ProcessDestGenerate (char * buf, size_t len);
  110. void ProcessNamingLookup (char * buf, size_t len);
  111. void SendI2PError(const std::string & msg);
  112. size_t ProcessDatagramSend (char * buf, size_t len, const char * data); // from SAM 1.0
  113. void ExtractParams (char * buf, std::map<std::string, std::string>& params);
  114. void Connect (std::shared_ptr<const i2p::data::LeaseSet> remote);
  115. void HandleConnectLeaseSetRequestComplete (std::shared_ptr<i2p::data::LeaseSet> leaseSet);
  116. void SendNamingLookupReply (std::shared_ptr<const i2p::data::IdentityEx> identity);
  117. void HandleNamingLookupLeaseSetRequestComplete (std::shared_ptr<i2p::data::LeaseSet> leaseSet, std::string name);
  118. void HandleSessionReadinessCheckTimer (const boost::system::error_code& ecode);
  119. void SendSessionCreateReplyOk ();
  120. void WriteI2PData(size_t sz);
  121. void WriteI2PDataImmediate(uint8_t * ptr, size_t sz);
  122. void HandleWriteI2PDataImmediate(const boost::system::error_code & ec, uint8_t * buff);
  123. void HandleStreamSend(const boost::system::error_code & ec);
  124. private:
  125. SAMBridge& m_Owner;
  126. Socket_t m_Socket;
  127. boost::asio::deadline_timer m_Timer;
  128. char m_Buffer[SAM_SOCKET_BUFFER_SIZE + 1];
  129. size_t m_BufferOffset;
  130. uint8_t m_StreamBuffer[SAM_SOCKET_BUFFER_SIZE];
  131. SAMSocketType m_SocketType;
  132. std::string m_ID; // nickname
  133. bool m_IsSilent;
  134. bool m_IsAccepting; // for eSAMSocketTypeAcceptor only
  135. std::shared_ptr<i2p::stream::Stream> m_Stream;
  136. };
  137. enum SAMSessionType
  138. {
  139. eSAMSessionTypeUnknown,
  140. eSAMSessionTypeStream,
  141. eSAMSessionTypeDatagram,
  142. eSAMSessionTypeRaw
  143. };
  144. struct SAMSession
  145. {
  146. SAMBridge & m_Bridge;
  147. std::shared_ptr<ClientDestination> localDestination;
  148. std::shared_ptr<boost::asio::ip::udp::endpoint> UDPEndpoint;
  149. std::string Name;
  150. SAMSessionType Type;
  151. SAMSession (SAMBridge & parent, const std::string & name, SAMSessionType type, std::shared_ptr<ClientDestination> dest);
  152. ~SAMSession ();
  153. void CloseStreams ();
  154. };
  155. class SAMBridge
  156. {
  157. public:
  158. SAMBridge (const std::string& address, int port);
  159. ~SAMBridge ();
  160. void Start ();
  161. void Stop ();
  162. boost::asio::io_service& GetService () { return m_Service; };
  163. std::shared_ptr<SAMSession> CreateSession (const std::string& id, SAMSessionType type, const std::string& destination, // empty string means transient
  164. const std::map<std::string, std::string> * params);
  165. void CloseSession (const std::string& id);
  166. std::shared_ptr<SAMSession> FindSession (const std::string& id) const;
  167. std::list<std::shared_ptr<SAMSocket> > ListSockets(const std::string & id) const;
  168. /** send raw data to remote endpoint from our UDP Socket */
  169. void SendTo(const uint8_t * buf, size_t len, std::shared_ptr<boost::asio::ip::udp::endpoint> remote);
  170. void RemoveSocket(const std::shared_ptr<SAMSocket> & socket);
  171. bool ResolveSignatureType (const std::string& name, i2p::data::SigningKeyType& type) const;
  172. private:
  173. void Run ();
  174. void Accept ();
  175. void HandleAccept(const boost::system::error_code& ecode, std::shared_ptr<SAMSocket> socket);
  176. void ReceiveDatagram ();
  177. void HandleReceivedDatagram (const boost::system::error_code& ecode, std::size_t bytes_transferred);
  178. private:
  179. bool m_IsRunning;
  180. std::thread * m_Thread;
  181. boost::asio::io_service m_Service;
  182. boost::asio::ip::tcp::acceptor m_Acceptor;
  183. boost::asio::ip::udp::endpoint m_DatagramEndpoint, m_SenderEndpoint;
  184. boost::asio::ip::udp::socket m_DatagramSocket;
  185. mutable std::mutex m_SessionsMutex;
  186. std::map<std::string, std::shared_ptr<SAMSession> > m_Sessions;
  187. mutable std::mutex m_OpenSocketsMutex;
  188. std::list<std::shared_ptr<SAMSocket> > m_OpenSockets;
  189. uint8_t m_DatagramReceiveBuffer[i2p::datagram::MAX_DATAGRAM_SIZE+1];
  190. std::map<std::string, i2p::data::SigningKeyType> m_SignatureTypes;
  191. public:
  192. // for HTTP
  193. const decltype(m_Sessions)& GetSessions () const { return m_Sessions; };
  194. };
  195. }
  196. }
  197. #endif