I2P Address: [http://git.idk.i2p]

Skip to content
Snippets Groups Projects
i2psam.cpp 37.2 KiB
Newer Older
  • Learn to ignore specific revisions
  • giv's avatar
    giv committed
    // Copyright (c) 2012-2013 giv
    // Distributed under the MIT/X11 software license, see the accompanying
    // file COPYING or http://www.opensource.org/licenses/mit-license.php.
    //--------------------------------------------------------------------------------------------------
    #include "i2psam.h"
    
    #include <iostream>
    #include <stdio.h>
    #include <string.h>         // for memset
    #include <stdlib.h>
    #include <time.h>
    #include <stdarg.h>
    
    #ifndef WIN32
    #include <errno.h>
    #endif
    
    #ifndef WIN32
    #define closesocket         close
    #endif
    
    #define SAM_BUFSIZE         65536
    #define I2P_DESTINATION_SIZE 516
    
    namespace SAM
    {
    
    static void print_error(const std::string& err)
    {
    #ifdef WIN32
        std::cout << err << "(" << WSAGetLastError() << ")" << std::endl;
    #else
        std::cout << err << "(" << errno << ")" << std::endl;
    #endif
    }
    
    #ifdef WIN32
    int Socket::instances_ = 0;
    
    void Socket::initWSA()
    {
        WSADATA wsadata;
        int ret = WSAStartup(MAKEWORD(2,2), &wsadata);
        if (ret != NO_ERROR)
            print_error("Failed to initialize winsock library");
    }
    
    void Socket::freeWSA()
    {
        WSACleanup();
    }
    #endif
    
    Socket::Socket(const std::string& SAMHost, uint16_t SAMPort, const std::string& minVer, const std::string &maxVer)
        : socket_(SAM_INVALID_SOCKET), SAMHost_(SAMHost), SAMPort_(SAMPort), minVer_(minVer), maxVer_(maxVer)
    {
    #ifdef WIN32
        if (instances_++ == 0)
            initWSA();
    #endif
    
        memset(&servAddr_, 0, sizeof(servAddr_));
    
        servAddr_.sin_family = AF_INET;
        servAddr_.sin_addr.s_addr = inet_addr(SAMHost.c_str());
        servAddr_.sin_port = htons(SAMPort);
    
        init();
        if (isOk())
            handshake();
    }
    
    Socket::Socket(const sockaddr_in& addr, const std::string &minVer, const std::string& maxVer)
        : socket_(SAM_INVALID_SOCKET), servAddr_(addr), minVer_(minVer), maxVer_(maxVer)
    {
    #ifdef WIN32
        if (instances_++ == 0)
            initWSA();
    #endif
    
        init();
        if (isOk())
            handshake();
    }
    
    Socket::Socket(const Socket& rhs)
        : socket_(SAM_INVALID_SOCKET), servAddr_(rhs.servAddr_), minVer_(rhs.minVer_), maxVer_(rhs.maxVer_)
    {
    #ifdef WIN32
        if (instances_++ == 0)
            initWSA();
    #endif
    
        init();
        if (isOk())
            handshake();
    }
    
    Socket::~Socket()
    {
        close();
    
    #ifdef WIN32
        if (--instances_ == 0)
            freeWSA();
    #endif
    }
    
    void Socket::init()
    {
        socket_ = socket(AF_INET, SOCK_STREAM, 0);
        if (socket_ == SAM_INVALID_SOCKET)
        {
            print_error("Failed to create socket");
            return;
        }
    
        if (connect(socket_, (const sockaddr*)&servAddr_, sizeof(servAddr_)) == SAM_SOCKET_ERROR)
        {
            close();
            print_error("Failed to connect to SAM");
            return;
        }
    }
    
    SOCKET Socket::release()
    {
        SOCKET temp = socket_;
        socket_ = SAM_INVALID_SOCKET;
        return temp;
    }
    
    void Socket::handshake()
    {
        this->write(Message::hello(minVer_, maxVer_));
        const std::string answer = this->read();
        const Message::eStatus answerStatus = Message::checkAnswer(answer);
        if (answerStatus == Message::OK)
            version_ = Message::getValue(answer, "VERSION");
        else
            print_error("Handshake failed");
    }
    
    void Socket::write(const std::string& msg)
    {
        if (!isOk())
        {
            print_error("Failed to send data because socket is closed");
            return;
        }
        std::cout << "Send: " << msg << std::endl;
        ssize_t sentBytes = send(socket_, msg.c_str(), msg.length(), 0);
        if (sentBytes == SAM_SOCKET_ERROR)
        {
            close();
            print_error("Failed to send data");
            return;
        }
        if (sentBytes == 0)
        {
            close();
            print_error("Socket was closed");
            return;
        }
    }
    
    std::string Socket::read()
    {
        if (!isOk())
        {
            print_error("Failed to read data because socket is closed");
            return std::string();
        }
        char buffer[SAM_BUFSIZE];
        memset(buffer, 0, SAM_BUFSIZE);
        ssize_t recievedBytes = recv(socket_, buffer, SAM_BUFSIZE, 0);
        if (recievedBytes == SAM_SOCKET_ERROR)
        {
            close();
    
    giv's avatar
    giv committed
            print_error("Failed to receive data");
    
    giv's avatar
    giv committed
            return std::string();
        }
        if (recievedBytes == 0)
        {
            close();
            print_error("Socket was closed");
        }
        std::cout << "Reply: " << buffer << std::endl;
        return std::string(buffer);
    }
    
    void Socket::close()
    {
        if (socket_ != SAM_INVALID_SOCKET)
            ::closesocket(socket_);
        socket_ = SAM_INVALID_SOCKET;
    }
    
    bool Socket::isOk() const
    {
        return socket_ != SAM_INVALID_SOCKET;
    }
    
    const std::string& Socket::getHost() const
    {
        return SAMHost_;
    }
    
    uint16_t Socket::getPort() const
    {
        return SAMPort_;
    }
    
    const std::string& Socket::getVersion() const
    {
        return version_;
    }
    
    const std::string& Socket::getMinVer() const
    {
        return minVer_;
    }
    
    const std::string& Socket::getMaxVer() const
    {
        return maxVer_;
    }
    
    const sockaddr_in& Socket::getAddress() const
    {
        return servAddr_;
    }
    
    
    //--------------------------------------------------------------------------------------------------
    
    
    giv's avatar
    giv committed
    NewStreamSession::NewStreamSession(
            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*/)
    
    giv's avatar
    giv committed
        : socket_(SAMHost, SAMPort, minVer, maxVer)
    
    giv's avatar
    giv committed
        , nickname_(nickname)
        , sessionID_(generateSessionID())
    //    , myDestination_(myDestination)
        , i2pOptions_(i2pOptions)
    //    , isDestGenerated_(myDestination == SAM_GENERATE_MY_DESTINATION)
        , isSick_(false)
    {
        myDestination_ = createStreamSession(destination);
    }
    
    NewStreamSession::NewStreamSession(NewStreamSession& rhs)
        : socket_(rhs.socket_)
        , nickname_(rhs.nickname_)
        , sessionID_(generateSessionID())
        , myDestination_(rhs.myDestination_)
        , i2pOptions_(rhs.i2pOptions_)
    //    , isDestGenerated_(rhs.isDestGenerated_)
        , isSick_(false)
    {
        rhs.fallSick();
    
    giv's avatar
    giv committed
        rhs.socket_.close();
    
    giv's avatar
    giv committed
        (void)createStreamSession(myDestination_.priv);
    
        for(ForwardedStreamsContainer::const_iterator it = rhs.forwardedStreams_.begin(), end = rhs.forwardedStreams_.end(); it != end; ++it)
            forward(it->host, it->port, it->silent);
    }
    
    giv's avatar
    giv committed
    
    
    giv's avatar
    giv committed
    NewStreamSession::~NewStreamSession()
    {
        stopForwardingAll();
        std::cout << "Closing SAM session..." << std::endl;
    }
    
    /*static*/
    std::string NewStreamSession::generateSessionID()
    
    giv's avatar
    giv committed
    {
        static const int minSessionIDLength = 5;
        static const int maxSessionIDLength = 9;
        static const char sessionIDAlphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        int length = minSessionIDLength - 1;
        std::string result;
    
        srand(time(NULL));
    
        while(length < minSessionIDLength)
            length = rand() % maxSessionIDLength;
    
        while (length-- > 0)
            result += sessionIDAlphabet[rand() % (sizeof(sessionIDAlphabet)-1)];
    
        return result;
    }
    
    
    giv's avatar
    giv committed
    RequestResult<std::auto_ptr<Socket> > NewStreamSession::accept(bool silent)
    {
        typedef RequestResult<std::auto_ptr<Socket> > ResultType;
    
    giv's avatar
    giv committed
    
    
    giv's avatar
    giv committed
        std::auto_ptr<Socket> streamSocket(new Socket(socket_));
    
    giv's avatar
    giv committed
        const Message::eStatus status = accept(*streamSocket, sessionID_, silent);
        switch(status)
        {
        case Message::OK:
            return RequestResult<std::auto_ptr<Socket> >(streamSocket);
        case Message::EMPTY_ANSWER:
        case Message::CLOSED_SOCKET:
        case Message::INVALID_ID:
            fallSick();
            break;
        default:
            break;
        }
        return ResultType();
    }
    
    RequestResult<std::auto_ptr<Socket> > NewStreamSession::connect(const std::string& destination, bool silent)
    
    giv's avatar
    giv committed
    {
    
    giv's avatar
    giv committed
        typedef RequestResult<std::auto_ptr<Socket> > ResultType;
    
    
    giv's avatar
    giv committed
        std::auto_ptr<Socket> streamSocket(new Socket(socket_));
    
    giv's avatar
    giv committed
        const Message::eStatus status = connect(*streamSocket, sessionID_, destination, silent);
        switch(status)
        {
        case Message::OK:
            return ResultType(streamSocket);
        case Message::EMPTY_ANSWER:
        case Message::CLOSED_SOCKET:
        case Message::INVALID_ID:
            fallSick();
            break;
        default:
            break;
        }
        return ResultType();
    }
    
    
    RequestResult<void> NewStreamSession::forward(const std::string& host, uint16_t port, bool silent)
    {
        typedef RequestResult<void> ResultType;
    
    
    giv's avatar
    giv committed
        std::auto_ptr<Socket> newSocket(new Socket(socket_));
    
    giv's avatar
    giv committed
        const Message::eStatus status = forward(*newSocket, sessionID_, host, port, silent);
        switch(status)
        {
        case Message::OK:
            forwardedStreams_.push_back(ForwardedStream(newSocket.get(), host, port, silent));
            newSocket.release();    // release after successful push_back only
            return ResultType(true);
        case Message::EMPTY_ANSWER:
        case Message::CLOSED_SOCKET:
        case Message::INVALID_ID:
            fallSick();
            break;
        default:
            break;
        }
        return ResultType();
    
    giv's avatar
    giv committed
    }
    
    
    giv's avatar
    giv committed
    RequestResult<const std::string> NewStreamSession::namingLookup(const std::string& name) const
    
    giv's avatar
    giv committed
    {
    
    giv's avatar
    giv committed
        typedef RequestResult<const std::string> ResultType;
        typedef Message::Answer<const std::string> AnswerType;
    
    
    giv's avatar
    giv committed
        std::auto_ptr<Socket> newSocket(new Socket(socket_));
    
    giv's avatar
    giv committed
        const AnswerType answer = namingLookup(*newSocket, name);
        switch(answer.status)
        {
        case Message::OK:
            return ResultType(answer.value);
        case Message::EMPTY_ANSWER:
        case Message::CLOSED_SOCKET:
            fallSick();
            break;
        default:
            break;
        }
        return ResultType();
    }
    
    
    RequestResult<const FullDestination> NewStreamSession::destGenerate() const
    {
        typedef RequestResult<const FullDestination> ResultType;
        typedef Message::Answer<const FullDestination> AnswerType;
    
    
    giv's avatar
    giv committed
        std::auto_ptr<Socket> newSocket(new Socket(socket_));
    
    giv's avatar
    giv committed
        const AnswerType answer = destGenerate(*newSocket);
        switch(answer.status)
        {
        case Message::OK:
            return ResultType(answer.value);
        case Message::EMPTY_ANSWER:
        case Message::CLOSED_SOCKET:
            fallSick();
            break;
        default:
            break;
        }
        return ResultType();
    }
    
    FullDestination NewStreamSession::createStreamSession(const std::string& destination)
    {
        typedef Message::Answer<const std::string> AnswerType;
    
    
    giv's avatar
    giv committed
        const AnswerType answer = createStreamSession(socket_, sessionID_, nickname_, destination, i2pOptions_);
    
    giv's avatar
    giv committed
        if (answer.status != Message::OK)
        {
            fallSick();
            return FullDestination()/*ResultType()*/;
        }
    
        return FullDestination(answer.value.substr(0, I2P_DESTINATION_SIZE), answer.value, (destination == SAM_GENERATE_MY_DESTINATION));
    
    //    myDestination_.pub = myDestination;
    //    myDestination_.priv = answer.value;
    //    myDestination_.isGenerated = (myDestination == SAM_GENERATE_MY_DESTINATION);
    }
    
    void NewStreamSession::fallSick() const
    {
        isSick_ = true;
    }
    
    void NewStreamSession::stopForwarding(const std::string& host, uint16_t port)
    {
        for (ForwardedStreamsContainer::iterator it = forwardedStreams_.begin(); it != forwardedStreams_.end(); )
        {
            if (it->port == port && it->host == host)
            {
                delete (it->socket);
                it = forwardedStreams_.erase(it);
            }
            else
                ++it;
        }
    }
    
    void NewStreamSession::stopForwardingAll()
    {
        for (ForwardedStreamsContainer::iterator it = forwardedStreams_.begin(); it != forwardedStreams_.end(); )
    
    giv's avatar
    giv committed
            delete (it->socket);
    
    giv's avatar
    giv committed
        forwardedStreams_.clear();
    
    giv's avatar
    giv committed
    }
    
    
    giv's avatar
    giv committed
    /*static*/
    Message::Answer<const std::string> NewStreamSession::rawRequest(Socket& socket, const std::string& requestStr)
    
    giv's avatar
    giv committed
    {
        if (!socket.isOk())
    
    giv's avatar
    giv committed
            return Message::Answer<const std::string>(Message::CLOSED_SOCKET);
    
    giv's avatar
    giv committed
        socket.write(requestStr);
        const std::string answer = socket.read();
        const Message::eStatus status = Message::checkAnswer(answer);
    
    giv's avatar
    giv committed
        return Message::Answer<const std::string>(status, answer);
    }
    
    /*static*/
    Message::Answer<const std::string> NewStreamSession::request(Socket& socket, const std::string& requestStr, const std::string& keyOnSuccess)
    {
        const Message::Answer<const std::string> answer = rawRequest(socket, requestStr);
        return (answer.status == Message::OK) ?
                    Message::Answer<const std::string>(answer.status, Message::getValue(answer.value, keyOnSuccess)) :
                    answer;
    
    giv's avatar
    giv committed
    }
    
    
    giv's avatar
    giv committed
    /*static*/
    Message::eStatus NewStreamSession::request(Socket& socket, const std::string& requestStr)
    {
        return rawRequest(socket, requestStr).status;
    }
    
    /*static*/
    Message::Answer<const std::string> NewStreamSession::createStreamSession(Socket& socket, const std::string& sessionID, const std::string& nickname, const std::string& destination, const std::string& options)
    
    giv's avatar
    giv committed
    {
    
    giv's avatar
    giv committed
        return request(socket, Message::sessionCreate(Message::sssStream, sessionID, nickname, destination, options), "DESTINATION");
    
    giv's avatar
    giv committed
    }
    
    
    giv's avatar
    giv committed
    /*static*/
    Message::Answer<const std::string> NewStreamSession::namingLookup(Socket& socket, const std::string& name)
    
    giv's avatar
    giv committed
    {
        return request(socket, Message::namingLookup(name), "VALUE");
    }
    
    
    giv's avatar
    giv committed
    /*static*/
    Message::Answer<const FullDestination> NewStreamSession::destGenerate(Socket& socket)
    
    giv's avatar
    giv committed
    {
    
    giv's avatar
    giv committed
    // while answer for a DEST GENERATE request doesn't contain a "RESULT" field we parse it manually
    
    giv's avatar
    giv committed
        typedef Message::Answer<const FullDestination> ResultType;
    
    giv's avatar
    giv committed
    
        if (!socket.isOk())
    
    giv's avatar
    giv committed
            return ResultType(Message::CLOSED_SOCKET, FullDestination());
    
    giv's avatar
    giv committed
        socket.write(Message::destGenerate());
        const std::string answer = socket.read();
        const std::string pub = Message::getValue(answer, "PUB");
        const std::string priv = Message::getValue(answer, "PRIV");
    
    giv's avatar
    giv committed
        return (!pub.empty() && !priv.empty()) ? ResultType(Message::OK, FullDestination(pub, priv, /*isGenerated*/ true)) : ResultType(Message::EMPTY_ANSWER, FullDestination());
    
    giv's avatar
    giv committed
    }
    
    
    giv's avatar
    giv committed
    /*static*/
    Message::eStatus NewStreamSession::accept(Socket& socket, const std::string& sessionID, bool silent)
    
    giv's avatar
    giv committed
    {
    
    giv's avatar
    giv committed
        return request(socket, Message::streamAccept(sessionID, silent));
    
    giv's avatar
    giv committed
    }
    
    
    giv's avatar
    giv committed
    /*static*/
    Message::eStatus NewStreamSession::connect(Socket& socket, const std::string& sessionID, const std::string& destination, bool silent)
    
    giv's avatar
    giv committed
    {
    
    giv's avatar
    giv committed
        return request(socket, Message::streamConnect(sessionID, destination, silent));
    
    giv's avatar
    giv committed
    }
    
    
    giv's avatar
    giv committed
    /*static*/
    Message::eStatus NewStreamSession::forward(Socket& socket, const std::string& sessionID, const std::string& host, uint16_t port, bool silent)
    
    giv's avatar
    giv committed
    {
    
    giv's avatar
    giv committed
        return request(socket, Message::streamForward(sessionID, host, port, silent));
    
    giv's avatar
    giv committed
    }
    
    
    giv's avatar
    giv committed
    const std::string& NewStreamSession::getNickname() const
    
    giv's avatar
    giv committed
    {
    
    giv's avatar
    giv committed
        return nickname_;
    }
    
    const std::string& NewStreamSession::getSessionID() const
    {
        return sessionID_;
    }
    
    giv's avatar
    giv committed
    
    
    giv's avatar
    giv committed
    //const std::string& NewStreamSession::getMyDestination() const
    //{
    //    return myDestination_;
    //}
    
    giv's avatar
    giv committed
    
    
    giv's avatar
    giv committed
    const std::string& NewStreamSession::getOptions() const
    {
        return i2pOptions_;
    
    giv's avatar
    giv committed
    }
    
    
    giv's avatar
    giv committed
    //bool NewStreamSession::isDestGenerated() const
    //{
    //    return isDestGenerated_;
    //}
    
    const FullDestination& NewStreamSession::getMyDestination() const
    
    giv's avatar
    giv committed
    {
    
    giv's avatar
    giv committed
        return myDestination_;
    
    giv's avatar
    giv committed
    }
    
    
    giv's avatar
    giv committed
    bool NewStreamSession::isSick() const
    
    giv's avatar
    giv committed
    {
    
    giv's avatar
    giv committed
        return isSick_;
    
    giv's avatar
    giv committed
    }
    
    
    giv's avatar
    giv committed
    const sockaddr_in& NewStreamSession::getSAMAddress() const
    
    giv's avatar
    giv committed
    {
    
    giv's avatar
    giv committed
        return socket_.getAddress();
    
    giv's avatar
    giv committed
    }
    
    giv's avatar
    giv committed
    
    
    giv's avatar
    giv committed
    const std::string& NewStreamSession::getSAMHost() const
    {
    
    giv's avatar
    giv committed
        return socket_.getHost();
    
    giv's avatar
    giv committed
    }
    
    
    giv's avatar
    giv committed
    uint16_t NewStreamSession::getSAMPort() const
    
    giv's avatar
    giv committed
    {
    
    giv's avatar
    giv committed
        return socket_.getPort();
    
    giv's avatar
    giv committed
    }
    
    
    giv's avatar
    giv committed
    const std::string& NewStreamSession::getSAMMinVer() const
    
    giv's avatar
    giv committed
    {
    
    giv's avatar
    giv committed
        return socket_.getMinVer();
    
    giv's avatar
    giv committed
    }
    
    
    giv's avatar
    giv committed
    const std::string& NewStreamSession::getSAMMaxVer() const
    
    giv's avatar
    giv committed
    {
    
    giv's avatar
    giv committed
        return socket_.getMaxVer();
    
    giv's avatar
    giv committed
    }
    
    
    giv's avatar
    giv committed
    const std::string& NewStreamSession::getSAMVersion() const
    
    giv's avatar
    giv committed
    {
    
    giv's avatar
    giv committed
        return socket_.getVersion();
    
    giv's avatar
    giv committed
    }
    
    
    giv's avatar
    giv committed
    //--------------------------------------------------------------------------------------------------
    
    class StreamSessionAdapter::SessionHolder
    
    giv's avatar
    giv committed
    {
    
    giv's avatar
    giv committed
    public:
        explicit SessionHolder(std::auto_ptr<NewStreamSession> session)
            : session_(session)
        {}
    
        const NewStreamSession& getSession() const
    
    giv's avatar
    giv committed
        {
    
    giv's avatar
    giv committed
            heal();
            return *session_;
    
    giv's avatar
    giv committed
        }
    
    
    giv's avatar
    giv committed
        NewStreamSession& getSession()
    
    giv's avatar
    giv committed
        {
    
    giv's avatar
    giv committed
            heal();
            return *session_;
        }
    
    private:
        void heal() const
        {
            if (!session_->isSick())
                return;
            reborn(); // if we don't know how to heal it just reborn it
    
    giv's avatar
    giv committed
        }
    
    
    giv's avatar
    giv committed
        void reborn() const
        {
            std::auto_ptr<NewStreamSession> newSession(new NewStreamSession(*session_));
    
    giv's avatar
    giv committed
            if (!newSession->isSick() && session_->isSick())
                session_ = newSession;
    
    giv's avatar
    giv committed
        }
    
    giv's avatar
    giv committed
    
    
    giv's avatar
    giv committed
        mutable std::auto_ptr<NewStreamSession> session_;
    };
    
    giv's avatar
    giv committed
    
    
    giv's avatar
    giv committed
    StreamSessionAdapter::StreamSessionAdapter(
            const std::string& nickname,
            const std::string& SAMHost       /*= SAM_DEFAULT_ADDRESS*/,
                  uint16_t     SAMPort       /*= SAM_DEFAULT_PORT*/,
            const std::string& myDestination /*= 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*/)
        : sessionHolder_(
              new SessionHolder(
                  std::auto_ptr<NewStreamSession>(
                      new NewStreamSession(nickname, SAMHost, SAMPort, myDestination, i2pOptions, minVer, maxVer))))
    {}
    
    SOCKET StreamSessionAdapter::accept(bool silent)
    {
        RequestResult<std::auto_ptr<Socket> > result = sessionHolder_->getSession().accept(silent);
    
    giv's avatar
    giv committed
        // call Socket::release
    
    giv's avatar
    giv committed
        return result.isOk ? result.value->release() : SAM_INVALID_SOCKET;
    
    giv's avatar
    giv committed
    }
    
    
    giv's avatar
    giv committed
    SOCKET StreamSessionAdapter::connect(const std::string& destination, bool silent)
    
    giv's avatar
    giv committed
    {
    
    giv's avatar
    giv committed
        RequestResult<std::auto_ptr<Socket> > result = sessionHolder_->getSession().connect(destination, silent);
    
    giv's avatar
    giv committed
        // call Socket::release
    
    giv's avatar
    giv committed
        return result.isOk ? result.value->release() : SAM_INVALID_SOCKET;
    
    giv's avatar
    giv committed
    }
    
    
    giv's avatar
    giv committed
    bool StreamSessionAdapter::forward(const std::string& host, uint16_t port, bool silent)
    
    giv's avatar
    giv committed
    {
    
    giv's avatar
    giv committed
        return sessionHolder_->getSession().forward(host, port, silent).isOk;
    
    giv's avatar
    giv committed
    }
    
    
    giv's avatar
    giv committed
    std::string StreamSessionAdapter::namingLookup(const std::string& name) const
    
    giv's avatar
    giv committed
    {
    
    giv's avatar
    giv committed
        RequestResult<const std::string> result = sessionHolder_->getSession().namingLookup(name);
        return result.isOk ? result.value : std::string();
    
    giv's avatar
    giv committed
    }
    
    
    giv's avatar
    giv committed
    FullDestination StreamSessionAdapter::destGenerate() const
    
    giv's avatar
    giv committed
    {
    
    giv's avatar
    giv committed
        RequestResult<const FullDestination> result = sessionHolder_->getSession().destGenerate();
        return result.isOk ? result.value : FullDestination();
    
    giv's avatar
    giv committed
    }
    
    
    giv's avatar
    giv committed
    void StreamSessionAdapter::stopForwarding(const std::string& host, uint16_t port)
    
    giv's avatar
    giv committed
    {
    
    giv's avatar
    giv committed
        sessionHolder_->getSession().stopForwarding(host, port);
    
    giv's avatar
    giv committed
    }
    
    
    giv's avatar
    giv committed
    void StreamSessionAdapter::stopForwardingAll()
    
    giv's avatar
    giv committed
    {
    
    giv's avatar
    giv committed
        sessionHolder_->getSession().stopForwardingAll();
    
    giv's avatar
    giv committed
    }
    
    
    giv's avatar
    giv committed
    const FullDestination& StreamSessionAdapter::getMyDestination() const
    
    giv's avatar
    giv committed
    {
    
    giv's avatar
    giv committed
        return sessionHolder_->getSession().getMyDestination();
    
    giv's avatar
    giv committed
    }
    
    
    giv's avatar
    giv committed
    const sockaddr_in& StreamSessionAdapter::getSAMAddress() const
    
    giv's avatar
    giv committed
    {
    
    giv's avatar
    giv committed
        return sessionHolder_->getSession().getSAMAddress();
    
    giv's avatar
    giv committed
    }
    
    
    giv's avatar
    giv committed
    const std::string& StreamSessionAdapter::getSAMHost() const
    
    giv's avatar
    giv committed
    {
    
    giv's avatar
    giv committed
        return sessionHolder_->getSession().getSAMHost();
    
    giv's avatar
    giv committed
    }
    
    
    giv's avatar
    giv committed
    uint16_t StreamSessionAdapter::getSAMPort() const
    
    giv's avatar
    giv committed
    {
    
    giv's avatar
    giv committed
        return sessionHolder_->getSession().getSAMPort();
    }
    
    const std::string& StreamSessionAdapter::getNickname() const
    {
        return sessionHolder_->getSession().getNickname();
    }
    
    const std::string& StreamSessionAdapter::getSAMMinVer() const
    {
        return sessionHolder_->getSession().getSAMMinVer();
    }
    
    const std::string& StreamSessionAdapter::getSAMMaxVer() const
    {
        return sessionHolder_->getSession().getSAMMaxVer();
    
    giv's avatar
    giv committed
    }
    
    
    giv's avatar
    giv committed
    const std::string& StreamSessionAdapter::getSAMVersion() const
    
    giv's avatar
    giv committed
    {
    
    giv's avatar
    giv committed
        return sessionHolder_->getSession().getSAMVersion();
    
    giv's avatar
    giv committed
    }
    
    giv's avatar
    giv committed
    
    
    giv's avatar
    giv committed
    const std::string& StreamSessionAdapter::getOptions() const
    {
        return sessionHolder_->getSession().getOptions();
    }
    
    //--------------------------------------------------------------------------------------------------
    
    //std::string StreamSession::generateSessionID()
    //{
    //    static const int minSessionIDLength = 5;
    //    static const int maxSessionIDLength = 9;
    //    static const char sessionIDAlphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    //    int length = minSessionIDLength - 1;
    //    std::string result;
    
    //    srand(time(NULL));
    
    //    while(length < minSessionIDLength)
    //        length = rand() % maxSessionIDLength;
    
    //    while (length-- > 0)
    //        result += sessionIDAlphabet[rand() % (sizeof(sessionIDAlphabet)-1)];
    
    //    return result;
    //}
    
    //StreamSession::StreamSession(
    //        const std::string& nickname,
    //        const std::string& SAMHost /*= SAM_DEFAULT_ADDRESS*/,
    //        uint16_t SAMPort /*= SAM_DEFAULT_PORT*/,
    //        const std::string& myDestination /*= 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*/)
    //    : socket_(new Socket(SAMHost, SAMPort, minVer, maxVer))/*,
    //      reconnects_(0)*/
    
    //{
    //    (void)createStreamSession(socket_, nickname, myDestination, i2pOptions);
    //}
    
    //StreamSession::~StreamSession()
    //{
    //    for (ForwardedStreamsContainer::const_iterator it = forwardedStreams_.begin(), end = forwardedStreams_.end(); it != end; ++it)
    //        delete (it->socket);
    //    std::cout << "Closing SAM session..." << std::endl;
    //}
    
    //Message::Answer StreamSession::rawRequest(Socket& socket, const std::string& requestStr)
    //{
    //    if (!socket.isOk())
    //        return Message::Answer(Message::CLOSED_SOCKET, std::string());
    //    socket.write(requestStr);
    //    const std::string answer = socket.read();
    //    const Message::eStatus status = Message::checkAnswer(answer);
    //    return Message::Answer(status, answer);
    //}
    
    //Message::Answer StreamSession::request(Socket& socket, const std::string& requestStr, const std::string& keyOnSuccess)
    //{
    //    Message::Answer answer = rawRequest(socket, requestStr);
    //    if (status == Message::OK)
    //        answer.value = Message::getValue(answer.value, keyOnSuccess);
    //    return answer;
    
    
    ////    if (!socket.isOk())
    ////        return Message::Answer(Message::CLOSED_SOCKET, std::string());
    ////    socket.write(requestStr);
    ////    const std::string answer = socket.read();
    ////    const Message::eStatus status = Message::checkAnswer(answer);
    ////    return Message::Answer(
    ////                status,
    ////                (status == Message::OK) ? Message::getValue(answer, keyOnSuccess) : answer);
    //}
    
    //Message::eStatus StreamSession::request(Socket& socket, const std::string& requestStr)
    //{
    //    return rawRequest(socket, requestStr).status;
    
    ////    if (!socket.isOk())
    ////        return Message::CLOSED_SOCKET;
    ////    socket.write(requestStr);
    ////    const std::string answer = socket.read();
    ////    return Message::checkAnswer(answer);
    //}
    
    //Message::Answer StreamSession::createStreamSession(Socket& socket, const std::string& sessionID, const std::string& nickname, const std::string& destination, const std::string& options)
    //{
    //    return request(socket, Message::sessionCreate(Message::sssStream, sessionID, nickname, destination, options), "DESTINATION");
    //}
    
    //Message::Answer StreamSession::namingLookup(Socket& socket, const std::string& name)
    //{
    //    return request(socket, Message::namingLookup(name), "VALUE");
    //}
    
    //std::pair
    //<
    //    const Message::eStatus,
    //    std::pair<const std::string, const std::string>
    //>
    //StreamSession::destGenerate(Socket &socket)
    //{
    //// while answer for a DEST GENERATE request doesn't contain a "RESULT" field we parse it manually
    
    //    typedef std::pair<const std::string, const std::string> AnswerType;
    //    typedef std::pair<const Message::eStatus, AnswerType> ResultType;
    
    //    if (!socket.isOk())
    //        return ResultType(Message::CLOSED_SOCKET, AnswerType());
    //    socket.write(Message::destGenerate());
    //    const std::string answer = socket.read();
    //    const std::string pub = Message::getValue(answer, "PUB");
    //    const std::string priv = Message::getValue(answer, "PRIV");
    //    return (!pub.empty() && !priv.empty()) ? ResultType(Message::OK, AnswerType(pub, priv)) : ResultType(Message::EMPTY_ANSWER, AnswerType());
    //}
    
    //Message::Answer StreamSession::accept(Socket& socket, const std::string& sessionID, bool silent)
    //{
    //    return request(socket, Message::streamAccept(sessionID, silent), "");
    //}
    
    //Message::Answer StreamSession::connect(Socket& socket, const std::string& sessionID, const std::string& destination, bool silent)
    //{
    //    return request(socket, Message::streamConnect(sessionID, destination, silent), "");
    //}
    
    //Message::Answer StreamSession::forward(Socket& socket, const std::string& sessionID, const std::string& host, uint16_t port, bool silent)
    //{
    //    return request(socket, Message::streamForward(sessionID, host, port, silent), "");
    //}
    
    //bool StreamSession::createStreamSession(
    //        std::auto_ptr<Socket>& newSocket,
    //        const std::string& nickname,
    //        const std::string& myDestination /*= SAM_GENERATE_MY_DESTINATION*/,
    //        const std::string& i2pOptions /*= SAM_DEFAULT_I2P_OPTIONS*/)
    //{
    //    const std::string newSessionID = generateSessionID();
    //    const Message::Answer result = createStreamSession(*newSocket, newSessionID, nickname, myDestination, i2pOptions);
    //    switch(result.first)
    //    {
    //    case Message::OK:
    //        break;
    //    default:
    //        return false;
    //    }
    
    //    nickname_ = nickname;
    //    myDestination_ = result.second;
    //    sessionID_ = newSessionID;
    //    socket_ = newSocket;    // release and copy
    //    i2pOptions_ = i2pOptions;
    //    isGenerated_ = (myDestination == SAM_GENERATE_MY_DESTINATION);
    
    //    return reforwardAll();
    //}
    
    //bool StreamSession::createStreamSession(
    //        const std::string& nickname,
    //        const std::string& SAMHost /*= SAM_DEFAULT_ADDRESS*/,
    //        uint16_t SAMPort /*= SAM_DEFAULT_PORT*/,
    //        const std::string& myDestination /*= SAM_GENERATE_MY_DESTINATION*/,
    //        const std::string& i2pOptions /*= SAM_DEFAULT_I2P_OPTIONS*/,
    //        const std::string& minVer, const std::string &maxVer /*= SAM_DEFAULT_MAX_VER*/)
    //{
    //    std::auto_ptr<Socket> newSocket(new Socket(SAMHost, SAMPort, minVer, maxVer));
    //    return createStreamSession(newSocket, nickname, myDestination, i2pOptions);
    //}
    
    //bool StreamSession::createStreamSession()
    //{
    //    const Socket& currSocket = *socket_;
    //    std::auto_ptr<Socket> newSocket(new Socket(currSocket));
    //    return createStreamSession(newSocket, nickname_, (isGenerated_ ? SAM_GENERATE_MY_DESTINATION : myDestination_), i2pOptions_);
    //}
    
    //bool StreamSession::reforwardAll()
    //{
    //    for (ForwardedStreamsContainer::iterator it = forwardedStreams_.begin(), end = forwardedStreams_.end(); it != end; ++it)
    //    {
    //        std::auto_ptr<Socket> newSocket(new Socket(*socket_));
    //        const Message::Answer result = forward(*newSocket, sessionID_, it->host, it->port, it->silent);
    //        switch(result.first)
    //        {
    //        case Message::OK:
    //            break;
    //        default:
    //            return false;
    //        }
    
    //        delete (it->socket);
    //        it->socket = newSocket.release();
    //    }
    //    return true;
    //}
    
    //std::string StreamSession::namingLookup(const std::string& name)
    //{
    //    const Message::Answer result = namingLookup(*socket_, name);
    //    switch(result.first)
    //    {
    //    case Message::OK:
    //        return result.second;
    //    case Message::EMPTY_ANSWER:
    //    case Message::CLOSED_SOCKET:
    //        return createStreamSession() ? namingLookup(name) : std::string();
    //    default:
    //        break;
    //    }
    //    return std::string();
    //}
    
    //std::string StreamSession::getMyAddress()
    //{
    ////    return namingLookup(SAM_MY_NAME);
    //    return myDestination_.substr(0, I2P_DESTINATION_SIZE);
    //}
    
    //std::pair<const std::string, const std::string> StreamSession::destGenerate()
    //{
    //    const std::pair<const Message::eStatus, std::pair<const std::string, const std::string> > result = destGenerate(*socket_);
    //    switch(result.first)
    //    {
    //    case Message::OK:
    //        return result.second;
    //    case Message::EMPTY_ANSWER:
    //    case Message::CLOSED_SOCKET:
    //        return createStreamSession() ? destGenerate() : std::pair<const std::string, const std::string>();
    //    default:
    //        break;
    //    }
    //    return std::pair<const std::string, const std::string>();
    //}
    
    //SOCKET StreamSession::accept(bool silent /*= false*/)
    //{
    //    Socket streamSocket(*socket_);
    //    const Message::Answer result = accept(streamSocket, sessionID_, silent);
    //    switch(result.first)
    //    {
    //    case Message::OK:
    //        return streamSocket.release();
    //    case Message::EMPTY_ANSWER:
    //    case Message::CLOSED_SOCKET:
    //    case Message::INVALID_ID:
    //        return createStreamSession() ? accept(silent) : SAM_INVALID_SOCKET;
    //    default:
    //        break;
    //    }
    //    return SAM_INVALID_SOCKET;
    //}
    
    //SOCKET StreamSession::connect(const std::string& destination, bool silent /*= false*/)
    //{
    //    Socket streamSocket(*socket_);
    //    const Message::Answer result = connect(streamSocket, sessionID_, destination, silent);
    //    switch(result.first)
    //    {
    //    case Message::OK:
    //        return streamSocket.release();
    //    case Message::EMPTY_ANSWER:
    //    case Message::CLOSED_SOCKET:
    //    case Message::INVALID_ID:
    //        return createStreamSession() ? connect(destination, silent) : SAM_INVALID_SOCKET;
    //    default:
    //        break;
    //    }
    //    return SAM_INVALID_SOCKET;
    //}
    
    //bool StreamSession::forward(const std::string& host, uint16_t port, bool silent /*= false*/)
    //{
    //    std::auto_ptr<Socket> newSocket(new Socket(*socket_));
    //    const Message::Answer result = forward(*newSocket, sessionID_, host, port, silent);
    //    switch(result.first)
    //    {
    //    case Message::OK: