Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1from . import NetError
3c"""header-before-namespace
4#include <openssl/ssl.h>
5"""
7c"""source-before-namespace
8#include <openssl/err.h>
9"""
11c"""
12static int bio_write(BIO *bio_p, const char *data_p, int dlen)
13{
14 Connection *connection_p = (Connection *)BIO_get_data(bio_p);
15 auto data = Bytes(dlen);
17 for (int i = 0; i < dlen; i++) {
18 data.get(i) = data_p[i];
19 }
21 connection_p->_io_handler->write(data);
23 return dlen;
24}
26static int bio_read(BIO *bio_p, char *data_p, int dlen)
27{
28 Connection *connection_p = (Connection *)BIO_get_data(bio_p);
30 try {
31 auto data = connection_p->_io_handler->read(dlen);
32 dlen = data.m_bytes->size();
34 for (int i = 0; i < dlen; i++) {
35 data_p[i] = data.get(i);
36 }
38 connection_p->m_error = nullptr;
39 } catch (const __Error& e) {
40 dlen = 0;
41 connection_p->m_error = e.m_error;
42 }
44 return dlen;
45}
47static long bio_ctrl(BIO *b, int cmd, long larg, void *pargs)
48{
49 long res = 0;
51 switch(cmd)
52 {
53 case BIO_CTRL_FLUSH:
54 res = 1;
55 break;
56 case BIO_CTRL_PUSH:
57 case BIO_CTRL_POP:
58 res = 0;
59 break;
60 default:
61 break;
62 }
64 return res;
65}
67static BIO_METHOD *create_bio(void)
68{
69 BIO_METHOD *bio_p = BIO_meth_new(BIO_get_new_index() | BIO_TYPE_SOURCE_SINK,
70 "mys_bio");
72 BIO_meth_set_write(bio_p, bio_write);
73 BIO_meth_set_read(bio_p, bio_read);
74 BIO_meth_set_ctrl(bio_p, bio_ctrl);
76 return bio_p;
77}
78"""
80class _Module:
81 c"BIO_METHOD *m_bio_method;"
83 func __init__(self):
84 c"""
85 SSL_load_error_strings();
86 SSL_library_init();
87 m_bio_method = create_bio();
88 """
90_MODULE: _Module = _Module()
92class Context:
93 c"SSL_CTX *m_context;"
95 func __init__(self):
96 c"""
97 m_context = SSL_CTX_new(SSLv23_client_method());
99 if (m_context == NULL) {
100 std::cout << "SSL_CTX_new() failed" << std::endl;
101 exit(1);
102 }
103 """
105trait IOHandler:
107 func write(self, data: bytes):
108 pass
110 func read(self, size: i64) -> bytes:
111 pass
113class Connection:
114 _context: Context
115 _io_handler: IOHandler
116 _connected: bool
117 c"mys::shared_ptr<mys::Error> m_error;"
118 c"SSL *m_ssl;"
120 func __init__(self, context: Context, io_handler: IOHandler):
121 self._context = context
122 self._io_handler = io_handler
123 self._connected = False
125 c"""
126 m_ssl = SSL_new(context->m_context);
128 if (m_ssl == NULL) {
129 std::cout << "SSL_new() failed" << std::endl;
130 exit(1);
131 }
133 BIO *bio_p = BIO_new(_MODULE->m_bio_method);
134 BIO_set_data(bio_p, this);
135 BIO_set_init(bio_p, 1);
136 SSL_set_bio(m_ssl, bio_p, bio_p);
137 """
139 func is_connected(self) -> bool:
140 """Returns true if conencted to the server, false otherwise.
142 """
144 return self._connected
146 func connect(self):
147 """Connect to a server using given `host` and `port`.
149 """
151 message: string? = None
153 c"""
154 int res = SSL_connect(m_ssl);
156 if (res != 1) {
157 message = String(ERR_error_string(ERR_get_error(), NULL));
158 }
159 """
161 if message is not None:
162 raise NetError(f"Connect failed with '{message}'.")
164 func disconnect(self):
165 """Disconnect from the server.
167 """
169 c"SSL_clear(m_ssl);"
171 func write(self, data: bytes):
172 """Write data to the server.
174 """
176 c"""
177 int res = SSL_write(m_ssl, data.m_bytes->data(), data.m_bytes->size());
179 if (res != data.m_bytes->size()) {
180 std::cout << "SSL_write(): " << res << " " << data.m_bytes->size() << std::endl;
181 exit(1);
182 }
183 """
185 func read(self, size: i64) -> bytes:
186 """Read data from the server. Always returns size number of bytes,
187 unless the connection was closed, in which case the remaining
188 data is returned.
190 """
192 data = bytes(size)
194 c"""
195 int pos = 0;
197 while (pos < data.m_bytes->size()) {
198 int res = SSL_read(m_ssl,
199 data.m_bytes->data() + pos,
200 data.m_bytes->size() - pos);
202 if (m_error) {
203 m_error->__throw();
204 } else if (res <= 0) {
205 data.m_bytes->resize(0);
206 break;
207 }
209 pos += res;
210 }
211 """
213 return data