Hide keyboard shortcuts

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 

2 

3c"""header-before-namespace 

4#include <openssl/ssl.h> 

5""" 

6 

7c"""source-before-namespace 

8#include <openssl/err.h> 

9""" 

10 

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); 

16 

17 for (int i = 0; i < dlen; i++) { 

18 data.get(i) = data_p[i]; 

19 } 

20 

21 connection_p->_io_handler->write(data); 

22 

23 return dlen; 

24} 

25 

26static int bio_read(BIO *bio_p, char *data_p, int dlen) 

27{ 

28 Connection *connection_p = (Connection *)BIO_get_data(bio_p); 

29 

30 try { 

31 auto data = connection_p->_io_handler->read(dlen); 

32 dlen = data.m_bytes->size(); 

33 

34 for (int i = 0; i < dlen; i++) { 

35 data_p[i] = data.get(i); 

36 } 

37 

38 connection_p->m_error = nullptr; 

39 } catch (const __Error& e) { 

40 dlen = 0; 

41 connection_p->m_error = e.m_error; 

42 } 

43 

44 return dlen; 

45} 

46 

47static long bio_ctrl(BIO *b, int cmd, long larg, void *pargs) 

48{ 

49 long res = 0; 

50 

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 } 

63 

64 return res; 

65} 

66 

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"); 

71 

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); 

75 

76 return bio_p; 

77} 

78""" 

79 

80class _Module: 

81 c"BIO_METHOD *m_bio_method;" 

82 

83 func __init__(self): 

84 c""" 

85 SSL_load_error_strings(); 

86 SSL_library_init(); 

87 m_bio_method = create_bio(); 

88 """ 

89 

90_MODULE: _Module = _Module() 

91 

92class Context: 

93 c"SSL_CTX *m_context;" 

94 

95 func __init__(self): 

96 c""" 

97 m_context = SSL_CTX_new(SSLv23_client_method()); 

98 

99 if (m_context == NULL) { 

100 std::cout << "SSL_CTX_new() failed" << std::endl; 

101 exit(1); 

102 } 

103 """ 

104 

105trait IOHandler: 

106 

107 func write(self, data: bytes): 

108 pass 

109 

110 func read(self, size: i64) -> bytes: 

111 pass 

112 

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;" 

119 

120 func __init__(self, context: Context, io_handler: IOHandler): 

121 self._context = context 

122 self._io_handler = io_handler 

123 self._connected = False 

124 

125 c""" 

126 m_ssl = SSL_new(context->m_context); 

127 

128 if (m_ssl == NULL) { 

129 std::cout << "SSL_new() failed" << std::endl; 

130 exit(1); 

131 } 

132 

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 """ 

138 

139 func is_connected(self) -> bool: 

140 """Returns true if conencted to the server, false otherwise. 

141 

142 """ 

143 

144 return self._connected 

145 

146 func connect(self): 

147 """Connect to a server using given `host` and `port`. 

148 

149 """ 

150 

151 message: string? = None 

152 

153 c""" 

154 int res = SSL_connect(m_ssl); 

155 

156 if (res != 1) { 

157 message = String(ERR_error_string(ERR_get_error(), NULL)); 

158 } 

159 """ 

160 

161 if message is not None: 

162 raise NetError(f"Connect failed with '{message}'.") 

163 

164 func disconnect(self): 

165 """Disconnect from the server. 

166 

167 """ 

168 

169 c"SSL_clear(m_ssl);" 

170 

171 func write(self, data: bytes): 

172 """Write data to the server. 

173 

174 """ 

175 

176 c""" 

177 int res = SSL_write(m_ssl, data.m_bytes->data(), data.m_bytes->size()); 

178 

179 if (res != data.m_bytes->size()) { 

180 std::cout << "SSL_write(): " << res << " " << data.m_bytes->size() << std::endl; 

181 exit(1); 

182 } 

183 """ 

184 

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. 

189 

190 """ 

191 

192 data = bytes(size) 

193 

194 c""" 

195 int pos = 0; 

196 

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); 

201 

202 if (m_error) { 

203 m_error->__throw(); 

204 } else if (res <= 0) { 

205 data.m_bytes->resize(0); 

206 break; 

207 } 

208 

209 pos += res; 

210 } 

211 """ 

212 

213 return data