Code

split utils into separate file
[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-2006 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 */
53 namespace Pedro
54 {
60 //########################################################################
61 //########################################################################
62 //# B A S E    6 4
63 //########################################################################
64 //########################################################################
67 //#################
68 //# ENCODER
69 //#################
72 static char *base64encode =
73     "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
77 /**
78  * Writes the specified byte to the output buffer
79  */
80 void Base64Encoder::append(int ch)
81 {
82     outBuf   <<=  8;
83     outBuf   |=  (ch & 0xff);
84     bitCount +=  8;
85     if (bitCount >= 24)
86         {
87         int indx  = (int)((outBuf & 0x00fc0000L) >> 18);
88         int obyte = (int)base64encode[indx & 63];
89         buf.push_back(obyte);
91         indx      = (int)((outBuf & 0x0003f000L) >> 12);
92         obyte     = (int)base64encode[indx & 63];
93         buf.push_back(obyte);
95         indx      = (int)((outBuf & 0x00000fc0L) >>  6);
96         obyte     = (int)base64encode[indx & 63];
97         buf.push_back(obyte);
99         indx      = (int)((outBuf & 0x0000003fL)      );
100         obyte     = (int)base64encode[indx & 63];
101         buf.push_back(obyte);
103         bitCount = 0;
104         outBuf   = 0L;
105         }
108 /**
109  * Writes the specified string to the output buffer
110  */
111 void Base64Encoder::append(char *str)
113     while (*str)
114         append((int)*str++);
117 /**
118  * Writes the specified string to the output buffer
119  */
120 void Base64Encoder::append(unsigned char *str, int len)
122     while (len>0)
123         {
124         append((int)*str++);
125         len--;
126         }
129 /**
130  * Writes the specified string to the output buffer
131  */
132 void Base64Encoder::append(const DOMString &str)
134     append((char *)str.c_str());
137 /**
138  * Closes this output stream and releases any system resources
139  * associated with this stream.
140  */
141 DOMString Base64Encoder::finish()
143     //get any last bytes (1 or 2) out of the buffer
144     if (bitCount == 16)
145         {
146         outBuf <<= 2;  //pad to make 18 bits
148         int indx  = (int)((outBuf & 0x0003f000L) >> 12);
149         int obyte = (int)base64encode[indx & 63];
150         buf.push_back(obyte);
152         indx      = (int)((outBuf & 0x00000fc0L) >>  6);
153         obyte     = (int)base64encode[indx & 63];
154         buf.push_back(obyte);
156         indx      = (int)((outBuf & 0x0000003fL)      );
157         obyte     = (int)base64encode[indx & 63];
158         buf.push_back(obyte);
160         buf.push_back('=');
161         }
162     else if (bitCount == 8)
163         {
164         outBuf <<= 4; //pad to make 12 bits
166         int indx  = (int)((outBuf & 0x00000fc0L) >>  6);
167         int obyte = (int)base64encode[indx & 63];
168         buf.push_back(obyte);
170         indx      = (int)((outBuf & 0x0000003fL)      );
171         obyte     = (int)base64encode[indx & 63];
172         buf.push_back(obyte);
174         buf.push_back('=');
175         buf.push_back('=');
176         }
178     DOMString ret = buf;
179     reset();
180     return ret;
184 DOMString Base64Encoder::encode(const DOMString &str)
186     Base64Encoder encoder;
187     encoder.append(str);
188     DOMString ret = encoder.finish();
189     return ret;
194 //#################
195 //# DECODER
196 //#################
198 static int base64decode[] =
200 /*00*/    -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
201 /*08*/    -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
202 /*10*/    -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
203 /*18*/    -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
204 /*20*/    -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
205 /*28*/    -1,   -1,   -1,   62,   -1,   -1,   -1,   63,
206 /*30*/    52,   53,   54,   55,   56,   57,   58,   59,
207 /*38*/    60,   61,   -1,   -1,   -1,   -1,   -1,   -1,
208 /*40*/    -1,    0,    1,    2,    3,    4,    5,    6,
209 /*48*/     7,    8,    9,   10,   11,   12,   13,   14,
210 /*50*/    15,   16,   17,   18,   19,   20,   21,   22,
211 /*58*/    23,   24,   25,   -1,   -1,   -1,   -1,   -1,
212 /*60*/    -1,   26,   27,   28,   29,   30,   31,   32,
213 /*68*/    33,   34,   35,   36,   37,   38,   39,   40,
214 /*70*/    41,   42,   43,   44,   45,   46,   47,   48,
215 /*78*/    49,   50,   51,   -1,   -1,   -1,   -1,   -1
216 };
220 /**
221  * Appends one char to the decoder
222  */
223 void Base64Decoder::append(int ch)
225     if (isspace(ch))
226         return;
227     else if (ch == '=') //padding
228         {
229         inBytes[inCount++] = 0;
230         }
231     else
232         {
233         int byteVal = base64decode[ch & 0x7f];
234         //printf("char:%c %d\n", ch, byteVal);
235         if (byteVal < 0)
236             {
237             //Bad lookup value
238             }
239         inBytes[inCount++] = byteVal;
240         }
242     if (inCount >=4 )
243         {
244         unsigned char b0 = ((inBytes[0]<<2) & 0xfc) | ((inBytes[1]>>4) & 0x03);
245         unsigned char b1 = ((inBytes[1]<<4) & 0xf0) | ((inBytes[2]>>2) & 0x0f);
246         unsigned char b2 = ((inBytes[2]<<6) & 0xc0) | ((inBytes[3]   ) & 0x3f);
247         buf.push_back(b0);
248         buf.push_back(b1);
249         buf.push_back(b2);
250         inCount = 0;
251         }
255 void Base64Decoder::append(char *str)
257     while (*str)
258         append((int)*str++);
261 void Base64Decoder::append(const DOMString &str)
263     append((char *)str.c_str());
266 std::vector<unsigned char> Base64Decoder::finish()
268     std::vector<unsigned char> ret = buf;
269     reset();
270     return ret;
273 std::vector<unsigned char> Base64Decoder::decode(const DOMString &str)
275     Base64Decoder decoder;
276     decoder.append(str);
277     std::vector<unsigned char> ret = decoder.finish();
278     return ret;
281 DOMString Base64Decoder::decodeToString(const DOMString &str)
283     Base64Decoder decoder;
284     decoder.append(str);
285     std::vector<unsigned char> ret = decoder.finish();
286     DOMString buf;
287     for (unsigned int i=0 ; i<ret.size() ; i++)
288         buf.push_back(ret[i]);
289     return buf;
298 //########################################################################
299 //########################################################################
300 //### S H A    1      H A S H I N G
301 //########################################################################
302 //########################################################################
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 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 void Sha1::init()
334     lenW   = 0;
335     sizeHi = 0;
336     sizeLo = 0;
338     // Initialize H with the magic constants (see FIPS180 for constants)
339     H[0] = 0x67452301L;
340     H[1] = 0xefcdab89L;
341     H[2] = 0x98badcfeL;
342     H[3] = 0x10325476L;
343     H[4] = 0xc3d2e1f0L;
345     for (int i = 0; i < 80; i++)
346         W[i] = 0;
350 void Sha1::append(unsigned char *dataIn, int len)
352     // Read the data into W and process blocks as they get full
353     for (int i = 0; i < len; i++)
354         {
355         W[lenW / 4] <<= 8;
356         W[lenW / 4] |= (unsigned long)dataIn[i];
357         if ((++lenW) % 64 == 0)
358             {
359             hashblock();
360             lenW = 0;
361             }
362         sizeLo += 8;
363         sizeHi += (sizeLo < 8);
364         }
368 void Sha1::finish(unsigned char hashout[20])
370     unsigned char pad0x80 = 0x80;
371     unsigned char pad0x00 = 0x00;
372     unsigned char padlen[8];
374     // Pad with a binary 1 (e.g. 0x80), then zeroes, then length
375     padlen[0] = (unsigned char)((sizeHi >> 24) & 255);
376     padlen[1] = (unsigned char)((sizeHi >> 16) & 255);
377     padlen[2] = (unsigned char)((sizeHi >>  8) & 255);
378     padlen[3] = (unsigned char)((sizeHi >>  0) & 255);
379     padlen[4] = (unsigned char)((sizeLo >> 24) & 255);
380     padlen[5] = (unsigned char)((sizeLo >> 16) & 255);
381     padlen[6] = (unsigned char)((sizeLo >>  8) & 255);
382     padlen[7] = (unsigned char)((sizeLo >>  0) & 255);
384     append(&pad0x80, 1);
386     while (lenW != 56)
387         append(&pad0x00, 1);
388     append(padlen, 8);
390     // Output hash
391     for (int i = 0; i < 20; i++)
392         {
393         hashout[i] = (unsigned char)(H[i / 4] >> 24);
394         H[i / 4] <<= 8;
395         }
397     // Re-initialize the context (also zeroizes contents)
398     init();
402 #define SHA_ROTL(X,n) ((((X) << (n)) | ((X) >> (32-(n)))) & 0xffffffffL)
404 void Sha1::hashblock()
407     for (int t = 16; t <= 79; t++)
408         W[t] = SHA_ROTL(W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16], 1);
410     unsigned long A = H[0];
411     unsigned long B = H[1];
412     unsigned long C = H[2];
413     unsigned long D = H[3];
414     unsigned long E = H[4];
416     unsigned long TEMP;
418     for (int t = 0; t <= 19; t++)
419         {
420         TEMP = (SHA_ROTL(A,5) + (((C^D)&B)^D) +
421                 E + W[t] + 0x5a827999L) & 0xffffffffL;
422         E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP;
423         }
424     for (int t = 20; t <= 39; t++)
425         {
426         TEMP = (SHA_ROTL(A,5) + (B^C^D) +
427                 E + W[t] + 0x6ed9eba1L) & 0xffffffffL;
428         E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP;
429         }
430     for (int t = 40; t <= 59; t++)
431         {
432         TEMP = (SHA_ROTL(A,5) + ((B&C)|(D&(B|C))) +
433                 E + W[t] + 0x8f1bbcdcL) & 0xffffffffL;
434         E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP;
435         }
436     for (int t = 60; t <= 79; t++)
437         {
438         TEMP = (SHA_ROTL(A,5) + (B^C^D) +
439                 E + W[t] + 0xca62c1d6L) & 0xffffffffL;
440         E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP;
441         }
443     H[0] += A;
444     H[1] += B;
445     H[2] += C;
446     H[3] += D;
447     H[4] += E;
455 //########################################################################
456 //########################################################################
457 //### M D 5      H A S H I N G
458 //########################################################################
459 //########################################################################
465 void Md5::hash(unsigned char *dataIn, unsigned long len, unsigned char *digest)
467     Md5 md5;
468     md5.append(dataIn, len);
469     md5.finish(digest);
472 DOMString Md5::hashHex(unsigned char *dataIn, unsigned long len)
474     Md5 md5;
475     md5.append(dataIn, len);
476     DOMString ret = md5.finishHex();
477     return ret;
482 /*
483  * Note: this code is harmless on little-endian machines.
484  */
485 /*
486 static void byteReverse(unsigned char *buf, unsigned long longs)
488     do
489         {
490         unsigned long t = (unsigned long)
491             ((unsigned) buf[3] << 8 | buf[2]) << 16 |
492             ((unsigned) buf[1] << 8 | buf[0]);
493         *(unsigned long *) buf = t;
494         buf += 4;
495         } while (--longs);
497 */
499 static void md5_memcpy(void *dest, void *src, int n)
501     unsigned char *s1 = (unsigned char *)dest;
502     unsigned char *s2 = (unsigned char *)src;
503     while (n--)
504         *s1++ = *s2++;
507 static void md5_memset(void *dest, char v, int n)
509     unsigned char *s = (unsigned char *)dest;
510     while (n--)
511         *s++ = v;
514 /**
515  * Initialize MD5 polynomials and storage
516  */
517 void Md5::init()
519     buf[0]  = 0x67452301;
520     buf[1]  = 0xefcdab89;
521     buf[2]  = 0x98badcfe;
522     buf[3]  = 0x10325476;
524     bits[0] = 0;
525     bits[1] = 0;
528 /*
529  * Update context to reflect the concatenation of another buffer full
530  * of bytes.
531  */
532 void Md5::append(unsigned char *source, unsigned long len)
535     // Update bitcount
536     unsigned long t = bits[0];
537     if ((bits[0] = t + ((unsigned long) len << 3)) < t)
538             bits[1]++;// Carry from low to high
539     bits[1] += len >> 29;
541         //Bytes already in shsInfo->data
542     t = (t >> 3) & 0x3f;
545     // Handle any leading odd-sized chunks
546     if (t)
547         {
548         unsigned char *p = (unsigned char *) in + t;
549         t = 64 - t;
550         if (len < t)
551             {
552             md5_memcpy(p, source, len);
553             return;
554             }
555         md5_memcpy(p, source, t);
556         //byteReverse(in, 16);
557         transform(buf, (unsigned long *) in);
558         source += t;
559         len    -= t;
560         }
562     // Process data in 64-byte chunks
563     while (len >= 64)
564         {
565         md5_memcpy(in, source, 64);
566         //byteReverse(in, 16);
567         transform(buf, (unsigned long *) in);
568         source += 64;
569         len    -= 64;
570         }
572     // Handle any remaining bytes of data.
573     md5_memcpy(in, source, len);
576 /*
577  * Update context to reflect the concatenation of another string
578  */
579 void Md5::append(const DOMString &str)
581     append((unsigned char *)str.c_str(), str.size());
584 /*
585  * Final wrapup - pad to 64-byte boundary with the bit pattern
586  * 1 0* (64-bit count of bits processed, MSB-first)
587  */
588 void Md5::finish(unsigned char *digest)
590     // Compute number of bytes mod 64
591     unsigned int count = (bits[0] >> 3) & 0x3F;
593     // Set the first char of padding to 0x80.
594     // This is safe since there is always at least one byte free
595     unsigned char *p = in + count;
596     *p++ = 0x80;
598     // Bytes of padding needed to make 64 bytes
599     count = 64 - 1 - count;
601     // Pad out to 56 mod 64
602     if (count < 8)
603         {
604             // Two lots of padding:  Pad the first block to 64 bytes
605             md5_memset(p, 0, count);
606             //byteReverse(in, 16);
607             transform(buf, (unsigned long *) in);
609             // Now fill the next block with 56 bytes
610             md5_memset(in, 0, 56);
611         }
612     else
613         {
614         // Pad block to 56 bytes
615         md5_memset(p, 0, count - 8);
616         }
617     //byteReverse(in, 14);
619     // Append length in bits and transform
620     ((unsigned long *) in)[14] = bits[0];
621     ((unsigned long *) in)[15] = bits[1];
623     transform(buf, (unsigned long *) in);
624     //byteReverse((unsigned char *) buf, 4);
625     md5_memcpy(digest, buf, 16);
626     init();  // Security!  ;-)
629 static char *md5hex = "0123456789abcdef";
631 DOMString Md5::finishHex()
633     unsigned char hashout[16];
634     finish(hashout);
635     DOMString ret;
636     for (int i=0 ; i<16 ; i++)
637         {
638         unsigned char ch = hashout[i];
639         ret.push_back(md5hex[ (ch>>4) & 15 ]);
640         ret.push_back(md5hex[ ch      & 15 ]);
641         }
642     return ret;
647 //#  The four core functions - F1 is optimized somewhat
649 //  #define F1(x, y, z) (x & y | ~x & z)
650 #define F1(x, y, z) (z ^ (x & (y ^ z)))
651 #define F2(x, y, z) F1(z, x, y)
652 #define F3(x, y, z) (x ^ y ^ z)
653 #define F4(x, y, z) (y ^ (x | ~z))
655 // ## This is the central step in the MD5 algorithm.
656 #define MD5STEP(f, w, x, y, z, data, s) \
657         ( w += f(x, y, z) + data,  w = w<<s | w>>(32-s),  w += x )
659 /*
660  * The core of the MD5 algorithm, this alters an existing MD5 hash to
661  * reflect the addition of 16 longwords of new data.  MD5Update blocks
662  * the data and converts bytes into longwords for this routine.
663  * @parm buf points to an array of 4 unsigned longs
664  * @parm in points to an array of 16 unsigned longs
665  */
666 void Md5::transform(unsigned long *buf, unsigned long *in)
668     unsigned long a = buf[0];
669     unsigned long b = buf[1];
670     unsigned long c = buf[2];
671     unsigned long d = buf[3];
673     MD5STEP(F1, a, b, c, d, in[ 0] + 0xd76aa478,  7);
674     MD5STEP(F1, d, a, b, c, in[ 1] + 0xe8c7b756, 12);
675     MD5STEP(F1, c, d, a, b, in[ 2] + 0x242070db, 17);
676     MD5STEP(F1, b, c, d, a, in[ 3] + 0xc1bdceee, 22);
677     MD5STEP(F1, a, b, c, d, in[ 4] + 0xf57c0faf,  7);
678     MD5STEP(F1, d, a, b, c, in[ 5] + 0x4787c62a, 12);
679     MD5STEP(F1, c, d, a, b, in[ 6] + 0xa8304613, 17);
680     MD5STEP(F1, b, c, d, a, in[ 7] + 0xfd469501, 22);
681     MD5STEP(F1, a, b, c, d, in[ 8] + 0x698098d8,  7);
682     MD5STEP(F1, d, a, b, c, in[ 9] + 0x8b44f7af, 12);
683     MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
684     MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
685     MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122,  7);
686     MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
687     MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
688     MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
690     MD5STEP(F2, a, b, c, d, in[ 1] + 0xf61e2562,  5);
691     MD5STEP(F2, d, a, b, c, in[ 6] + 0xc040b340,  9);
692     MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
693     MD5STEP(F2, b, c, d, a, in[ 0] + 0xe9b6c7aa, 20);
694     MD5STEP(F2, a, b, c, d, in[ 5] + 0xd62f105d,  5);
695     MD5STEP(F2, d, a, b, c, in[10] + 0x02441453,  9);
696     MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
697     MD5STEP(F2, b, c, d, a, in[ 4] + 0xe7d3fbc8, 20);
698     MD5STEP(F2, a, b, c, d, in[ 9] + 0x21e1cde6,  5);
699     MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6,  9);
700     MD5STEP(F2, c, d, a, b, in[ 3] + 0xf4d50d87, 14);
701     MD5STEP(F2, b, c, d, a, in[ 8] + 0x455a14ed, 20);
702     MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905,  5);
703     MD5STEP(F2, d, a, b, c, in[ 2] + 0xfcefa3f8,  9);
704     MD5STEP(F2, c, d, a, b, in[ 7] + 0x676f02d9, 14);
705     MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
707     MD5STEP(F3, a, b, c, d, in[ 5] + 0xfffa3942,  4);
708     MD5STEP(F3, d, a, b, c, in[ 8] + 0x8771f681, 11);
709     MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
710     MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
711     MD5STEP(F3, a, b, c, d, in[ 1] + 0xa4beea44,  4);
712     MD5STEP(F3, d, a, b, c, in[ 4] + 0x4bdecfa9, 11);
713     MD5STEP(F3, c, d, a, b, in[ 7] + 0xf6bb4b60, 16);
714     MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
715     MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6,  4);
716     MD5STEP(F3, d, a, b, c, in[ 0] + 0xeaa127fa, 11);
717     MD5STEP(F3, c, d, a, b, in[ 3] + 0xd4ef3085, 16);
718     MD5STEP(F3, b, c, d, a, in[ 6] + 0x04881d05, 23);
719     MD5STEP(F3, a, b, c, d, in[ 9] + 0xd9d4d039,  4);
720     MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
721     MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
722     MD5STEP(F3, b, c, d, a, in[ 2] + 0xc4ac5665, 23);
724     MD5STEP(F4, a, b, c, d, in[ 0] + 0xf4292244,  6);
725     MD5STEP(F4, d, a, b, c, in[ 7] + 0x432aff97, 10);
726     MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
727     MD5STEP(F4, b, c, d, a, in[ 5] + 0xfc93a039, 21);
728     MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3,  6);
729     MD5STEP(F4, d, a, b, c, in[ 3] + 0x8f0ccc92, 10);
730     MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
731     MD5STEP(F4, b, c, d, a, in[ 1] + 0x85845dd1, 21);
732     MD5STEP(F4, a, b, c, d, in[ 8] + 0x6fa87e4f,  6);
733     MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
734     MD5STEP(F4, c, d, a, b, in[ 6] + 0xa3014314, 15);
735     MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
736     MD5STEP(F4, a, b, c, d, in[ 4] + 0xf7537e82,  6);
737     MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
738     MD5STEP(F4, c, d, a, b, in[ 2] + 0x2ad7d2bb, 15);
739     MD5STEP(F4, b, c, d, a, in[ 9] + 0xeb86d391, 21);
741     buf[0] += a;
742     buf[1] += b;
743     buf[2] += c;
744     buf[3] += d;
756 //########################################################################
757 //########################################################################
758 //### T H R E A D
759 //########################################################################
760 //########################################################################
766 #ifdef __WIN32__
769 static DWORD WINAPI WinThreadFunction(LPVOID context)
771     Thread *thread = (Thread *)context;
772     thread->execute();
773     return 0;
777 void Thread::start()
779     DWORD dwThreadId;
780     HANDLE hThread = CreateThread(NULL, 0, WinThreadFunction,
781                (LPVOID)this,  0,  &dwThreadId);
782     //Make sure the thread is started before 'this' is deallocated
783     while (!started)
784         sleep(10);
785     CloseHandle(hThread);
788 void Thread::sleep(unsigned long millis)
790     Sleep(millis);
793 #else /* UNIX */
796 void *PthreadThreadFunction(void *context)
798     Thread *thread = (Thread *)context;
799     thread->execute();
800     return NULL;
804 void Thread::start()
806     pthread_t thread;
808     int ret = pthread_create(&thread, NULL,
809             PthreadThreadFunction, (void *)this);
810     if (ret != 0)
811         printf("Thread::start: thread creation failed: %s\n", strerror(ret));
813     //Make sure the thread is started before 'this' is deallocated
814     while (!started)
815         sleep(10);
819 void Thread::sleep(unsigned long millis)
821     timespec requested;
822     requested.tv_sec = millis / 1000;
823     requested.tv_nsec = (millis % 1000 ) * 1000000L;
824     nanosleep(&requested, NULL);
827 #endif
836 //########################################################################
837 //########################################################################
838 //### S O C K E T
839 //########################################################################
840 //########################################################################
846 //#########################################################################
847 //# U T I L I T Y
848 //#########################################################################
850 static void mybzero(void *s, size_t n)
852     unsigned char *p = (unsigned char *)s;
853     while (n > 0)
854         {
855         *p++ = (unsigned char)0;
856         n--;
857         }
860 static void mybcopy(void *src, void *dest, size_t n)
862     unsigned char *p = (unsigned char *)dest;
863     unsigned char *q = (unsigned char *)src;
864     while (n > 0)
865         {
866         *p++ = *q++;
867         n--;
868         }
873 //#########################################################################
874 //# T C P    C O N N E C T I O N
875 //#########################################################################
877 TcpSocket::TcpSocket()
879     init();
883 TcpSocket::TcpSocket(const char *hostnameArg, int port)
885     init();
886     hostname  = hostnameArg;
887     portno    = port;
890 TcpSocket::TcpSocket(const std::string &hostnameArg, int port)
892     init();
893     hostname  = hostnameArg;
894     portno    = port;
898 #ifdef HAVE_SSL
900 static void cryptoLockCallback(int mode, int type, const char *file, int line)
902     //printf("########### LOCK\n");
903     static int modes[CRYPTO_NUM_LOCKS]; /* = {0, 0, ... } */
904     const char *errstr = NULL;
906     int rw = mode & (CRYPTO_READ|CRYPTO_WRITE);
907     if (!((rw == CRYPTO_READ) || (rw == CRYPTO_WRITE)))
908         {
909         errstr = "invalid mode";
910         goto err;
911         }
913     if (type < 0 || type >= CRYPTO_NUM_LOCKS)
914         {
915         errstr = "type out of bounds";
916         goto err;
917         }
919     if (mode & CRYPTO_LOCK)
920         {
921         if (modes[type])
922             {
923             errstr = "already locked";
924             /* must not happen in a single-threaded program
925              * (would deadlock)
926              */
927             goto err;
928             }
930         modes[type] = rw;
931         }
932     else if (mode & CRYPTO_UNLOCK)
933         {
934         if (!modes[type])
935             {
936              errstr = "not locked";
937              goto err;
938              }
940         if (modes[type] != rw)
941             {
942             errstr = (rw == CRYPTO_READ) ?
943                   "CRYPTO_r_unlock on write lock" :
944                   "CRYPTO_w_unlock on read lock";
945             }
947         modes[type] = 0;
948         }
949     else
950         {
951         errstr = "invalid mode";
952         goto err;
953         }
955     err:
956     if (errstr)
957         {
958         /* we cannot use bio_err here */
959         fprintf(stderr, "openssl (lock_dbg_cb): %s (mode=%d, type=%d) at %s:%d\n",
960                 errstr, mode, type, file, line);
961         }
964 static unsigned long cryptoIdCallback()
966 #ifdef __WIN32__
967     unsigned long ret = (unsigned long) GetCurrentThreadId();
968 #else
969     unsigned long ret = (unsigned long) pthread_self();
970 #endif
971     return ret;
974 #endif
977 TcpSocket::TcpSocket(const TcpSocket &other)
979     init();
980     sock      = other.sock;
981     hostname  = other.hostname;
982     portno    = other.portno;
985 static bool tcp_socket_inited = false;
987 void TcpSocket::init()
989     if (!tcp_socket_inited)
990         {
991 #ifdef __WIN32__
992         WORD wVersionRequested = MAKEWORD( 2, 2 );
993         WSADATA wsaData;
994         WSAStartup( wVersionRequested, &wsaData );
995 #endif
996 #ifdef HAVE_SSL
997         sslStream  = NULL;
998         sslContext = NULL;
999             CRYPTO_set_locking_callback(cryptoLockCallback);
1000         CRYPTO_set_id_callback(cryptoIdCallback);
1001         SSL_library_init();
1002         SSL_load_error_strings();
1003 #endif
1004         tcp_socket_inited = true;
1005         }
1006     sock           = -1;
1007     connected      = false;
1008     hostname       = "";
1009     portno         = -1;
1010     sslEnabled     = false;
1011     receiveTimeout = 0;
1014 TcpSocket::~TcpSocket()
1016     disconnect();
1019 bool TcpSocket::isConnected()
1021     if (!connected || sock < 0)
1022         return false;
1023     return true;
1026 void TcpSocket::enableSSL(bool val)
1028     sslEnabled = val;
1031 bool TcpSocket::getEnableSSL()
1033     return sslEnabled;
1037 bool TcpSocket::connect(const char *hostnameArg, int portnoArg)
1039     hostname = hostnameArg;
1040     portno   = portnoArg;
1041     return connect();
1044 bool TcpSocket::connect(const std::string &hostnameArg, int portnoArg)
1046     hostname = hostnameArg;
1047     portno   = portnoArg;
1048     return connect();
1053 #ifdef HAVE_SSL
1054 /*
1055 static int password_cb(char *buf, int bufLen, int rwflag, void *userdata)
1057     char *password = "password";
1058     if (bufLen < (int)(strlen(password)+1))
1059         return 0;
1061     strcpy(buf,password);
1062     int ret = strlen(password);
1063     return ret;
1066 static void infoCallback(const SSL *ssl, int where, int ret)
1068     switch (where)
1069         {
1070         case SSL_CB_ALERT:
1071             {
1072             printf("## %d SSL ALERT: %s\n",  where, SSL_alert_desc_string_long(ret));
1073             break;
1074             }
1075         default:
1076             {
1077             printf("## %d SSL: %s\n",  where, SSL_state_string_long(ssl));
1078             break;
1079             }
1080         }
1082 */
1083 #endif
1086 bool TcpSocket::startTls()
1088 #ifdef HAVE_SSL
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 #if 0
1099     char *keyFile  = "client.pem";
1100     char *caList   = "root.pem";
1101     /* Load our keys and certificates*/
1102     if (!(SSL_CTX_use_certificate_chain_file(sslContext, keyFile)))
1103         {
1104         fprintf(stderr, "Can't read certificate file\n");
1105         disconnect();
1106         return false;
1107         }
1109     SSL_CTX_set_default_passwd_cb(sslContext, password_cb);
1111     if (!(SSL_CTX_use_PrivateKey_file(sslContext, keyFile, SSL_FILETYPE_PEM)))
1112         {
1113         fprintf(stderr, "Can't read key file\n");
1114         disconnect();
1115         return false;
1116         }
1118     /* Load the CAs we trust*/
1119     if (!(SSL_CTX_load_verify_locations(sslContext, caList, 0)))
1120         {
1121         fprintf(stderr, "Can't read CA list\n");
1122         disconnect();
1123         return false;
1124         }
1125 #endif
1127     /* Connect the SSL socket */
1128     sslStream  = SSL_new(sslContext);
1129     SSL_set_fd(sslStream, sock);
1131     int ret = SSL_connect(sslStream);
1132     if (ret == 0)
1133         {
1134         fprintf(stderr, "SSL connection not successful\n");
1135         disconnect();
1136         return false;
1137         }
1138     else if (ret < 0)
1139         {
1140         int err = SSL_get_error(sslStream, ret);
1141         fprintf(stderr, "SSL connect error %d\n", err);
1142         disconnect();
1143         return false;
1144         }
1146     sslEnabled = true;
1147 #endif /*HAVE_SSL*/
1148     return true;
1152 bool TcpSocket::connect()
1154     if (hostname.size()<1)
1155         {
1156         fprintf(stderr, "open: null hostname\n");
1157         return false;
1158         }
1160     if (portno<1)
1161         {
1162         fprintf(stderr, "open: bad port number\n");
1163         return false;
1164         }
1166     sock = socket(PF_INET, SOCK_STREAM, 0);
1167     if (sock < 0)
1168         {
1169         fprintf(stderr, "open: error creating socket\n");
1170         return false;
1171         }
1173     char *c_hostname = (char *)hostname.c_str();
1174     struct hostent *server = gethostbyname(c_hostname);
1175     if (!server)
1176         {
1177         fprintf(stderr, "open: could not locate host '%s'\n", c_hostname);
1178         return false;
1179         }
1181     struct sockaddr_in serv_addr;
1182     mybzero((char *) &serv_addr, sizeof(serv_addr));
1183     serv_addr.sin_family = AF_INET;
1184     mybcopy((char *)server->h_addr, (char *)&serv_addr.sin_addr.s_addr,
1185          server->h_length);
1186     serv_addr.sin_port = htons(portno);
1188     int ret = ::connect(sock, (const sockaddr *)&serv_addr, sizeof(serv_addr));
1189     if (ret < 0)
1190         {
1191         fprintf(stderr, "open: could not connect to host '%s'\n", c_hostname);
1192         return false;
1193         }
1195      if (sslEnabled)
1196         {
1197         if (!startTls())
1198             return false;
1199         }
1200     connected = true;
1201     return true;
1204 bool TcpSocket::disconnect()
1206     bool ret  = true;
1207     connected = false;
1208 #ifdef HAVE_SSL
1209     if (sslEnabled)
1210         {
1211         if (sslStream)
1212             {
1213             int r = SSL_shutdown(sslStream);
1214             switch(r)
1215                 {
1216                 case 1:
1217                     break; /* Success */
1218                 case 0:
1219                 case -1:
1220                 default:
1221                     //printf("Shutdown failed");
1222                     ret = false;
1223                 }
1224             SSL_free(sslStream);
1225             }
1226         if (sslContext)
1227             SSL_CTX_free(sslContext);
1228         }
1229     sslStream  = NULL;
1230     sslContext = NULL;
1231 #endif /*HAVE_SSL*/
1233 #ifdef __WIN32__
1234     closesocket(sock);
1235 #else
1236     ::close(sock);
1237 #endif
1238     sock = -1;
1239     sslEnabled = false;
1241     return ret;
1246 bool TcpSocket::setReceiveTimeout(unsigned long millis)
1248     receiveTimeout = millis;
1249     return true;
1252 /**
1253  * For normal sockets, return the number of bytes waiting to be received.
1254  * For SSL, just return >0 when something is ready to be read.
1255  */
1256 long TcpSocket::available()
1258     if (!isConnected())
1259         return -1;
1261     long count = 0;
1262 #ifdef __WIN32__
1263     if (ioctlsocket(sock, FIONREAD, (unsigned long *)&count) != 0)
1264         return -1;
1265 #else
1266     if (ioctl(sock, FIONREAD, &count) != 0)
1267         return -1;
1268 #endif
1269     if (count<=0 && sslEnabled)
1270         {
1271 #ifdef HAVE_SSL
1272         return SSL_pending(sslStream);
1273 #endif
1274         }
1275     return count;
1280 bool TcpSocket::write(int ch)
1282     if (!isConnected())
1283         {
1284         fprintf(stderr, "write: socket closed\n");
1285         return false;
1286         }
1287     unsigned char c = (unsigned char)ch;
1289     if (sslEnabled)
1290         {
1291 #ifdef HAVE_SSL
1292         int r = SSL_write(sslStream, &c, 1);
1293         if (r<=0)
1294             {
1295             switch(SSL_get_error(sslStream, r))
1296                 {
1297                 default:
1298                     fprintf(stderr, "SSL write problem");
1299                     return -1;
1300                 }
1301             }
1302 #endif
1303         }
1304     else
1305         {
1306         if (send(sock, (const char *)&c, 1, 0) < 0)
1307         //if (send(sock, &c, 1, 0) < 0)
1308             {
1309             fprintf(stderr, "write: could not send data\n");
1310             return false;
1311             }
1312         }
1313     return true;
1316 bool TcpSocket::write(char *str)
1318    if (!isConnected())
1319         {
1320         fprintf(stderr, "write(str): socket closed\n");
1321         return false;
1322         }
1323     int len = strlen(str);
1325     if (sslEnabled)
1326         {
1327 #ifdef HAVE_SSL
1328         int r = SSL_write(sslStream, (unsigned char *)str, len);
1329         if (r<=0)
1330             {
1331             switch(SSL_get_error(sslStream, r))
1332                 {
1333                 default:
1334                     fprintf(stderr, "SSL write problem");
1335                     return -1;
1336                 }
1337             }
1338 #endif
1339         }
1340     else
1341         {
1342         if (send(sock, str, len, 0) < 0)
1343         //if (send(sock, &c, 1, 0) < 0)
1344             {
1345             fprintf(stderr, "write: could not send data\n");
1346             return false;
1347             }
1348         }
1349     return true;
1352 bool TcpSocket::write(const std::string &str)
1354     return write((char *)str.c_str());
1357 int TcpSocket::read()
1359     if (!isConnected())
1360         return -1;
1362     //We'll use this loop for timeouts, so that SSL and plain sockets
1363     //will behave the same way
1364     if (receiveTimeout > 0)
1365         {
1366         unsigned long tim = 0;
1367         while (true)
1368             {
1369             int avail = available();
1370             if (avail > 0)
1371                 break;
1372             if (tim >= receiveTimeout)
1373                 return -2;
1374             Thread::sleep(20);
1375             tim += 20;
1376             }
1377         }
1379     //check again
1380     if (!isConnected())
1381         return -1;
1383     unsigned char ch;
1384     if (sslEnabled)
1385         {
1386 #ifdef HAVE_SSL
1387         if (!sslStream)
1388             return -1;
1389         int r = SSL_read(sslStream, &ch, 1);
1390         unsigned long err = SSL_get_error(sslStream, r);
1391         switch (err)
1392             {
1393             case SSL_ERROR_NONE:
1394                  break;
1395             case SSL_ERROR_ZERO_RETURN:
1396                 return -1;
1397             case SSL_ERROR_SYSCALL:
1398                 fprintf(stderr, "SSL read problem(syscall) %s\n",
1399                      ERR_error_string(ERR_get_error(), NULL));
1400                 return -1;
1401             default:
1402                 fprintf(stderr, "SSL read problem %s\n",
1403                      ERR_error_string(ERR_get_error(), NULL));
1404                 return -1;
1405             }
1406 #endif
1407         }
1408     else
1409         {
1410         if (recv(sock, (char *)&ch, 1, 0) <= 0)
1411             {
1412             fprintf(stderr, "read: could not receive data\n");
1413             disconnect();
1414             return -1;
1415             }
1416         }
1417     return (int)ch;
1420 std::string TcpSocket::readLine()
1422     std::string ret;
1424     while (isConnected())
1425         {
1426         int ch = read();
1427         if (ch<0)
1428             return ret;
1429         if (ch=='\r' || ch=='\n')
1430             return ret;
1431         ret.push_back((char)ch);
1432         }
1434     return ret;
1445 } //namespace Pedro
1446 //########################################################################
1447 //# E N D    O F     F I L E
1448 //########################################################################