1 |
|
|
/* $OpenBSD: bss_conn.c,v 1.32 2014/11/26 05:37:26 bcook Exp $ */ |
2 |
|
|
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) |
3 |
|
|
* All rights reserved. |
4 |
|
|
* |
5 |
|
|
* This package is an SSL implementation written |
6 |
|
|
* by Eric Young (eay@cryptsoft.com). |
7 |
|
|
* The implementation was written so as to conform with Netscapes SSL. |
8 |
|
|
* |
9 |
|
|
* This library is free for commercial and non-commercial use as long as |
10 |
|
|
* the following conditions are aheared to. The following conditions |
11 |
|
|
* apply to all code found in this distribution, be it the RC4, RSA, |
12 |
|
|
* lhash, DES, etc., code; not just the SSL code. The SSL documentation |
13 |
|
|
* included with this distribution is covered by the same copyright terms |
14 |
|
|
* except that the holder is Tim Hudson (tjh@cryptsoft.com). |
15 |
|
|
* |
16 |
|
|
* Copyright remains Eric Young's, and as such any Copyright notices in |
17 |
|
|
* the code are not to be removed. |
18 |
|
|
* If this package is used in a product, Eric Young should be given attribution |
19 |
|
|
* as the author of the parts of the library used. |
20 |
|
|
* This can be in the form of a textual message at program startup or |
21 |
|
|
* in documentation (online or textual) provided with the package. |
22 |
|
|
* |
23 |
|
|
* Redistribution and use in source and binary forms, with or without |
24 |
|
|
* modification, are permitted provided that the following conditions |
25 |
|
|
* are met: |
26 |
|
|
* 1. Redistributions of source code must retain the copyright |
27 |
|
|
* notice, this list of conditions and the following disclaimer. |
28 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright |
29 |
|
|
* notice, this list of conditions and the following disclaimer in the |
30 |
|
|
* documentation and/or other materials provided with the distribution. |
31 |
|
|
* 3. All advertising materials mentioning features or use of this software |
32 |
|
|
* must display the following acknowledgement: |
33 |
|
|
* "This product includes cryptographic software written by |
34 |
|
|
* Eric Young (eay@cryptsoft.com)" |
35 |
|
|
* The word 'cryptographic' can be left out if the rouines from the library |
36 |
|
|
* being used are not cryptographic related :-). |
37 |
|
|
* 4. If you include any Windows specific code (or a derivative thereof) from |
38 |
|
|
* the apps directory (application code) you must include an acknowledgement: |
39 |
|
|
* "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" |
40 |
|
|
* |
41 |
|
|
* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND |
42 |
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
43 |
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
44 |
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
45 |
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
46 |
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
47 |
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
48 |
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
49 |
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
50 |
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
51 |
|
|
* SUCH DAMAGE. |
52 |
|
|
* |
53 |
|
|
* The licence and distribution terms for any publically available version or |
54 |
|
|
* derivative of this code cannot be changed. i.e. this code cannot simply be |
55 |
|
|
* copied and put under another distribution licence |
56 |
|
|
* [including the GNU Public Licence.] |
57 |
|
|
*/ |
58 |
|
|
|
59 |
|
|
#include <sys/socket.h> |
60 |
|
|
|
61 |
|
|
#include <netinet/in.h> |
62 |
|
|
|
63 |
|
|
#include <errno.h> |
64 |
|
|
#include <netdb.h> |
65 |
|
|
#include <stdio.h> |
66 |
|
|
#include <string.h> |
67 |
|
|
#include <unistd.h> |
68 |
|
|
|
69 |
|
|
#include <openssl/bio.h> |
70 |
|
|
#include <openssl/buffer.h> |
71 |
|
|
#include <openssl/err.h> |
72 |
|
|
|
73 |
|
|
#define SOCKET_PROTOCOL IPPROTO_TCP |
74 |
|
|
|
75 |
|
|
typedef struct bio_connect_st { |
76 |
|
|
int state; |
77 |
|
|
|
78 |
|
|
char *param_hostname; |
79 |
|
|
char *param_port; |
80 |
|
|
int nbio; |
81 |
|
|
|
82 |
|
|
unsigned char ip[4]; |
83 |
|
|
unsigned short port; |
84 |
|
|
|
85 |
|
|
struct sockaddr_in them; |
86 |
|
|
|
87 |
|
|
/* int socket; this will be kept in bio->num so that it is |
88 |
|
|
* compatible with the bss_sock bio */ |
89 |
|
|
|
90 |
|
|
/* called when the connection is initially made |
91 |
|
|
* callback(BIO,state,ret); The callback should return |
92 |
|
|
* 'ret'. state is for compatibility with the ssl info_callback */ |
93 |
|
|
int (*info_callback)(const BIO *bio, int state, int ret); |
94 |
|
|
} BIO_CONNECT; |
95 |
|
|
|
96 |
|
|
static int conn_write(BIO *h, const char *buf, int num); |
97 |
|
|
static int conn_read(BIO *h, char *buf, int size); |
98 |
|
|
static int conn_puts(BIO *h, const char *str); |
99 |
|
|
static long conn_ctrl(BIO *h, int cmd, long arg1, void *arg2); |
100 |
|
|
static int conn_new(BIO *h); |
101 |
|
|
static int conn_free(BIO *data); |
102 |
|
|
static long conn_callback_ctrl(BIO *h, int cmd, bio_info_cb *); |
103 |
|
|
|
104 |
|
|
static int conn_state(BIO *b, BIO_CONNECT *c); |
105 |
|
|
static void conn_close_socket(BIO *data); |
106 |
|
|
BIO_CONNECT *BIO_CONNECT_new(void); |
107 |
|
|
void BIO_CONNECT_free(BIO_CONNECT *a); |
108 |
|
|
|
109 |
|
|
static BIO_METHOD methods_connectp = { |
110 |
|
|
.type = BIO_TYPE_CONNECT, |
111 |
|
|
.name = "socket connect", |
112 |
|
|
.bwrite = conn_write, |
113 |
|
|
.bread = conn_read, |
114 |
|
|
.bputs = conn_puts, |
115 |
|
|
.ctrl = conn_ctrl, |
116 |
|
|
.create = conn_new, |
117 |
|
|
.destroy = conn_free, |
118 |
|
|
.callback_ctrl = conn_callback_ctrl |
119 |
|
|
}; |
120 |
|
|
|
121 |
|
|
static int |
122 |
|
|
conn_state(BIO *b, BIO_CONNECT *c) |
123 |
|
|
{ |
124 |
|
|
int ret = -1, i; |
125 |
|
|
unsigned long l; |
126 |
|
|
char *p, *q; |
127 |
|
|
int (*cb)(const BIO *, int, int) = NULL; |
128 |
|
|
|
129 |
|
|
if (c->info_callback != NULL) |
130 |
|
|
cb = c->info_callback; |
131 |
|
|
|
132 |
|
|
for (;;) { |
133 |
|
|
switch (c->state) { |
134 |
|
|
case BIO_CONN_S_BEFORE: |
135 |
|
|
p = c->param_hostname; |
136 |
|
|
if (p == NULL) { |
137 |
|
|
BIOerr(BIO_F_CONN_STATE, BIO_R_NO_HOSTNAME_SPECIFIED); |
138 |
|
|
goto exit_loop; |
139 |
|
|
} |
140 |
|
|
for (; *p != '\0'; p++) { |
141 |
|
|
if ((*p == ':') || (*p == '/')) |
142 |
|
|
break; |
143 |
|
|
} |
144 |
|
|
|
145 |
|
|
i= *p; |
146 |
|
|
if ((i == ':') || (i == '/')) { |
147 |
|
|
*(p++) = '\0'; |
148 |
|
|
if (i == ':') { |
149 |
|
|
for (q = p; *q; q++) |
150 |
|
|
if (*q == '/') { |
151 |
|
|
*q = '\0'; |
152 |
|
|
break; |
153 |
|
|
} |
154 |
|
|
free(c->param_port); |
155 |
|
|
c->param_port = strdup(p); |
156 |
|
|
} |
157 |
|
|
} |
158 |
|
|
|
159 |
|
|
if (c->param_port == NULL) { |
160 |
|
|
BIOerr(BIO_F_CONN_STATE, BIO_R_NO_PORT_SPECIFIED); |
161 |
|
|
ERR_asprintf_error_data("host=%s", |
162 |
|
|
c->param_hostname); |
163 |
|
|
goto exit_loop; |
164 |
|
|
} |
165 |
|
|
c->state = BIO_CONN_S_GET_IP; |
166 |
|
|
break; |
167 |
|
|
|
168 |
|
|
case BIO_CONN_S_GET_IP: |
169 |
|
|
if (BIO_get_host_ip(c->param_hostname, &(c->ip[0])) <= 0) |
170 |
|
|
goto exit_loop; |
171 |
|
|
c->state = BIO_CONN_S_GET_PORT; |
172 |
|
|
break; |
173 |
|
|
|
174 |
|
|
case BIO_CONN_S_GET_PORT: |
175 |
|
|
if (c->param_port == NULL) { |
176 |
|
|
/* abort(); */ |
177 |
|
|
goto exit_loop; |
178 |
|
|
} else if (BIO_get_port(c->param_port, &c->port) <= 0) |
179 |
|
|
goto exit_loop; |
180 |
|
|
c->state = BIO_CONN_S_CREATE_SOCKET; |
181 |
|
|
break; |
182 |
|
|
|
183 |
|
|
case BIO_CONN_S_CREATE_SOCKET: |
184 |
|
|
/* now setup address */ |
185 |
|
|
memset((char *)&c->them, 0, sizeof(c->them)); |
186 |
|
|
c->them.sin_family = AF_INET; |
187 |
|
|
c->them.sin_port = htons((unsigned short)c->port); |
188 |
|
|
l = (unsigned long) |
189 |
|
|
((unsigned long)c->ip[0] << 24L)| |
190 |
|
|
((unsigned long)c->ip[1] << 16L)| |
191 |
|
|
((unsigned long)c->ip[2] << 8L)| |
192 |
|
|
((unsigned long)c->ip[3]); |
193 |
|
|
c->them.sin_addr.s_addr = htonl(l); |
194 |
|
|
c->state = BIO_CONN_S_CREATE_SOCKET; |
195 |
|
|
|
196 |
|
|
ret = socket(AF_INET, SOCK_STREAM, SOCKET_PROTOCOL); |
197 |
|
|
if (ret == -1) { |
198 |
|
|
SYSerr(SYS_F_SOCKET, errno); |
199 |
|
|
ERR_asprintf_error_data("host=%s:%s", |
200 |
|
|
c->param_hostname, c->param_port); |
201 |
|
|
BIOerr(BIO_F_CONN_STATE, |
202 |
|
|
BIO_R_UNABLE_TO_CREATE_SOCKET); |
203 |
|
|
goto exit_loop; |
204 |
|
|
} |
205 |
|
|
b->num = ret; |
206 |
|
|
c->state = BIO_CONN_S_NBIO; |
207 |
|
|
break; |
208 |
|
|
|
209 |
|
|
case BIO_CONN_S_NBIO: |
210 |
|
|
if (c->nbio) { |
211 |
|
|
if (!BIO_socket_nbio(b->num, 1)) { |
212 |
|
|
BIOerr(BIO_F_CONN_STATE, |
213 |
|
|
BIO_R_ERROR_SETTING_NBIO); |
214 |
|
|
ERR_asprintf_error_data("host=%s:%s", |
215 |
|
|
c->param_hostname, c->param_port); |
216 |
|
|
goto exit_loop; |
217 |
|
|
} |
218 |
|
|
} |
219 |
|
|
c->state = BIO_CONN_S_CONNECT; |
220 |
|
|
|
221 |
|
|
#if defined(SO_KEEPALIVE) |
222 |
|
|
i = 1; |
223 |
|
|
i = setsockopt(b->num, SOL_SOCKET, SO_KEEPALIVE, &i, sizeof(i)); |
224 |
|
|
if (i < 0) { |
225 |
|
|
SYSerr(SYS_F_SOCKET, errno); |
226 |
|
|
ERR_asprintf_error_data("host=%s:%s", |
227 |
|
|
c->param_hostname, c->param_port); |
228 |
|
|
BIOerr(BIO_F_CONN_STATE, BIO_R_KEEPALIVE); |
229 |
|
|
goto exit_loop; |
230 |
|
|
} |
231 |
|
|
#endif |
232 |
|
|
break; |
233 |
|
|
|
234 |
|
|
case BIO_CONN_S_CONNECT: |
235 |
|
|
BIO_clear_retry_flags(b); |
236 |
|
|
ret = connect(b->num, |
237 |
|
|
(struct sockaddr *)&c->them, |
238 |
|
|
sizeof(c->them)); |
239 |
|
|
b->retry_reason = 0; |
240 |
|
|
if (ret < 0) { |
241 |
|
|
if (BIO_sock_should_retry(ret)) { |
242 |
|
|
BIO_set_retry_special(b); |
243 |
|
|
c->state = BIO_CONN_S_BLOCKED_CONNECT; |
244 |
|
|
b->retry_reason = BIO_RR_CONNECT; |
245 |
|
|
} else { |
246 |
|
|
SYSerr(SYS_F_CONNECT, errno); |
247 |
|
|
ERR_asprintf_error_data("host=%s:%s", |
248 |
|
|
c->param_hostname, c->param_port); |
249 |
|
|
BIOerr(BIO_F_CONN_STATE, |
250 |
|
|
BIO_R_CONNECT_ERROR); |
251 |
|
|
} |
252 |
|
|
goto exit_loop; |
253 |
|
|
} else |
254 |
|
|
c->state = BIO_CONN_S_OK; |
255 |
|
|
break; |
256 |
|
|
|
257 |
|
|
case BIO_CONN_S_BLOCKED_CONNECT: |
258 |
|
|
i = BIO_sock_error(b->num); |
259 |
|
|
if (i) { |
260 |
|
|
BIO_clear_retry_flags(b); |
261 |
|
|
SYSerr(SYS_F_CONNECT, i); |
262 |
|
|
ERR_asprintf_error_data("host=%s:%s", |
263 |
|
|
c->param_hostname, c->param_port); |
264 |
|
|
BIOerr(BIO_F_CONN_STATE, |
265 |
|
|
BIO_R_NBIO_CONNECT_ERROR); |
266 |
|
|
ret = 0; |
267 |
|
|
goto exit_loop; |
268 |
|
|
} else |
269 |
|
|
c->state = BIO_CONN_S_OK; |
270 |
|
|
break; |
271 |
|
|
|
272 |
|
|
case BIO_CONN_S_OK: |
273 |
|
|
ret = 1; |
274 |
|
|
goto exit_loop; |
275 |
|
|
default: |
276 |
|
|
/* abort(); */ |
277 |
|
|
goto exit_loop; |
278 |
|
|
} |
279 |
|
|
|
280 |
|
|
if (cb != NULL) { |
281 |
|
|
if (!(ret = cb((BIO *)b, c->state, ret))) |
282 |
|
|
goto end; |
283 |
|
|
} |
284 |
|
|
} |
285 |
|
|
|
286 |
|
|
/* Loop does not exit */ |
287 |
|
|
exit_loop: |
288 |
|
|
if (cb != NULL) |
289 |
|
|
ret = cb((BIO *)b, c->state, ret); |
290 |
|
|
end: |
291 |
|
|
return (ret); |
292 |
|
|
} |
293 |
|
|
|
294 |
|
|
BIO_CONNECT * |
295 |
|
|
BIO_CONNECT_new(void) |
296 |
|
|
{ |
297 |
|
|
BIO_CONNECT *ret; |
298 |
|
|
|
299 |
|
|
if ((ret = malloc(sizeof(BIO_CONNECT))) == NULL) |
300 |
|
|
return (NULL); |
301 |
|
|
ret->state = BIO_CONN_S_BEFORE; |
302 |
|
|
ret->param_hostname = NULL; |
303 |
|
|
ret->param_port = NULL; |
304 |
|
|
ret->info_callback = NULL; |
305 |
|
|
ret->nbio = 0; |
306 |
|
|
ret->ip[0] = 0; |
307 |
|
|
ret->ip[1] = 0; |
308 |
|
|
ret->ip[2] = 0; |
309 |
|
|
ret->ip[3] = 0; |
310 |
|
|
ret->port = 0; |
311 |
|
|
memset((char *)&ret->them, 0, sizeof(ret->them)); |
312 |
|
|
return (ret); |
313 |
|
|
} |
314 |
|
|
|
315 |
|
|
void |
316 |
|
|
BIO_CONNECT_free(BIO_CONNECT *a) |
317 |
|
|
{ |
318 |
|
|
if (a == NULL) |
319 |
|
|
return; |
320 |
|
|
|
321 |
|
|
free(a->param_hostname); |
322 |
|
|
free(a->param_port); |
323 |
|
|
free(a); |
324 |
|
|
} |
325 |
|
|
|
326 |
|
|
BIO_METHOD * |
327 |
|
|
BIO_s_connect(void) |
328 |
|
|
{ |
329 |
|
|
return (&methods_connectp); |
330 |
|
|
} |
331 |
|
|
|
332 |
|
|
static int |
333 |
|
|
conn_new(BIO *bi) |
334 |
|
|
{ |
335 |
|
|
bi->init = 0; |
336 |
|
|
bi->num = -1; |
337 |
|
|
bi->flags = 0; |
338 |
|
|
if ((bi->ptr = (char *)BIO_CONNECT_new()) == NULL) |
339 |
|
|
return (0); |
340 |
|
|
else |
341 |
|
|
return (1); |
342 |
|
|
} |
343 |
|
|
|
344 |
|
|
static void |
345 |
|
|
conn_close_socket(BIO *bio) |
346 |
|
|
{ |
347 |
|
|
BIO_CONNECT *c; |
348 |
|
|
|
349 |
|
|
c = (BIO_CONNECT *)bio->ptr; |
350 |
|
|
if (bio->num != -1) { |
351 |
|
|
/* Only do a shutdown if things were established */ |
352 |
|
|
if (c->state == BIO_CONN_S_OK) |
353 |
|
|
shutdown(bio->num, SHUT_RDWR); |
354 |
|
|
close(bio->num); |
355 |
|
|
bio->num = -1; |
356 |
|
|
} |
357 |
|
|
} |
358 |
|
|
|
359 |
|
|
static int |
360 |
|
|
conn_free(BIO *a) |
361 |
|
|
{ |
362 |
|
|
BIO_CONNECT *data; |
363 |
|
|
|
364 |
|
|
if (a == NULL) |
365 |
|
|
return (0); |
366 |
|
|
data = (BIO_CONNECT *)a->ptr; |
367 |
|
|
|
368 |
|
|
if (a->shutdown) { |
369 |
|
|
conn_close_socket(a); |
370 |
|
|
BIO_CONNECT_free(data); |
371 |
|
|
a->ptr = NULL; |
372 |
|
|
a->flags = 0; |
373 |
|
|
a->init = 0; |
374 |
|
|
} |
375 |
|
|
return (1); |
376 |
|
|
} |
377 |
|
|
|
378 |
|
|
static int |
379 |
|
|
conn_read(BIO *b, char *out, int outl) |
380 |
|
|
{ |
381 |
|
|
int ret = 0; |
382 |
|
|
BIO_CONNECT *data; |
383 |
|
|
|
384 |
|
|
data = (BIO_CONNECT *)b->ptr; |
385 |
|
|
if (data->state != BIO_CONN_S_OK) { |
386 |
|
|
ret = conn_state(b, data); |
387 |
|
|
if (ret <= 0) |
388 |
|
|
return (ret); |
389 |
|
|
} |
390 |
|
|
|
391 |
|
|
if (out != NULL) { |
392 |
|
|
errno = 0; |
393 |
|
|
ret = read(b->num, out, outl); |
394 |
|
|
BIO_clear_retry_flags(b); |
395 |
|
|
if (ret <= 0) { |
396 |
|
|
if (BIO_sock_should_retry(ret)) |
397 |
|
|
BIO_set_retry_read(b); |
398 |
|
|
} |
399 |
|
|
} |
400 |
|
|
return (ret); |
401 |
|
|
} |
402 |
|
|
|
403 |
|
|
static int |
404 |
|
|
conn_write(BIO *b, const char *in, int inl) |
405 |
|
|
{ |
406 |
|
|
int ret; |
407 |
|
|
BIO_CONNECT *data; |
408 |
|
|
|
409 |
|
|
data = (BIO_CONNECT *)b->ptr; |
410 |
|
|
if (data->state != BIO_CONN_S_OK) { |
411 |
|
|
ret = conn_state(b, data); |
412 |
|
|
if (ret <= 0) |
413 |
|
|
return (ret); |
414 |
|
|
} |
415 |
|
|
|
416 |
|
|
errno = 0; |
417 |
|
|
ret = write(b->num, in, inl); |
418 |
|
|
BIO_clear_retry_flags(b); |
419 |
|
|
if (ret <= 0) { |
420 |
|
|
if (BIO_sock_should_retry(ret)) |
421 |
|
|
BIO_set_retry_write(b); |
422 |
|
|
} |
423 |
|
|
return (ret); |
424 |
|
|
} |
425 |
|
|
|
426 |
|
|
static long |
427 |
|
|
conn_ctrl(BIO *b, int cmd, long num, void *ptr) |
428 |
|
|
{ |
429 |
|
|
BIO *dbio; |
430 |
|
|
int *ip; |
431 |
|
|
const char **pptr; |
432 |
|
|
long ret = 1; |
433 |
|
|
BIO_CONNECT *data; |
434 |
|
|
|
435 |
|
|
data = (BIO_CONNECT *)b->ptr; |
436 |
|
|
|
437 |
|
|
switch (cmd) { |
438 |
|
|
case BIO_CTRL_RESET: |
439 |
|
|
ret = 0; |
440 |
|
|
data->state = BIO_CONN_S_BEFORE; |
441 |
|
|
conn_close_socket(b); |
442 |
|
|
b->flags = 0; |
443 |
|
|
break; |
444 |
|
|
case BIO_C_DO_STATE_MACHINE: |
445 |
|
|
/* use this one to start the connection */ |
446 |
|
|
if (data->state != BIO_CONN_S_OK) |
447 |
|
|
ret = (long)conn_state(b, data); |
448 |
|
|
else |
449 |
|
|
ret = 1; |
450 |
|
|
break; |
451 |
|
|
case BIO_C_GET_CONNECT: |
452 |
|
|
if (ptr != NULL) { |
453 |
|
|
pptr = (const char **)ptr; |
454 |
|
|
if (num == 0) { |
455 |
|
|
*pptr = data->param_hostname; |
456 |
|
|
|
457 |
|
|
} else if (num == 1) { |
458 |
|
|
*pptr = data->param_port; |
459 |
|
|
} else if (num == 2) { |
460 |
|
|
*pptr = (char *)&(data->ip[0]); |
461 |
|
|
} else if (num == 3) { |
462 |
|
|
*((int *)ptr) = data->port; |
463 |
|
|
} |
464 |
|
|
if ((!b->init) || (ptr == NULL)) |
465 |
|
|
*pptr = "not initialized"; |
466 |
|
|
ret = 1; |
467 |
|
|
} |
468 |
|
|
break; |
469 |
|
|
case BIO_C_SET_CONNECT: |
470 |
|
|
if (ptr != NULL) { |
471 |
|
|
b->init = 1; |
472 |
|
|
if (num == 0) { |
473 |
|
|
free(data->param_hostname); |
474 |
|
|
data->param_hostname = strdup(ptr); |
475 |
|
|
} else if (num == 1) { |
476 |
|
|
free(data->param_port); |
477 |
|
|
data->param_port = strdup(ptr); |
478 |
|
|
} else if (num == 2) { |
479 |
|
|
unsigned char *p = ptr; |
480 |
|
|
free(data->param_hostname); |
481 |
|
|
if (asprintf(&data->param_hostname, |
482 |
|
|
"%u.%u.%u.%u", p[0], p[1], |
483 |
|
|
p[2], p[3]) == -1) |
484 |
|
|
data->param_hostname = NULL; |
485 |
|
|
memcpy(&(data->ip[0]), ptr, 4); |
486 |
|
|
} else if (num == 3) { |
487 |
|
|
free(data->param_port); |
488 |
|
|
data->port= *(int *)ptr; |
489 |
|
|
if (asprintf(&data->param_port, "%d", |
490 |
|
|
data->port) == -1) |
491 |
|
|
data->param_port = NULL; |
492 |
|
|
} |
493 |
|
|
} |
494 |
|
|
break; |
495 |
|
|
case BIO_C_SET_NBIO: |
496 |
|
|
data->nbio = (int)num; |
497 |
|
|
break; |
498 |
|
|
case BIO_C_GET_FD: |
499 |
|
|
if (b->init) { |
500 |
|
|
ip = (int *)ptr; |
501 |
|
|
if (ip != NULL) |
502 |
|
|
*ip = b->num; |
503 |
|
|
ret = b->num; |
504 |
|
|
} else |
505 |
|
|
ret = -1; |
506 |
|
|
break; |
507 |
|
|
case BIO_CTRL_GET_CLOSE: |
508 |
|
|
ret = b->shutdown; |
509 |
|
|
break; |
510 |
|
|
case BIO_CTRL_SET_CLOSE: |
511 |
|
|
b->shutdown = (int)num; |
512 |
|
|
break; |
513 |
|
|
case BIO_CTRL_PENDING: |
514 |
|
|
case BIO_CTRL_WPENDING: |
515 |
|
|
ret = 0; |
516 |
|
|
break; |
517 |
|
|
case BIO_CTRL_FLUSH: |
518 |
|
|
break; |
519 |
|
|
case BIO_CTRL_DUP: |
520 |
|
|
{ |
521 |
|
|
dbio = (BIO *)ptr; |
522 |
|
|
if (data->param_port) |
523 |
|
|
BIO_set_conn_port(dbio, data->param_port); |
524 |
|
|
if (data->param_hostname) |
525 |
|
|
BIO_set_conn_hostname(dbio, |
526 |
|
|
data->param_hostname); |
527 |
|
|
BIO_set_nbio(dbio, data->nbio); |
528 |
|
|
/* FIXME: the cast of the function seems unlikely to be a good idea */ |
529 |
|
|
(void)BIO_set_info_callback(dbio, |
530 |
|
|
(bio_info_cb *)data->info_callback); |
531 |
|
|
} |
532 |
|
|
break; |
533 |
|
|
case BIO_CTRL_SET_CALLBACK: |
534 |
|
|
{ |
535 |
|
|
#if 0 /* FIXME: Should this be used? -- Richard Levitte */ |
536 |
|
|
BIOerr(BIO_F_CONN_CTRL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); |
537 |
|
|
ret = -1; |
538 |
|
|
#else |
539 |
|
|
ret = 0; |
540 |
|
|
#endif |
541 |
|
|
} |
542 |
|
|
break; |
543 |
|
|
case BIO_CTRL_GET_CALLBACK: |
544 |
|
|
{ |
545 |
|
|
int (**fptr)(const BIO *bio, int state, int xret); |
546 |
|
|
|
547 |
|
|
fptr = (int (**)(const BIO *bio, int state, int xret))ptr; |
548 |
|
|
*fptr = data->info_callback; |
549 |
|
|
} |
550 |
|
|
break; |
551 |
|
|
default: |
552 |
|
|
ret = 0; |
553 |
|
|
break; |
554 |
|
|
} |
555 |
|
|
return (ret); |
556 |
|
|
} |
557 |
|
|
|
558 |
|
|
static long |
559 |
|
|
conn_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp) |
560 |
|
|
{ |
561 |
|
|
long ret = 1; |
562 |
|
|
BIO_CONNECT *data; |
563 |
|
|
|
564 |
|
|
data = (BIO_CONNECT *)b->ptr; |
565 |
|
|
|
566 |
|
|
switch (cmd) { |
567 |
|
|
case BIO_CTRL_SET_CALLBACK: |
568 |
|
|
{ |
569 |
|
|
data->info_callback = (int (*)(const struct bio_st *, int, int))fp; |
570 |
|
|
} |
571 |
|
|
break; |
572 |
|
|
default: |
573 |
|
|
ret = 0; |
574 |
|
|
break; |
575 |
|
|
} |
576 |
|
|
return (ret); |
577 |
|
|
} |
578 |
|
|
|
579 |
|
|
static int |
580 |
|
|
conn_puts(BIO *bp, const char *str) |
581 |
|
|
{ |
582 |
|
|
int n, ret; |
583 |
|
|
|
584 |
|
|
n = strlen(str); |
585 |
|
|
ret = conn_write(bp, str, n); |
586 |
|
|
return (ret); |
587 |
|
|
} |
588 |
|
|
|
589 |
|
|
BIO * |
590 |
|
|
BIO_new_connect(char *str) |
591 |
|
|
{ |
592 |
|
|
BIO *ret; |
593 |
|
|
|
594 |
|
|
ret = BIO_new(BIO_s_connect()); |
595 |
|
|
if (ret == NULL) |
596 |
|
|
return (NULL); |
597 |
|
|
if (BIO_set_conn_hostname(ret, str)) |
598 |
|
|
return (ret); |
599 |
|
|
else { |
600 |
|
|
BIO_free(ret); |
601 |
|
|
return (NULL); |
602 |
|
|
} |
603 |
|
|
} |
604 |
|
|
|