1 /*
2 * Support classes for the Pedro mini-XMPP client
3 *
4 * Authors:
5 * Bob Jamison
6 *
7 * Copyright (C) 2005-2007 Bob Jamison
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 */
25 #include <stdio.h>
26 #include <stdarg.h>
28 #include <sys/stat.h>
30 #include "pedroutil.h"
34 #ifdef __WIN32__
36 #include <windows.h>
38 #else /* UNIX */
40 #include <sys/types.h>
41 #include <sys/socket.h>
42 #include <netinet/in.h>
43 #include <netdb.h>
44 #include <unistd.h>
45 #include <sys/ioctl.h>
47 #include <pthread.h>
49 #endif /* UNIX */
51 #ifdef HAVE_SSL
52 RELAYTOOL_SSL
53 #endif
56 namespace Pedro
57 {
63 //########################################################################
64 //########################################################################
65 //# B A S E 6 4
66 //########################################################################
67 //########################################################################
70 //#################
71 //# ENCODER
72 //#################
75 static char *base64encode =
76 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
80 /**
81 * Writes the specified byte to the output buffer
82 */
83 void Base64Encoder::append(int ch)
84 {
85 outBuf <<= 8;
86 outBuf |= (ch & 0xff);
87 bitCount += 8;
88 if (bitCount >= 24)
89 {
90 int indx = (int)((outBuf & 0x00fc0000L) >> 18);
91 int obyte = (int)base64encode[indx & 63];
92 buf.push_back(obyte);
94 indx = (int)((outBuf & 0x0003f000L) >> 12);
95 obyte = (int)base64encode[indx & 63];
96 buf.push_back(obyte);
98 indx = (int)((outBuf & 0x00000fc0L) >> 6);
99 obyte = (int)base64encode[indx & 63];
100 buf.push_back(obyte);
102 indx = (int)((outBuf & 0x0000003fL) );
103 obyte = (int)base64encode[indx & 63];
104 buf.push_back(obyte);
106 bitCount = 0;
107 outBuf = 0L;
108 }
109 }
111 /**
112 * Writes the specified string to the output buffer
113 */
114 void Base64Encoder::append(char *str)
115 {
116 while (*str)
117 append((int)*str++);
118 }
120 /**
121 * Writes the specified string to the output buffer
122 */
123 void Base64Encoder::append(unsigned char *str, int len)
124 {
125 while (len>0)
126 {
127 append((int)*str++);
128 len--;
129 }
130 }
132 /**
133 * Writes the specified string to the output buffer
134 */
135 void Base64Encoder::append(const DOMString &str)
136 {
137 append((char *)str.c_str());
138 }
140 /**
141 * Closes this output stream and releases any system resources
142 * associated with this stream.
143 */
144 DOMString Base64Encoder::finish()
145 {
146 //get any last bytes (1 or 2) out of the buffer
147 if (bitCount == 16)
148 {
149 outBuf <<= 2; //pad to make 18 bits
151 int indx = (int)((outBuf & 0x0003f000L) >> 12);
152 int obyte = (int)base64encode[indx & 63];
153 buf.push_back(obyte);
155 indx = (int)((outBuf & 0x00000fc0L) >> 6);
156 obyte = (int)base64encode[indx & 63];
157 buf.push_back(obyte);
159 indx = (int)((outBuf & 0x0000003fL) );
160 obyte = (int)base64encode[indx & 63];
161 buf.push_back(obyte);
163 buf.push_back('=');
164 }
165 else if (bitCount == 8)
166 {
167 outBuf <<= 4; //pad to make 12 bits
169 int indx = (int)((outBuf & 0x00000fc0L) >> 6);
170 int obyte = (int)base64encode[indx & 63];
171 buf.push_back(obyte);
173 indx = (int)((outBuf & 0x0000003fL) );
174 obyte = (int)base64encode[indx & 63];
175 buf.push_back(obyte);
177 buf.push_back('=');
178 buf.push_back('=');
179 }
181 DOMString ret = buf;
182 reset();
183 return ret;
184 }
187 DOMString Base64Encoder::encode(const DOMString &str)
188 {
189 Base64Encoder encoder;
190 encoder.append(str);
191 DOMString ret = encoder.finish();
192 return ret;
193 }
197 //#################
198 //# DECODER
199 //#################
201 static int base64decode[] =
202 {
203 /*00*/ -1, -1, -1, -1, -1, -1, -1, -1,
204 /*08*/ -1, -1, -1, -1, -1, -1, -1, -1,
205 /*10*/ -1, -1, -1, -1, -1, -1, -1, -1,
206 /*18*/ -1, -1, -1, -1, -1, -1, -1, -1,
207 /*20*/ -1, -1, -1, -1, -1, -1, -1, -1,
208 /*28*/ -1, -1, -1, 62, -1, -1, -1, 63,
209 /*30*/ 52, 53, 54, 55, 56, 57, 58, 59,
210 /*38*/ 60, 61, -1, -1, -1, -1, -1, -1,
211 /*40*/ -1, 0, 1, 2, 3, 4, 5, 6,
212 /*48*/ 7, 8, 9, 10, 11, 12, 13, 14,
213 /*50*/ 15, 16, 17, 18, 19, 20, 21, 22,
214 /*58*/ 23, 24, 25, -1, -1, -1, -1, -1,
215 /*60*/ -1, 26, 27, 28, 29, 30, 31, 32,
216 /*68*/ 33, 34, 35, 36, 37, 38, 39, 40,
217 /*70*/ 41, 42, 43, 44, 45, 46, 47, 48,
218 /*78*/ 49, 50, 51, -1, -1, -1, -1, -1
219 };
223 /**
224 * Appends one char to the decoder
225 */
226 void Base64Decoder::append(int ch)
227 {
228 if (isspace(ch))
229 return;
230 else if (ch == '=') //padding
231 {
232 inBytes[inCount++] = 0;
233 }
234 else
235 {
236 int byteVal = base64decode[ch & 0x7f];
237 //printf("char:%c %d\n", ch, byteVal);
238 if (byteVal < 0)
239 {
240 //Bad lookup value
241 }
242 inBytes[inCount++] = byteVal;
243 }
245 if (inCount >=4 )
246 {
247 unsigned char b0 = ((inBytes[0]<<2) & 0xfc) | ((inBytes[1]>>4) & 0x03);
248 unsigned char b1 = ((inBytes[1]<<4) & 0xf0) | ((inBytes[2]>>2) & 0x0f);
249 unsigned char b2 = ((inBytes[2]<<6) & 0xc0) | ((inBytes[3] ) & 0x3f);
250 buf.push_back(b0);
251 buf.push_back(b1);
252 buf.push_back(b2);
253 inCount = 0;
254 }
256 }
258 void Base64Decoder::append(char *str)
259 {
260 while (*str)
261 append((int)*str++);
262 }
264 void Base64Decoder::append(const DOMString &str)
265 {
266 append((char *)str.c_str());
267 }
269 std::vector<unsigned char> Base64Decoder::finish()
270 {
271 std::vector<unsigned char> ret = buf;
272 reset();
273 return ret;
274 }
276 std::vector<unsigned char> Base64Decoder::decode(const DOMString &str)
277 {
278 Base64Decoder decoder;
279 decoder.append(str);
280 std::vector<unsigned char> ret = decoder.finish();
281 return ret;
282 }
284 DOMString Base64Decoder::decodeToString(const DOMString &str)
285 {
286 Base64Decoder decoder;
287 decoder.append(str);
288 std::vector<unsigned char> ret = decoder.finish();
289 DOMString buf;
290 for (unsigned int i=0 ; i<ret.size() ; i++)
291 buf.push_back(ret[i]);
292 return buf;
293 }
301 //########################################################################
302 //########################################################################
303 //### S H A 1 H A S H I N G
304 //########################################################################
305 //########################################################################
310 void Sha1::hash(unsigned char *dataIn, int len, unsigned char *digest)
311 {
312 Sha1 sha1;
313 sha1.append(dataIn, len);
314 sha1.finish(digest);
315 }
317 static char *sha1hex = "0123456789abcdef";
319 DOMString Sha1::hashHex(unsigned char *dataIn, int len)
320 {
321 unsigned char hashout[20];
322 hash(dataIn, len, hashout);
323 DOMString ret;
324 for (int i=0 ; i<20 ; i++)
325 {
326 unsigned char ch = hashout[i];
327 ret.push_back(sha1hex[ (ch>>4) & 15 ]);
328 ret.push_back(sha1hex[ ch & 15 ]);
329 }
330 return ret;
331 }
334 DOMString Sha1::hashHex(const DOMString &str)
335 {
336 return hashHex((unsigned char *)str.c_str(), str.size());
337 }
340 void Sha1::init()
341 {
343 lenW = 0;
344 sizeHi = 0;
345 sizeLo = 0;
347 // Initialize H with the magic constants (see FIPS180 for constants)
348 H[0] = 0x67452301L;
349 H[1] = 0xefcdab89L;
350 H[2] = 0x98badcfeL;
351 H[3] = 0x10325476L;
352 H[4] = 0xc3d2e1f0L;
354 for (int i = 0; i < 80; i++)
355 W[i] = 0;
356 }
359 void Sha1::append(unsigned char ch)
360 {
361 // Read the data into W and process blocks as they get full
362 W[lenW / 4] <<= 8;
363 W[lenW / 4] |= (unsigned long)ch;
364 if ((++lenW) % 64 == 0)
365 {
366 hashblock();
367 lenW = 0;
368 }
369 sizeLo += 8;
370 sizeHi += (sizeLo < 8);
371 }
374 void Sha1::append(unsigned char *dataIn, int len)
375 {
376 // Read the data into W and process blocks as they get full
377 for (int i = 0; i < len; i++)
378 append(dataIn[i]);
379 }
382 void Sha1::append(const DOMString &str)
383 {
384 append((unsigned char *)str.c_str(), str.size());
385 }
388 void Sha1::finish(unsigned char hashout[20])
389 {
390 unsigned char pad0x80 = 0x80;
391 unsigned char pad0x00 = 0x00;
392 unsigned char padlen[8];
394 // Pad with a binary 1 (e.g. 0x80), then zeroes, then length
395 padlen[0] = (unsigned char)((sizeHi >> 24) & 255);
396 padlen[1] = (unsigned char)((sizeHi >> 16) & 255);
397 padlen[2] = (unsigned char)((sizeHi >> 8) & 255);
398 padlen[3] = (unsigned char)((sizeHi >> 0) & 255);
399 padlen[4] = (unsigned char)((sizeLo >> 24) & 255);
400 padlen[5] = (unsigned char)((sizeLo >> 16) & 255);
401 padlen[6] = (unsigned char)((sizeLo >> 8) & 255);
402 padlen[7] = (unsigned char)((sizeLo >> 0) & 255);
404 append(&pad0x80, 1);
406 while (lenW != 56)
407 append(&pad0x00, 1);
408 append(padlen, 8);
410 // Output hash
411 for (int i = 0; i < 20; i++)
412 {
413 hashout[i] = (unsigned char)(H[i / 4] >> 24);
414 H[i / 4] <<= 8;
415 }
417 // Re-initialize the context (also zeroizes contents)
418 init();
419 }
422 #define SHA_ROTL(X,n) ((((X) << (n)) | ((X) >> (32-(n)))) & 0xffffffffL)
424 void Sha1::hashblock()
425 {
427 for (int t = 16; t <= 79; t++)
428 W[t] = SHA_ROTL(W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16], 1);
430 unsigned long A = H[0];
431 unsigned long B = H[1];
432 unsigned long C = H[2];
433 unsigned long D = H[3];
434 unsigned long E = H[4];
436 unsigned long TEMP;
438 for (int t = 0; t <= 19; t++)
439 {
440 TEMP = (SHA_ROTL(A,5) + (((C^D)&B)^D) +
441 E + W[t] + 0x5a827999L) & 0xffffffffL;
442 E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP;
443 }
444 for (int t = 20; t <= 39; t++)
445 {
446 TEMP = (SHA_ROTL(A,5) + (B^C^D) +
447 E + W[t] + 0x6ed9eba1L) & 0xffffffffL;
448 E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP;
449 }
450 for (int t = 40; t <= 59; t++)
451 {
452 TEMP = (SHA_ROTL(A,5) + ((B&C)|(D&(B|C))) +
453 E + W[t] + 0x8f1bbcdcL) & 0xffffffffL;
454 E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP;
455 }
456 for (int t = 60; t <= 79; t++)
457 {
458 TEMP = (SHA_ROTL(A,5) + (B^C^D) +
459 E + W[t] + 0xca62c1d6L) & 0xffffffffL;
460 E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP;
461 }
463 H[0] += A;
464 H[1] += B;
465 H[2] += C;
466 H[3] += D;
467 H[4] += E;
468 }
475 //########################################################################
476 //########################################################################
477 //### M D 5 H A S H I N G
478 //########################################################################
479 //########################################################################
485 void Md5::hash(unsigned char *dataIn, unsigned long len, unsigned char *digest)
486 {
487 Md5 md5;
488 md5.append(dataIn, len);
489 md5.finish(digest);
490 }
492 DOMString Md5::hashHex(unsigned char *dataIn, unsigned long len)
493 {
494 Md5 md5;
495 md5.append(dataIn, len);
496 DOMString ret = md5.finishHex();
497 return ret;
498 }
500 DOMString Md5::hashHex(const DOMString &str)
501 {
502 Md5 md5;
503 md5.append(str);
504 DOMString ret = md5.finishHex();
505 return ret;
506 }
509 /**
510 * Initialize MD5 polynomials and storage
511 */
512 void Md5::init()
513 {
514 hashBuf[0] = 0x67452301;
515 hashBuf[1] = 0xefcdab89;
516 hashBuf[2] = 0x98badcfe;
517 hashBuf[3] = 0x10325476;
519 nrBytesHi = 0;
520 nrBytesLo = 0;
521 byteNr = 0;
522 longNr = 0;
523 }
528 /*
529 * Update with one character
530 */
531 void Md5::append(unsigned char ch)
532 {
533 if (nrBytesLo == 0xffffffff)
534 {
535 nrBytesLo = 0;
536 nrBytesHi++;
537 }
538 else
539 nrBytesLo++;
541 //pack 64 bytes into 16 longs
542 inb[byteNr++] = (unsigned long)ch;
543 if (byteNr >= 4)
544 {
545 unsigned long val =
546 inb[3] << 24 | inb[2] << 16 | inb[1] << 8 | inb[0];
547 inBuf[longNr++] = val;
548 byteNr = 0;
549 }
550 if (longNr >= 16)
551 {
552 transform();
553 longNr = 0;
554 }
555 }
558 /*
559 * Update context to reflect the concatenation of another buffer full
560 * of bytes.
561 */
562 void Md5::append(unsigned char *source, unsigned long len)
563 {
564 while (len--)
565 append(*source++);
566 }
569 /*
570 * Update context to reflect the concatenation of another string
571 */
572 void Md5::append(const DOMString &str)
573 {
574 append((unsigned char *)str.c_str(), str.size());
575 }
578 /*
579 * Final wrapup - pad to 64-byte boundary with the bit pattern
580 * 1 0* (64-bit count of bits processed, MSB-first)
581 */
582 void Md5::finish(unsigned char *digest)
583 {
584 //snapshot the bit count now before padding
585 unsigned long nrBitsLo = nrBytesLo << 3;
586 unsigned long nrBitsHi = (nrBytesHi << 3) | ((nrBytesLo >> 29) & 7);
588 //Append terminal char
589 append(0x80);
591 //pad until we have a 56 of 64 bits, allowing for 8 bytes at the end
592 while (true)
593 {
594 int remain = (int)(nrBytesLo & 63);
595 if (remain == 56)
596 break;
597 append(0);
598 }
600 //##### Append length in bits
601 int shift;
602 shift = 0;
603 for (int i=0 ; i<4 ; i++)
604 {
605 unsigned char ch = (unsigned char)((nrBitsLo>>shift) & 0xff);
606 append(ch);
607 shift += 8;
608 }
610 shift = 0;
611 for (int i=0 ; i<4 ; i++)
612 {
613 unsigned char ch = (unsigned char)((nrBitsHi>>shift) & 0xff);
614 append(ch);
615 shift += 8;
616 }
618 //copy out answer
619 int indx = 0;
620 for (int i=0 ; i<4 ; i++)
621 {
622 digest[indx++] = (unsigned char)((hashBuf[i] ) & 0xff);
623 digest[indx++] = (unsigned char)((hashBuf[i] >> 8) & 0xff);
624 digest[indx++] = (unsigned char)((hashBuf[i] >> 16) & 0xff);
625 digest[indx++] = (unsigned char)((hashBuf[i] >> 24) & 0xff);
626 }
628 init(); // Security! ;-)
629 }
633 static const char *md5hex = "0123456789abcdef";
635 DOMString Md5::finishHex()
636 {
637 unsigned char hashout[16];
638 finish(hashout);
639 DOMString ret;
640 for (int i=0 ; i<16 ; i++)
641 {
642 unsigned char ch = hashout[i];
643 ret.push_back(md5hex[ (ch>>4) & 15 ]);
644 ret.push_back(md5hex[ ch & 15 ]);
645 }
646 return ret;
647 }
651 //# The four core functions - F1 is optimized somewhat
653 // #define F1(x, y, z) (x & y | ~x & z)
654 #define F1(x, y, z) (z ^ (x & (y ^ z)))
655 #define F2(x, y, z) F1(z, x, y)
656 #define F3(x, y, z) (x ^ y ^ z)
657 #define F4(x, y, z) (y ^ (x | ~z))
659 // ## This is the central step in the MD5 algorithm.
660 #define MD5STEP(f, w, x, y, z, data, s) \
661 ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
663 /*
664 * The core of the MD5 algorithm, this alters an existing MD5 hash to
665 * reflect the addition of 16 longwords of new data. MD5Update blocks
666 * the data and converts bytes into longwords for this routine.
667 * @parm buf points to an array of 4 unsigned longs
668 * @parm in points to an array of 16 unsigned longs
669 */
670 void Md5::transform()
671 {
672 unsigned long *i = inBuf;
673 unsigned long a = hashBuf[0];
674 unsigned long b = hashBuf[1];
675 unsigned long c = hashBuf[2];
676 unsigned long d = hashBuf[3];
678 MD5STEP(F1, a, b, c, d, i[ 0] + 0xd76aa478, 7);
679 MD5STEP(F1, d, a, b, c, i[ 1] + 0xe8c7b756, 12);
680 MD5STEP(F1, c, d, a, b, i[ 2] + 0x242070db, 17);
681 MD5STEP(F1, b, c, d, a, i[ 3] + 0xc1bdceee, 22);
682 MD5STEP(F1, a, b, c, d, i[ 4] + 0xf57c0faf, 7);
683 MD5STEP(F1, d, a, b, c, i[ 5] + 0x4787c62a, 12);
684 MD5STEP(F1, c, d, a, b, i[ 6] + 0xa8304613, 17);
685 MD5STEP(F1, b, c, d, a, i[ 7] + 0xfd469501, 22);
686 MD5STEP(F1, a, b, c, d, i[ 8] + 0x698098d8, 7);
687 MD5STEP(F1, d, a, b, c, i[ 9] + 0x8b44f7af, 12);
688 MD5STEP(F1, c, d, a, b, i[10] + 0xffff5bb1, 17);
689 MD5STEP(F1, b, c, d, a, i[11] + 0x895cd7be, 22);
690 MD5STEP(F1, a, b, c, d, i[12] + 0x6b901122, 7);
691 MD5STEP(F1, d, a, b, c, i[13] + 0xfd987193, 12);
692 MD5STEP(F1, c, d, a, b, i[14] + 0xa679438e, 17);
693 MD5STEP(F1, b, c, d, a, i[15] + 0x49b40821, 22);
695 MD5STEP(F2, a, b, c, d, i[ 1] + 0xf61e2562, 5);
696 MD5STEP(F2, d, a, b, c, i[ 6] + 0xc040b340, 9);
697 MD5STEP(F2, c, d, a, b, i[11] + 0x265e5a51, 14);
698 MD5STEP(F2, b, c, d, a, i[ 0] + 0xe9b6c7aa, 20);
699 MD5STEP(F2, a, b, c, d, i[ 5] + 0xd62f105d, 5);
700 MD5STEP(F2, d, a, b, c, i[10] + 0x02441453, 9);
701 MD5STEP(F2, c, d, a, b, i[15] + 0xd8a1e681, 14);
702 MD5STEP(F2, b, c, d, a, i[ 4] + 0xe7d3fbc8, 20);
703 MD5STEP(F2, a, b, c, d, i[ 9] + 0x21e1cde6, 5);
704 MD5STEP(F2, d, a, b, c, i[14] + 0xc33707d6, 9);
705 MD5STEP(F2, c, d, a, b, i[ 3] + 0xf4d50d87, 14);
706 MD5STEP(F2, b, c, d, a, i[ 8] + 0x455a14ed, 20);
707 MD5STEP(F2, a, b, c, d, i[13] + 0xa9e3e905, 5);
708 MD5STEP(F2, d, a, b, c, i[ 2] + 0xfcefa3f8, 9);
709 MD5STEP(F2, c, d, a, b, i[ 7] + 0x676f02d9, 14);
710 MD5STEP(F2, b, c, d, a, i[12] + 0x8d2a4c8a, 20);
712 MD5STEP(F3, a, b, c, d, i[ 5] + 0xfffa3942, 4);
713 MD5STEP(F3, d, a, b, c, i[ 8] + 0x8771f681, 11);
714 MD5STEP(F3, c, d, a, b, i[11] + 0x6d9d6122, 16);
715 MD5STEP(F3, b, c, d, a, i[14] + 0xfde5380c, 23);
716 MD5STEP(F3, a, b, c, d, i[ 1] + 0xa4beea44, 4);
717 MD5STEP(F3, d, a, b, c, i[ 4] + 0x4bdecfa9, 11);
718 MD5STEP(F3, c, d, a, b, i[ 7] + 0xf6bb4b60, 16);
719 MD5STEP(F3, b, c, d, a, i[10] + 0xbebfbc70, 23);
720 MD5STEP(F3, a, b, c, d, i[13] + 0x289b7ec6, 4);
721 MD5STEP(F3, d, a, b, c, i[ 0] + 0xeaa127fa, 11);
722 MD5STEP(F3, c, d, a, b, i[ 3] + 0xd4ef3085, 16);
723 MD5STEP(F3, b, c, d, a, i[ 6] + 0x04881d05, 23);
724 MD5STEP(F3, a, b, c, d, i[ 9] + 0xd9d4d039, 4);
725 MD5STEP(F3, d, a, b, c, i[12] + 0xe6db99e5, 11);
726 MD5STEP(F3, c, d, a, b, i[15] + 0x1fa27cf8, 16);
727 MD5STEP(F3, b, c, d, a, i[ 2] + 0xc4ac5665, 23);
729 MD5STEP(F4, a, b, c, d, i[ 0] + 0xf4292244, 6);
730 MD5STEP(F4, d, a, b, c, i[ 7] + 0x432aff97, 10);
731 MD5STEP(F4, c, d, a, b, i[14] + 0xab9423a7, 15);
732 MD5STEP(F4, b, c, d, a, i[ 5] + 0xfc93a039, 21);
733 MD5STEP(F4, a, b, c, d, i[12] + 0x655b59c3, 6);
734 MD5STEP(F4, d, a, b, c, i[ 3] + 0x8f0ccc92, 10);
735 MD5STEP(F4, c, d, a, b, i[10] + 0xffeff47d, 15);
736 MD5STEP(F4, b, c, d, a, i[ 1] + 0x85845dd1, 21);
737 MD5STEP(F4, a, b, c, d, i[ 8] + 0x6fa87e4f, 6);
738 MD5STEP(F4, d, a, b, c, i[15] + 0xfe2ce6e0, 10);
739 MD5STEP(F4, c, d, a, b, i[ 6] + 0xa3014314, 15);
740 MD5STEP(F4, b, c, d, a, i[13] + 0x4e0811a1, 21);
741 MD5STEP(F4, a, b, c, d, i[ 4] + 0xf7537e82, 6);
742 MD5STEP(F4, d, a, b, c, i[11] + 0xbd3af235, 10);
743 MD5STEP(F4, c, d, a, b, i[ 2] + 0x2ad7d2bb, 15);
744 MD5STEP(F4, b, c, d, a, i[ 9] + 0xeb86d391, 21);
746 hashBuf[0] += a;
747 hashBuf[1] += b;
748 hashBuf[2] += c;
749 hashBuf[3] += d;
750 }
758 //########################################################################
759 //########################################################################
760 //### T H R E A D
761 //########################################################################
762 //########################################################################
768 #ifdef __WIN32__
771 static DWORD WINAPI WinThreadFunction(LPVOID context)
772 {
773 Thread *thread = (Thread *)context;
774 thread->execute();
775 return 0;
776 }
779 void Thread::start()
780 {
781 DWORD dwThreadId;
782 HANDLE hThread = CreateThread(NULL, 0, WinThreadFunction,
783 (LPVOID)this, 0, &dwThreadId);
784 //Make sure the thread is started before 'this' is deallocated
785 while (!started)
786 sleep(10);
787 CloseHandle(hThread);
788 }
790 void Thread::sleep(unsigned long millis)
791 {
792 Sleep(millis);
793 }
795 #else /* UNIX */
798 void *PthreadThreadFunction(void *context)
799 {
800 Thread *thread = (Thread *)context;
801 thread->execute();
802 return NULL;
803 }
806 void Thread::start()
807 {
808 pthread_t thread;
810 int ret = pthread_create(&thread, NULL,
811 PthreadThreadFunction, (void *)this);
812 if (ret != 0)
813 printf("Thread::start: thread creation failed: %s\n", strerror(ret));
815 //Make sure the thread is started before 'this' is deallocated
816 while (!started)
817 sleep(10);
819 }
821 void Thread::sleep(unsigned long millis)
822 {
823 timespec requested;
824 requested.tv_sec = millis / 1000;
825 requested.tv_nsec = (millis % 1000 ) * 1000000L;
826 nanosleep(&requested, NULL);
827 }
829 #endif
838 //########################################################################
839 //########################################################################
840 //### S O C K E T
841 //########################################################################
842 //########################################################################
848 //#########################################################################
849 //# U T I L I T Y
850 //#########################################################################
852 static void mybzero(void *s, size_t n)
853 {
854 unsigned char *p = (unsigned char *)s;
855 while (n > 0)
856 {
857 *p++ = (unsigned char)0;
858 n--;
859 }
860 }
862 static void mybcopy(void *src, void *dest, size_t n)
863 {
864 unsigned char *p = (unsigned char *)dest;
865 unsigned char *q = (unsigned char *)src;
866 while (n > 0)
867 {
868 *p++ = *q++;
869 n--;
870 }
871 }
875 //#########################################################################
876 //# T C P C O N N E C T I O N
877 //#########################################################################
879 TcpSocket::TcpSocket()
880 {
881 init();
882 }
885 TcpSocket::TcpSocket(const std::string &hostnameArg, int port)
886 {
887 init();
888 hostname = hostnameArg;
889 portno = port;
890 }
895 #ifdef HAVE_SSL
897 static void cryptoLockCallback(int mode, int type, const char *file, int line)
898 {
899 //printf("########### LOCK\n");
900 static int modes[CRYPTO_NUM_LOCKS]; /* = {0, 0, ... } */
901 const char *errstr = NULL;
903 int rw = mode & (CRYPTO_READ|CRYPTO_WRITE);
904 if (!((rw == CRYPTO_READ) || (rw == CRYPTO_WRITE)))
905 {
906 errstr = "invalid mode";
907 goto err;
908 }
910 if (type < 0 || type >= CRYPTO_NUM_LOCKS)
911 {
912 errstr = "type out of bounds";
913 goto err;
914 }
916 if (mode & CRYPTO_LOCK)
917 {
918 if (modes[type])
919 {
920 errstr = "already locked";
921 /* must not happen in a single-threaded program
922 * (would deadlock)
923 */
924 goto err;
925 }
927 modes[type] = rw;
928 }
929 else if (mode & CRYPTO_UNLOCK)
930 {
931 if (!modes[type])
932 {
933 errstr = "not locked";
934 goto err;
935 }
937 if (modes[type] != rw)
938 {
939 errstr = (rw == CRYPTO_READ) ?
940 "CRYPTO_r_unlock on write lock" :
941 "CRYPTO_w_unlock on read lock";
942 }
944 modes[type] = 0;
945 }
946 else
947 {
948 errstr = "invalid mode";
949 goto err;
950 }
952 err:
953 if (errstr)
954 {
955 //how do we pass a context pointer here?
956 //error("openssl (lock_dbg_cb): %s (mode=%d, type=%d) at %s:%d",
957 // errstr, mode, type, file, line);
958 }
959 }
961 static unsigned long cryptoIdCallback()
962 {
963 #ifdef __WIN32__
964 unsigned long ret = (unsigned long) GetCurrentThreadId();
965 #else
966 unsigned long ret = (unsigned long) pthread_self();
967 #endif
968 return ret;
969 }
971 #endif
974 TcpSocket::TcpSocket(const TcpSocket &other)
975 {
976 init();
977 sock = other.sock;
978 hostname = other.hostname;
979 portno = other.portno;
980 }
983 void TcpSocket::error(char *fmt, ...)
984 {
985 static char buf[256];
986 lastError = "TcpSocket err: ";
987 va_list args;
988 va_start(args, fmt);
989 vsnprintf(buf, 255, fmt, args);
990 va_end(args);
991 lastError.append(buf);
992 fprintf(stderr, "%s\n", lastError.c_str());
993 }
996 DOMString &TcpSocket::getLastError()
997 {
998 return lastError;
999 }
1003 static bool tcp_socket_inited = false;
1005 void TcpSocket::init()
1006 {
1007 if (!tcp_socket_inited)
1008 {
1009 #ifdef __WIN32__
1010 WORD wVersionRequested = MAKEWORD( 2, 2 );
1011 WSADATA wsaData;
1012 WSAStartup( wVersionRequested, &wsaData );
1013 #endif
1014 #ifdef HAVE_SSL
1015 if (libssl_is_present)
1016 {
1017 sslStream = NULL;
1018 sslContext = NULL;
1019 CRYPTO_set_locking_callback(cryptoLockCallback);
1020 CRYPTO_set_id_callback(cryptoIdCallback);
1021 SSL_library_init();
1022 SSL_load_error_strings();
1023 }
1024 #endif
1025 tcp_socket_inited = true;
1026 }
1027 sock = -1;
1028 connected = false;
1029 hostname = "";
1030 portno = -1;
1031 sslEnabled = false;
1032 receiveTimeout = 0;
1033 }
1035 TcpSocket::~TcpSocket()
1036 {
1037 disconnect();
1038 }
1040 bool TcpSocket::isConnected()
1041 {
1042 if (!connected || sock < 0)
1043 return false;
1044 return true;
1045 }
1047 bool TcpSocket::getHaveSSL()
1048 {
1049 #ifdef HAVE_SSL
1050 if (libssl_is_present)
1051 {
1052 return true;
1053 } else {
1054 return false;
1055 }
1056 #else
1057 return false;
1058 #endif
1059 }
1061 void TcpSocket::enableSSL(bool val)
1062 {
1063 sslEnabled = val;
1064 }
1066 bool TcpSocket::getEnableSSL()
1067 {
1068 return sslEnabled;
1069 }
1073 bool TcpSocket::connect(const std::string &hostnameArg, int portnoArg)
1074 {
1075 hostname = hostnameArg;
1076 portno = portnoArg;
1077 return connect();
1078 }
1082 #ifdef HAVE_SSL
1083 /*
1084 static int password_cb(char *buf, int bufLen, int rwflag, void *userdata)
1085 {
1086 char *password = "password";
1087 if (bufLen < (int)(strlen(password)+1))
1088 return 0;
1090 strcpy(buf,password);
1091 int ret = strlen(password);
1092 return ret;
1093 }
1095 static void infoCallback(const SSL *ssl, int where, int ret)
1096 {
1097 switch (where)
1098 {
1099 case SSL_CB_ALERT:
1100 {
1101 printf("## %d SSL ALERT: %s\n", where, SSL_alert_desc_string_long(ret));
1102 break;
1103 }
1104 default:
1105 {
1106 printf("## %d SSL: %s\n", where, SSL_state_string_long(ssl));
1107 break;
1108 }
1109 }
1110 }
1111 */
1112 #endif
1115 bool TcpSocket::startTls()
1116 {
1117 #ifndef HAVE_SSL
1118 error("SSL starttls() error: client not compiled with SSL enabled");
1119 return false;
1120 #else /*HAVE_SSL*/
1121 if (!libssl_is_present)
1122 {
1123 error("SSL starttls() error: the correct version of libssl was not found");
1124 return false;
1125 }
1127 sslStream = NULL;
1128 sslContext = NULL;
1130 //SSL_METHOD *meth = SSLv23_method();
1131 //SSL_METHOD *meth = SSLv3_client_method();
1132 SSL_METHOD *meth = TLSv1_client_method();
1133 sslContext = SSL_CTX_new(meth);
1134 //SSL_CTX_set_info_callback(sslContext, infoCallback);
1136 /**
1137 * For now, let's accept all connections. Ignore this
1138 * block of code
1139 *
1140 char *keyFile = "client.pem";
1141 char *caList = "root.pem";
1142 //# Load our keys and certificates
1143 if (!(SSL_CTX_use_certificate_chain_file(sslContext, keyFile)))
1144 {
1145 fprintf(stderr, "Can't read certificate file\n");
1146 disconnect();
1147 return false;
1148 }
1150 SSL_CTX_set_default_passwd_cb(sslContext, password_cb);
1152 if (!(SSL_CTX_use_PrivateKey_file(sslContext, keyFile, SSL_FILETYPE_PEM)))
1153 {
1154 fprintf(stderr, "Can't read key file\n");
1155 disconnect();
1156 return false;
1157 }
1159 //## Load the CAs we trust
1160 if (!(SSL_CTX_load_verify_locations(sslContext, caList, 0)))
1161 {
1162 fprintf(stderr, "Can't read CA list\n");
1163 disconnect();
1164 return false;
1165 }
1166 */
1168 /* Connect the SSL socket */
1169 sslStream = SSL_new(sslContext);
1170 SSL_set_fd(sslStream, sock);
1172 int ret = SSL_connect(sslStream);
1173 if (ret == 0)
1174 {
1175 error("SSL connection not successful");
1176 disconnect();
1177 return false;
1178 }
1179 else if (ret < 0)
1180 {
1181 int err = SSL_get_error(sslStream, ret);
1182 error("SSL connect error %d", err);
1183 disconnect();
1184 return false;
1185 }
1187 sslEnabled = true;
1188 return true;
1189 #endif /* HAVE_SSL */
1190 }
1193 bool TcpSocket::connect()
1194 {
1195 if (hostname.size()<1)
1196 {
1197 error("open: null hostname");
1198 return false;
1199 }
1201 if (portno<1)
1202 {
1203 error("open: bad port number");
1204 return false;
1205 }
1207 sock = socket(PF_INET, SOCK_STREAM, 0);
1208 if (sock < 0)
1209 {
1210 error("open: error creating socket");
1211 return false;
1212 }
1214 char *c_hostname = (char *)hostname.c_str();
1215 struct hostent *server = gethostbyname(c_hostname);
1216 if (!server)
1217 {
1218 error("open: could not locate host '%s'", c_hostname);
1219 return false;
1220 }
1222 struct sockaddr_in serv_addr;
1223 mybzero((char *) &serv_addr, sizeof(serv_addr));
1224 serv_addr.sin_family = AF_INET;
1225 mybcopy((char *)server->h_addr, (char *)&serv_addr.sin_addr.s_addr,
1226 server->h_length);
1227 serv_addr.sin_port = htons(portno);
1229 int ret = ::connect(sock, (const sockaddr *)&serv_addr, sizeof(serv_addr));
1230 if (ret < 0)
1231 {
1232 error("open: could not connect to host '%s'", c_hostname);
1233 return false;
1234 }
1236 if (sslEnabled)
1237 {
1238 if (!startTls())
1239 return false;
1240 }
1241 connected = true;
1242 return true;
1243 }
1245 bool TcpSocket::disconnect()
1246 {
1247 bool ret = true;
1248 connected = false;
1249 #ifdef HAVE_SSL
1250 if (libssl_is_present)
1251 {
1252 if (sslEnabled)
1253 {
1254 if (sslStream)
1255 {
1256 int r = SSL_shutdown(sslStream);
1257 switch(r)
1258 {
1259 case 1:
1260 break; /* Success */
1261 case 0:
1262 case -1:
1263 default:
1264 error("Shutdown failed");
1265 ret = false;
1266 }
1267 SSL_free(sslStream);
1268 }
1269 if (sslContext)
1270 SSL_CTX_free(sslContext);
1271 }
1272 sslStream = NULL;
1273 sslContext = NULL;
1274 }
1275 #endif /*HAVE_SSL*/
1277 #ifdef __WIN32__
1278 closesocket(sock);
1279 #else
1280 ::close(sock);
1281 #endif
1282 sock = -1;
1283 sslEnabled = false;
1285 return ret;
1286 }
1290 bool TcpSocket::setReceiveTimeout(unsigned long millis)
1291 {
1292 receiveTimeout = millis;
1293 return true;
1294 }
1296 /**
1297 * For normal sockets, return the number of bytes waiting to be received.
1298 * For SSL, just return >0 when something is ready to be read.
1299 */
1300 long TcpSocket::available()
1301 {
1302 if (!isConnected())
1303 return -1;
1305 long count = 0;
1306 #ifdef __WIN32__
1307 if (ioctlsocket(sock, FIONREAD, (unsigned long *)&count) != 0)
1308 return -1;
1309 #else
1310 if (ioctl(sock, FIONREAD, &count) != 0)
1311 return -1;
1312 #endif
1313 if (count<=0 && sslEnabled)
1314 {
1315 #ifdef HAVE_SSL
1316 if (libssl_is_present)
1317 {
1318 return SSL_pending(sslStream);
1319 }
1320 #endif
1321 }
1322 return count;
1323 }
1327 bool TcpSocket::write(int ch)
1328 {
1329 if (!isConnected())
1330 {
1331 error("write: socket closed");
1332 return false;
1333 }
1334 unsigned char c = (unsigned char)ch;
1336 if (sslEnabled)
1337 {
1338 #ifdef HAVE_SSL
1339 if (libssl_is_present)
1340 {
1341 int r = SSL_write(sslStream, &c, 1);
1342 if (r<=0)
1343 {
1344 switch(SSL_get_error(sslStream, r))
1345 {
1346 default:
1347 error("SSL write problem");
1348 return -1;
1349 }
1350 }
1351 }
1352 #endif
1353 }
1354 else
1355 {
1356 if (send(sock, (const char *)&c, 1, 0) < 0)
1357 //if (send(sock, &c, 1, 0) < 0)
1358 {
1359 error("write: could not send data");
1360 return false;
1361 }
1362 }
1363 return true;
1364 }
1366 bool TcpSocket::write(char *str)
1367 {
1368 if (!isConnected())
1369 {
1370 error("write(str): socket closed");
1371 return false;
1372 }
1373 int len = strlen(str);
1375 if (sslEnabled)
1376 {
1377 #ifdef HAVE_SSL
1378 if (libssl_is_present)
1379 {
1380 int r = SSL_write(sslStream, (unsigned char *)str, len);
1381 if (r<=0)
1382 {
1383 switch(SSL_get_error(sslStream, r))
1384 {
1385 default:
1386 error("SSL write problem");
1387 return -1;
1388 }
1389 }
1390 }
1391 #endif
1392 }
1393 else
1394 {
1395 if (send(sock, str, len, 0) < 0)
1396 //if (send(sock, &c, 1, 0) < 0)
1397 {
1398 error("write: could not send data");
1399 return false;
1400 }
1401 }
1402 return true;
1403 }
1405 bool TcpSocket::write(const std::string &str)
1406 {
1407 return write((char *)str.c_str());
1408 }
1410 int TcpSocket::read()
1411 {
1412 if (!isConnected())
1413 return -1;
1415 //We'll use this loop for timeouts, so that SSL and plain sockets
1416 //will behave the same way
1417 if (receiveTimeout > 0)
1418 {
1419 unsigned long tim = 0;
1420 while (true)
1421 {
1422 int avail = available();
1423 if (avail > 0)
1424 break;
1425 if (tim >= receiveTimeout)
1426 return -2;
1427 Thread::sleep(20);
1428 tim += 20;
1429 }
1430 }
1432 //check again
1433 if (!isConnected())
1434 return -1;
1436 unsigned char ch;
1437 if (sslEnabled)
1438 {
1439 #ifdef HAVE_SSL
1440 if (libssl_is_present)
1441 {
1442 if (!sslStream)
1443 return -1;
1444 int r = SSL_read(sslStream, &ch, 1);
1445 unsigned long err = SSL_get_error(sslStream, r);
1446 switch (err)
1447 {
1448 case SSL_ERROR_NONE:
1449 break;
1450 case SSL_ERROR_ZERO_RETURN:
1451 return -1;
1452 case SSL_ERROR_SYSCALL:
1453 error("SSL read problem(syscall) %s",
1454 ERR_error_string(ERR_get_error(), NULL));
1455 return -1;
1456 default:
1457 error("SSL read problem %s",
1458 ERR_error_string(ERR_get_error(), NULL));
1459 return -1;
1460 }
1461 }
1462 #endif
1463 }
1464 else
1465 {
1466 if (recv(sock, (char *)&ch, 1, 0) <= 0)
1467 {
1468 error("read: could not receive data");
1469 disconnect();
1470 return -1;
1471 }
1472 }
1473 return (int)ch;
1474 }
1476 std::string TcpSocket::readLine()
1477 {
1478 std::string ret;
1480 while (isConnected())
1481 {
1482 int ch = read();
1483 if (ch<0)
1484 return ret;
1485 if (ch=='\r' || ch=='\n')
1486 return ret;
1487 ret.push_back((char)ch);
1488 }
1490 return ret;
1491 }
1501 } //namespace Pedro
1502 //########################################################################
1503 //# E N D O F F I L E
1504 //########################################################################