Merge pull request #10 from polistern/feat/base-session-class
feat: Datagrams and etc.
This commit is contained in:
45
.gitignore
vendored
45
.gitignore
vendored
@ -1,3 +1,48 @@
|
||||
# emacs
|
||||
*~
|
||||
\#*\#
|
||||
tramp
|
||||
.\#*
|
||||
|
||||
# IDE
|
||||
/.idea/
|
||||
/.vscode/
|
||||
/.gradle/
|
||||
/gradle/
|
||||
*.code-workspace
|
||||
|
||||
# Prerequisites
|
||||
*.d
|
||||
|
||||
# Compiled Object files
|
||||
*.slo
|
||||
*.lo
|
||||
*.o
|
||||
*.obj
|
||||
|
||||
# Precompiled Headers
|
||||
*.gch
|
||||
*.pch
|
||||
|
||||
# Compiled Dynamic libraries
|
||||
*.so
|
||||
*.dylib
|
||||
*.dll
|
||||
|
||||
# Fortran module files
|
||||
*.mod
|
||||
*.smod
|
||||
|
||||
# Compiled Static libraries
|
||||
*.lai
|
||||
*.la
|
||||
*.a
|
||||
*.lib
|
||||
|
||||
# Executables
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
|
||||
# Misc
|
||||
eepget
|
||||
|
1
LICENSE
1
LICENSE
@ -1,5 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019-2022 polistern
|
||||
Copyright (c) 2017 The I2P Project
|
||||
Copyright (c) 2013-2015 The Anoncoin Core developers
|
||||
Copyright (c) 2012-2013 giv
|
||||
|
4
Makefile
4
Makefile
@ -5,11 +5,11 @@ OBJS=$(SRCS:.cpp=.o)
|
||||
TARGET=libi2psam.a
|
||||
|
||||
$(TARGET): $(OBJS)
|
||||
$(AR) $(ARFLAGS) $(TARGET) $(OBJS)
|
||||
$(AR) $(ARFLAGS) $(TARGET) $(OBJS)
|
||||
|
||||
LOADLIBES=-L./ -li2psam
|
||||
|
||||
eepget: eepget.cpp $(TARGET)
|
||||
|
||||
clean:
|
||||
$(RM) $(TARGET) $(OBJS) eepget
|
||||
$(RM) $(TARGET) $(OBJS) eepget
|
||||
|
21
README.md
21
README.md
@ -1,19 +1,30 @@
|
||||
[](https://github.com/i2p/i2psam/blob/master/LICENSE)
|
||||
|
||||
# i2psam
|
||||
|
||||
A C++ library for the [SAM v3 API](https://geti2p.net/en/docs/api/samv3).
|
||||
|
||||
## Development Status
|
||||
|
||||
The library will require SAM v3.1 server.
|
||||
The library will require SAM v3.1 server.
|
||||
Pre-release (ongoing refactoring work and migration to C++11).
|
||||
|
||||
## Usage
|
||||
|
||||
Copy the files `i2psam.cpp` and `i2psam.h` into your codebase, or build the
|
||||
library `libi2psam.a`:
|
||||
### Library
|
||||
|
||||
make
|
||||
Copy the files `i2psam.cpp` and `i2psam.h` into your codebase.
|
||||
You can also build the library `libi2psam.a`:
|
||||
|
||||
See `eepget.cpp` for example tcp client usage (build with `make eepget`).
|
||||
```
|
||||
make
|
||||
```
|
||||
|
||||
### Example
|
||||
|
||||
See `eepget.cpp` for example TCP client usage.
|
||||
Build with:
|
||||
|
||||
```
|
||||
make eepget
|
||||
```
|
||||
|
93
compat.h
93
compat.h
@ -1,34 +1,45 @@
|
||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2014 The Bitcoin developers
|
||||
// Copyright (c) 2013-2015 The Anoncoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
/**
|
||||
* Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
* Copyright (c) 2009-2014 The Bitcoin developers
|
||||
* Copyright (c) 2013-2015 The Anoncoin Core developers
|
||||
*
|
||||
* Distributed under the MIT software license, see the accompanying
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
*
|
||||
* See full documentation about SAM at http://www.i2p2.i2p/samv3.html
|
||||
*/
|
||||
|
||||
#ifndef I2PSAM_COMPAT_H
|
||||
#define I2PSAM_COMPAT_H
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
#ifdef _WIN32_WINNT
|
||||
#undef _WIN32_WINNT
|
||||
#endif
|
||||
#endif // _WIN32_WINNT
|
||||
|
||||
#define _WIN32_WINNT 0x0501
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN 1
|
||||
#endif
|
||||
#endif // WIN32_LEAN_AND_MEAN
|
||||
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
#endif // NOMINMAX
|
||||
|
||||
#ifdef FD_SETSIZE
|
||||
#undef FD_SETSIZE // prevent redefinition compiler warning
|
||||
#endif
|
||||
#endif // FD_SETSIZE
|
||||
|
||||
#define FD_SETSIZE 1024 // max number of fds in fd_set
|
||||
|
||||
#include <winsock2.h> // Must be included before mswsock.h and windows.h
|
||||
|
||||
#include <winsock2.h> // Must be included before mswsock.h and windows.h
|
||||
#include <mswsock.h>
|
||||
#include <windows.h>
|
||||
#include <ws2tcpip.h>
|
||||
#else
|
||||
|
||||
#else // WIN32
|
||||
|
||||
#include <sys/fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/socket.h>
|
||||
@ -40,34 +51,34 @@
|
||||
#include <limits.h>
|
||||
#include <netdb.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#endif // WIN32
|
||||
|
||||
#ifdef WIN32
|
||||
#define MSG_DONTWAIT 0
|
||||
#else
|
||||
#define MSG_DONTWAIT 0
|
||||
#else // WIN32
|
||||
typedef u_int SOCKET;
|
||||
#include "errno.h"
|
||||
#define WSAGetLastError() errno
|
||||
#define WSAEINVAL EINVAL
|
||||
#define WSAEALREADY EALREADY
|
||||
#define WSAEWOULDBLOCK EWOULDBLOCK
|
||||
#define WSAEMSGSIZE EMSGSIZE
|
||||
#define WSAEINTR EINTR
|
||||
#define WSAEINPROGRESS EINPROGRESS
|
||||
#define WSAEADDRINUSE EADDRINUSE
|
||||
#define WSAENOTSOCK EBADF
|
||||
#define INVALID_SOCKET (SOCKET)(~0)
|
||||
#define SOCKET_ERROR -1
|
||||
#endif
|
||||
#define WSAGetLastError() errno
|
||||
#define WSAEINVAL EINVAL
|
||||
#define WSAEALREADY EALREADY
|
||||
#define WSAEWOULDBLOCK EWOULDBLOCK
|
||||
#define WSAEMSGSIZE EMSGSIZE
|
||||
#define WSAEINTR EINTR
|
||||
#define WSAEINPROGRESS EINPROGRESS
|
||||
#define WSAEADDRINUSE EADDRINUSE
|
||||
#define WSAENOTSOCK EBADF
|
||||
#define INVALID_SOCKET (SOCKET)(~0)
|
||||
#define SOCKET_ERROR -1
|
||||
#endif // WIN32
|
||||
|
||||
#ifdef WIN32
|
||||
#ifndef S_IRUSR
|
||||
#define S_IRUSR 0400
|
||||
#define S_IWUSR 0200
|
||||
#endif
|
||||
#else
|
||||
#define MAX_PATH 1024
|
||||
#endif
|
||||
#define S_IRUSR 0400
|
||||
#define S_IWUSR 0200
|
||||
#endif // S_IRUSR
|
||||
#else // WIN32
|
||||
#define MAX_PATH 1024
|
||||
#endif // WIN32
|
||||
|
||||
// As Solaris does not have the MSG_NOSIGNAL flag for send(2) syscall, it is defined as 0
|
||||
#if !defined(HAVE_MSG_NOSIGNAL) && !defined(MSG_NOSIGNAL)
|
||||
@ -75,16 +86,18 @@ typedef u_int SOCKET;
|
||||
#endif
|
||||
|
||||
#ifndef WIN32
|
||||
|
||||
// PRIO_MAX is not defined on Solaris
|
||||
#ifndef PRIO_MAX
|
||||
#define PRIO_MAX 20
|
||||
#endif
|
||||
#define THREAD_PRIORITY_LOWEST PRIO_MAX
|
||||
#define THREAD_PRIORITY_BELOW_NORMAL 2
|
||||
#define THREAD_PRIORITY_NORMAL 0
|
||||
#define THREAD_PRIORITY_ABOVE_NORMAL (-2)
|
||||
#endif
|
||||
#endif // PRIO_MAX
|
||||
|
||||
size_t strnlen_int( const char *start, size_t max_len);
|
||||
#define THREAD_PRIORITY_LOWEST PRIO_MAX
|
||||
#define THREAD_PRIORITY_BELOW_NORMAL 2
|
||||
#define THREAD_PRIORITY_NORMAL 0
|
||||
#define THREAD_PRIORITY_ABOVE_NORMAL (-2)
|
||||
#endif // WIN32
|
||||
|
||||
size_t strnlen_int(const char *start, size_t max_len);
|
||||
|
||||
#endif // I2PSAM_COMPAT_H
|
||||
|
47
eepget.cpp
47
eepget.cpp
@ -1,28 +1,35 @@
|
||||
// Copyright (c) 2017 The I2P Project
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file LICENSE or http://www.opensource.org/licenses/mit-license.php.
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/**
|
||||
* Copyright (c) 2017 The I2P Project
|
||||
*
|
||||
* Distributed under the MIT software license, see the accompanying
|
||||
* file LICENSE or http://www.opensource.org/licenses/mit-license.php.
|
||||
*
|
||||
* See full documentation about SAM at http://www.i2p2.i2p/samv3.html
|
||||
*/
|
||||
|
||||
#include "i2psam.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (argc < 2) {
|
||||
std::cerr << "Usage: eepget <hostname.i2p>" << std::endl;
|
||||
return 1;
|
||||
if (argc < 2)
|
||||
{
|
||||
std::cerr << "Usage: eepget <hostname.i2p>" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
std::string target(argv[1]);
|
||||
SAM::StreamSession s("eepget");
|
||||
auto lookupResult = s.namingLookup(target);
|
||||
auto connResult = s.connect(lookupResult.value, false);
|
||||
auto conn = connResult.value.get();
|
||||
conn->write("GET / HTTP/1.1\r\n\r\n");
|
||||
auto reply = conn->read();
|
||||
while (!reply.empty()) {
|
||||
std::cout << reply << std::flush;
|
||||
reply = conn->read();
|
||||
|
||||
std::string target(argv[1]);
|
||||
SAM::StreamSession s("eepget");
|
||||
auto lookupResult = s.namingLookup(target);
|
||||
auto connResult = s.connect(lookupResult.value, false);
|
||||
auto conn = connResult.value.get();
|
||||
conn->write("GET / HTTP/1.1\r\n\r\n");
|
||||
auto reply = conn->read();
|
||||
|
||||
while (!reply.empty())
|
||||
{
|
||||
std::cout << reply << std::flush;
|
||||
reply = conn->read();
|
||||
}
|
||||
conn->close();
|
||||
|
||||
conn->close();
|
||||
}
|
||||
|
173
i2psam-c.h
173
i2psam-c.h
@ -1,9 +1,10 @@
|
||||
//
|
||||
// c wrapper for i2psam
|
||||
// Author: jeff
|
||||
// License: MIT
|
||||
// probably contains bugs :-DDDD
|
||||
//
|
||||
/**
|
||||
* C wrapper for i2psam
|
||||
* Author: jeff
|
||||
* License: MIT
|
||||
* probably contains bugs :-DDDD
|
||||
*/
|
||||
|
||||
#ifndef I2PSAM_C_H
|
||||
#define I2PSAM_C_H
|
||||
|
||||
@ -17,182 +18,182 @@ struct i2psam_socket;
|
||||
struct i2psam_stream_settings
|
||||
{
|
||||
/**
|
||||
hostname of sam interface
|
||||
* hostname of sam interface
|
||||
*/
|
||||
const char * samhost;
|
||||
const char *samhost;
|
||||
/**
|
||||
port of sam interface
|
||||
* port of sam interface
|
||||
*/
|
||||
const uint16_t samport;
|
||||
/**
|
||||
nickname for sam session
|
||||
* nickname for sam session
|
||||
*/
|
||||
const char * nickname;
|
||||
const char *nickname;
|
||||
/**
|
||||
i2cp options string
|
||||
* i2cp options string
|
||||
*/
|
||||
const char * i2cp_opts;
|
||||
const char *i2cp_opts;
|
||||
/**
|
||||
destination private key
|
||||
* destination private key
|
||||
*/
|
||||
const char * destination;
|
||||
const char *destination;
|
||||
};
|
||||
|
||||
/**
|
||||
create new stream session
|
||||
* create new stream session
|
||||
*/
|
||||
struct i2psam_stream_session * i2psam_stream_session_new(struct i2psam_stream_settings *);
|
||||
struct i2psam_stream_session *i2psam_stream_session_new(struct i2psam_stream_settings *);
|
||||
|
||||
/**
|
||||
close and free stream session
|
||||
* close and free stream session
|
||||
*/
|
||||
void i2psam_stream_session_free(struct i2psam_stream_session *);
|
||||
|
||||
/**
|
||||
get sam host of stream session
|
||||
@return must be free()'d by caller
|
||||
* get sam host of stream session
|
||||
* @return must be free()'d by caller
|
||||
*/
|
||||
const char * i2psam_get_samhost(struct i2psam_stream_session *);
|
||||
const char *i2psam_get_samhost(struct i2psam_stream_session *);
|
||||
|
||||
/**
|
||||
get sam port of stream session
|
||||
* get sam port of stream session
|
||||
*/
|
||||
uint16_t i2psam_get_samport(struct i2psam_stream_session *);
|
||||
|
||||
/**
|
||||
get sam session's nickname
|
||||
@return must be free()'d by caller
|
||||
* get sam session's nickname
|
||||
* @return must be free()'d by caller
|
||||
*/
|
||||
const char * i2psam_get_nickname(struct i2psam_stream_session *);
|
||||
const char *i2psam_get_nickname(struct i2psam_stream_session *);
|
||||
|
||||
/**
|
||||
get sam session's id
|
||||
@return must be free()'d by caller
|
||||
* get sam session's id
|
||||
* @return must be free()'d by caller
|
||||
*/
|
||||
const char * i2psam_get_session_id(struct i2psam_stream_session *);
|
||||
const char *i2psam_get_session_id(struct i2psam_stream_session *);
|
||||
|
||||
/**
|
||||
get min version from sam session's handshake
|
||||
@return must be free()'d by caller
|
||||
* get min version from sam session's handshake
|
||||
* @return must be free()'d by caller
|
||||
*/
|
||||
const char * i2psam_get_sam_min_version(struct i2psam_stream_session *);
|
||||
const char *i2psam_get_sam_min_version(struct i2psam_stream_session *);
|
||||
|
||||
/**
|
||||
get max version from sam session's handshake
|
||||
@return must be free()'d by caller
|
||||
* get max version from sam session's handshake
|
||||
* @return must be free()'d by caller
|
||||
*/
|
||||
const char * i2psam_get_sam_max_version(struct i2psam_stream_session *);
|
||||
const char *i2psam_get_sam_max_version(struct i2psam_stream_session *);
|
||||
|
||||
/**
|
||||
get current version in use with sam session
|
||||
@return must be free()'d by caller
|
||||
* get current version in use with sam session
|
||||
* @return must be free()'d by caller
|
||||
*/
|
||||
const char * i2psam_get_sam_version(struct i2psam_stream_session *);
|
||||
const char *i2psam_get_sam_version(struct i2psam_stream_session *);
|
||||
|
||||
/**
|
||||
get i2cp options used by sam session
|
||||
@return must be free()'d by caller
|
||||
* get i2cp options used by sam session
|
||||
* @return must be free()'d by caller
|
||||
*/
|
||||
const char * i2psam_get_i2cp_options(struct i2psam_stream_session *);
|
||||
const char *i2psam_get_i2cp_options(struct i2psam_stream_session *);
|
||||
|
||||
/**
|
||||
return 1 if session is sick otherwise returns 0
|
||||
* return 1 if session is sick otherwise returns 0
|
||||
*/
|
||||
int i2psam_is_sick(struct i2psam_stream_session *);
|
||||
|
||||
/**
|
||||
accept a new inbound connection
|
||||
@param silent 0 if we want to obtain the remote's destination, nonzero means don't
|
||||
* accept a new inbound connection
|
||||
* @param silent 0 if we want to obtain the remote's destination, nonzero means don't
|
||||
*/
|
||||
struct i2psam_socket * i2psam_accept(struct i2psam_stream_session *, int silent);
|
||||
struct i2psam_socket *i2psam_accept(struct i2psam_stream_session *, int silent);
|
||||
|
||||
/**
|
||||
connect to remote destination
|
||||
@param destination full public destination base64 blob
|
||||
@param silent 0 if we want to get verbose error info from connect, nonzero means don't
|
||||
* connect to remote destination
|
||||
* @param destination full public destination base64 blob
|
||||
* @param silent 0 if we want to get verbose error info from connect, nonzero means don't
|
||||
*/
|
||||
struct i2psam_socket * i2psam_connect(struct i2psam_stream_session *, const char * destination, int silent);
|
||||
struct i2psam_socket *i2psam_connect(struct i2psam_stream_session *, const char *destination, int silent);
|
||||
|
||||
/**
|
||||
forward all inbound connections to a remote endpoint
|
||||
@param host remote hostname of endpoint
|
||||
@param port remote port of endpoint
|
||||
@param silent 0 if we want to be verbose when forwarding to remote endpoint, nonzero means don't
|
||||
@return -1 on fail, otherwise 0
|
||||
* forward all inbound connections to a remote endpoint
|
||||
* @param host remote hostname of endpoint
|
||||
* @param port remote port of endpoint
|
||||
* @param silent 0 if we want to be verbose when forwarding to remote endpoint, nonzero means don't
|
||||
* @return -1 on fail, otherwise 0
|
||||
*/
|
||||
int i2psam_forward(struct i2psam_stream_session *, const char * host, uint16_t port, int silent);
|
||||
int i2psam_forward(struct i2psam_stream_session *, const char *host, uint16_t port, int silent);
|
||||
|
||||
/**
|
||||
do a name lookup, if return is non null caller must free()'d
|
||||
@param name the name to resolve
|
||||
@return public destination base64 blob for the name or NULL if the name lookup fails
|
||||
* do a name lookup, if return is non null caller must free()'d
|
||||
* @param name the name to resolve
|
||||
* @return public destination base64 blob for the name or NULL if the name lookup fails
|
||||
*/
|
||||
const char * i2psam_namelookup(struct i2psam_stream_session *, const char * name);
|
||||
const char *i2psam_namelookup(struct i2psam_stream_session *, const char *name);
|
||||
|
||||
/**
|
||||
generate a new i2p destination keypair, return value must be free()'d when done
|
||||
@return newly generated keypair
|
||||
* generate a new i2p destination keypair, return value must be free()'d when done
|
||||
* @return newly generated keypair
|
||||
*/
|
||||
struct i2psam_destination * i2psam_dest_generate(struct i2psam_stream_session *);
|
||||
struct i2psam_destination *i2psam_dest_generate(struct i2psam_stream_session *);
|
||||
|
||||
/**
|
||||
stop forwarding to remote endpoint
|
||||
@param host hostname of remote endpoint
|
||||
@param port port of remote endpoint
|
||||
* stop forwarding to remote endpoint
|
||||
* @param host hostname of remote endpoint
|
||||
* @param port port of remote endpoint
|
||||
*/
|
||||
void i2psam_stop_forwarding(struct i2psam_stream_session*, const char * host, uint16_t port);
|
||||
void i2psam_stop_forwarding(struct i2psam_stream_session *, const char *host, uint16_t port);
|
||||
|
||||
/**
|
||||
stop forwarding to all remote endpoints
|
||||
* stop forwarding to all remote endpoints
|
||||
*/
|
||||
void i2psam_stop_forwarding_all(struct i2psam_stream_session *);
|
||||
|
||||
/**
|
||||
get remote destination for our stream session
|
||||
@return must be free()'d by caller when done with it
|
||||
* get remote destination for our stream session
|
||||
* @return must be free()'d by caller when done with it
|
||||
*/
|
||||
struct i2psam_destination * i2psam_get_my_destination(struct i2psam_stream_session *);
|
||||
struct i2psam_destination *i2psam_get_my_destination(struct i2psam_stream_session *);
|
||||
|
||||
/**
|
||||
blocking write a buffer of data with an i2psocket
|
||||
@param data buffer to be written
|
||||
@param dlen size of buffer
|
||||
* blocking write a buffer of data with an i2psocket
|
||||
* @param data buffer to be written
|
||||
* @param dlen size of buffer
|
||||
*/
|
||||
void i2psam_write(struct i2psam_socket *, const char * data, size_t dlen);
|
||||
void i2psam_write(struct i2psam_socket *, const char *data, size_t dlen);
|
||||
|
||||
/**
|
||||
blocking read on an i2p socket
|
||||
@param pointer to size read
|
||||
@return pointer to read segment, must be free()'d when done if error while reading returns nullptr
|
||||
* blocking read on an i2p socket
|
||||
* @param pointer to size read
|
||||
* @return pointer to read segment, must be free()'d when done if error while reading returns nullptr
|
||||
*/
|
||||
char * i2psam_read(struct i2psam_socket *, size_t * dlen);
|
||||
char *i2psam_read(struct i2psam_socket *, size_t *dlen);
|
||||
|
||||
/**
|
||||
close an i2p socket, does not free()
|
||||
* close an i2p socket, does not free()
|
||||
*/
|
||||
void i2psam_socket_close(struct i2psam_socket *);
|
||||
|
||||
/**
|
||||
@return 1 if an i2p socket is okay otherwise returns 0
|
||||
* @return 1 if an i2p socket is okay otherwise returns 0
|
||||
*/
|
||||
int i2psam_socket_is_ok(struct i2psam_socket *);
|
||||
|
||||
/**
|
||||
free() an i2p socket, must be closed
|
||||
* free() an i2p socket, must be closed
|
||||
*/
|
||||
void i2psam_socket_free(struct i2psam_socket *);
|
||||
|
||||
/**
|
||||
get private key for destination as null terminated base64 string
|
||||
@return must be free()'d by caller when done
|
||||
* get private key for destination as null terminated base64 string
|
||||
* @return must be free()'d by caller when done
|
||||
*/
|
||||
const char * i2psam_destination_priv(struct i2psam_destination *);
|
||||
const char *i2psam_destination_priv(struct i2psam_destination *);
|
||||
|
||||
/**
|
||||
get public base64 destination blob as null terminated string
|
||||
@return must be free()'d by caller when done
|
||||
* get public base64 destination blob as null terminated string
|
||||
* @return must be free()'d by caller when done
|
||||
*/
|
||||
const char * i2psam_destination_pub(struct i2psam_destination *);
|
||||
const char *i2psam_destination_pub(struct i2psam_destination *);
|
||||
|
||||
void i2psam_destination_free(struct i2psam_destination *);
|
||||
|
||||
|
1849
i2psam.cpp
1849
i2psam.cpp
File diff suppressed because it is too large
Load Diff
789
i2psam.h
789
i2psam.h
@ -1,19 +1,28 @@
|
||||
// Copyright (c) 2017 The I2P Project
|
||||
// Copyright (c) 2013-2015 The Anoncoin Core developers
|
||||
// Copyright (c) 2012-2013 giv
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file LICENSE or http://www.opensource.org/licenses/mit-license.php.
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// see full documentation about SAM at http://www.i2p2.i2p/samv3.html
|
||||
#ifndef I2PSAM_H
|
||||
#define I2PSAM_H
|
||||
/**
|
||||
* Copyright (c) 2019-2022 polistern
|
||||
* Copyright (c) 2017 The I2P Project
|
||||
* Copyright (c) 2013-2015 The Anoncoin Core developers
|
||||
* Copyright (c) 2012-2013 giv
|
||||
*
|
||||
* Distributed under the MIT software license, see the accompanying
|
||||
* file LICENSE or http://www.opensource.org/licenses/mit-license.php.
|
||||
*
|
||||
* See full documentation about SAM at http://www.i2p2.i2p/samv3.html
|
||||
*/
|
||||
|
||||
#ifndef I2PSAM_H__
|
||||
#define I2PSAM_H__
|
||||
|
||||
#define SAM_BUFSIZE 8192
|
||||
#define SAM_DEFAULT_ADDRESS "127.0.0.1"
|
||||
#define SAM_DEFAULT_PORT 7656
|
||||
#define SAM_DEFAULT_PORT_TCP 7656
|
||||
#define SAM_DEFAULT_PORT_UDP 7655
|
||||
#define SAM_DEFAULT_CLIENT_TCP 7666
|
||||
#define SAM_DEFAULT_CLIENT_UDP 7667
|
||||
#define SAM_GENERATE_MY_DESTINATION "TRANSIENT"
|
||||
#define SAM_MY_NAME "ME"
|
||||
#define SAM_DEFAULT_I2P_OPTIONS ""
|
||||
#define SAM_SIGNATURE_TYPE "EdDSA_SHA512_Ed25519"
|
||||
#define SAM_DEFAULT_I2P_OPTIONS SAM_NAME_I2CP_LEASESET_ENC_TYPE "=" SAM_DEFAULT_I2CP_LEASESET_ENC_TYPE // i2cp.leaseSetEncType=0,4
|
||||
#define SAM_SIGNATURE_TYPE "EdDSA_SHA512_Ed25519"
|
||||
|
||||
#define SAM_NAME_INBOUND_QUANTITY "inbound.quantity"
|
||||
#define SAM_DEFAULT_INBOUND_QUANTITY 3 // Three tunnels is default now
|
||||
@ -41,375 +50,575 @@
|
||||
#define SAM_DEFAULT_OUTBOUND_IPRESTRICTION 2
|
||||
#define SAM_NAME_OUTBOUND_PRIORITY "outbound.priority"
|
||||
#define SAM_DEFAULT_OUTBOUND_PRIORITY
|
||||
#define SAM_NAME_I2CP_LEASESET_ENC_TYPE "i2cp.leaseSetEncType"
|
||||
#define SAM_DEFAULT_I2CP_LEASESET_ENC_TYPE "0,4"
|
||||
|
||||
// Define this, if you want more of the original standard output diagnostics
|
||||
//#define DEBUG_ON_STDOUT
|
||||
|
||||
#ifdef __cplusplus // __cplusplus
|
||||
#include "compat.h"
|
||||
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
#include <stdint.h>
|
||||
#include <memory>
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace SAM
|
||||
{
|
||||
|
||||
typedef u_int SOCKET;
|
||||
|
||||
static void print_error(const std::string &err)
|
||||
{
|
||||
#ifdef DEBUG_ON_STDOUT
|
||||
#ifdef WIN32
|
||||
std::cout << err << "(" << WSAGetLastError() << ")" << std::endl;
|
||||
#else // WIN32
|
||||
std::cout << err << "(" << errno << ")" << std::endl;
|
||||
#endif // WIN32
|
||||
#endif // DEBUG_ON_STDOUT
|
||||
}
|
||||
|
||||
class Message
|
||||
{
|
||||
public:
|
||||
enum SessionStyle
|
||||
public:
|
||||
enum SessionStyle
|
||||
{
|
||||
sssStream,
|
||||
sssDatagram, // not supported now
|
||||
sssRaw // not supported now
|
||||
sssStream,
|
||||
sssDatagram,
|
||||
sssRaw
|
||||
};
|
||||
|
||||
enum eStatus
|
||||
enum eStatus
|
||||
{
|
||||
OK,
|
||||
EMPTY_ANSWER,
|
||||
CLOSED_SOCKET,
|
||||
CANNOT_PARSE_ERROR,
|
||||
|
||||
// The destination is already in use
|
||||
//
|
||||
// -> SESSION CREATE ...
|
||||
// <- SESSION STATUS RESULT=DUPLICATED_DEST
|
||||
DUPLICATED_DEST,
|
||||
|
||||
// The nickname is already associated with a session
|
||||
//
|
||||
// -> SESSION CREATE ...
|
||||
// <- SESSION STATUS RESULT=DUPLICATED_ID
|
||||
DUPLICATED_ID,
|
||||
|
||||
// A generic I2P error (e.g. I2CP disconnection, etc.)
|
||||
//
|
||||
// -> HELLO VERSION ...
|
||||
// <- HELLO REPLY RESULT=I2P_ERROR MESSAGE={$message}
|
||||
//
|
||||
// -> SESSION CREATE ...
|
||||
// <- SESSION STATUS RESULT=I2P_ERROR MESSAGE={$message}
|
||||
//
|
||||
// -> STREAM CONNECT ...
|
||||
// <- STREAM STATUS RESULT=I2P_ERROR MESSAGE={$message}
|
||||
//
|
||||
// -> STREAM ACCEPT ...
|
||||
// <- STREAM STATUS RESULT=I2P_ERROR MESSAGE={$message}
|
||||
//
|
||||
// -> STREAM FORWARD ...
|
||||
// <- STREAM STATUS RESULT=I2P_ERROR MESSAGE={$message}
|
||||
//
|
||||
// -> NAMING LOOKUP ...
|
||||
// <- NAMING REPLY RESULT=INVALID_KEY NAME={$name} MESSAGE={$message}
|
||||
I2P_ERROR,
|
||||
|
||||
// Stream session ID doesn't exist
|
||||
//
|
||||
// -> STREAM CONNECT ...
|
||||
// <- STREAM STATUS RESULT=INVALID_ID MESSAGE={$message}
|
||||
//
|
||||
// -> STREAM ACCEPT ...
|
||||
// <- STREAM STATUS RESULT=INVALID_ID MESSAGE={$message}
|
||||
//
|
||||
// -> STREAM FORWARD ...
|
||||
// <- STREAM STATUS RESULT=INVALID_ID MESSAGE={$message}
|
||||
INVALID_ID,
|
||||
|
||||
// The destination is not a valid private destination key
|
||||
//
|
||||
// -> SESSION CREATE ...
|
||||
// <- SESSION STATUS RESULT=INVALID_KEY MESSAGE={$message}
|
||||
//
|
||||
// -> STREAM CONNECT ...
|
||||
// <- STREAM STATUS RESULT=INVALID_KEY MESSAGE={$message}
|
||||
//
|
||||
// -> NAMING LOOKUP ...
|
||||
// <- NAMING REPLY RESULT=INVALID_KEY NAME={$name} MESSAGE={$message}
|
||||
INVALID_KEY,
|
||||
|
||||
// The peer exists, but cannot be reached
|
||||
//
|
||||
// -> STREAM CONNECT ...
|
||||
// <- STREAM STATUS RESULT=CANT_REACH_PEER MESSAGE={$message}
|
||||
CANT_REACH_PEER,
|
||||
|
||||
// Timeout while waiting for an event (e.g. peer answer)
|
||||
//
|
||||
// -> STREAM CONNECT ...
|
||||
// <- STREAM STATUS RESULT=TIMEOUT MESSAGE={$message}
|
||||
TIMEOUT,
|
||||
|
||||
// The SAM bridge cannot find a suitable version
|
||||
//
|
||||
// -> HELLO VERSION ...
|
||||
// <- HELLO REPLY RESULT=NOVERSION MESSAGE={$message}
|
||||
NOVERSION,
|
||||
|
||||
// The naming system can't resolve the given name
|
||||
//
|
||||
// -> NAMING LOOKUP ...
|
||||
// <- NAMING REPLY RESULT=INVALID_KEY NAME={$name} MESSAGE={$message}
|
||||
KEY_NOT_FOUND,
|
||||
|
||||
// The peer cannot be found on the network
|
||||
//
|
||||
// ??
|
||||
PEER_NOT_FOUND,
|
||||
|
||||
// ??
|
||||
//
|
||||
// -> STREAM ACCEPT
|
||||
// <- STREAM STATUS RESULT=ALREADY_ACCEPTING
|
||||
ALREADY_ACCEPTING,
|
||||
|
||||
// ??
|
||||
FAILED,
|
||||
// ??
|
||||
CLOSED
|
||||
OK,
|
||||
EMPTY_ANSWER,
|
||||
CLOSED_SOCKET,
|
||||
CANNOT_PARSE_ERROR,
|
||||
/** The destination is already in use
|
||||
*
|
||||
* -> SESSION CREATE ...
|
||||
* <- SESSION STATUS RESULT=DUPLICATED_DEST
|
||||
*/
|
||||
DUPLICATED_DEST,
|
||||
/**
|
||||
* The nickname is already associated with a session
|
||||
*
|
||||
* -> SESSION CREATE ...
|
||||
* <- SESSION STATUS RESULT=DUPLICATED_ID
|
||||
*/
|
||||
DUPLICATED_ID,
|
||||
/**
|
||||
* A generic I2P error (e.g. I2CP disconnection, etc.)
|
||||
*
|
||||
* -> HELLO VERSION ...
|
||||
* <- HELLO REPLY RESULT=I2P_ERROR MESSAGE={$message}
|
||||
*
|
||||
* -> SESSION CREATE ...
|
||||
* <- SESSION STATUS RESULT=I2P_ERROR MESSAGE={$message}
|
||||
*
|
||||
* -> STREAM CONNECT ...
|
||||
* <- STREAM STATUS RESULT=I2P_ERROR MESSAGE={$message}
|
||||
*
|
||||
* -> STREAM ACCEPT ...
|
||||
* <- STREAM STATUS RESULT=I2P_ERROR MESSAGE={$message}
|
||||
*
|
||||
* -> STREAM FORWARD ...
|
||||
* <- STREAM STATUS RESULT=I2P_ERROR MESSAGE={$message}
|
||||
*
|
||||
* -> NAMING LOOKUP ...
|
||||
* <- NAMING REPLY RESULT=INVALID_KEY NAME={$name} MESSAGE={$message}
|
||||
*/
|
||||
I2P_ERROR,
|
||||
/**
|
||||
* Stream session ID doesn't exist
|
||||
*
|
||||
* -> STREAM CONNECT ...
|
||||
* <- STREAM STATUS RESULT=INVALID_ID MESSAGE={$message}
|
||||
*
|
||||
* -> STREAM ACCEPT ...
|
||||
* <- STREAM STATUS RESULT=INVALID_ID MESSAGE={$message}
|
||||
*
|
||||
* -> STREAM FORWARD ...
|
||||
* <- STREAM STATUS RESULT=INVALID_ID MESSAGE={$message}
|
||||
*/
|
||||
INVALID_ID,
|
||||
/**
|
||||
* The destination is not a valid private destination key
|
||||
*
|
||||
* -> SESSION CREATE ...
|
||||
* <- SESSION STATUS RESULT=INVALID_KEY MESSAGE={$message}
|
||||
*
|
||||
* -> STREAM CONNECT ...
|
||||
* <- STREAM STATUS RESULT=INVALID_KEY MESSAGE={$message}
|
||||
*
|
||||
* -> NAMING LOOKUP ...
|
||||
* <- NAMING REPLY RESULT=INVALID_KEY NAME={$name} MESSAGE={$message}
|
||||
*/
|
||||
INVALID_KEY,
|
||||
/**
|
||||
* The peer exists, but cannot be reached
|
||||
*
|
||||
* -> STREAM CONNECT ...
|
||||
* <- STREAM STATUS RESULT=CANT_REACH_PEER MESSAGE={$message}
|
||||
*/
|
||||
CANT_REACH_PEER,
|
||||
/**
|
||||
* Timeout while waiting for an event (e.g. peer answer)
|
||||
*
|
||||
* -> STREAM CONNECT ...
|
||||
* <- STREAM STATUS RESULT=TIMEOUT MESSAGE={$message}
|
||||
*/
|
||||
TIMEOUT,
|
||||
/**
|
||||
* The SAM bridge cannot find a suitable version
|
||||
*
|
||||
* -> HELLO VERSION ...
|
||||
* <- HELLO REPLY RESULT=NOVERSION MESSAGE={$message}
|
||||
*/
|
||||
NOVERSION,
|
||||
/**
|
||||
* The naming system can't resolve the given name
|
||||
*
|
||||
* -> NAMING LOOKUP ...
|
||||
* <- NAMING REPLY RESULT=INVALID_KEY NAME={$name} MESSAGE={$message}
|
||||
*/
|
||||
KEY_NOT_FOUND,
|
||||
/**
|
||||
* The peer cannot be found on the network
|
||||
*
|
||||
* ??
|
||||
*/
|
||||
PEER_NOT_FOUND,
|
||||
/**
|
||||
* ??
|
||||
*
|
||||
* -> STREAM ACCEPT
|
||||
* <- STREAM STATUS RESULT=ALREADY_ACCEPTING
|
||||
*/
|
||||
ALREADY_ACCEPTING,
|
||||
/**
|
||||
* ??
|
||||
*/
|
||||
FAILED,
|
||||
/**
|
||||
* ??
|
||||
*/
|
||||
CLOSED
|
||||
};
|
||||
|
||||
template<class T>
|
||||
struct Answer
|
||||
{
|
||||
const Message::eStatus status;
|
||||
T value;
|
||||
template<class T>
|
||||
struct Answer
|
||||
{
|
||||
const Message::eStatus status;
|
||||
T value;
|
||||
|
||||
Answer(Message::eStatus status, const T& value)
|
||||
: status(status), value(value) {}
|
||||
explicit Answer(Message::eStatus status)
|
||||
: status(status), value() {}
|
||||
};
|
||||
Answer(Message::eStatus status, const T &value)
|
||||
: status(status), value(value) {}
|
||||
explicit Answer(Message::eStatus status) : status(status), value() {}
|
||||
};
|
||||
|
||||
static std::string hello(const std::string& minVer, const std::string& maxVer);
|
||||
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 = "", const std::string& signatureType = SAM_SIGNATURE_TYPE);
|
||||
static std::string streamAccept(const std::string& sessionID, bool silent = false);
|
||||
static std::string streamConnect(const std::string& sessionID, const std::string& destination, bool silent = false);
|
||||
static std::string streamForward(const std::string& sessionID, const std::string& host, uint16_t port, bool silent = false);
|
||||
static std::string hello(const std::string &minVer,
|
||||
const std::string &maxVer);
|
||||
// Stream session
|
||||
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 = "",
|
||||
const std::string &signatureType = SAM_SIGNATURE_TYPE);
|
||||
static std::string streamAccept(const std::string &sessionID,
|
||||
bool silent = false);
|
||||
static std::string streamConnect(const std::string &sessionID,
|
||||
const std::string &destination,
|
||||
bool silent = false);
|
||||
static std::string streamForward(const std::string &sessionID,
|
||||
const std::string &host, uint16_t port,
|
||||
bool silent = false);
|
||||
|
||||
static std::string namingLookup(const std::string& name);
|
||||
static std::string destGenerate();
|
||||
// Datagram session
|
||||
static std::string
|
||||
sessionCreate(SessionStyle style, const std::string &sessionID,
|
||||
const std::string &nickname, const uint16_t port,
|
||||
const std::string &host = "127.0.0.1",
|
||||
const std::string &destination = SAM_GENERATE_MY_DESTINATION,
|
||||
const std::string &options = "",
|
||||
const std::string &signatureType = SAM_SIGNATURE_TYPE);
|
||||
static std::string datagramSend(const std::string &nickname,
|
||||
const std::string &destination/*,
|
||||
const std::string &datagram_payload*/);
|
||||
static std::string datagramParse(const std::string &datagram_payload);
|
||||
|
||||
static eStatus checkAnswer(const std::string& answer);
|
||||
static std::string getValue(const std::string& answer, const std::string& key);
|
||||
private:
|
||||
static std::string createSAMRequest(const char* format, ...);
|
||||
static std::string namingLookup(const std::string &name);
|
||||
static std::string destGenerate();
|
||||
|
||||
static eStatus checkAnswer(const std::string &answer);
|
||||
static std::string getValue(const std::string &answer,
|
||||
const std::string &key);
|
||||
|
||||
private:
|
||||
template<typename... t_args>
|
||||
static std::string
|
||||
createSAMRequest(const char *msg) { return {msg}; }
|
||||
|
||||
template<typename... t_args>
|
||||
static std::string
|
||||
createSAMRequest(const char *format, t_args &&... args)
|
||||
{
|
||||
// ToDo: Check allocated buffer size
|
||||
|
||||
const int bufferStatus = std::snprintf(nullptr, 0, format, args...);
|
||||
if (bufferStatus < 0)
|
||||
{
|
||||
print_error("Failed to allocate buffer");
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<char> buffer(bufferStatus + 1);
|
||||
const int status =
|
||||
std::snprintf(buffer.data(), buffer.size(), format, args...);
|
||||
|
||||
if (status < 0)
|
||||
{
|
||||
print_error("Failed to format message");
|
||||
return {};
|
||||
}
|
||||
|
||||
#ifdef DEBUG_ON_STDOUT
|
||||
std::cout << "Status: " << status << std::endl;
|
||||
#endif // DEBUG_ON_STDOUT
|
||||
|
||||
return {buffer.data()};
|
||||
}
|
||||
};
|
||||
|
||||
class I2pSocket
|
||||
{
|
||||
public:
|
||||
I2pSocket(const std::string& SAMHost, uint16_t SAMPort);
|
||||
I2pSocket(const sockaddr_in& addr);
|
||||
// explicit because we don't want to create any socket implicity
|
||||
explicit I2pSocket(const I2pSocket& rhs); // creates a new socket with the same parameters
|
||||
~I2pSocket();
|
||||
public:
|
||||
I2pSocket(const std::string &SAMHost, uint16_t SAMPort);
|
||||
I2pSocket(const sockaddr_in &addr); // explicit because we don't want to create any socket implicity
|
||||
explicit I2pSocket(const I2pSocket &rhs); // creates a new socket with the same parameters
|
||||
~I2pSocket();
|
||||
|
||||
void bootstrapI2P();
|
||||
void bootstrapI2P();
|
||||
|
||||
void write(const std::string& msg);
|
||||
std::string read();
|
||||
SOCKET release();
|
||||
void close();
|
||||
void write(const std::string &msg);
|
||||
std::string read();
|
||||
SOCKET release();
|
||||
void close();
|
||||
|
||||
bool isOk() const;
|
||||
bool isOk() const;
|
||||
|
||||
const std::string& getVersion() const;
|
||||
const std::string& getHost() const;
|
||||
uint16_t getPort() const;
|
||||
const std::string &getVersion() const;
|
||||
const std::string &getHost() const;
|
||||
uint16_t getPort() const;
|
||||
|
||||
const sockaddr_in& getAddress() const;
|
||||
const sockaddr_in &getAddress() const;
|
||||
|
||||
const std::string minVer_ = "3.0";
|
||||
const std::string maxVer_ = "3.1";
|
||||
const std::string minVer_ = "3.0";
|
||||
const std::string maxVer_ = "3.1";
|
||||
|
||||
private:
|
||||
SOCKET socket_;
|
||||
sockaddr_in servAddr_;
|
||||
std::string SAMHost_;
|
||||
uint16_t SAMPort_;
|
||||
std::string version_;
|
||||
private:
|
||||
SOCKET socket_;
|
||||
sockaddr_in servAddr_;
|
||||
std::string SAMHost_;
|
||||
uint16_t SAMPort_;
|
||||
std::string version_;
|
||||
|
||||
#ifdef WIN32
|
||||
static int instances_;
|
||||
static void initWSA();
|
||||
static void freeWSA();
|
||||
#endif
|
||||
static int instances_;
|
||||
static void initWSA();
|
||||
static void freeWSA();
|
||||
#endif // WIN32
|
||||
|
||||
void handshake();
|
||||
void init();
|
||||
void handshake();
|
||||
void init();
|
||||
|
||||
I2pSocket& operator=(const I2pSocket&);
|
||||
I2pSocket &operator=(const I2pSocket &);
|
||||
};
|
||||
|
||||
struct FullDestination
|
||||
{
|
||||
std::string pub;
|
||||
std::string priv;
|
||||
bool isGenerated;
|
||||
std::string pub;
|
||||
std::string priv;
|
||||
bool isGenerated;
|
||||
|
||||
FullDestination() {}
|
||||
FullDestination(const std::string& pub, const std::string& priv, bool isGenerated)
|
||||
:pub(pub), priv(priv), isGenerated(isGenerated) {}
|
||||
FullDestination() {}
|
||||
FullDestination(const std::string &pub, const std::string &priv, bool isGenerated)
|
||||
: pub(pub), priv(priv), isGenerated(isGenerated) {}
|
||||
};
|
||||
|
||||
template<class T>
|
||||
struct RequestResult
|
||||
{
|
||||
bool isOk;
|
||||
T value;
|
||||
bool isOk;
|
||||
T value;
|
||||
|
||||
RequestResult()
|
||||
: isOk(false) {}
|
||||
RequestResult() : isOk(false) {}
|
||||
|
||||
explicit RequestResult(const T& value)
|
||||
: isOk(true), value(value) {}
|
||||
explicit RequestResult(const T &value) : isOk(true), value(value) {}
|
||||
};
|
||||
|
||||
template<class T>
|
||||
struct RequestResult<std::unique_ptr<T> >
|
||||
struct RequestResult<std::unique_ptr<T>>
|
||||
{
|
||||
// a class-helper for resolving a problem with conversion from temporary RequestResult to non-const RequestResult&
|
||||
struct RequestResultRef
|
||||
{
|
||||
bool isOk;
|
||||
T* value;
|
||||
|
||||
RequestResultRef(bool isOk, T* value)
|
||||
: isOk(isOk), value(value) {}
|
||||
};
|
||||
|
||||
/**
|
||||
* a class-helper for resolving a problem with conversion
|
||||
* from temporary RequestResult to non-const RequestResult&
|
||||
*/
|
||||
struct RequestResultRef
|
||||
{
|
||||
bool isOk;
|
||||
std::unique_ptr<T> value;
|
||||
T *value;
|
||||
|
||||
RequestResult()
|
||||
: isOk(false) {}
|
||||
RequestResultRef(bool isOk, T *value) : isOk(isOk), value(value) {}
|
||||
};
|
||||
|
||||
explicit RequestResult(std::unique_ptr<T>&& value)
|
||||
: isOk(true), value(std::move(value)) {}
|
||||
bool isOk;
|
||||
std::unique_ptr<T> value;
|
||||
|
||||
RequestResult() : isOk(false) {}
|
||||
|
||||
// some C++ magic
|
||||
RequestResult(RequestResultRef ref)
|
||||
: isOk(ref.isOk), value(ref.value) {}
|
||||
explicit RequestResult(std::unique_ptr<T> &&value)
|
||||
: isOk(true), value(std::move(value)) {}
|
||||
|
||||
RequestResult& operator=(RequestResultRef ref)
|
||||
{
|
||||
if (value.get() != ref.value)
|
||||
{
|
||||
isOk = ref.isOk;
|
||||
value.reset(ref.value);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
// some C++ magic
|
||||
RequestResult(RequestResultRef ref) : isOk(ref.isOk), value(ref.value) {}
|
||||
|
||||
operator RequestResultRef()
|
||||
{
|
||||
return RequestResultRef(this->isOk, this->value.release());
|
||||
}
|
||||
RequestResult &operator=(RequestResultRef ref)
|
||||
{
|
||||
if (value.get() != ref.value)
|
||||
{
|
||||
isOk = ref.isOk;
|
||||
value.reset(ref.value);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator RequestResultRef()
|
||||
{
|
||||
return RequestResultRef(this->isOk, this->value.release());
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct RequestResult<void>
|
||||
{
|
||||
bool isOk;
|
||||
bool isOk;
|
||||
|
||||
RequestResult()
|
||||
: isOk(false) {}
|
||||
RequestResult() : isOk(false) {}
|
||||
|
||||
explicit RequestResult(bool isOk)
|
||||
: isOk(isOk) {}
|
||||
explicit RequestResult(bool isOk) : isOk(isOk) {}
|
||||
};
|
||||
|
||||
class StreamSession
|
||||
|
||||
class SAMSession
|
||||
{
|
||||
public:
|
||||
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& signatureType = SAM_SIGNATURE_TYPE);
|
||||
explicit StreamSession(StreamSession& rhs);
|
||||
~StreamSession();
|
||||
public:
|
||||
SAMSession(const std::string &nickname,
|
||||
const std::string &SAMHost = SAM_DEFAULT_ADDRESS,
|
||||
uint16_t SAMPort = SAM_DEFAULT_PORT_TCP,
|
||||
const std::string &i2pOptions = SAM_DEFAULT_I2P_OPTIONS,
|
||||
const std::string &signatureType = SAM_SIGNATURE_TYPE);
|
||||
SAMSession(SAMSession& rhs);
|
||||
virtual ~SAMSession() = default;
|
||||
|
||||
static std::string generateSessionID();
|
||||
static std::string generateSessionID();
|
||||
RequestResult<const std::string> namingLookup(const std::string &name) const;
|
||||
RequestResult<const FullDestination> destGenerate() const;
|
||||
|
||||
RequestResult<std::unique_ptr<I2pSocket> > accept(bool silent);
|
||||
RequestResult<std::unique_ptr<I2pSocket> > connect(const std::string& destination, bool silent);
|
||||
RequestResult<void> forward(const std::string& host, uint16_t port, bool silent);
|
||||
RequestResult<const std::string> namingLookup(const std::string& name) const;
|
||||
RequestResult<const FullDestination> destGenerate() const;
|
||||
FullDestination createSession(const std::string &destination);
|
||||
FullDestination createSession(const std::string &destination, const std::string &sigType);
|
||||
virtual FullDestination createSession(const std::string &destination, const std::string &sigType, const std::string &i2pOptions) = 0;
|
||||
|
||||
void stopForwarding(const std::string& host, uint16_t port);
|
||||
void stopForwardingAll();
|
||||
const FullDestination &getMyDestination() const;
|
||||
|
||||
const FullDestination& getMyDestination() const;
|
||||
const sockaddr_in &getSAMAddress() const;
|
||||
const std::string &getSAMHost() const;
|
||||
uint16_t getSAMPort() const;
|
||||
const std::string &getNickname() const;
|
||||
const std::string &getSessionID() const;
|
||||
const std::string &getSAMMinVer() const;
|
||||
const std::string &getSAMMaxVer() const;
|
||||
const std::string &getSAMVersion() const;
|
||||
const std::string &getOptions() const;
|
||||
|
||||
const sockaddr_in& getSAMAddress() const;
|
||||
const std::string& getSAMHost() const;
|
||||
uint16_t getSAMPort() const;
|
||||
const std::string& getNickname() const;
|
||||
const std::string& getSessionID() const;
|
||||
const std::string& getSAMMinVer() const;
|
||||
const std::string& getSAMMaxVer() const;
|
||||
const std::string& getSAMVersion() const;
|
||||
const std::string& getOptions() const;
|
||||
bool isSick() const;
|
||||
|
||||
bool isSick() const;
|
||||
protected:
|
||||
static Message::Answer<const std::string> rawRequest(I2pSocket &socket, const std::string &requestStr);
|
||||
static Message::Answer<const std::string> request(I2pSocket &socket, const std::string &requestStr, const std::string &keyOnSuccess);
|
||||
static Message::eStatus request(I2pSocket &socket, const std::string &requestStr);
|
||||
|
||||
private:
|
||||
StreamSession(const StreamSession& rhs);
|
||||
StreamSession& operator=(const StreamSession& rhs);
|
||||
static Message::Answer<const std::string> namingLookup(I2pSocket &socket, const std::string &name);
|
||||
static Message::Answer<const FullDestination> destGenerate(I2pSocket &socket);
|
||||
|
||||
struct ForwardedStream
|
||||
{
|
||||
I2pSocket* socket;
|
||||
std::string host;
|
||||
uint16_t port;
|
||||
bool silent;
|
||||
void fallSick() const;
|
||||
|
||||
ForwardedStream(I2pSocket* socket, const std::string& host, uint16_t port, bool silent)
|
||||
: socket(socket), host(host), port(port), silent(silent) {}
|
||||
};
|
||||
I2pSocket socket_;
|
||||
const std::string nickname_;
|
||||
const std::string sessionID_;
|
||||
FullDestination myDestination_;
|
||||
const std::string i2pOptions_;
|
||||
mutable bool isSick_;
|
||||
};
|
||||
|
||||
typedef std::list<ForwardedStream> ForwardedStreamsContainer;
|
||||
class StreamSession : public SAMSession
|
||||
{
|
||||
public:
|
||||
StreamSession(const std::string &nickname,
|
||||
const std::string &SAMHost = SAM_DEFAULT_ADDRESS,
|
||||
uint16_t SAMPort = SAM_DEFAULT_PORT_TCP,
|
||||
const std::string &destination = SAM_GENERATE_MY_DESTINATION,
|
||||
const std::string &i2pOptions = SAM_DEFAULT_I2P_OPTIONS,
|
||||
const std::string &signatureType = SAM_SIGNATURE_TYPE);
|
||||
explicit StreamSession(StreamSession &rhs);
|
||||
~StreamSession();
|
||||
|
||||
I2pSocket socket_;
|
||||
const std::string nickname_;
|
||||
const std::string sessionID_;
|
||||
FullDestination myDestination_;
|
||||
const std::string i2pOptions_;
|
||||
ForwardedStreamsContainer forwardedStreams_;
|
||||
mutable bool isSick_;
|
||||
RequestResult<std::unique_ptr<I2pSocket>> accept(bool silent);
|
||||
RequestResult<std::unique_ptr<I2pSocket>>
|
||||
connect(const std::string &destination, bool silent);
|
||||
RequestResult<void> forward(const std::string &host, uint16_t port, bool silent);
|
||||
|
||||
void fallSick() const;
|
||||
FullDestination createStreamSession(const std::string &destination);
|
||||
FullDestination createStreamSession(const std::string &destination, const std::string &sigType);
|
||||
FullDestination createStreamSession(const std::string &destination, const std::string &sigType, const std::string &i2pOptions);
|
||||
void stopForwarding(const std::string &host, uint16_t port);
|
||||
void stopForwardingAll();
|
||||
|
||||
static Message::Answer<const std::string> rawRequest(I2pSocket& socket, const std::string& requestStr);
|
||||
static Message::Answer<const std::string> request(I2pSocket& socket, const std::string& requestStr, const std::string& keyOnSuccess);
|
||||
static Message::eStatus request(I2pSocket& socket, const std::string& requestStr);
|
||||
// commands
|
||||
static Message::Answer<const std::string> createStreamSession(I2pSocket& socket, const std::string& sessionID, const std::string& nickname, const std::string& destination, const std::string& options, const std::string& signatureType);
|
||||
static Message::Answer<const std::string> namingLookup(I2pSocket& socket, const std::string& name);
|
||||
static Message::Answer<const FullDestination> destGenerate(I2pSocket& socket);
|
||||
private:
|
||||
StreamSession(const StreamSession &rhs);
|
||||
StreamSession &operator=(const StreamSession &rhs);
|
||||
|
||||
static Message::eStatus accept(I2pSocket& socket, const std::string& sessionID, bool silent);
|
||||
static Message::eStatus connect(I2pSocket& socket, const std::string& sessionID, const std::string& destination, bool silent);
|
||||
static Message::eStatus forward(I2pSocket& socket, const std::string& sessionID, const std::string& host, uint16_t port, bool silent);
|
||||
struct ForwardedStream
|
||||
{
|
||||
I2pSocket *socket;
|
||||
std::string host;
|
||||
uint16_t port;
|
||||
bool silent;
|
||||
|
||||
ForwardedStream(I2pSocket *socket, const std::string &host, uint16_t port,
|
||||
bool silent)
|
||||
: socket(socket), host(host), port(port), silent(silent) {}
|
||||
};
|
||||
|
||||
typedef std::list<ForwardedStream> ForwardedStreamsContainer;
|
||||
|
||||
ForwardedStreamsContainer forwardedStreams_;
|
||||
|
||||
FullDestination createStreamSession(const std::string &destination);
|
||||
FullDestination createStreamSession(const std::string &destination, const std::string &sigType);
|
||||
FullDestination createStreamSession(const std::string &destination, const std::string &sigType, const std::string &i2pOptions);
|
||||
FullDestination createSession(const std::string &destination, const std::string &sigType, const std::string &i2pOptions);
|
||||
|
||||
// commands
|
||||
static Message::Answer<const std::string> createStreamSession(
|
||||
I2pSocket &socket, const std::string &sessionID,
|
||||
const std::string &nickname, const std::string &destination,
|
||||
const std::string &options, const std::string &signatureType);
|
||||
|
||||
static Message::eStatus accept(I2pSocket &socket,
|
||||
const std::string &sessionID, bool silent);
|
||||
static Message::eStatus connect(I2pSocket &socket,
|
||||
const std::string &sessionID,
|
||||
const std::string &destination, bool silent);
|
||||
static Message::eStatus forward(I2pSocket &socket,
|
||||
const std::string &sessionID,
|
||||
const std::string &host, uint16_t port,
|
||||
bool silent);
|
||||
};
|
||||
|
||||
/**
|
||||
* WARNING:
|
||||
* Can only create a TCP session for manage connection.
|
||||
* The UDP client/server is need to be implemented from your app side.
|
||||
*/
|
||||
|
||||
class DatagramSession : public SAMSession
|
||||
{
|
||||
public:
|
||||
DatagramSession(const std::string &nickname,
|
||||
const std::string &SAMHost = SAM_DEFAULT_ADDRESS,
|
||||
uint16_t SAMPortTCP = SAM_DEFAULT_PORT_TCP,
|
||||
uint16_t SAMPortUDP = SAM_DEFAULT_PORT_UDP,
|
||||
const std::string &ClientAddress = SAM_DEFAULT_ADDRESS,
|
||||
uint16_t clientPortUDP = SAM_DEFAULT_CLIENT_UDP,
|
||||
const std::string &destination = SAM_GENERATE_MY_DESTINATION,
|
||||
const std::string &i2pOptions = SAM_DEFAULT_I2P_OPTIONS,
|
||||
const std::string &signatureType = SAM_SIGNATURE_TYPE);
|
||||
explicit DatagramSession(DatagramSession &rhs);
|
||||
~DatagramSession();
|
||||
|
||||
private:
|
||||
DatagramSession(const DatagramSession &rhs);
|
||||
DatagramSession &operator=(const DatagramSession &rhs);
|
||||
|
||||
std::string listenAddress_;
|
||||
uint16_t listenPortUDP_;
|
||||
uint16_t SAMPortUDP_;
|
||||
|
||||
// commands
|
||||
FullDestination createDatagramSession(const std::string &destination);
|
||||
FullDestination createDatagramSession(const std::string &destination, const std::string &sigType);
|
||||
FullDestination createDatagramSession(const std::string &destination, const std::string &sigType, const std::string &i2pOptions);
|
||||
FullDestination createSession(const std::string &destination, const std::string &sigType, const std::string &i2pOptions);
|
||||
|
||||
static Message::Answer<const std::string>
|
||||
createDatagramSession(I2pSocket &socket, const std::string &sessionID,
|
||||
const std::string &nickname, const uint16_t port,
|
||||
const std::string &host, const std::string &destination,
|
||||
const std::string &options,
|
||||
const std::string &signatureType);
|
||||
};
|
||||
|
||||
/**
|
||||
* WARNING:
|
||||
* Can only create a TCP session for manage connection.
|
||||
* The UDP client/server is need to be implemented from your app side.
|
||||
*/
|
||||
|
||||
class RawSession : public SAMSession
|
||||
{
|
||||
public:
|
||||
RawSession(const std::string &nickname,
|
||||
const std::string &SAMHost = SAM_DEFAULT_ADDRESS,
|
||||
uint16_t SAMPortTCP = SAM_DEFAULT_PORT_TCP,
|
||||
uint16_t SAMPortUDP = SAM_DEFAULT_PORT_UDP,
|
||||
const std::string &ClientAddress = SAM_DEFAULT_ADDRESS,
|
||||
uint16_t clientPortUDP = SAM_DEFAULT_CLIENT_UDP,
|
||||
const std::string &destination = SAM_GENERATE_MY_DESTINATION,
|
||||
const std::string &i2pOptions = SAM_DEFAULT_I2P_OPTIONS,
|
||||
const std::string &signatureType = SAM_SIGNATURE_TYPE);
|
||||
explicit RawSession(RawSession &rhs);
|
||||
~RawSession();
|
||||
|
||||
private:
|
||||
RawSession(const RawSession &rhs);
|
||||
RawSession &operator=(const RawSession &rhs);
|
||||
|
||||
std::string listenAddress_;
|
||||
uint16_t listenPortUDP_;
|
||||
uint16_t SAMPortUDP_;
|
||||
|
||||
FullDestination createRawSession(const std::string &destination);
|
||||
FullDestination createRawSession(const std::string &destination, const std::string &sigType);
|
||||
FullDestination createRawSession(const std::string &destination, const std::string &sigType, const std::string &i2pOptions);
|
||||
FullDestination createSession(const std::string &destination, const std::string &sigType, const std::string &i2pOptions);
|
||||
|
||||
static Message::Answer<const std::string>
|
||||
createRawSession(I2pSocket &socket, const std::string &sessionID,
|
||||
const std::string &nickname, const uint16_t port,
|
||||
const std::string &host, const std::string &destination,
|
||||
const std::string &options,
|
||||
const std::string &signatureType);
|
||||
};
|
||||
|
||||
} // namespace SAM
|
||||
|
||||
|
||||
#else // __cplusplus
|
||||
#include "i2psam-c.h"
|
||||
#endif // __cplusplus
|
||||
#endif // I2PSAM_H
|
||||
#endif // I2PSAM_H__
|
||||
|
Reference in New Issue
Block a user