Code

Fix SHA1 64bit-ism. Clean up warnings.
[inkscape.git] / src / pedro / pedroutil.cpp
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 const 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         }
111 /**
112  * Writes the specified string to the output buffer
113  */
114 void Base64Encoder::append(char *str)
116     while (*str)
117         append((int)*str++);
120 /**
121  * Writes the specified string to the output buffer
122  */
123 void Base64Encoder::append(unsigned char *str, int len)
125     while (len>0)
126         {
127         append((int)*str++);
128         len--;
129         }
132 /**
133  * Writes the specified string to the output buffer
134  */
135 void Base64Encoder::append(const DOMString &str)
137     append((char *)str.c_str());
140 /**
141  * Closes this output stream and releases any system resources
142  * associated with this stream.
143  */
144 DOMString Base64Encoder::finish()
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;
187 DOMString Base64Encoder::encode(const DOMString &str)
189     Base64Encoder encoder;
190     encoder.append(str);
191     DOMString ret = encoder.finish();
192     return ret;
197 //#################
198 //# DECODER
199 //#################
201 static int base64decode[] =
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)
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         }
258 void Base64Decoder::append(char *str)
260     while (*str)
261         append((int)*str++);
264 void Base64Decoder::append(const DOMString &str)
266     append((char *)str.c_str());
269 std::vector<unsigned char> Base64Decoder::finish()
271     std::vector<unsigned char> ret = buf;
272     reset();
273     return ret;
276 std::vector<unsigned char> Base64Decoder::decode(const DOMString &str)
278     Base64Decoder decoder;
279     decoder.append(str);
280     std::vector<unsigned char> ret = decoder.finish();
281     return ret;
284 DOMString Base64Decoder::decodeToString(const DOMString &str)
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;
301 //########################################################################
302 //########################################################################
303 //### S H A    1      H A S H I N G
304 //########################################################################
305 //########################################################################
307 void Sha1::hash(unsigned char *dataIn, int len, unsigned char *digest)
309     Sha1 sha1;
310     sha1.append(dataIn, len);
311     sha1.finish(digest);
314 static const char *sha1hex = "0123456789abcdef";
316 DOMString Sha1::hashHex(unsigned char *dataIn, int len)
318     unsigned char hashout[20];
319     hash(dataIn, len, hashout);
320     DOMString ret;
321     for (int i=0 ; i<20 ; i++)
322         {
323         unsigned char ch = hashout[i];
324         ret.push_back(sha1hex[ (ch>>4) & 15 ]);
325         ret.push_back(sha1hex[ ch      & 15 ]);
326         }
327     return ret;
331 DOMString Sha1::hashHex(const DOMString &str)
333     return hashHex((unsigned char *)str.c_str(), str.size());
337 void Sha1::init()
340     longNr    = 0;
341     byteNr    = 0;
342     nrBytesHi = 0;
343     nrBytesLo = 0;
345     // Initialize H with the magic constants (see FIPS180 for constants)
346     hashBuf[0] = 0x67452301L;
347     hashBuf[1] = 0xefcdab89L;
348     hashBuf[2] = 0x98badcfeL;
349     hashBuf[3] = 0x10325476L;
350     hashBuf[4] = 0xc3d2e1f0L;
352     for (int i = 0; i < 4; i++)
353         inb[i] = 0;
355     for (int i = 0; i < 80; i++)
356         inBuf[i] = 0;
360 void Sha1::append(unsigned char ch)
362     if (nrBytesLo == 0xffffffffL)
363         {
364         nrBytesHi++;
365         nrBytesLo = 0;
366         }
367     else
368         nrBytesLo++;
370     inb[byteNr++] = (unsigned long)ch;
371     if (byteNr >= 4)
372         {
373         inBuf[longNr++] = inb[0] << 24 | inb[1] << 16 |
374                           inb[2] << 8  | inb[3];
375         byteNr = 0;
376         }
377     if (longNr >= 16)
378         {
379         transform();
380         longNr = 0;
381         }
385 void Sha1::append(unsigned char *dataIn, int len)
387     for (int i = 0; i < len; i++)
388         append(dataIn[i]);
392 void Sha1::append(const DOMString &str)
394     append((unsigned char *)str.c_str(), str.size());
398 void Sha1::finish(unsigned char digest[20])
400     //snapshot the bit count now before padding
401     unsigned long nrBitsLo = (nrBytesLo << 3) & 0xffffffff;
402     unsigned long nrBitsHi = (nrBytesHi << 3) | ((nrBytesLo >> 29) & 7);
404     //Append terminal char
405     append(0x80);
407     //pad until we have a 56 of 64 bytes, allowing for 8 bytes at the end
408     while (longNr != 14)
409         append(0);
412     //##### Append length in bits
413     append((unsigned char)((nrBitsHi>>24) & 0xff));
414     append((unsigned char)((nrBitsHi>>16) & 0xff));
415     append((unsigned char)((nrBitsHi>> 8) & 0xff));
416     append((unsigned char)((nrBitsHi    ) & 0xff));
417     append((unsigned char)((nrBitsLo>>24) & 0xff));
418     append((unsigned char)((nrBitsLo>>16) & 0xff));
419     append((unsigned char)((nrBitsLo>> 8) & 0xff));
420     append((unsigned char)((nrBitsLo    ) & 0xff));
423     //copy out answer
424     int indx = 0;
425     for (int i=0 ; i<5 ; i++)
426         {
427         digest[indx++] = (unsigned char)((hashBuf[i] >> 24) & 0xff);
428         digest[indx++] = (unsigned char)((hashBuf[i] >> 16) & 0xff);
429         digest[indx++] = (unsigned char)((hashBuf[i] >>  8) & 0xff);
430         digest[indx++] = (unsigned char)((hashBuf[i]      ) & 0xff);
431         }
433     // Re-initialize the context (also zeroizes contents)
434     init();
439 #define SHA_ROTL(X,n) ((((X) << (n)) & 0xffffffff) | (((X) >> (32-(n))) & 0xffffffff))
441 void Sha1::transform()
443     unsigned long *W = inBuf;
444     unsigned long *H = hashBuf;
446     for (int t = 16; t <= 79; t++)
447         W[t] = SHA_ROTL(W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16], 1);
449     unsigned long A = H[0];
450     unsigned long B = H[1];
451     unsigned long C = H[2];
452     unsigned long D = H[3];
453     unsigned long E = H[4];
455     unsigned long TEMP;
457     for (int t = 0; t <= 19; t++)
458         {
459         TEMP = (SHA_ROTL(A,5) + ((B&C)|((~B)&D)) +
460                 E + W[t] + 0x5a827999L) & 0xffffffffL;
461         E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP;
462         }
463     for (int t = 20; t <= 39; t++)
464         {
465         TEMP = (SHA_ROTL(A,5) + (B^C^D) +
466                 E + W[t] + 0x6ed9eba1L) & 0xffffffffL;
467         E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP;
468         }
469     for (int t = 40; t <= 59; t++)
470         {
471         TEMP = (SHA_ROTL(A,5) + ((B&C)|(B&D)|(C&D)) +
472                 E + W[t] + 0x8f1bbcdcL) & 0xffffffffL;
473         E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP;
474         }
475     for (int t = 60; t <= 79; t++)
476         {
477         TEMP = (SHA_ROTL(A,5) + (B^C^D) +
478                 E + W[t] + 0xca62c1d6L) & 0xffffffffL;
479         E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP;
480         }
482     H[0] = (H[0] + A) & 0xffffffffL;
483     H[1] = (H[1] + B) & 0xffffffffL;
484     H[2] = (H[2] + C) & 0xffffffffL;
485     H[3] = (H[3] + D) & 0xffffffffL;
486     H[4] = (H[4] + E) & 0xffffffffL;
491 //########################################################################
492 //########################################################################
493 //### M D 5      H A S H I N G
494 //########################################################################
495 //########################################################################
500 void Md5::hash(unsigned char *dataIn, unsigned long len, unsigned char *digest)
502     Md5 md5;
503     md5.append(dataIn, len);
504     md5.finish(digest);
507 DOMString Md5::hashHex(unsigned char *dataIn, unsigned long len)
509     Md5 md5;
510     md5.append(dataIn, len);
511     DOMString ret = md5.finishHex();
512     return ret;
515 DOMString Md5::hashHex(const DOMString &str)
517     Md5 md5;
518     md5.append(str);
519     DOMString ret = md5.finishHex();
520     return ret;
524 /**
525  * Initialize MD5 polynomials and storage
526  */
527 void Md5::init()
529     hashBuf[0]  = 0x67452301;
530     hashBuf[1]  = 0xefcdab89;
531     hashBuf[2]  = 0x98badcfe;
532     hashBuf[3]  = 0x10325476;
534     nrBytesHi = 0;
535     nrBytesLo = 0;
536     byteNr    = 0;
537     longNr    = 0;
543 /**
544  * Update with one character
545  */
546 void Md5::append(unsigned char ch)
548     if (nrBytesLo == 0xffffffff)
549         {
550         nrBytesLo = 0;
551         nrBytesHi++;
552         }
553     else
554         nrBytesLo++;
556     //pack 64 bytes into 16 longs
557     inb[byteNr++] = (unsigned long)ch;
558     if (byteNr >= 4)
559         {
560         unsigned long val =
561              inb[3] << 24 | inb[2] << 16 | inb[1] << 8 | inb[0];
562         inBuf[longNr++] = val;
563         byteNr = 0;
564         }
565     if (longNr >= 16)
566         {
567         transform();
568         longNr = 0;
569         }
573 /*
574  * Update context to reflect the concatenation of another buffer full
575  * of bytes.
576  */
577 void Md5::append(unsigned char *source, unsigned long len)
579     while (len--)
580         append(*source++);
584 /*
585  * Update context to reflect the concatenation of another string
586  */
587 void Md5::append(const DOMString &str)
589     append((unsigned char *)str.c_str(), str.size());
593 /*
594  * Final wrapup - pad to 64-byte boundary with the bit pattern
595  * 1 0* (64-bit count of bits processed, MSB-first)
596  */
597 void Md5::finish(unsigned char *digest)
599     //snapshot the bit count now before padding
600     unsigned long nrBitsLo = (nrBytesLo << 3) & 0xffffffff;
601     unsigned long nrBitsHi = (nrBytesHi << 3) | ((nrBytesLo >> 29) & 7);
603     //Append terminal char
604     append(0x80);
606     //pad until we have a 56 of 64 bytes, allowing for 8 bytes at the end
607     while (longNr != 14)
608         append(0);
610     //##### Append length in bits
611     append((unsigned char)((nrBitsLo    ) & 0xff));
612     append((unsigned char)((nrBitsLo>> 8) & 0xff));
613     append((unsigned char)((nrBitsLo>>16) & 0xff));
614     append((unsigned char)((nrBitsLo>>24) & 0xff));
615     append((unsigned char)((nrBitsHi    ) & 0xff));
616     append((unsigned char)((nrBitsHi>> 8) & 0xff));
617     append((unsigned char)((nrBitsHi>>16) & 0xff));
618     append((unsigned char)((nrBitsHi>>24) & 0xff));
620     //copy out answer
621     int indx = 0;
622     for (int i=0 ; i<4 ; i++)
623         {
624         digest[indx++] = (unsigned char)((hashBuf[i]      ) & 0xff);
625         digest[indx++] = (unsigned char)((hashBuf[i] >>  8) & 0xff);
626         digest[indx++] = (unsigned char)((hashBuf[i] >> 16) & 0xff);
627         digest[indx++] = (unsigned char)((hashBuf[i] >> 24) & 0xff);
628         }
630     init();  // Security!  ;-)
635 static const char *md5hex = "0123456789abcdef";
637 DOMString Md5::finishHex()
639     unsigned char hashout[16];
640     finish(hashout);
641     DOMString ret;
642     for (int i=0 ; i<16 ; i++)
643         {
644         unsigned char ch = hashout[i];
645         ret.push_back(md5hex[ (ch>>4) & 15 ]);
646         ret.push_back(md5hex[ ch      & 15 ]);
647         }
648     return ret;
653 //#  The four core functions - F1 is optimized somewhat
655 // #define F1(x, y, z) (x & y | ~x & z)
656 #define M(x) ((x) &= 0xffffffff)
657 #define F1(x, y, z) (z ^ (x & (y ^ z)))
658 #define F2(x, y, z) F1(z, x, y)
659 #define F3(x, y, z) (x ^ y ^ z)
660 #define F4(x, y, z) (y ^ (x | ~z))
662 // ## This is the central step in the MD5 algorithm.
663 #define MD5STEP(f, w, x, y, z, data, s) \
664         ( w += (f(x, y, z) + data), M(w), w = w<<s | w>>(32-s), w += x, M(w) )
666 /*
667  * The core of the MD5 algorithm, this alters an existing MD5 hash to
668  * reflect the addition of 16 longwords of new data.  MD5Update blocks
669  * the data and converts bytes into longwords for this routine.
670  * @parm buf points to an array of 4 unsigned 32bit (at least) integers
671  * @parm in points to an array of 16 unsigned 32bit (at least) integers
672  */
673 void Md5::transform()
675     unsigned long *i = inBuf;
676     unsigned long a  = hashBuf[0];
677     unsigned long b  = hashBuf[1];
678     unsigned long c  = hashBuf[2];
679     unsigned long d  = hashBuf[3];
681     MD5STEP(F1, a, b, c, d, i[ 0] + 0xd76aa478,  7);
682     MD5STEP(F1, d, a, b, c, i[ 1] + 0xe8c7b756, 12);
683     MD5STEP(F1, c, d, a, b, i[ 2] + 0x242070db, 17);
684     MD5STEP(F1, b, c, d, a, i[ 3] + 0xc1bdceee, 22);
685     MD5STEP(F1, a, b, c, d, i[ 4] + 0xf57c0faf,  7);
686     MD5STEP(F1, d, a, b, c, i[ 5] + 0x4787c62a, 12);
687     MD5STEP(F1, c, d, a, b, i[ 6] + 0xa8304613, 17);
688     MD5STEP(F1, b, c, d, a, i[ 7] + 0xfd469501, 22);
689     MD5STEP(F1, a, b, c, d, i[ 8] + 0x698098d8,  7);
690     MD5STEP(F1, d, a, b, c, i[ 9] + 0x8b44f7af, 12);
691     MD5STEP(F1, c, d, a, b, i[10] + 0xffff5bb1, 17);
692     MD5STEP(F1, b, c, d, a, i[11] + 0x895cd7be, 22);
693     MD5STEP(F1, a, b, c, d, i[12] + 0x6b901122,  7);
694     MD5STEP(F1, d, a, b, c, i[13] + 0xfd987193, 12);
695     MD5STEP(F1, c, d, a, b, i[14] + 0xa679438e, 17);
696     MD5STEP(F1, b, c, d, a, i[15] + 0x49b40821, 22);
698     MD5STEP(F2, a, b, c, d, i[ 1] + 0xf61e2562,  5);
699     MD5STEP(F2, d, a, b, c, i[ 6] + 0xc040b340,  9);
700     MD5STEP(F2, c, d, a, b, i[11] + 0x265e5a51, 14);
701     MD5STEP(F2, b, c, d, a, i[ 0] + 0xe9b6c7aa, 20);
702     MD5STEP(F2, a, b, c, d, i[ 5] + 0xd62f105d,  5);
703     MD5STEP(F2, d, a, b, c, i[10] + 0x02441453,  9);
704     MD5STEP(F2, c, d, a, b, i[15] + 0xd8a1e681, 14);
705     MD5STEP(F2, b, c, d, a, i[ 4] + 0xe7d3fbc8, 20);
706     MD5STEP(F2, a, b, c, d, i[ 9] + 0x21e1cde6,  5);
707     MD5STEP(F2, d, a, b, c, i[14] + 0xc33707d6,  9);
708     MD5STEP(F2, c, d, a, b, i[ 3] + 0xf4d50d87, 14);
709     MD5STEP(F2, b, c, d, a, i[ 8] + 0x455a14ed, 20);
710     MD5STEP(F2, a, b, c, d, i[13] + 0xa9e3e905,  5);
711     MD5STEP(F2, d, a, b, c, i[ 2] + 0xfcefa3f8,  9);
712     MD5STEP(F2, c, d, a, b, i[ 7] + 0x676f02d9, 14);
713     MD5STEP(F2, b, c, d, a, i[12] + 0x8d2a4c8a, 20);
715     MD5STEP(F3, a, b, c, d, i[ 5] + 0xfffa3942,  4);
716     MD5STEP(F3, d, a, b, c, i[ 8] + 0x8771f681, 11);
717     MD5STEP(F3, c, d, a, b, i[11] + 0x6d9d6122, 16);
718     MD5STEP(F3, b, c, d, a, i[14] + 0xfde5380c, 23);
719     MD5STEP(F3, a, b, c, d, i[ 1] + 0xa4beea44,  4);
720     MD5STEP(F3, d, a, b, c, i[ 4] + 0x4bdecfa9, 11);
721     MD5STEP(F3, c, d, a, b, i[ 7] + 0xf6bb4b60, 16);
722     MD5STEP(F3, b, c, d, a, i[10] + 0xbebfbc70, 23);
723     MD5STEP(F3, a, b, c, d, i[13] + 0x289b7ec6,  4);
724     MD5STEP(F3, d, a, b, c, i[ 0] + 0xeaa127fa, 11);
725     MD5STEP(F3, c, d, a, b, i[ 3] + 0xd4ef3085, 16);
726     MD5STEP(F3, b, c, d, a, i[ 6] + 0x04881d05, 23);
727     MD5STEP(F3, a, b, c, d, i[ 9] + 0xd9d4d039,  4);
728     MD5STEP(F3, d, a, b, c, i[12] + 0xe6db99e5, 11);
729     MD5STEP(F3, c, d, a, b, i[15] + 0x1fa27cf8, 16);
730     MD5STEP(F3, b, c, d, a, i[ 2] + 0xc4ac5665, 23);
732     MD5STEP(F4, a, b, c, d, i[ 0] + 0xf4292244,  6);
733     MD5STEP(F4, d, a, b, c, i[ 7] + 0x432aff97, 10);
734     MD5STEP(F4, c, d, a, b, i[14] + 0xab9423a7, 15);
735     MD5STEP(F4, b, c, d, a, i[ 5] + 0xfc93a039, 21);
736     MD5STEP(F4, a, b, c, d, i[12] + 0x655b59c3,  6);
737     MD5STEP(F4, d, a, b, c, i[ 3] + 0x8f0ccc92, 10);
738     MD5STEP(F4, c, d, a, b, i[10] + 0xffeff47d, 15);
739     MD5STEP(F4, b, c, d, a, i[ 1] + 0x85845dd1, 21);
740     MD5STEP(F4, a, b, c, d, i[ 8] + 0x6fa87e4f,  6);
741     MD5STEP(F4, d, a, b, c, i[15] + 0xfe2ce6e0, 10);
742     MD5STEP(F4, c, d, a, b, i[ 6] + 0xa3014314, 15);
743     MD5STEP(F4, b, c, d, a, i[13] + 0x4e0811a1, 21);
744     MD5STEP(F4, a, b, c, d, i[ 4] + 0xf7537e82,  6);
745     MD5STEP(F4, d, a, b, c, i[11] + 0xbd3af235, 10);
746     MD5STEP(F4, c, d, a, b, i[ 2] + 0x2ad7d2bb, 15);
747     MD5STEP(F4, b, c, d, a, i[ 9] + 0xeb86d391, 21);
749     hashBuf[0] += a;
750     hashBuf[1] += b;
751     hashBuf[2] += c;
752     hashBuf[3] += d;
759 //########################################################################
760 //########################################################################
761 //### T H R E A D
762 //########################################################################
763 //########################################################################
769 #ifdef __WIN32__
772 static DWORD WINAPI WinThreadFunction(LPVOID context)
774     Thread *thread = (Thread *)context;
775     thread->execute();
776     return 0;
780 void Thread::start()
782     DWORD dwThreadId;
783     HANDLE hThread = CreateThread(NULL, 0, WinThreadFunction,
784                (LPVOID)this,  0,  &dwThreadId);
785     //Make sure the thread is started before 'this' is deallocated
786     while (!started)
787         sleep(10);
788     CloseHandle(hThread);
791 void Thread::sleep(unsigned long millis)
793     Sleep(millis);
796 #else /* UNIX */
799 void *PthreadThreadFunction(void *context)
801     Thread *thread = (Thread *)context;
802     thread->execute();
803     return NULL;
807 void Thread::start()
809     pthread_t thread;
811     int ret = pthread_create(&thread, NULL,
812             PthreadThreadFunction, (void *)this);
813     if (ret != 0)
814         printf("Thread::start: thread creation failed: %s\n", strerror(ret));
816     //Make sure the thread is started before 'this' is deallocated
817     while (!started)
818         sleep(10);
822 void Thread::sleep(unsigned long millis)
824     timespec requested;
825     requested.tv_sec = millis / 1000;
826     requested.tv_nsec = (millis % 1000 ) * 1000000L;
827     nanosleep(&requested, NULL);
830 #endif
839 //########################################################################
840 //########################################################################
841 //### S O C K E T
842 //########################################################################
843 //########################################################################
849 //#########################################################################
850 //# U T I L I T Y
851 //#########################################################################
853 static void mybzero(void *s, size_t n)
855     unsigned char *p = (unsigned char *)s;
856     while (n > 0)
857         {
858         *p++ = (unsigned char)0;
859         n--;
860         }
863 static void mybcopy(void *src, void *dest, size_t n)
865     unsigned char *p = (unsigned char *)dest;
866     unsigned char *q = (unsigned char *)src;
867     while (n > 0)
868         {
869         *p++ = *q++;
870         n--;
871         }
876 //#########################################################################
877 //# T C P    C O N N E C T I O N
878 //#########################################################################
880 TcpSocket::TcpSocket()
882     init();
886 TcpSocket::TcpSocket(const std::string &hostnameArg, int port)
888     init();
889     hostname  = hostnameArg;
890     portno    = port;
896 #ifdef HAVE_SSL
898 static void cryptoLockCallback(int mode, int type, const char */*file*/, int /*line*/)
900     //printf("########### LOCK\n");
901     static int modes[CRYPTO_NUM_LOCKS]; /* = {0, 0, ... } */
902     const char *errstr = NULL;
904     int rw = mode & (CRYPTO_READ|CRYPTO_WRITE);
905     if (!((rw == CRYPTO_READ) || (rw == CRYPTO_WRITE)))
906         {
907         errstr = "invalid mode";
908         goto err;
909         }
911     if (type < 0 || type >= CRYPTO_NUM_LOCKS)
912         {
913         errstr = "type out of bounds";
914         goto err;
915         }
917     if (mode & CRYPTO_LOCK)
918         {
919         if (modes[type])
920             {
921             errstr = "already locked";
922             /* must not happen in a single-threaded program
923              * (would deadlock)
924              */
925             goto err;
926             }
928         modes[type] = rw;
929         }
930     else if (mode & CRYPTO_UNLOCK)
931         {
932         if (!modes[type])
933             {
934              errstr = "not locked";
935              goto err;
936              }
938         if (modes[type] != rw)
939             {
940             errstr = (rw == CRYPTO_READ) ?
941                   "CRYPTO_r_unlock on write lock" :
942                   "CRYPTO_w_unlock on read lock";
943             }
945         modes[type] = 0;
946         }
947     else
948         {
949         errstr = "invalid mode";
950         goto err;
951         }
953     err:
954     if (errstr)
955         {
956         //how do we pass a context pointer here?
957         //error("openssl (lock_dbg_cb): %s (mode=%d, type=%d) at %s:%d",
958         //        errstr, mode, type, file, line);
959         }
962 static unsigned long cryptoIdCallback()
964 #ifdef __WIN32__
965     unsigned long ret = (unsigned long) GetCurrentThreadId();
966 #else
967     unsigned long ret = (unsigned long) pthread_self();
968 #endif
969     return ret;
972 #endif
975 TcpSocket::TcpSocket(const TcpSocket &other)
977     init();
978     sock      = other.sock;
979     hostname  = other.hostname;
980     portno    = other.portno;
984 void TcpSocket::error(const char *fmt, ...)
986     static char buf[256];
987     lastError = "TcpSocket err: ";
988     va_list args;
989     va_start(args, fmt);
990     vsnprintf(buf, 255, fmt, args);
991     va_end(args);
992     lastError.append(buf);
993     fprintf(stderr, "%s\n", lastError.c_str());
997 DOMString &TcpSocket::getLastError()
999     return lastError;
1004 static bool tcp_socket_inited = false;
1006 void TcpSocket::init()
1008     if (!tcp_socket_inited)
1009         {
1010 #ifdef __WIN32__
1011         WORD wVersionRequested = MAKEWORD( 2, 2 );
1012         WSADATA wsaData;
1013         WSAStartup( wVersionRequested, &wsaData );
1014 #endif
1015 #ifdef HAVE_SSL
1016         if (libssl_is_present)
1017         {
1018         sslStream  = NULL;
1019         sslContext = NULL;
1020             CRYPTO_set_locking_callback(cryptoLockCallback);
1021         CRYPTO_set_id_callback(cryptoIdCallback);
1022         SSL_library_init();
1023         SSL_load_error_strings();
1024         }
1025 #endif
1026         tcp_socket_inited = true;
1027         }
1028     sock           = -1;
1029     connected      = false;
1030     hostname       = "";
1031     portno         = -1;
1032     sslEnabled     = false;
1033     receiveTimeout = 0;
1036 TcpSocket::~TcpSocket()
1038     disconnect();
1041 bool TcpSocket::isConnected()
1043     if (!connected || sock < 0)
1044         return false;
1045     return true;
1048 bool TcpSocket::getHaveSSL()
1050 #ifdef HAVE_SSL
1051     if (libssl_is_present)
1052     {
1053         return true;
1054     } else {
1055         return false;
1056     }
1057 #else
1058     return false;
1059 #endif
1062 void TcpSocket::enableSSL(bool val)
1064     sslEnabled = val;
1067 bool TcpSocket::getEnableSSL()
1069     return sslEnabled;
1074 bool TcpSocket::connect(const std::string &hostnameArg, int portnoArg)
1076     hostname = hostnameArg;
1077     portno   = portnoArg;
1078     return connect();
1083 #ifdef HAVE_SSL
1084 /*
1085 static int password_cb(char *buf, int bufLen, int rwflag, void *userdata)
1087     char *password = "password";
1088     if (bufLen < (int)(strlen(password)+1))
1089         return 0;
1091     strcpy(buf,password);
1092     int ret = strlen(password);
1093     return ret;
1096 static void infoCallback(const SSL *ssl, int where, int ret)
1098     switch (where)
1099         {
1100         case SSL_CB_ALERT:
1101             {
1102             printf("## %d SSL ALERT: %s\n",  where, SSL_alert_desc_string_long(ret));
1103             break;
1104             }
1105         default:
1106             {
1107             printf("## %d SSL: %s\n",  where, SSL_state_string_long(ssl));
1108             break;
1109             }
1110         }
1112 */
1113 #endif
1116 bool TcpSocket::startTls()
1118 #ifndef HAVE_SSL
1119     error("SSL starttls() error:  client not compiled with SSL enabled");
1120     return false;
1121 #else /*HAVE_SSL*/
1122     if (!libssl_is_present)
1123         {
1124         error("SSL starttls() error:  the correct version of libssl was not found");
1125         return false;
1126         }
1128     sslStream  = NULL;
1129     sslContext = NULL;
1131     //SSL_METHOD *meth = SSLv23_method();
1132     //SSL_METHOD *meth = SSLv3_client_method();
1133     SSL_METHOD *meth = TLSv1_client_method();
1134     sslContext = SSL_CTX_new(meth);
1135     //SSL_CTX_set_info_callback(sslContext, infoCallback);
1137     /**
1138      * For now, let's accept all connections.  Ignore this
1139      * block of code     
1140      *       
1141     char *keyFile  = "client.pem";
1142     char *caList   = "root.pem";
1143     //#  Load our keys and certificates
1144     if (!(SSL_CTX_use_certificate_chain_file(sslContext, keyFile)))
1145         {
1146         fprintf(stderr, "Can't read certificate file\n");
1147         disconnect();
1148         return false;
1149         }
1151     SSL_CTX_set_default_passwd_cb(sslContext, password_cb);
1153     if (!(SSL_CTX_use_PrivateKey_file(sslContext, keyFile, SSL_FILETYPE_PEM)))
1154         {
1155         fprintf(stderr, "Can't read key file\n");
1156         disconnect();
1157         return false;
1158         }
1160     //## Load the CAs we trust
1161     if (!(SSL_CTX_load_verify_locations(sslContext, caList, 0)))
1162         {
1163         fprintf(stderr, "Can't read CA list\n");
1164         disconnect();
1165         return false;
1166         }
1167     */
1169     /* Connect the SSL socket */
1170     sslStream  = SSL_new(sslContext);
1171     SSL_set_fd(sslStream, sock);
1173     int ret = SSL_connect(sslStream);
1174     if (ret == 0)
1175         {
1176         error("SSL connection not successful");
1177         disconnect();
1178         return false;
1179         }
1180     else if (ret < 0)
1181         {
1182         int err = SSL_get_error(sslStream, ret);
1183         error("SSL connect error %d", err);
1184         disconnect();
1185         return false;
1186         }
1188     sslEnabled = true;
1189     return true;
1190 #endif /* HAVE_SSL */
1194 bool TcpSocket::connect()
1196     if (hostname.size()<1)
1197         {
1198         error("open: null hostname");
1199         return false;
1200         }
1202     if (portno<1)
1203         {
1204         error("open: bad port number");
1205         return false;
1206         }
1208     sock = socket(PF_INET, SOCK_STREAM, 0);
1209     if (sock < 0)
1210         {
1211         error("open: error creating socket");
1212         return false;
1213         }
1215     char *c_hostname = (char *)hostname.c_str();
1216     struct hostent *server = gethostbyname(c_hostname);
1217     if (!server)
1218         {
1219         error("open: could not locate host '%s'", c_hostname);
1220         return false;
1221         }
1223     struct sockaddr_in serv_addr;
1224     mybzero((char *) &serv_addr, sizeof(serv_addr));
1225     serv_addr.sin_family = AF_INET;
1226     mybcopy((char *)server->h_addr, (char *)&serv_addr.sin_addr.s_addr,
1227          server->h_length);
1228     serv_addr.sin_port = htons(portno);
1230     int ret = ::connect(sock, (const sockaddr *)&serv_addr, sizeof(serv_addr));
1231     if (ret < 0)
1232         {
1233         error("open: could not connect to host '%s'", c_hostname);
1234         return false;
1235         }
1237      if (sslEnabled)
1238         {
1239         if (!startTls())
1240             return false;
1241         }
1242     connected = true;
1243     return true;
1246 bool TcpSocket::disconnect()
1248     bool ret  = true;
1249     connected = false;
1250 #ifdef HAVE_SSL
1251     if (libssl_is_present)
1252     {
1253     if (sslEnabled)
1254         {
1255         if (sslStream)
1256             {
1257             int r = SSL_shutdown(sslStream);
1258             switch(r)
1259                 {
1260                 case 1:
1261                     break; /* Success */
1262                 case 0:
1263                 case -1:
1264                 default:
1265                     error("Shutdown failed");
1266                     ret = false;
1267                 }
1268             SSL_free(sslStream);
1269             }
1270         if (sslContext)
1271             SSL_CTX_free(sslContext);
1272         }
1273     sslStream  = NULL;
1274     sslContext = NULL;
1275     }
1276 #endif /*HAVE_SSL*/
1278 #ifdef __WIN32__
1279     closesocket(sock);
1280 #else
1281     ::close(sock);
1282 #endif
1283     sock = -1;
1284     sslEnabled = false;
1286     return ret;
1291 bool TcpSocket::setReceiveTimeout(unsigned long millis)
1293     receiveTimeout = millis;
1294     return true;
1297 /**
1298  * For normal sockets, return the number of bytes waiting to be received.
1299  * For SSL, just return >0 when something is ready to be read.
1300  */
1301 long TcpSocket::available()
1303     if (!isConnected())
1304         return -1;
1306     long count = 0;
1307 #ifdef __WIN32__
1308     if (ioctlsocket(sock, FIONREAD, (unsigned long *)&count) != 0)
1309         return -1;
1310 #else
1311     if (ioctl(sock, FIONREAD, &count) != 0)
1312         return -1;
1313 #endif
1314     if (count<=0 && sslEnabled)
1315         {
1316 #ifdef HAVE_SSL
1317             if (libssl_is_present)
1318                 {
1319             return SSL_pending(sslStream);
1320                 }
1321 #endif
1322         }
1323     return count;
1328 bool TcpSocket::write(int ch)
1330     if (!isConnected())
1331         {
1332         error("write: socket closed");
1333         return false;
1334         }
1335     unsigned char c = (unsigned char)ch;
1337     if (sslEnabled)
1338         {
1339 #ifdef HAVE_SSL
1340         if (libssl_is_present)
1341         {
1342         int r = SSL_write(sslStream, &c, 1);
1343         if (r<=0)
1344             {
1345             switch(SSL_get_error(sslStream, r))
1346                 {
1347                 default:
1348                     error("SSL write problem");
1349                     return -1;
1350                 }
1351             }
1352         }
1353 #endif
1354         }
1355     else
1356         {
1357         if (send(sock, (const char *)&c, 1, 0) < 0)
1358         //if (send(sock, &c, 1, 0) < 0)
1359             {
1360             error("write: could not send data");
1361             return false;
1362             }
1363         }
1364     return true;
1367 bool TcpSocket::write(char *str)
1369    if (!isConnected())
1370         {
1371         error("write(str): socket closed");
1372         return false;
1373         }
1374     int len = strlen(str);
1376     if (sslEnabled)
1377         {
1378 #ifdef HAVE_SSL
1379         if (libssl_is_present)
1380         {
1381         int r = SSL_write(sslStream, (unsigned char *)str, len);
1382         if (r<=0)
1383             {
1384             switch(SSL_get_error(sslStream, r))
1385                 {
1386                 default:
1387                     error("SSL write problem");
1388                     return -1;
1389                 }
1390             }
1391         }
1392 #endif
1393         }
1394     else
1395         {
1396         if (send(sock, str, len, 0) < 0)
1397         //if (send(sock, &c, 1, 0) < 0)
1398             {
1399             error("write: could not send data");
1400             return false;
1401             }
1402         }
1403     return true;
1406 bool TcpSocket::write(const std::string &str)
1408     return write((char *)str.c_str());
1411 int TcpSocket::read()
1413     if (!isConnected())
1414         return -1;
1416     //We'll use this loop for timeouts, so that SSL and plain sockets
1417     //will behave the same way
1418     if (receiveTimeout > 0)
1419         {
1420         unsigned long tim = 0;
1421         while (true)
1422             {
1423             int avail = available();
1424             if (avail > 0)
1425                 break;
1426             if (tim >= receiveTimeout)
1427                 return -2;
1428             Thread::sleep(20);
1429             tim += 20;
1430             }
1431         }
1433     //check again
1434     if (!isConnected())
1435         return -1;
1437     unsigned char ch;
1438     if (sslEnabled)
1439         {
1440 #ifdef HAVE_SSL
1441         if (libssl_is_present)
1442         {
1443         if (!sslStream)
1444             return -1;
1445         int r = SSL_read(sslStream, &ch, 1);
1446         unsigned long err = SSL_get_error(sslStream, r);
1447         switch (err)
1448             {
1449             case SSL_ERROR_NONE:
1450                  break;
1451             case SSL_ERROR_ZERO_RETURN:
1452                 return -1;
1453             case SSL_ERROR_SYSCALL:
1454                 error("SSL read problem(syscall) %s",
1455                      ERR_error_string(ERR_get_error(), NULL));
1456                 return -1;
1457             default:
1458                 error("SSL read problem %s",
1459                      ERR_error_string(ERR_get_error(), NULL));
1460                 return -1;
1461             }
1462         }
1463 #endif
1464         }
1465     else
1466         {
1467         if (recv(sock, (char *)&ch, 1, 0) <= 0)
1468             {
1469             error("read: could not receive data");
1470             disconnect();
1471             return -1;
1472             }
1473         }
1474     return (int)ch;
1477 std::string TcpSocket::readLine()
1479     std::string ret;
1481     while (isConnected())
1482         {
1483         int ch = read();
1484         if (ch<0)
1485             return ret;
1486         if (ch=='\r' || ch=='\n')
1487             return ret;
1488         ret.push_back((char)ch);
1489         }
1491     return ret;
1502 } //namespace Pedro
1503 //########################################################################
1504 //# E N D    O F     F I L E
1505 //########################################################################