We have a connector that's tested, the skeletons for the tests of a listener and...
[Arachnida.git] / lib / Spin / Connector.cpp
blobe274163ad222d76203df93cbcf0d051008f0672f
1 #include "Connector.h"
2 extern "C" {
3 #include <openssl/bio.h>
4 #include <openssl/ssl.h>
6 #include <boost/format.hpp>
7 #include <loki/ScopeGuard.h>
9 namespace Spin
11 /*static */Connector & Connector::getInstance()
13 static Connector instance__;
14 return instance__;
17 Connection Connector::connect(const std::string & remote_address, boost::uint16_t port, bool use_ssl/* = false*/)
19 boost::format fmt("%1%:%2%");
20 fmt % remote_address % port;
21 ::BIO * bio(use_ssl ? connectSSL_(fmt.str()) : connect_(fmt.str()));
22 return Connection(bio);
25 Connector::Connector()
26 { /* no-op */ }
28 Connector::~Connector()
29 { /* no-op */ }
31 ::BIO * Connector::connectSSL_(const std::string & target)
33 ::SSL_CTX * ssl_context = ::SSL_CTX_new(::SSLv23_client_method());
34 if (!ssl_context)
35 throw std::runtime_error("failed to allocate SSL context"); // HERE be more eloquent
36 else
37 { /* all is well */ }
38 Loki::ScopeGuard ssl_context_guard = Loki::MakeGuard(SSL_CTX_free, ssl_context);
39 /* We'd normally set some stuff like the verify paths and
40 * mode here because as things stand this will connect to
41 * any server whose certificate is signed by any CA. */
42 ::BIO * bio(BIO_new_ssl_connect(ssl_context));
43 if (!bio)
44 throw std::runtime_error("Failed to create connection socket"); // HERE too
45 else
46 { /* all is well */ }
47 Loki::ScopeGuard bio_guard = Loki::MakeGuard(::BIO_free, bio);
48 SSL * ssl(0);
49 BIO_get_ssl(bio, &ssl);
50 if (!ssl)
51 throw std::runtime_error("Can't locate SSL pointer");
52 else
53 { /* all is well */ }
54 SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
55 // we might want to do some other things with the SSL HERE
56 BIO_set_conn_hostname(bio, target.c_str());
57 if (BIO_do_connect(bio) <= 0)
58 throw std::runtime_error("Failed to create connection"); // HERE again
59 else
60 { /* all is well */ }
61 if (BIO_do_handshake(bio) <= 0)
62 throw std::runtime_error("handshake failed"); // HERE again
63 else
64 { /* all is well */ }
66 bio_guard.Dismiss();
67 ssl_context_guard.Dismiss();
68 return bio;
71 ::BIO * Connector::connect_(const std::string & target)
73 // BIO_new_connect wants a char*, not a const char*
74 std::vector< char > buff(target.begin(), target.end());
75 buff.push_back(0);
76 ::BIO * bio(::BIO_new_connect(&(buff[0])));
77 if (!bio)
78 throw std::runtime_error("Failed to create connection socket"); // HERE be more eloquent
79 else
80 { /* all is well */ }
81 Loki::ScopeGuard bio_guard = Loki::MakeGuard(::BIO_free, bio);
82 if (::BIO_do_connect(bio) <= 0)
83 throw std::runtime_error("Failed to create the connection");
84 else
85 { /* all is well */ }
86 bio_guard.Dismiss();
87 return bio;