diff --git a/i2psam-c.h b/i2psam-c.h new file mode 100644 index 0000000..e5a04ab --- /dev/null +++ b/i2psam-c.h @@ -0,0 +1,199 @@ +// +// c wrapper for i2psam +// Author: jeff +// License: MIT +// probably contains bugs :-DDDD +// +#ifndef I2PSAM_C_H +#define I2PSAM_C_H + +#include +#include + +struct i2psam_destination; +struct i2psam_stream_session; +struct i2psam_socket; + +struct i2psam_stream_settings +{ + /** + hostname of sam interface + */ + const char * samhost; + /** + port of sam interface + */ + const uint16_t samport; + /** + nickname for sam session + */ + const char * nickname; + /** + i2cp options string + */ + const char * i2cp_opts; + /** + destination private key + */ + const char * destination; +}; + +/** + create new stream session + */ +struct i2psam_stream_session * i2psam_stream_session_new(struct i2psam_stream_settings *); + +/** + 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 + */ +const char * i2psam_get_samhost(struct i2psam_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 + */ +const char * i2psam_get_nickname(struct i2psam_stream_session *); + +/** + get sam session's id + @return must be free()'d by caller + */ +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 + */ +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 + */ +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 + */ +const char * i2psam_get_sam_version(struct i2psam_stream_session *); + +/** + get i2cp options used by sam session + @return must be free()'d by caller + */ +const char * i2psam_get_i2cp_options(struct i2psam_stream_session *); + +/** + 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 + */ +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 + */ +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 + */ +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 + */ +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 + */ +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 + */ +void i2psam_stop_forwarding(struct i2psam_stream_session*, const char * host, uint16_t port); + +/** + 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 + */ +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 + */ +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 + */ +char * i2psam_read(struct i2psam_socket *, size_t * dlen); + +/** + 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 + */ +int i2psam_socket_is_ok(struct i2psam_socket *); + +/** + 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 + */ +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 + */ +const char * i2psam_destination_pub(struct i2psam_destination *); + +void i2psam_destination_free(struct i2psam_destination *); + +#endif // I2PSAM_C_H diff --git a/i2psam.cpp b/i2psam.cpp index 17d981c..7c28bdf 100644 --- a/i2psam.cpp +++ b/i2psam.cpp @@ -819,3 +819,225 @@ std::string Message::getValue(const std::string& answer, const std::string& key) } // namespace SAM + + +// C interface + +extern "C" { + +#include "i2psam-c.h" + + struct i2psam_stream_session + { + SAM::StreamSession * impl = nullptr; + }; + + struct i2psam_socket + { + std::unique_ptr impl; + }; + + struct i2psam_destination + { + char * pub; + char * priv; + }; + + struct i2psam_stream_session * i2psam_stream_session_new(struct i2psam_stream_settings * settings) + { + struct i2psam_stream_session * session = new i2psam_stream_session; + session->impl = new SAM::StreamSession(settings->nickname, + settings->samhost, + settings->samport, + settings->destination, + settings->i2cp_opts); + return session; + } + + void i2psam_stream_session_free(struct i2psam_stream_session * session) + { + delete session->impl; + delete session; + } + + const char * i2psam_get_samhost(struct i2psam_stream_session * session) + { + return strdup(session->impl->getSAMHost().c_str()); + } + + uint16_t i2psam_get_samport(struct i2psam_stream_session * session) + { + return session->impl->getSAMPort(); + } + + const char * i2psam_get_nickname(struct i2psam_stream_session * session) + { + return strdup(session->impl->getNickname().c_str()); + } + + const char * i2psam_get_session_id(struct i2psam_stream_session * session) + { + return strdup(session->impl->getSessionID().c_str()); + } + + const char * i2psam_get_sam_min_version(struct i2psam_stream_session * session) + { + return strdup(session->impl->getSAMMinVer().c_str()); + } + + const char * i2psam_get_sam_max_version(struct i2psam_stream_session * session) + { + return strdup(session->impl->getSAMMaxVer().c_str()); + } + + const char * i2psam_get_sam_version(struct i2psam_stream_session * session) + { + return strdup(session->impl->getSAMVersion().c_str()); + } + + const char * i2psam_get_i2cp_options(struct i2psam_stream_session * session) + { + return strdup(session->impl->getOptions().c_str()); + } + + int i2psam_is_sick(struct i2psam_stream_session * session) + { + if(session->impl->isSick()) + return 1; + else + return 0; + } + + struct i2psam_socket * i2psam_accept(struct i2psam_stream_session * session, int silent) + { + auto result = session->impl->accept(silent); + if (result.isOk) + { + struct i2psam_socket * socket = new i2psam_socket; + socket->impl = std::move(result.value); + return socket; + } + else + return nullptr; + } + + struct i2psam_socket * i2psam_connect(struct i2psam_stream_session * session, const char * destination, int silent) + { + auto result = session->impl->connect(destination, silent != 0); + if(result.isOk) + { + struct i2psam_socket * socket = new i2psam_socket; + socket->impl = std::move(result.value); + return socket; + } + else + return nullptr; + } + + int i2psam_forward(struct i2psam_stream_session * session, const char * host, uint16_t port, int silent) + { + std::string remote(host); + auto result = session->impl->forward(host, port, silent); + + if(result.isOk) return 0; + else return -1; + } + + const char * i2psam_namelookup(struct i2psam_stream_session * session, const char * name) + { + auto result = session->impl->namingLookup(name); + + if(result.isOk) return strdup(result.value.c_str()); + else return nullptr; + } + + struct i2psam_destination * i2psam_dest_generate(struct i2psam_stream_session * session) + { + auto result = session->impl->destGenerate(); + if(result.isOk) + { + struct i2psam_destination * dest = new i2psam_destination; + dest->pub = strdup(result.value.pub.c_str()); + dest->priv = strdup(result.value.priv.c_str()); + return dest; + } + else + return nullptr; + } + + void i2psam_stop_forwarding(struct i2psam_stream_session * session, const char * host, uint16_t port) + { + session->impl->stopForwarding(host, port); + } + + void i2psam_stop_forwarding_all(struct i2psam_stream_session * session) + { + session->impl->stopForwardingAll(); + } + + struct i2psam_destination * i2psam_get_my_destination(struct i2psam_stream_session * session) + { + struct i2psam_destination * dest = new i2psam_destination; + const auto & mydest = session->impl->getMyDestination(); + dest->pub = strdup(mydest.pub.c_str()); + dest->priv = strdup(mydest.priv.c_str()); + return dest; + } + + void i2psam_write(struct i2psam_socket * sock, const char * data, size_t dlen) + { + const std::string buf(data, dlen); + sock->impl->write(buf); + } + + char * i2psam_read(struct i2psam_socket * sock, size_t * dlen) + { + std::string buf = sock->impl->read(); + size_t sz = sizeof(char) * buf.size(); + *dlen = sz; + if(sz) + { + char * ret = (char*) malloc(sz); + memcpy(ret, buf.c_str(), sz); + return ret; + } + else + return nullptr; + } + + void i2psam_socket_close(struct i2psam_socket *sock) + { + sock->impl->close(); + } + + int i2psam_socket_is_ok(struct i2psam_socket * sock) + { + if(sock->impl->isOk()) + return 1; + else + return 0; + } + + void i2psam_socket_free(struct i2psam_socket * sock) + { + delete sock; + } + + const char * i2psam_destination_priv(struct i2psam_destination * dest) + { + return strdup(dest->priv); + } + + const char * i2psam_destination_pub(struct i2psam_destination * dest) + { + return strdup(dest->pub); + } + + void i2psam_destination_free(struct i2psam_destination * dest) + { + free(dest->pub); + free(dest->priv); + delete dest; + } + +} diff --git a/i2psam.h b/i2psam.h index 8a081d2..e5826fb 100644 --- a/i2psam.h +++ b/i2psam.h @@ -8,14 +8,6 @@ #ifndef I2PSAM_H #define I2PSAM_H -#include "compat.h" - -#include -#include -#include -#include -#include - #define SAM_DEFAULT_ADDRESS "127.0.0.1" #define SAM_DEFAULT_PORT 7656 #define SAM_GENERATE_MY_DESTINATION "TRANSIENT" @@ -47,7 +39,16 @@ #define SAM_NAME_OUTBOUND_IPRESTRICTION "outbound.IPRestriction" #define SAM_DEFAULT_OUTBOUND_IPRESTRICTION 2 #define SAM_NAME_OUTBOUND_PRIORITY "outbound.priority" -#define SAM_DEFAULT_OUTBOUND_PRIORITY 0 +#define SAM_DEFAULT_OUTBOUND_PRIORITY + +#ifdef __cplusplus // __cplusplus +#include "compat.h" + +#include +#include +#include +#include +#include namespace SAM { @@ -400,4 +401,8 @@ private: } // namespace SAM + +#else // __cplusplus +#include "i2psam-c.h" +#endif // __cplusplus #endif // I2PSAM_H