Anoncoin  0.9.4
P2P Digital Currency
i2psam.h
Go to the documentation of this file.
1 // Copyright (c) 2013-2014 The Anoncoin Core developers
2 // Copyright (c) 2012-2013 giv
3 // Distributed under the MIT/X11 software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 //--------------------------------------------------------------------------------------------------
6 // see full documentation about SAM at http://www.i2p2.i2p/samv3.html
7 #ifndef I2PSAM_H
8 #define I2PSAM_H
9 
10 #include <string>
11 #include <list>
12 #include <stdint.h>
13 #include <memory>
14 #include <utility>
15 
16 #ifdef WIN32
17 #include <winsock2.h>
18 #else
19 #include <sys/socket.h>
20 #include <netinet/in.h> // for sockaddr_in
21 #include <arpa/inet.h> // for ntohs and htons
22 #endif
23 
24 // TODO: check a possible bug about cast -1 to SOCKET
25 #define SAM_INVALID_SOCKET (-1)
26 #define SAM_SOCKET_ERROR (-1)
27 
28 #define SAM_DEFAULT_ADDRESS "127.0.0.1"
29 #define SAM_DEFAULT_PORT 7656
30 #define SAM_DEFAULT_MIN_VER "3.0"
31 #define SAM_DEFAULT_MAX_VER "3.0"
32 #define SAM_GENERATE_MY_DESTINATION "TRANSIENT"
33 #define SAM_MY_NAME "ME"
34 #define SAM_DEFAULT_I2P_OPTIONS ""
35 
36 #define SAM_NAME_INBOUND_QUANTITY "inbound.quantity"
37 #define SAM_DEFAULT_INBOUND_QUANTITY 3 // Three tunnels is default now
38 #define SAM_NAME_INBOUND_LENGTH "inbound.length"
39 #define SAM_DEFAULT_INBOUND_LENGTH 3 // Three jumps is default now
40 #define SAM_NAME_INBOUND_LENGTHVARIANCE "inbound.lengthVariance"
41 #define SAM_DEFAULT_INBOUND_LENGTHVARIANCE 0
42 #define SAM_NAME_INBOUND_BACKUPQUANTITY "inbound.backupQuantity"
43 #define SAM_DEFAULT_INBOUND_BACKUPQUANTITY 1 // One backup tunnel
44 #define SAM_NAME_INBOUND_ALLOWZEROHOP "inbound.allowZeroHop"
45 #define SAM_DEFAULT_INBOUND_ALLOWZEROHOP true
46 #define SAM_NAME_INBOUND_IPRESTRICTION "inbound.IPRestriction"
47 #define SAM_DEFAULT_INBOUND_IPRESTRICTION 2
48 #define SAM_NAME_OUTBOUND_QUANTITY "outbound.quantity"
49 #define SAM_DEFAULT_OUTBOUND_QUANTITY 3
50 #define SAM_NAME_OUTBOUND_LENGTH "outbound.length"
51 #define SAM_DEFAULT_OUTBOUND_LENGTH 3
52 #define SAM_NAME_OUTBOUND_LENGTHVARIANCE "outbound.lengthVariance"
53 #define SAM_DEFAULT_OUTBOUND_LENGTHVARIANCE 0
54 #define SAM_NAME_OUTBOUND_BACKUPQUANTITY "outbound.backupQuantity"
55 #define SAM_DEFAULT_OUTBOUND_BACKUPQUANTITY 1
56 #define SAM_NAME_OUTBOUND_ALLOWZEROHOP "outbound.allowZeroHop"
57 #define SAM_DEFAULT_OUTBOUND_ALLOWZEROHOP true
58 #define SAM_NAME_OUTBOUND_IPRESTRICTION "outbound.IPRestriction"
59 #define SAM_DEFAULT_OUTBOUND_IPRESTRICTION 2
60 #define SAM_NAME_OUTBOUND_PRIORITY "outbound.priority"
61 #define SAM_DEFAULT_OUTBOUND_PRIORITY 0
62 
63 namespace SAM
64 {
65 
66 // ToDo: GR Notes: Seems this is a very bad idea, SOCKET should be defined as per the compilers standard library definition is set to, the
67 // rest of the coin code assumes that is what this definition is using, and 99.9% of the time it's probably true 'int' may not however be
68 // the correct choice for every build envirnment and research needs to be done to get this module changed to insure that is the case.
69 typedef int SOCKET;
70 
71 class Message
72 {
73 public:
75  {
77  sssDatagram, // not supported now
78  sssRaw // not supported now
79  };
80 
81  enum eStatus
82  {
83  OK,
87 
88  // The destination is already in use
89  //
90  // -> SESSION CREATE ...
91  // <- SESSION STATUS RESULT=DUPLICATED_DEST
93 
94  // The nickname is already associated with a session
95  //
96  // -> SESSION CREATE ...
97  // <- SESSION STATUS RESULT=DUPLICATED_ID
99 
100  // A generic I2P error (e.g. I2CP disconnection, etc.)
101  //
102  // -> HELLO VERSION ...
103  // <- HELLO REPLY RESULT=I2P_ERROR MESSAGE={$message}
104  //
105  // -> SESSION CREATE ...
106  // <- SESSION STATUS RESULT=I2P_ERROR MESSAGE={$message}
107  //
108  // -> STREAM CONNECT ...
109  // <- STREAM STATUS RESULT=I2P_ERROR MESSAGE={$message}
110  //
111  // -> STREAM ACCEPT ...
112  // <- STREAM STATUS RESULT=I2P_ERROR MESSAGE={$message}
113  //
114  // -> STREAM FORWARD ...
115  // <- STREAM STATUS RESULT=I2P_ERROR MESSAGE={$message}
116  //
117  // -> NAMING LOOKUP ...
118  // <- NAMING REPLY RESULT=INVALID_KEY NAME={$name} MESSAGE={$message}
120 
121  // Stream session ID doesn't exist
122  //
123  // -> STREAM CONNECT ...
124  // <- STREAM STATUS RESULT=INVALID_ID MESSAGE={$message}
125  //
126  // -> STREAM ACCEPT ...
127  // <- STREAM STATUS RESULT=INVALID_ID MESSAGE={$message}
128  //
129  // -> STREAM FORWARD ...
130  // <- STREAM STATUS RESULT=INVALID_ID MESSAGE={$message}
132 
133  // The destination is not a valid private destination key
134  //
135  // -> SESSION CREATE ...
136  // <- SESSION STATUS RESULT=INVALID_KEY MESSAGE={$message}
137  //
138  // -> STREAM CONNECT ...
139  // <- STREAM STATUS RESULT=INVALID_KEY MESSAGE={$message}
140  //
141  // -> NAMING LOOKUP ...
142  // <- NAMING REPLY RESULT=INVALID_KEY NAME={$name} MESSAGE={$message}
144 
145  // The peer exists, but cannot be reached
146  //
147  // -> STREAM CONNECT ...
148  // <- STREAM STATUS RESULT=CANT_REACH_PEER MESSAGE={$message}
150 
151  // Timeout while waiting for an event (e.g. peer answer)
152  //
153  // -> STREAM CONNECT ...
154  // <- STREAM STATUS RESULT=TIMEOUT MESSAGE={$message}
156 
157  // The SAM bridge cannot find a suitable version
158  //
159  // -> HELLO VERSION ...
160  // <- HELLO REPLY RESULT=NOVERSION MESSAGE={$message}
162 
163  // The naming system can't resolve the given name
164  //
165  // -> NAMING LOOKUP ...
166  // <- NAMING REPLY RESULT=INVALID_KEY NAME={$name} MESSAGE={$message}
168 
169  // The peer cannot be found on the network
170  //
171  // ??
173 
174  // ??
175  //
176  // -> STREAM ACCEPT
177  // <- STREAM STATUS RESULT=ALREADY_ACCEPTING
179 
180  // ??
182  // ??
184  };
185 
186  template<class T>
187  struct Answer
188  {
190  T value;
191 
192  Answer(Message::eStatus status, const T& value)
193  : status(status), value(value) {}
194  explicit Answer(Message::eStatus status)
195  : status(status), value() {}
196  };
197 
198  static std::string hello(const std::string& minVer, const std::string& maxVer);
199  static std::string sessionCreate(SessionStyle style, const std::string& sessionID, const std::string& nickname, const std::string& destination = SAM_GENERATE_MY_DESTINATION, const std::string& options = "");
200  static std::string streamAccept(const std::string& sessionID, bool silent = false);
201  static std::string streamConnect(const std::string& sessionID, const std::string& destination, bool silent = false);
202  static std::string streamForward(const std::string& sessionID, const std::string& host, uint16_t port, bool silent = false);
203 
204  static std::string namingLookup(const std::string& name);
205  static std::string destGenerate();
206 
207  static eStatus checkAnswer(const std::string& answer);
208  static std::string getValue(const std::string& answer, const std::string& key);
209 private:
210  static std::string createSAMRequest(const char* format, ...);
211 };
212 
213 class Socket
214 {
215 public:
216  Socket(const std::string& SAMHost, uint16_t SAMPort, const std::string &minVer, const std::string& maxVer);
217  Socket(const sockaddr_in& addr, const std::string& minVer, const std::string& maxVer);
218  // explicit because we don't want to create any socket implicity
219  explicit Socket(const Socket& rhs); // creates a new socket with the same parameters
220  ~Socket();
221 
222  void bootstrapI2P();
223 
224  void write(const std::string& msg);
225  std::string read();
226  SOCKET release();
227  void close();
228 
229  bool isOk() const;
230 
231  const std::string& getVersion() const;
232  const std::string& getHost() const;
233  uint16_t getPort() const;
234  const std::string& getMinVer() const;
235  const std::string& getMaxVer() const;
236 
237  const sockaddr_in& getAddress() const;
238 
239 private:
240  SOCKET socket_;
241  sockaddr_in servAddr_;
242  std::string SAMHost_;
243  uint16_t SAMPort_;
244  const std::string minVer_;
245  const std::string maxVer_;
246  std::string version_;
247 
248 #ifdef WIN32
249  static int instances_;
250  static void initWSA();
251  static void freeWSA();
252 #endif
253 
254  void handshake();
255  void init();
256 
257  Socket& operator=(const Socket&);
258 };
259 
261 {
262  std::string pub;
263  std::string priv;
265 
267  FullDestination(const std::string& pub, const std::string& priv, bool isGenerated)
268  :pub(pub), priv(priv), isGenerated(isGenerated) {}
269 };
270 
271 template<class T>
273 {
274  bool isOk;
275  T value;
276 
278  : isOk(false) {}
279 
280  explicit RequestResult(const T& value)
281  : isOk(true), value(value) {}
282 };
283 
284 template<class T>
285 struct RequestResult<std::auto_ptr<T> >
286 {
287  // a class-helper for resolving a problem with conversion from temporary RequestResult to non-const RequestResult&
288  struct RequestResultRef
289  {
290  bool isOk;
291  T* value;
292 
293  RequestResultRef(bool isOk, T* value)
294  : isOk(isOk), value(value) {}
295  };
296 
297  bool isOk;
298  std::auto_ptr<T> value;
299 
301  : isOk(false) {}
302 
303  explicit RequestResult(std::auto_ptr<T>& value)
304  : isOk(true), value(value) {}
305 
306 
307  // some C++ magic
308  RequestResult(RequestResultRef ref)
309  : isOk(ref.isOk), value(ref.value) {}
310 
311  RequestResult& operator=(RequestResultRef ref)
312  {
313  if (value.get() != ref.value)
314  {
315  isOk = ref.isOk;
316  value.reset(ref.value);
317  }
318  return *this;
319  }
320 
321  operator RequestResultRef()
322  {
323  return RequestResultRef(this->isOk, this->value.release());
324  }
325 };
326 
327 template<>
328 struct RequestResult<void>
329 {
330  bool isOk;
331 
333  : isOk(false) {}
334 
335  explicit RequestResult(bool isOk)
336  : isOk(isOk) {}
337 };
338 
340 {
341 public:
343  const std::string& nickname,
344  const std::string& SAMHost = SAM_DEFAULT_ADDRESS,
345  uint16_t SAMPort = SAM_DEFAULT_PORT,
346  const std::string& destination = SAM_GENERATE_MY_DESTINATION,
347  const std::string& i2pOptions = SAM_DEFAULT_I2P_OPTIONS,
348  const std::string& minVer = SAM_DEFAULT_MIN_VER,
349  const std::string& maxVer = SAM_DEFAULT_MAX_VER);
350  explicit StreamSession(StreamSession& rhs);
351  ~StreamSession();
352 
353  static std::string generateSessionID();
354 
356  RequestResult<std::auto_ptr<Socket> > connect(const std::string& destination, bool silent);
357  RequestResult<void> forward(const std::string& host, uint16_t port, bool silent);
358  RequestResult<const std::string> namingLookup(const std::string& name) const;
360 
361  void stopForwarding(const std::string& host, uint16_t port);
362  void stopForwardingAll();
363 
364  const FullDestination& getMyDestination() const;
365 
366  const sockaddr_in& getSAMAddress() const;
367  const std::string& getSAMHost() const;
368  uint16_t getSAMPort() const;
369  const std::string& getNickname() const;
370  const std::string& getSessionID() const;
371  const std::string& getSAMMinVer() const;
372  const std::string& getSAMMaxVer() const;
373  const std::string& getSAMVersion() const;
374  const std::string& getOptions() const;
375 
376  bool isSick() const;
377 
378 private:
379  StreamSession(const StreamSession& rhs);
381 
383  {
385  std::string host;
386  uint16_t port;
387  bool silent;
388 
389  ForwardedStream(Socket* socket, const std::string& host, uint16_t port, bool silent)
390  : socket(socket), host(host), port(port), silent(silent) {}
391  };
392 
393  typedef std::list<ForwardedStream> ForwardedStreamsContainer;
394 
396  const std::string nickname_;
397  const std::string sessionID_;
399  const std::string i2pOptions_;
400  ForwardedStreamsContainer forwardedStreams_;
401  mutable bool isSick_;
402 
403  void fallSick() const;
404  FullDestination createStreamSession(const std::string &destination);
405 
406  static Message::Answer<const std::string> rawRequest(Socket& socket, const std::string& requestStr);
407  static Message::Answer<const std::string> request(Socket& socket, const std::string& requestStr, const std::string& keyOnSuccess);
408  static Message::eStatus request(Socket& socket, const std::string& requestStr);
409  // commands
410  static Message::Answer<const std::string> createStreamSession(Socket& socket, const std::string& sessionID, const std::string& nickname, const std::string& destination, const std::string& options);
411  static Message::Answer<const std::string> namingLookup(Socket& socket, const std::string& name);
413 
414  static Message::eStatus accept(Socket& socket, const std::string& sessionID, bool silent);
415  static Message::eStatus connect(Socket& socket, const std::string& sessionID, const std::string& destination, bool silent);
416  static Message::eStatus forward(Socket& socket, const std::string& sessionID, const std::string& host, uint16_t port, bool silent);
417 };
418 
419 } // namespace SAM
420 
421 #endif // I2PSAM_H
const std::string & getMaxVer() const
Definition: i2psam.cpp:247
#define SAM_DEFAULT_ADDRESS
Definition: i2psam.h:28
SOCKET socket_
Definition: i2psam.h:240
const std::string sessionID_
Definition: i2psam.h:397
bool isSick() const
Definition: i2psam.cpp:572
const std::string & getSAMVersion() const
Definition: i2psam.cpp:602
std::string read()
Definition: i2psam.cpp:188
static std::string streamAccept(const std::string &sessionID, bool silent=false)
Definition: i2psam.cpp:676
RequestResult< std::auto_ptr< Socket > > accept(bool silent)
Definition: i2psam.cpp:328
const std::string & getOptions() const
Definition: i2psam.cpp:562
const std::string & getSAMMaxVer() const
Definition: i2psam.cpp:597
std::string pub
Definition: i2psam.h:262
int SOCKET
Definition: i2psam.h:69
std::string version_
Definition: i2psam.h:246
uint16_t getPort() const
Definition: i2psam.cpp:232
const std::string & getVersion() const
Definition: i2psam.cpp:237
uint16_t getSAMPort() const
Definition: i2psam.cpp:587
RequestResult< void > forward(const std::string &host, uint16_t port, bool silent)
Definition: i2psam.cpp:372
const std::string maxVer_
Definition: i2psam.h:245
RequestResult & operator=(RequestResultRef ref)
Definition: i2psam.h:311
uint16_t SAMPort_
Definition: i2psam.h:243
RequestResult(bool isOk)
Definition: i2psam.h:335
static std::string destGenerate()
Definition: i2psam.cpp:750
static Message::Answer< const std::string > rawRequest(Socket &socket, const std::string &requestStr)
Definition: i2psam.cpp:478
const std::string & getSAMMinVer() const
Definition: i2psam.cpp:592
FullDestination myDestination_
Definition: i2psam.h:398
void init()
Definition: i2psam.cpp:127
static Message::Answer< const std::string > request(Socket &socket, const std::string &requestStr, const std::string &keyOnSuccess)
Definition: i2psam.cpp:491
Answer(Message::eStatus status, const T &value)
Definition: i2psam.h:192
Socket(const std::string &SAMHost, uint16_t SAMPort, const std::string &minVer, const std::string &maxVer)
Definition: i2psam.cpp:74
Definition: i2psam.cpp:36
#define SAM_DEFAULT_MIN_VER
Definition: i2psam.h:30
FullDestination createStreamSession(const std::string &destination)
Definition: i2psam.cpp:438
const Message::eStatus status
Definition: i2psam.h:189
const std::string nickname_
Definition: i2psam.h:396
const std::string & getHost() const
Definition: i2psam.cpp:227
static std::string createSAMRequest(const char *format,...)
Definition: i2psam.cpp:610
static std::string streamForward(const std::string &sessionID, const std::string &host, uint16_t port, bool silent=false)
Definition: i2psam.cpp:713
#define SAM_DEFAULT_I2P_OPTIONS
Definition: i2psam.h:34
void close()
Definition: i2psam.cpp:215
const std::string minVer_
Definition: i2psam.h:244
std::string SAMHost_
Definition: i2psam.h:242
RequestResult< const std::string > namingLookup(const std::string &name) const
Definition: i2psam.cpp:396
RequestResult< std::auto_ptr< Socket > > connect(const std::string &destination, bool silent)
Definition: i2psam.cpp:350
static eStatus checkAnswer(const std::string &answer)
Definition: i2psam.cpp:772
const FullDestination & getMyDestination() const
Definition: i2psam.cpp:567
ForwardedStream(Socket *socket, const std::string &host, uint16_t port, bool silent)
Definition: i2psam.h:389
const std::string i2pOptions_
Definition: i2psam.h:399
RequestResult(const T &value)
Definition: i2psam.h:280
static std::string hello(const std::string &minVer, const std::string &maxVer)
Definition: i2psam.cpp:630
std::list< ForwardedStream > ForwardedStreamsContainer
Definition: i2psam.h:393
#define SAM_GENERATE_MY_DESTINATION
Definition: i2psam.h:32
Socket & operator=(const Socket &)
StreamSession(const std::string &nickname, const std::string &SAMHost=SAM_DEFAULT_ADDRESS, uint16_t SAMPort=SAM_DEFAULT_PORT, const std::string &destination=SAM_GENERATE_MY_DESTINATION, const std::string &i2pOptions=SAM_DEFAULT_I2P_OPTIONS, const std::string &minVer=SAM_DEFAULT_MIN_VER, const std::string &maxVer=SAM_DEFAULT_MAX_VER)
Definition: i2psam.cpp:260
static std::string streamConnect(const std::string &sessionID, const std::string &destination, bool silent=false)
Definition: i2psam.cpp:694
const sockaddr_in & getSAMAddress() const
Definition: i2psam.cpp:577
const std::string & getSessionID() const
Definition: i2psam.cpp:557
void stopForwardingAll()
Definition: i2psam.cpp:470
static std::string generateSessionID()
Definition: i2psam.cpp:309
const sockaddr_in & getAddress() const
Definition: i2psam.cpp:252
RequestResult(std::auto_ptr< T > &value)
Definition: i2psam.h:303
void bootstrapI2P()
Definition: i2psam.cpp:120
static std::string namingLookup(const std::string &name)
Definition: i2psam.cpp:732
static std::string sessionCreate(SessionStyle style, const std::string &sessionID, const std::string &nickname, const std::string &destination=SAM_GENERATE_MY_DESTINATION, const std::string &options="")
Definition: i2psam.cpp:648
StreamSession & operator=(const StreamSession &rhs)
#define SAM_DEFAULT_PORT
Definition: i2psam.h:29
std::string priv
Definition: i2psam.h:263
static std::string getValue(const std::string &answer, const std::string &key)
Definition: i2psam.cpp:799
const std::string & getSAMHost() const
Definition: i2psam.cpp:582
void fallSick() const
Definition: i2psam.cpp:451
void write(const std::string &msg)
Definition: i2psam.cpp:163
ForwardedStreamsContainer forwardedStreams_
Definition: i2psam.h:400
sockaddr_in servAddr_
Definition: i2psam.h:241
const std::string & getMinVer() const
Definition: i2psam.cpp:242
SOCKET release()
Definition: i2psam.cpp:144
const std::string & getNickname() const
Definition: i2psam.cpp:552
void stopForwarding(const std::string &host, uint16_t port)
Definition: i2psam.cpp:456
bool isOk() const
Definition: i2psam.cpp:222
RequestResult(RequestResultRef ref)
Definition: i2psam.h:308
#define SAM_DEFAULT_MAX_VER
Definition: i2psam.h:31
Socket socket_
Definition: i2psam.h:395
void format(FormatIterator &fmtIter)
Definition: tinyformat.h:870
Answer(Message::eStatus status)
Definition: i2psam.h:194
FullDestination(const std::string &pub, const std::string &priv, bool isGenerated)
Definition: i2psam.h:267
void handshake()
Definition: i2psam.cpp:152
RequestResult< const FullDestination > destGenerate() const
Definition: i2psam.cpp:417