8 #if defined(HAVE_CONFIG_H)
27 #define closesocket close
30 #define SAM_BUFSIZE 65536
31 #define I2P_DESTINATION_SIZE 516
39 static void print_error(
const std::string& err)
52 std::cout << err <<
"(" << errno <<
")" << std::endl;
58 int Socket::instances_ = 0;
60 void Socket::initWSA()
63 int ret = WSAStartup(MAKEWORD(2,2), &wsadata);
65 print_error(
"Failed to initialize winsock library");
68 void Socket::freeWSA()
74 Socket::Socket(
const std::string& SAMHost, uint16_t SAMPort,
const std::string& minVer,
const std::string &maxVer)
75 : socket_(
SAM_INVALID_SOCKET), SAMHost_(SAMHost), SAMPort_(SAMPort), minVer_(minVer), maxVer_(maxVer)
78 if (instances_++ == 0)
85 servAddr_.sin_addr.s_addr = inet_addr(SAMHost.c_str());
90 Socket::Socket(
const sockaddr_in& addr,
const std::string &minVer,
const std::string& maxVer)
94 if (instances_++ == 0)
101 : socket_(
SAM_INVALID_SOCKET), servAddr_(rhs.servAddr_), minVer_(rhs.minVer_), maxVer_(rhs.maxVer_)
104 if (instances_++ == 0)
115 if (--instances_ == 0)
129 socket_ = socket(AF_INET, SOCK_STREAM, 0);
132 print_error(
"Failed to create socket");
139 print_error(
"Failed to connect to SAM");
155 const std::string answer = this->
read();
160 print_error(
"Handshake failed");
167 print_error(
"Failed to send data because socket is closed");
170 #ifdef DEBUG_ON_STDOUT
171 std::cout <<
"Send: " << msg << std::endl;
173 ssize_t sentBytes = send(
socket_, msg.c_str(), msg.length(), 0);
177 print_error(
"Failed to send data");
183 print_error(
"Socket was closed");
192 print_error(
"Failed to read data because socket is closed");
193 return std::string();
201 print_error(
"Failed to receive data");
202 return std::string();
204 if (recievedBytes == 0)
207 print_error(
"Socket was closed");
209 #ifdef DEBUG_ON_STDOUT
210 std::cout <<
"Reply: " << buffer << std::endl;
212 return std::string(buffer);
261 const std::string& nickname,
262 const std::string& SAMHost ,
264 const std::string& destination ,
265 const std::string& i2pOptions ,
266 const std::string& minVer ,
267 const std::string& maxVer )
268 : socket_(SAMHost, SAMPort, minVer, maxVer)
269 , nickname_(nickname)
270 , sessionID_(generateSessionID())
271 , i2pOptions_(i2pOptions)
275 #ifdef DEBUG_ON_STDOUT
276 std::cout <<
"Created a brand new SAM session (" <<
sessionID_ <<
")" << std::endl;
281 : socket_(rhs.socket_)
282 , nickname_(rhs.nickname_)
283 , sessionID_(generateSessionID())
284 , myDestination_(rhs.myDestination_)
285 , i2pOptions_(rhs.i2pOptions_)
293 forward(it->host, it->port, it->silent);
296 std::cout <<
"Created a new SAM session (" <<
sessionID_ <<
") from another (" << rhs.
sessionID_ <<
")" << std::endl;
303 #ifdef DEBUG_ON_STDOUT
304 std::cout <<
"Closing SAM session (" <<
sessionID_ <<
") ..." << std::endl;
311 static const int minSessionIDLength = 5;
312 static const int maxSessionIDLength = 9;
313 static const char sessionIDAlphabet[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
314 int length = minSessionIDLength - 1;
319 while(length < minSessionIDLength)
320 length = rand() % maxSessionIDLength;
323 result += sessionIDAlphabet[rand() % (
sizeof(sessionIDAlphabet)-1)];
359 return ResultType(streamSocket);
383 return ResultType(
true);
402 const AnswerType answer =
namingLookup(*newSocket, name);
403 switch(answer.status)
406 return ResultType(answer.value);
424 switch(answer.status)
427 return ResultType(answer.value);
460 if (it->port == port && it->host == host)
484 socket.
write(requestStr);
485 const std::string answer = socket.
read();
487 return AnswerType(status, answer);
495 const AnswerType answer =
rawRequest(socket, requestStr);
528 const std::string answer = socket.
read();
618 va_start (args, format);
619 const int sizeToSend = vsnprintf(buffer,
SAM_BUFSIZE, format, args);
624 print_error(
"Failed to format message");
625 return std::string();
627 return std::string(buffer);
644 static const char* helloFormat =
"HELLO VERSION MIN=%s MAX=%s\n";
664 std::string sessionStyle;
667 case sssStream: sessionStyle =
"STREAM";
break;
668 case sssDatagram: sessionStyle =
"DATAGRAM";
break;
669 case sssRaw: sessionStyle =
"RAW";
break;
672 static const char* sessionCreateFormat =
"SESSION CREATE STYLE=%s ID=%s DESTINATION=%s inbound.nickname=%s %s\n";
673 return createSAMRequest(sessionCreateFormat, sessionStyle.c_str(), sessionID.c_str(), destination.c_str(), nickname.c_str(), options.c_str());
690 static const char* streamAcceptFormat =
"STREAM ACCEPT ID=%s SILENT=%s\n";
691 return createSAMRequest(streamAcceptFormat, sessionID.c_str(), silent ?
"true" :
"false");
709 static const char* streamConnectFormat =
"STREAM CONNECT ID=%s DESTINATION=%s SILENT=%s\n";
710 return createSAMRequest(streamConnectFormat, sessionID.c_str(), destination.c_str(), silent ?
"true" :
"false");
728 static const char* streamForwardFormat =
"STREAM FORWARD ID=%s PORT=%u HOST=%s SILENT=%s\n";
729 return createSAMRequest(streamForwardFormat, sessionID.c_str(), (unsigned)port, host.c_str(), silent ?
"true" :
"false");
746 static const char* namingLookupFormat =
"NAMING LOOKUP NAME=%s\n";
762 static const char* destGenerateFormat =
"DEST GENERATE\n";
766 #define SAM_MAKESTRING(X) SAM_MAKESTRING2(X)
767 #define SAM_MAKESTRING2(X) #X
769 #define SAM_CHECK_RESULT(value) \
770 if (result == SAM_MAKESTRING(value)) return value
777 const std::string result =
getValue(answer,
"RESULT");
795 #undef SAM_CHECK_RESULT
796 #undef SAM_MAKESTRING2
797 #undef SAM_MAKESTRING
802 return std::string();
804 const std::string keyPattern = key +
"=";
805 size_t valueStart = answer.find(keyPattern);
806 if (valueStart == std::string::npos)
807 return std::string();
809 valueStart += keyPattern.length();
810 size_t valueEnd = answer.find_first_of(
' ', valueStart);
811 if (valueEnd == std::string::npos)
812 valueEnd = answer.find_first_of(
'\n', valueStart);
813 return answer.substr(valueStart, valueEnd - valueStart);
const std::string & getMaxVer() const
const std::string sessionID_
const std::string & getSAMVersion() const
static std::string streamAccept(const std::string &sessionID, bool silent=false)
RequestResult< std::auto_ptr< Socket > > accept(bool silent)
const std::string & getOptions() const
const std::string & getSAMMaxVer() const
#define SAM_INVALID_SOCKET
const std::string & getVersion() const
uint16_t getSAMPort() const
RequestResult< void > forward(const std::string &host, uint16_t port, bool silent)
const std::string maxVer_
#define SAM_CHECK_RESULT(value)
static std::string destGenerate()
static Message::Answer< const std::string > rawRequest(Socket &socket, const std::string &requestStr)
#define I2P_DESTINATION_SIZE
const std::string & getSAMMinVer() const
FullDestination myDestination_
#define WSAGetLastError()
static Message::Answer< const std::string > request(Socket &socket, const std::string &requestStr, const std::string &keyOnSuccess)
Socket(const std::string &SAMHost, uint16_t SAMPort, const std::string &minVer, const std::string &maxVer)
FullDestination createStreamSession(const std::string &destination)
const std::string nickname_
const std::string & getHost() const
static std::string createSAMRequest(const char *format,...)
static std::string streamForward(const std::string &sessionID, const std::string &host, uint16_t port, bool silent=false)
const std::string minVer_
RequestResult< const std::string > namingLookup(const std::string &name) const
RequestResult< std::auto_ptr< Socket > > connect(const std::string &destination, bool silent)
static eStatus checkAnswer(const std::string &answer)
const FullDestination & getMyDestination() const
const std::string i2pOptions_
static std::string hello(const std::string &minVer, const std::string &maxVer)
#define SAM_GENERATE_MY_DESTINATION
StreamSession(const std::string &nickname, const std::string &SAMHost=SAM_DEFAULT_ADDRESS, uint16_t SAMPort=SAM_DEFAULT_PORT, const std::string &destination=SAM_GENERATE_MY_DESTINATION, const std::string &i2pOptions=SAM_DEFAULT_I2P_OPTIONS, const std::string &minVer=SAM_DEFAULT_MIN_VER, const std::string &maxVer=SAM_DEFAULT_MAX_VER)
static std::string streamConnect(const std::string &sessionID, const std::string &destination, bool silent=false)
const sockaddr_in & getSAMAddress() const
const std::string & getSessionID() const
static std::string generateSessionID()
const sockaddr_in & getAddress() const
static std::string namingLookup(const std::string &name)
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="")
static std::string getValue(const std::string &answer, const std::string &key)
const std::string & getSAMHost() const
void write(const std::string &msg)
ForwardedStreamsContainer forwardedStreams_
const std::string & getMinVer() const
const std::string & getNickname() const
void stopForwarding(const std::string &host, uint16_t port)
RequestResult< const FullDestination > destGenerate() const