Code

Rewrote code to get rid of 32/64 bit problems, and to make is more stream-like. A...
[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 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 //########################################################################
310 void Sha1::hash(unsigned char *dataIn, int len, unsigned char *digest)
312     Sha1 sha1;
313     sha1.append(dataIn, len);
314     sha1.finish(digest);
317 static char *sha1hex = "0123456789abcdef";
319 DOMString Sha1::hashHex(unsigned char *dataIn, int len)
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;
334 void Sha1::init()
337     lenW   = 0;
338     sizeHi = 0;
339     sizeLo = 0;
341     // Initialize H with the magic constants (see FIPS180 for constants)
342     H[0] = 0x67452301L;
343     H[1] = 0xefcdab89L;
344     H[2] = 0x98badcfeL;
345     H[3] = 0x10325476L;
346     H[4] = 0xc3d2e1f0L;
348     for (int i = 0; i < 80; i++)
349         W[i] = 0;
353 void Sha1::append(unsigned char *dataIn, int len)
355     // Read the data into W and process blocks as they get full
356     for (int i = 0; i < len; i++)
357         {
358         W[lenW / 4] <<= 8;
359         W[lenW / 4] |= (unsigned long)dataIn[i];
360         if ((++lenW) % 64 == 0)
361             {
362             hashblock();
363             lenW = 0;
364             }
365         sizeLo += 8;
366         sizeHi += (sizeLo < 8);
367         }
371 void Sha1::finish(unsigned char hashout[20])
373     unsigned char pad0x80 = 0x80;
374     unsigned char pad0x00 = 0x00;
375     unsigned char padlen[8];
377     // Pad with a binary 1 (e.g. 0x80), then zeroes, then length
378     padlen[0] = (unsigned char)((sizeHi >> 24) & 255);
379     padlen[1] = (unsigned char)((sizeHi >> 16) & 255);
380     padlen[2] = (unsigned char)((sizeHi >>  8) & 255);
381     padlen[3] = (unsigned char)((sizeHi >>  0) & 255);
382     padlen[4] = (unsigned char)((sizeLo >> 24) & 255);
383     padlen[5] = (unsigned char)((sizeLo >> 16) & 255);
384     padlen[6] = (unsigned char)((sizeLo >>  8) & 255);
385     padlen[7] = (unsigned char)((sizeLo >>  0) & 255);
387     append(&pad0x80, 1);
389     while (lenW != 56)
390         append(&pad0x00, 1);
391     append(padlen, 8);
393     // Output hash
394     for (int i = 0; i < 20; i++)
395         {
396         hashout[i] = (unsigned char)(H[i / 4] >> 24);
397         H[i / 4] <<= 8;
398         }
400     // Re-initialize the context (also zeroizes contents)
401     init();
405 #define SHA_ROTL(X,n) ((((X) << (n)) | ((X) >> (32-(n)))) & 0xffffffffL)
407 void Sha1::hashblock()
410     for (int t = 16; t <= 79; t++)
411         W[t] = SHA_ROTL(W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16], 1);
413     unsigned long A = H[0];
414     unsigned long B = H[1];
415     unsigned long C = H[2];
416     unsigned long D = H[3];
417     unsigned long E = H[4];
419     unsigned long TEMP;
421     for (int t = 0; t <= 19; t++)
422         {
423         TEMP = (SHA_ROTL(A,5) + (((C^D)&B)^D) +
424                 E + W[t] + 0x5a827999L) & 0xffffffffL;
425         E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP;
426         }
427     for (int t = 20; t <= 39; t++)
428         {
429         TEMP = (SHA_ROTL(A,5) + (B^C^D) +
430                 E + W[t] + 0x6ed9eba1L) & 0xffffffffL;
431         E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP;
432         }
433     for (int t = 40; t <= 59; t++)
434         {
435         TEMP = (SHA_ROTL(A,5) + ((B&C)|(D&(B|C))) +
436                 E + W[t] + 0x8f1bbcdcL) & 0xffffffffL;
437         E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP;
438         }
439     for (int t = 60; t <= 79; t++)
440         {
441         TEMP = (SHA_ROTL(A,5) + (B^C^D) +
442                 E + W[t] + 0xca62c1d6L) & 0xffffffffL;
443         E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP;
444         }
446     H[0] += A;
447     H[1] += B;
448     H[2] += C;
449     H[3] += D;
450     H[4] += E;
458 //########################################################################
459 //########################################################################
460 //### M D 5      H A S H I N G
461 //########################################################################
462 //########################################################################
468 void Md5::hash(unsigned char *dataIn, unsigned long len, unsigned char *digest)
470     Md5 md5;
471     md5.append(dataIn, len);
472     md5.finish(digest);
475 DOMString Md5::hashHex(unsigned char *dataIn, unsigned long len)
477     Md5 md5;
478     md5.append(dataIn, len);
479     DOMString ret = md5.finishHex();
480     return ret;
483 DOMString Md5::hashHex(const DOMString &str)
485     Md5 md5;
486     md5.append(str);
487     DOMString ret = md5.finishHex();
488     return ret;
492 /**
493  * Initialize MD5 polynomials and storage
494  */
495 void Md5::init()
497     hashBuf[0]  = 0x67452301;
498     hashBuf[1]  = 0xefcdab89;
499     hashBuf[2]  = 0x98badcfe;
500     hashBuf[3]  = 0x10325476;
502     nrBytesHi = 0;
503     nrBytesLo = 0;
504     byteNr    = 0;
505     longNr    = 0;
511 /*
512  * Update with one character
513  */
514 void Md5::append(unsigned char ch)
516     if (nrBytesLo == 0xffffffff)
517         {
518         nrBytesLo = 0;
519         nrBytesHi++;
520         }
521     else
522         nrBytesLo++;
524     //pack 64 bytes into 16 longs
525     inb[byteNr++] = (unsigned long)ch;
526     if (byteNr >= 4)
527         {
528         unsigned long val =
529              inb[3] << 24 | inb[2] << 16 | inb[1] << 8 | inb[0];
530         inBuf[longNr++] = val;
531         byteNr = 0;
532         }
533     if (longNr >= 16)
534         {
535         transform();
536         longNr = 0;
537         }
541 /*
542  * Update context to reflect the concatenation of another buffer full
543  * of bytes.
544  */
545 void Md5::append(unsigned char *source, unsigned long len)
547     while (len--)
548         append(*source++);
552 /*
553  * Update context to reflect the concatenation of another string
554  */
555 void Md5::append(const DOMString &str)
557     append((unsigned char *)str.c_str(), str.size());
561 /*
562  * Final wrapup - pad to 64-byte boundary with the bit pattern
563  * 1 0* (64-bit count of bits processed, MSB-first)
564  */
565 void Md5::finish(unsigned char *digest)
567     //snapshot the bit count now before padding
568     unsigned long nrBitsLo = nrBytesLo << 3;
569     unsigned long nrBitsHi = (nrBytesHi << 3) | ((nrBytesLo >> 29) & 7);
571     //Append terminal char
572     append(0x80);
574     //pad until we have a 56 of 64 bits, allowing for 8 bytes at the end
575     while (true)
576         {
577         int remain = (int)(nrBytesLo & 63);
578         if (remain == 56)
579             break;
580         append(0);
581         }
583     //##### Append length in bits
584     int shift;
585     shift = 0;
586     for (int i=0 ; i<4 ; i++)
587         {
588         unsigned char ch = (unsigned char)((nrBitsLo>>shift) & 0xff);
589         append(ch);
590         shift += 8;
591         }
593     shift = 0;
594     for (int i=0 ; i<4 ; i++)
595         {
596         unsigned char ch = (unsigned char)((nrBitsHi>>shift) & 0xff);
597         append(ch);
598         shift += 8;
599         }
601     //copy out answer
602     int indx = 0;
603     for (int i=0 ; i<4 ; i++)
604         {
605         digest[indx++] = (unsigned char)((hashBuf[i]      ) & 0xff);
606         digest[indx++] = (unsigned char)((hashBuf[i] >>  8) & 0xff);
607         digest[indx++] = (unsigned char)((hashBuf[i] >> 16) & 0xff);
608         digest[indx++] = (unsigned char)((hashBuf[i] >> 24) & 0xff);
609         }
611     init();  // Security!  ;-)
616 static const char *md5hex = "0123456789abcdef";
618 DOMString Md5::finishHex()
620     unsigned char hashout[16];
621     finish(hashout);
622     DOMString ret;
623     for (int i=0 ; i<16 ; i++)
624         {
625         unsigned char ch = hashout[i];
626         ret.push_back(md5hex[ (ch>>4) & 15 ]);
627         ret.push_back(md5hex[ ch      & 15 ]);
628         }
629     return ret;
634 //#  The four core functions - F1 is optimized somewhat
636 //  #define F1(x, y, z) (x & y | ~x & z)
637 #define F1(x, y, z) (z ^ (x & (y ^ z)))
638 #define F2(x, y, z) F1(z, x, y)
639 #define F3(x, y, z) (x ^ y ^ z)
640 #define F4(x, y, z) (y ^ (x | ~z))
642 // ## This is the central step in the MD5 algorithm.
643 #define MD5STEP(f, w, x, y, z, data, s) \
644         ( w += f(x, y, z) + data,  w = w<<s | w>>(32-s),  w += x )
646 /*
647  * The core of the MD5 algorithm, this alters an existing MD5 hash to
648  * reflect the addition of 16 longwords of new data.  MD5Update blocks
649  * the data and converts bytes into longwords for this routine.
650  * @parm buf points to an array of 4 unsigned longs
651  * @parm in points to an array of 16 unsigned longs
652  */
653 void Md5::transform()
655     unsigned long *i = inBuf;
656     unsigned long a  = hashBuf[0];
657     unsigned long b  = hashBuf[1];
658     unsigned long c  = hashBuf[2];
659     unsigned long d  = hashBuf[3];
661     MD5STEP(F1, a, b, c, d, i[ 0] + 0xd76aa478,  7);
662     MD5STEP(F1, d, a, b, c, i[ 1] + 0xe8c7b756, 12);
663     MD5STEP(F1, c, d, a, b, i[ 2] + 0x242070db, 17);
664     MD5STEP(F1, b, c, d, a, i[ 3] + 0xc1bdceee, 22);
665     MD5STEP(F1, a, b, c, d, i[ 4] + 0xf57c0faf,  7);
666     MD5STEP(F1, d, a, b, c, i[ 5] + 0x4787c62a, 12);
667     MD5STEP(F1, c, d, a, b, i[ 6] + 0xa8304613, 17);
668     MD5STEP(F1, b, c, d, a, i[ 7] + 0xfd469501, 22);
669     MD5STEP(F1, a, b, c, d, i[ 8] + 0x698098d8,  7);
670     MD5STEP(F1, d, a, b, c, i[ 9] + 0x8b44f7af, 12);
671     MD5STEP(F1, c, d, a, b, i[10] + 0xffff5bb1, 17);
672     MD5STEP(F1, b, c, d, a, i[11] + 0x895cd7be, 22);
673     MD5STEP(F1, a, b, c, d, i[12] + 0x6b901122,  7);
674     MD5STEP(F1, d, a, b, c, i[13] + 0xfd987193, 12);
675     MD5STEP(F1, c, d, a, b, i[14] + 0xa679438e, 17);
676     MD5STEP(F1, b, c, d, a, i[15] + 0x49b40821, 22);
678     MD5STEP(F2, a, b, c, d, i[ 1] + 0xf61e2562,  5);
679     MD5STEP(F2, d, a, b, c, i[ 6] + 0xc040b340,  9);
680     MD5STEP(F2, c, d, a, b, i[11] + 0x265e5a51, 14);
681     MD5STEP(F2, b, c, d, a, i[ 0] + 0xe9b6c7aa, 20);
682     MD5STEP(F2, a, b, c, d, i[ 5] + 0xd62f105d,  5);
683     MD5STEP(F2, d, a, b, c, i[10] + 0x02441453,  9);
684     MD5STEP(F2, c, d, a, b, i[15] + 0xd8a1e681, 14);
685     MD5STEP(F2, b, c, d, a, i[ 4] + 0xe7d3fbc8, 20);
686     MD5STEP(F2, a, b, c, d, i[ 9] + 0x21e1cde6,  5);
687     MD5STEP(F2, d, a, b, c, i[14] + 0xc33707d6,  9);
688     MD5STEP(F2, c, d, a, b, i[ 3] + 0xf4d50d87, 14);
689     MD5STEP(F2, b, c, d, a, i[ 8] + 0x455a14ed, 20);
690     MD5STEP(F2, a, b, c, d, i[13] + 0xa9e3e905,  5);
691     MD5STEP(F2, d, a, b, c, i[ 2] + 0xfcefa3f8,  9);
692     MD5STEP(F2, c, d, a, b, i[ 7] + 0x676f02d9, 14);
693     MD5STEP(F2, b, c, d, a, i[12] + 0x8d2a4c8a, 20);
695     MD5STEP(F3, a, b, c, d, i[ 5] + 0xfffa3942,  4);
696     MD5STEP(F3, d, a, b, c, i[ 8] + 0x8771f681, 11);
697     MD5STEP(F3, c, d, a, b, i[11] + 0x6d9d6122, 16);
698     MD5STEP(F3, b, c, d, a, i[14] + 0xfde5380c, 23);
699     MD5STEP(F3, a, b, c, d, i[ 1] + 0xa4beea44,  4);
700     MD5STEP(F3, d, a, b, c, i[ 4] + 0x4bdecfa9, 11);
701     MD5STEP(F3, c, d, a, b, i[ 7] + 0xf6bb4b60, 16);
702     MD5STEP(F3, b, c, d, a, i[10] + 0xbebfbc70, 23);
703     MD5STEP(F3, a, b, c, d, i[13] + 0x289b7ec6,  4);
704     MD5STEP(F3, d, a, b, c, i[ 0] + 0xeaa127fa, 11);
705     MD5STEP(F3, c, d, a, b, i[ 3] + 0xd4ef3085, 16);
706     MD5STEP(F3, b, c, d, a, i[ 6] + 0x04881d05, 23);
707     MD5STEP(F3, a, b, c, d, i[ 9] + 0xd9d4d039,  4);
708     MD5STEP(F3, d, a, b, c, i[12] + 0xe6db99e5, 11);
709     MD5STEP(F3, c, d, a, b, i[15] + 0x1fa27cf8, 16);
710     MD5STEP(F3, b, c, d, a, i[ 2] + 0xc4ac5665, 23);
712     MD5STEP(F4, a, b, c, d, i[ 0] + 0xf4292244,  6);
713     MD5STEP(F4, d, a, b, c, i[ 7] + 0x432aff97, 10);
714     MD5STEP(F4, c, d, a, b, i[14] + 0xab9423a7, 15);
715     MD5STEP(F4, b, c, d, a, i[ 5] + 0xfc93a039, 21);
716     MD5STEP(F4, a, b, c, d, i[12] + 0x655b59c3,  6);
717     MD5STEP(F4, d, a, b, c, i[ 3] + 0x8f0ccc92, 10);
718     MD5STEP(F4, c, d, a, b, i[10] + 0xffeff47d, 15);
719     MD5STEP(F4, b, c, d, a, i[ 1] + 0x85845dd1, 21);
720     MD5STEP(F4, a, b, c, d, i[ 8] + 0x6fa87e4f,  6);
721     MD5STEP(F4, d, a, b, c, i[15] + 0xfe2ce6e0, 10);
722     MD5STEP(F4, c, d, a, b, i[ 6] + 0xa3014314, 15);
723     MD5STEP(F4, b, c, d, a, i[13] + 0x4e0811a1, 21);
724     MD5STEP(F4, a, b, c, d, i[ 4] + 0xf7537e82,  6);
725     MD5STEP(F4, d, a, b, c, i[11] + 0xbd3af235, 10);
726     MD5STEP(F4, c, d, a, b, i[ 2] + 0x2ad7d2bb, 15);
727     MD5STEP(F4, b, c, d, a, i[ 9] + 0xeb86d391, 21);
729     hashBuf[0] += a;
730     hashBuf[1] += b;
731     hashBuf[2] += c;
732     hashBuf[3] += d;
741 //########################################################################
742 //########################################################################
743 //### T H R E A D
744 //########################################################################
745 //########################################################################
751 #ifdef __WIN32__
754 static DWORD WINAPI WinThreadFunction(LPVOID context)
756     Thread *thread = (Thread *)context;
757     thread->execute();
758     return 0;
762 void Thread::start()
764     DWORD dwThreadId;
765     HANDLE hThread = CreateThread(NULL, 0, WinThreadFunction,
766                (LPVOID)this,  0,  &dwThreadId);
767     //Make sure the thread is started before 'this' is deallocated
768     while (!started)
769         sleep(10);
770     CloseHandle(hThread);
773 void Thread::sleep(unsigned long millis)
775     Sleep(millis);
778 #else /* UNIX */
781 void *PthreadThreadFunction(void *context)
783     Thread *thread = (Thread *)context;
784     thread->execute();
785     return NULL;
789 void Thread::start()
791     pthread_t thread;
793     int ret = pthread_create(&thread, NULL,
794             PthreadThreadFunction, (void *)this);
795     if (ret != 0)
796         printf("Thread::start: thread creation failed: %s\n", strerror(ret));
798     //Make sure the thread is started before 'this' is deallocated
799     while (!started)
800         sleep(10);
804 void Thread::sleep(unsigned long millis)
806     timespec requested;
807     requested.tv_sec = millis / 1000;
808     requested.tv_nsec = (millis % 1000 ) * 1000000L;
809     nanosleep(&requested, NULL);
812 #endif
821 //########################################################################
822 //########################################################################
823 //### S O C K E T
824 //########################################################################
825 //########################################################################
831 //#########################################################################
832 //# U T I L I T Y
833 //#########################################################################
835 static void mybzero(void *s, size_t n)
837     unsigned char *p = (unsigned char *)s;
838     while (n > 0)
839         {
840         *p++ = (unsigned char)0;
841         n--;
842         }
845 static void mybcopy(void *src, void *dest, size_t n)
847     unsigned char *p = (unsigned char *)dest;
848     unsigned char *q = (unsigned char *)src;
849     while (n > 0)
850         {
851         *p++ = *q++;
852         n--;
853         }
858 //#########################################################################
859 //# T C P    C O N N E C T I O N
860 //#########################################################################
862 TcpSocket::TcpSocket()
864     init();
868 TcpSocket::TcpSocket(const std::string &hostnameArg, int port)
870     init();
871     hostname  = hostnameArg;
872     portno    = port;
876 #ifdef HAVE_SSL
878 static void cryptoLockCallback(int mode, int type, const char *file, int line)
880     //printf("########### LOCK\n");
881     static int modes[CRYPTO_NUM_LOCKS]; /* = {0, 0, ... } */
882     const char *errstr = NULL;
884     int rw = mode & (CRYPTO_READ|CRYPTO_WRITE);
885     if (!((rw == CRYPTO_READ) || (rw == CRYPTO_WRITE)))
886         {
887         errstr = "invalid mode";
888         goto err;
889         }
891     if (type < 0 || type >= CRYPTO_NUM_LOCKS)
892         {
893         errstr = "type out of bounds";
894         goto err;
895         }
897     if (mode & CRYPTO_LOCK)
898         {
899         if (modes[type])
900             {
901             errstr = "already locked";
902             /* must not happen in a single-threaded program
903              * (would deadlock)
904              */
905             goto err;
906             }
908         modes[type] = rw;
909         }
910     else if (mode & CRYPTO_UNLOCK)
911         {
912         if (!modes[type])
913             {
914              errstr = "not locked";
915              goto err;
916              }
918         if (modes[type] != rw)
919             {
920             errstr = (rw == CRYPTO_READ) ?
921                   "CRYPTO_r_unlock on write lock" :
922                   "CRYPTO_w_unlock on read lock";
923             }
925         modes[type] = 0;
926         }
927     else
928         {
929         errstr = "invalid mode";
930         goto err;
931         }
933     err:
934     if (errstr)
935         {
936         /* we cannot use bio_err here */
937         fprintf(stderr, "openssl (lock_dbg_cb): %s (mode=%d, type=%d) at %s:%d\n",
938                 errstr, mode, type, file, line);
939         }
942 static unsigned long cryptoIdCallback()
944 #ifdef __WIN32__
945     unsigned long ret = (unsigned long) GetCurrentThreadId();
946 #else
947     unsigned long ret = (unsigned long) pthread_self();
948 #endif
949     return ret;
952 #endif
955 TcpSocket::TcpSocket(const TcpSocket &other)
957     init();
958     sock      = other.sock;
959     hostname  = other.hostname;
960     portno    = other.portno;
963 static bool tcp_socket_inited = false;
965 void TcpSocket::init()
967     if (!tcp_socket_inited)
968         {
969 #ifdef __WIN32__
970         WORD wVersionRequested = MAKEWORD( 2, 2 );
971         WSADATA wsaData;
972         WSAStartup( wVersionRequested, &wsaData );
973 #endif
974 #ifdef HAVE_SSL
975         if (libssl_is_present)
976         {
977         sslStream  = NULL;
978         sslContext = NULL;
979             CRYPTO_set_locking_callback(cryptoLockCallback);
980         CRYPTO_set_id_callback(cryptoIdCallback);
981         SSL_library_init();
982         SSL_load_error_strings();
983         }
984 #endif
985         tcp_socket_inited = true;
986         }
987     sock           = -1;
988     connected      = false;
989     hostname       = "";
990     portno         = -1;
991     sslEnabled     = false;
992     receiveTimeout = 0;
995 TcpSocket::~TcpSocket()
997     disconnect();
1000 bool TcpSocket::isConnected()
1002     if (!connected || sock < 0)
1003         return false;
1004     return true;
1007 bool TcpSocket::getHaveSSL()
1009 #ifdef HAVE_SSL
1010     if (libssl_is_present)
1011     {
1012         return true;
1013     } else {
1014         return false;
1015     }
1016 #else
1017     return false;
1018 #endif
1021 void TcpSocket::enableSSL(bool val)
1023     sslEnabled = val;
1026 bool TcpSocket::getEnableSSL()
1028     return sslEnabled;
1033 bool TcpSocket::connect(const std::string &hostnameArg, int portnoArg)
1035     hostname = hostnameArg;
1036     portno   = portnoArg;
1037     return connect();
1042 #ifdef HAVE_SSL
1043 /*
1044 static int password_cb(char *buf, int bufLen, int rwflag, void *userdata)
1046     char *password = "password";
1047     if (bufLen < (int)(strlen(password)+1))
1048         return 0;
1050     strcpy(buf,password);
1051     int ret = strlen(password);
1052     return ret;
1055 static void infoCallback(const SSL *ssl, int where, int ret)
1057     switch (where)
1058         {
1059         case SSL_CB_ALERT:
1060             {
1061             printf("## %d SSL ALERT: %s\n",  where, SSL_alert_desc_string_long(ret));
1062             break;
1063             }
1064         default:
1065             {
1066             printf("## %d SSL: %s\n",  where, SSL_state_string_long(ssl));
1067             break;
1068             }
1069         }
1071 */
1072 #endif
1075 bool TcpSocket::startTls()
1077 #ifndef HAVE_SSL
1078     fprintf(stderr,
1079             "SSL starttls() error:  client not compiled with SSL enabled\n");
1080     return false;
1081 #else /*HAVE_SSL*/
1082     if (!libssl_is_present)
1083     {
1084     fprintf(stderr,
1085             "SSL starttls() error:  the correct version of libssl was not found \n");
1086     return false;
1087     } else {
1088             
1089     sslStream  = NULL;
1090     sslContext = NULL;
1092     //SSL_METHOD *meth = SSLv23_method();
1093     //SSL_METHOD *meth = SSLv3_client_method();
1094     SSL_METHOD *meth = TLSv1_client_method();
1095     sslContext = SSL_CTX_new(meth);
1096     //SSL_CTX_set_info_callback(sslContext, infoCallback);
1098     /**
1099      * For now, let's accept all connections.  Ignore this
1100      * block of code     
1101      *       
1102     char *keyFile  = "client.pem";
1103     char *caList   = "root.pem";
1104     //#  Load our keys and certificates
1105     if (!(SSL_CTX_use_certificate_chain_file(sslContext, keyFile)))
1106         {
1107         fprintf(stderr, "Can't read certificate file\n");
1108         disconnect();
1109         return false;
1110         }
1112     SSL_CTX_set_default_passwd_cb(sslContext, password_cb);
1114     if (!(SSL_CTX_use_PrivateKey_file(sslContext, keyFile, SSL_FILETYPE_PEM)))
1115         {
1116         fprintf(stderr, "Can't read key file\n");
1117         disconnect();
1118         return false;
1119         }
1121     //## Load the CAs we trust
1122     if (!(SSL_CTX_load_verify_locations(sslContext, caList, 0)))
1123         {
1124         fprintf(stderr, "Can't read CA list\n");
1125         disconnect();
1126         return false;
1127         }
1128     */
1130     /* Connect the SSL socket */
1131     sslStream  = SSL_new(sslContext);
1132     SSL_set_fd(sslStream, sock);
1134     int ret = SSL_connect(sslStream);
1135     if (ret == 0)
1136         {
1137         fprintf(stderr, "SSL connection not successful\n");
1138         disconnect();
1139         return false;
1140         }
1141     else if (ret < 0)
1142         {
1143         int err = SSL_get_error(sslStream, ret);
1144         fprintf(stderr, "SSL connect error %d\n", err);
1145         disconnect();
1146         return false;
1147         }
1149     sslEnabled = true;
1150     return true;
1151     }
1152 #endif /* HAVE_SSL */
1156 bool TcpSocket::connect()
1158     if (hostname.size()<1)
1159         {
1160         fprintf(stderr, "open: null hostname\n");
1161         return false;
1162         }
1164     if (portno<1)
1165         {
1166         fprintf(stderr, "open: bad port number\n");
1167         return false;
1168         }
1170     sock = socket(PF_INET, SOCK_STREAM, 0);
1171     if (sock < 0)
1172         {
1173         fprintf(stderr, "open: error creating socket\n");
1174         return false;
1175         }
1177     char *c_hostname = (char *)hostname.c_str();
1178     struct hostent *server = gethostbyname(c_hostname);
1179     if (!server)
1180         {
1181         fprintf(stderr, "open: could not locate host '%s'\n", c_hostname);
1182         return false;
1183         }
1185     struct sockaddr_in serv_addr;
1186     mybzero((char *) &serv_addr, sizeof(serv_addr));
1187     serv_addr.sin_family = AF_INET;
1188     mybcopy((char *)server->h_addr, (char *)&serv_addr.sin_addr.s_addr,
1189          server->h_length);
1190     serv_addr.sin_port = htons(portno);
1192     int ret = ::connect(sock, (const sockaddr *)&serv_addr, sizeof(serv_addr));
1193     if (ret < 0)
1194         {
1195         fprintf(stderr, "open: could not connect to host '%s'\n", c_hostname);
1196         return false;
1197         }
1199      if (sslEnabled)
1200         {
1201         if (!startTls())
1202             return false;
1203         }
1204     connected = true;
1205     return true;
1208 bool TcpSocket::disconnect()
1210     bool ret  = true;
1211     connected = false;
1212 #ifdef HAVE_SSL
1213     if (libssl_is_present)
1214     {
1215     if (sslEnabled)
1216         {
1217         if (sslStream)
1218             {
1219             int r = SSL_shutdown(sslStream);
1220             switch(r)
1221                 {
1222                 case 1:
1223                     break; /* Success */
1224                 case 0:
1225                 case -1:
1226                 default:
1227                     //printf("Shutdown failed");
1228                     ret = false;
1229                 }
1230             SSL_free(sslStream);
1231             }
1232         if (sslContext)
1233             SSL_CTX_free(sslContext);
1234         }
1235     sslStream  = NULL;
1236     sslContext = NULL;
1237     }
1238 #endif /*HAVE_SSL*/
1240 #ifdef __WIN32__
1241     closesocket(sock);
1242 #else
1243     ::close(sock);
1244 #endif
1245     sock = -1;
1246     sslEnabled = false;
1248     return ret;
1253 bool TcpSocket::setReceiveTimeout(unsigned long millis)
1255     receiveTimeout = millis;
1256     return true;
1259 /**
1260  * For normal sockets, return the number of bytes waiting to be received.
1261  * For SSL, just return >0 when something is ready to be read.
1262  */
1263 long TcpSocket::available()
1265     if (!isConnected())
1266         return -1;
1268     long count = 0;
1269 #ifdef __WIN32__
1270     if (ioctlsocket(sock, FIONREAD, (unsigned long *)&count) != 0)
1271         return -1;
1272 #else
1273     if (ioctl(sock, FIONREAD, &count) != 0)
1274         return -1;
1275 #endif
1276     if (count<=0 && sslEnabled)
1277         {
1278 #ifdef HAVE_SSL
1279         if (libssl_is_present)
1280         {
1281             return SSL_pending(sslStream);
1282         }
1283 #endif
1284         }
1285     return count;
1290 bool TcpSocket::write(int ch)
1292     if (!isConnected())
1293         {
1294         fprintf(stderr, "write: socket closed\n");
1295         return false;
1296         }
1297     unsigned char c = (unsigned char)ch;
1299     if (sslEnabled)
1300         {
1301 #ifdef HAVE_SSL
1302         if (libssl_is_present)
1303         {
1304         int r = SSL_write(sslStream, &c, 1);
1305         if (r<=0)
1306             {
1307             switch(SSL_get_error(sslStream, r))
1308                 {
1309                 default:
1310                     fprintf(stderr, "SSL write problem");
1311                     return -1;
1312                 }
1313             }
1314         }
1315 #endif
1316         }
1317     else
1318         {
1319         if (send(sock, (const char *)&c, 1, 0) < 0)
1320         //if (send(sock, &c, 1, 0) < 0)
1321             {
1322             fprintf(stderr, "write: could not send data\n");
1323             return false;
1324             }
1325         }
1326     return true;
1329 bool TcpSocket::write(char *str)
1331    if (!isConnected())
1332         {
1333         fprintf(stderr, "write(str): socket closed\n");
1334         return false;
1335         }
1336     int len = strlen(str);
1338     if (sslEnabled)
1339         {
1340 #ifdef HAVE_SSL
1341         if (libssl_is_present)
1342         {
1343         int r = SSL_write(sslStream, (unsigned char *)str, len);
1344         if (r<=0)
1345             {
1346             switch(SSL_get_error(sslStream, r))
1347                 {
1348                 default:
1349                     fprintf(stderr, "SSL write problem");
1350                     return -1;
1351                 }
1352             }
1353         }
1354 #endif
1355         }
1356     else
1357         {
1358         if (send(sock, str, len, 0) < 0)
1359         //if (send(sock, &c, 1, 0) < 0)
1360             {
1361             fprintf(stderr, "write: could not send data\n");
1362             return false;
1363             }
1364         }
1365     return true;
1368 bool TcpSocket::write(const std::string &str)
1370     return write((char *)str.c_str());
1373 int TcpSocket::read()
1375     if (!isConnected())
1376         return -1;
1378     //We'll use this loop for timeouts, so that SSL and plain sockets
1379     //will behave the same way
1380     if (receiveTimeout > 0)
1381         {
1382         unsigned long tim = 0;
1383         while (true)
1384             {
1385             int avail = available();
1386             if (avail > 0)
1387                 break;
1388             if (tim >= receiveTimeout)
1389                 return -2;
1390             Thread::sleep(20);
1391             tim += 20;
1392             }
1393         }
1395     //check again
1396     if (!isConnected())
1397         return -1;
1399     unsigned char ch;
1400     if (sslEnabled)
1401         {
1402 #ifdef HAVE_SSL
1403         if (libssl_is_present)
1404         {
1405         if (!sslStream)
1406             return -1;
1407         int r = SSL_read(sslStream, &ch, 1);
1408         unsigned long err = SSL_get_error(sslStream, r);
1409         switch (err)
1410             {
1411             case SSL_ERROR_NONE:
1412                  break;
1413             case SSL_ERROR_ZERO_RETURN:
1414                 return -1;
1415             case SSL_ERROR_SYSCALL:
1416                 fprintf(stderr, "SSL read problem(syscall) %s\n",
1417                      ERR_error_string(ERR_get_error(), NULL));
1418                 return -1;
1419             default:
1420                 fprintf(stderr, "SSL read problem %s\n",
1421                      ERR_error_string(ERR_get_error(), NULL));
1422                 return -1;
1423             }
1424         }
1425 #endif
1426         }
1427     else
1428         {
1429         if (recv(sock, (char *)&ch, 1, 0) <= 0)
1430             {
1431             fprintf(stderr, "read: could not receive data\n");
1432             disconnect();
1433             return -1;
1434             }
1435         }
1436     return (int)ch;
1439 std::string TcpSocket::readLine()
1441     std::string ret;
1443     while (isConnected())
1444         {
1445         int ch = read();
1446         if (ch<0)
1447             return ret;
1448         if (ch=='\r' || ch=='\n')
1449             return ret;
1450         ret.push_back((char)ch);
1451         }
1453     return ret;
1464 } //namespace Pedro
1465 //########################################################################
1466 //# E N D    O F     F I L E
1467 //########################################################################