comparison mcabber/connwrap/connwrap.c @ 25:bf3d6e241714

[/trunk] Changeset 41 by mikael * Add libjabber to trunk. Let the game begin! :-)
author mikael
date Sun, 27 Mar 2005 20:18:21 +0000
parents
children edb5591e2e64
comparison
equal deleted inserted replaced
24:e88b15cbf2de 25:bf3d6e241714
1 #include "connwrap.h"
2
3 #include <netdb.h>
4 #include <string.h>
5 #include <netinet/in.h>
6 #include <errno.h>
7 #include <arpa/inet.h>
8 #include <fcntl.h>
9 #include <sys/time.h>
10
11 #define PROXY_TIMEOUT 10
12 // HTTP proxy timeout in seconds (for the CONNECT method)
13
14 #ifdef HAVE_OPENSSL
15
16 #define OPENSSL_NO_KRB5 1
17 #include <openssl/ssl.h>
18 #include <openssl/err.h>
19
20 #elif HAVE_GNUTLS
21
22 #include <gnutls/openssl.h>
23 #define HAVE_OPENSSL
24
25 #endif
26
27 static int in_http_connect = 0;
28
29 #ifdef HAVE_OPENSSL
30
31 static SSL_CTX *ctx = 0;
32
33 typedef struct { int fd; SSL *ssl; } sslsock;
34
35 static sslsock *socks = 0;
36 static int sockcount = 0;
37
38 static sslsock *getsock(int fd) {
39 int i;
40
41 for(i = 0; i < sockcount; i++)
42 if(socks[i].fd == fd)
43 return &socks[i];
44
45 return 0;
46 }
47
48 static sslsock *addsock(int fd) {
49 sslsock *p;
50 socks = (sslsock *) realloc(socks, sizeof(sslsock)*++sockcount);
51
52 p = &socks[sockcount-1];
53
54 if(!ctx) {
55 SSL_library_init();
56 SSL_load_error_strings();
57
58 #ifdef HAVE_SSLEAY
59 SSLeay_add_all_algorithms();
60 #else
61 OpenSSL_add_all_algorithms();
62 #endif
63
64 ctx = SSL_CTX_new(SSLv23_method());
65 }
66
67 p->ssl = SSL_new(ctx);
68 SSL_set_fd(p->ssl, p->fd = fd);
69
70 return p;
71 }
72
73 static void delsock(int fd) {
74 int i, nsockcount;
75 sslsock *nsocks;
76
77 nsockcount = 0;
78 nsocks = (sslsock *) malloc(sizeof(sslsock)*(sockcount-1));
79
80 for(i = 0; i < sockcount; i++) {
81 if(socks[i].fd != fd) {
82 nsocks[nsockcount++] = socks[i];
83 } else {
84 SSL_free(socks[i].ssl);
85 }
86 }
87
88 free(socks);
89
90 socks = nsocks;
91 sockcount = nsockcount;
92 }
93
94 #endif
95
96 static char *bindaddr = 0, *proxyhost = 0, *proxyuser = 0, *proxypass = 0;
97 static int proxyport = 3128;
98 static int proxy_ssl = 0;
99
100 #define SOCKOUT(s) write(sockfd, s, strlen(s))
101
102 int cw_http_connect(int sockfd, const struct sockaddr *serv_addr, int addrlen) {
103 int err, pos, fl;
104 struct hostent *server;
105 struct sockaddr_in paddr;
106 char buf[512];
107 fd_set rfds;
108
109 err = 0;
110 in_http_connect = 1;
111
112 if(!(server = gethostbyname(proxyhost))) {
113 errno = h_errno;
114 err = -1;
115 }
116
117 if(!err) {
118 memset(&paddr, 0, sizeof(paddr));
119 paddr.sin_family = AF_INET;
120 memcpy(&paddr.sin_addr.s_addr, *server->h_addr_list, server->h_length);
121 paddr.sin_port = htons(proxyport);
122
123 fl = fcntl(sockfd, F_GETFL);
124 fcntl(sockfd, F_SETFL, fl & ~O_NONBLOCK);
125
126 buf[0] = 0;
127
128 err = cw_connect(sockfd, (struct sockaddr *) &paddr, sizeof(paddr), proxy_ssl);
129 }
130
131 errno = ECONNREFUSED;
132
133 if(!err) {
134 struct sockaddr_in *sin = (struct sockaddr_in *) serv_addr;
135 char *ip = inet_ntoa(sin->sin_addr), c;
136 struct timeval tv;
137
138 sprintf(buf, "%d", ntohs(sin->sin_port));
139 SOCKOUT("CONNECT ");
140 SOCKOUT(ip);
141 SOCKOUT(":");
142 SOCKOUT(buf);
143 SOCKOUT(" HTTP/1.0\r\n");
144
145 if(proxyuser) {
146 char *b;
147 SOCKOUT("Proxy-Authorization: Basic ");
148
149 sprintf(buf, "%s:%s", proxyuser, proxypass);
150 b = cw_base64_encode(buf);
151 SOCKOUT(b);
152 free(b);
153
154 SOCKOUT("\r\n");
155 }
156
157 SOCKOUT("\r\n");
158
159 buf[0] = 0;
160
161 while(err != -1) {
162 FD_ZERO(&rfds);
163 FD_SET(sockfd, &rfds);
164
165 tv.tv_sec = PROXY_TIMEOUT;
166 tv.tv_usec = 0;
167
168 err = select(sockfd+1, &rfds, 0, 0, &tv);
169
170 if(err < 1) err = -1;
171
172 if(err != -1 && FD_ISSET(sockfd, &rfds)) {
173 err = read(sockfd, &c, 1);
174 if(!err) err = -1;
175
176 if(err != -1) {
177 pos = strlen(buf);
178 buf[pos] = c;
179 buf[pos+1] = 0;
180
181 if(strlen(buf) > 4)
182 if(!strcmp(buf+strlen(buf)-4, "\r\n\r\n"))
183 break;
184 }
185 }
186 }
187 }
188
189 if(err != -1 && strlen(buf)) {
190 char *p = strstr(buf, " ");
191
192 err = -1;
193
194 if(p)
195 if(atoi(++p) == 200)
196 err = 0;
197
198 fcntl(sockfd, F_SETFL, fl);
199 if(fl & O_NONBLOCK) {
200 errno = EINPROGRESS;
201 err = -1;
202 }
203 }
204
205 in_http_connect = 0;
206
207 return err;
208 }
209
210 int cw_connect(int sockfd, const struct sockaddr *serv_addr, int addrlen, int ssl) {
211 int rc;
212 struct sockaddr_in ba;
213
214 if(bindaddr)
215 if(strlen(bindaddr)) {
216 #ifdef HAVE_INET_ATON
217 struct in_addr addr;
218 rc = inet_aton(bindaddr, &addr);
219 ba.sin_addr.s_addr = addr.s_addr;
220 #else
221 rc = inet_pton(AF_INET, bindaddr, &ba);
222 #endif
223
224 if(rc) {
225 ba.sin_port = 0;
226 rc = bind(sockfd, (struct sockaddr *) &ba, sizeof(ba));
227 } else {
228 rc = -1;
229 }
230
231 if(rc) return rc;
232 }
233
234 if(proxyhost && !in_http_connect) rc = cw_http_connect(sockfd, serv_addr, addrlen);
235 else rc = connect(sockfd, serv_addr, addrlen);
236
237 #ifdef HAVE_OPENSSL
238 if(ssl && !rc) {
239 sslsock *p = addsock(sockfd);
240 if(SSL_connect(p->ssl) != 1)
241 return -1;
242 }
243 #endif
244
245 return rc;
246 }
247
248 int cw_nb_connect(int sockfd, const struct sockaddr *serv_addr, int addrlen, int ssl, int *state) {
249 int rc = 0;
250 struct sockaddr_in ba;
251
252 if(bindaddr)
253 if(strlen(bindaddr)) {
254 #ifdef HAVE_INET_ATON
255 struct in_addr addr;
256 rc = inet_aton(bindaddr, &addr);
257 ba.sin_addr.s_addr = addr.s_addr;
258 #else
259 rc = inet_pton(AF_INET, bindaddr, &ba);
260 #endif
261
262 if(rc) {
263 ba.sin_port = 0;
264 rc = bind(sockfd, (struct sockaddr *) &ba, sizeof(ba));
265 } else {
266 rc = -1;
267 }
268
269 if(rc) return rc;
270 }
271
272 #ifdef HAVE_OPENSSL
273 if(ssl) {
274 if ( !(*state & CW_CONNECT_WANT_SOMETHING))
275 rc = cw_connect(sockfd, serv_addr, addrlen, 0);
276 else{ /* check if the socket is connected correctly */
277 int optlen = sizeof(int), optval;
278 if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval, &optlen) || optval)
279 return -1;
280 }
281
282 if(!rc) {
283 sslsock *p;
284 if (*state & CW_CONNECT_SSL)
285 p = getsock(sockfd);
286 else
287 p = addsock(sockfd);
288
289 rc = SSL_connect(p->ssl);
290 switch(rc){
291 case 1:
292 *state = 0;
293 return 0;
294 case 0:
295 return -1;
296 default:
297 switch (SSL_get_error(p->ssl, rc)){
298 case SSL_ERROR_WANT_READ:
299 *state = CW_CONNECT_SSL | CW_CONNECT_WANT_READ;
300 return 0;
301 case SSL_ERROR_WANT_WRITE:
302 *state = CW_CONNECT_SSL | CW_CONNECT_WANT_WRITE;
303 return 0;
304 default:
305 return -1;
306 }
307 }
308 }
309 else{ /* catch EINPROGRESS error from the connect call */
310 if (errno == EINPROGRESS){
311 *state = CW_CONNECT_STARTED | CW_CONNECT_WANT_WRITE;
312 return 0;
313 }
314 }
315
316 return rc;
317 }
318 #endif
319 if ( !(*state & CW_CONNECT_WANT_SOMETHING))
320 rc = connect(sockfd, serv_addr, addrlen);
321 else{ /* check if the socket is connected correctly */
322 int optlen = sizeof(int), optval;
323 if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval, &optlen) || optval)
324 return -1;
325 *state = 0;
326 return 0;
327 }
328 if (rc)
329 if (errno == EINPROGRESS){
330 *state = CW_CONNECT_STARTED | CW_CONNECT_WANT_WRITE;
331 return 0;
332 }
333 return rc;
334 }
335
336 int cw_accept(int s, struct sockaddr *addr, int *addrlen, int ssl) {
337 #ifdef HAVE_OPENSSL
338 int rc;
339
340 if(ssl) {
341 rc = accept(s, addr, addrlen);
342
343 if(!rc) {
344 sslsock *p = addsock(s);
345 if(SSL_accept(p->ssl) != 1)
346 return -1;
347
348 }
349
350 return rc;
351 }
352 #endif
353 return accept(s, addr, addrlen);
354 }
355
356 int cw_write(int fd, const void *buf, int count, int ssl) {
357 #ifdef HAVE_OPENSSL
358 sslsock *p;
359
360 if(ssl)
361 if(p = getsock(fd))
362 return SSL_write(p->ssl, buf, count);
363 #endif
364 return write(fd, buf, count);
365 }
366
367 int cw_read(int fd, void *buf, int count, int ssl) {
368 #ifdef HAVE_OPENSSL
369 sslsock *p;
370
371 if(ssl)
372 if(p = getsock(fd))
373 return SSL_read(p->ssl, buf, count);
374 #endif
375 return read(fd, buf, count);
376 }
377
378 int cw_close(int fd) {
379 #ifdef HAVE_OPENSSL
380 delsock(fd);
381 #endif
382 close(fd);
383 }
384
385 #define FREEVAR(v) if(v) free(v), v = 0;
386
387 void cw_setbind(const char *abindaddr) {
388 FREEVAR(bindaddr);
389 bindaddr = strdup(abindaddr);
390 }
391
392 void cw_setproxy(const char *aproxyhost, int aproxyport, const char *aproxyuser, const char *aproxypass) {
393 FREEVAR(proxyhost);
394 FREEVAR(proxyuser);
395 FREEVAR(proxypass);
396
397 if(aproxyhost && strlen(aproxyhost)) proxyhost = strdup(aproxyhost);
398 if(aproxyuser && strlen(aproxyuser)) proxyuser = strdup(aproxyuser);
399 if(aproxypass && strlen(aproxypass)) proxypass = strdup(aproxypass);
400 proxyport = aproxyport;
401 }
402
403 char *cw_base64_encode(const char *in) {
404 static char base64digits[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._";
405
406 int j = 0;
407 int inlen = strlen(in);
408 char *out = (char *) malloc(inlen*4+1), c;
409
410 for(out[0] = 0; inlen >= 3; inlen -= 3) {
411 strncat(out, &base64digits[ in[j] >> 2 ], 1);
412 strncat(out, &base64digits[ ((in[j] << 4) & 0x30) | (in[j+1] >> 4) ], 1);
413 strncat(out, &base64digits[ ((in[j+1] << 2) & 0x3c) | (in[j+2] >> 6) ], 1);
414 strncat(out, &base64digits[ in[j+2] & 0x3f ], 1);
415 j += 3;
416 }
417
418 if(inlen > 0) {
419 unsigned char fragment;
420
421 strncat(out, &base64digits[in[j] >> 2], 1);
422 fragment = (in[j] << 4) & 0x30;
423
424 if(inlen > 1)
425 fragment |= in[j+1] >> 4;
426
427 strncat(out, &base64digits[fragment], 1);
428
429 c = (inlen < 2) ? '-' : base64digits[ (in[j+1] << 2) & 0x3c ];
430 strncat(out, &c, 1);
431 c = '-';
432 strncat(out, &c, 1);
433 }
434
435 return out;
436 }