Code

6d988c719a7844a109e1e6033d3c21ad8d0f6af8
[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 std::string &hostnameArg, int port)
885     init();
886     hostname  = hostnameArg;
887     portno    = port;
891 #ifdef HAVE_SSL
893 static void cryptoLockCallback(int mode, int type, const char *file, int line)
895     //printf("########### LOCK\n");
896     static int modes[CRYPTO_NUM_LOCKS]; /* = {0, 0, ... } */
897     const char *errstr = NULL;
899     int rw = mode & (CRYPTO_READ|CRYPTO_WRITE);
900     if (!((rw == CRYPTO_READ) || (rw == CRYPTO_WRITE)))
901         {
902         errstr = "invalid mode";
903         goto err;
904         }
906     if (type < 0 || type >= CRYPTO_NUM_LOCKS)
907         {
908         errstr = "type out of bounds";
909         goto err;
910         }
912     if (mode & CRYPTO_LOCK)
913         {
914         if (modes[type])
915             {
916             errstr = "already locked";
917             /* must not happen in a single-threaded program
918              * (would deadlock)
919              */
920             goto err;
921             }
923         modes[type] = rw;
924         }
925     else if (mode & CRYPTO_UNLOCK)
926         {
927         if (!modes[type])
928             {
929              errstr = "not locked";
930              goto err;
931              }
933         if (modes[type] != rw)
934             {
935             errstr = (rw == CRYPTO_READ) ?
936                   "CRYPTO_r_unlock on write lock" :
937                   "CRYPTO_w_unlock on read lock";
938             }
940         modes[type] = 0;
941         }
942     else
943         {
944         errstr = "invalid mode";
945         goto err;
946         }
948     err:
949     if (errstr)
950         {
951         /* we cannot use bio_err here */
952         fprintf(stderr, "openssl (lock_dbg_cb): %s (mode=%d, type=%d) at %s:%d\n",
953                 errstr, mode, type, file, line);
954         }
957 static unsigned long cryptoIdCallback()
959 #ifdef __WIN32__
960     unsigned long ret = (unsigned long) GetCurrentThreadId();
961 #else
962     unsigned long ret = (unsigned long) pthread_self();
963 #endif
964     return ret;
967 #endif
970 TcpSocket::TcpSocket(const TcpSocket &other)
972     init();
973     sock      = other.sock;
974     hostname  = other.hostname;
975     portno    = other.portno;
978 static bool tcp_socket_inited = false;
980 void TcpSocket::init()
982     if (!tcp_socket_inited)
983         {
984 #ifdef __WIN32__
985         WORD wVersionRequested = MAKEWORD( 2, 2 );
986         WSADATA wsaData;
987         WSAStartup( wVersionRequested, &wsaData );
988 #endif
989 #ifdef HAVE_SSL
990         sslStream  = NULL;
991         sslContext = NULL;
992             CRYPTO_set_locking_callback(cryptoLockCallback);
993         CRYPTO_set_id_callback(cryptoIdCallback);
994         SSL_library_init();
995         SSL_load_error_strings();
996 #endif
997         tcp_socket_inited = true;
998         }
999     sock           = -1;
1000     connected      = false;
1001     hostname       = "";
1002     portno         = -1;
1003     sslEnabled     = false;
1004     receiveTimeout = 0;
1007 TcpSocket::~TcpSocket()
1009     disconnect();
1012 bool TcpSocket::isConnected()
1014     if (!connected || sock < 0)
1015         return false;
1016     return true;
1019 bool TcpSocket::getHaveSSL()
1021 #ifdef HAVE_SSL
1022     return true;
1023 #else
1024     return false;
1025 #endif
1028 void TcpSocket::enableSSL(bool val)
1030     sslEnabled = val;
1033 bool TcpSocket::getEnableSSL()
1035     return sslEnabled;
1040 bool TcpSocket::connect(const std::string &hostnameArg, int portnoArg)
1042     hostname = hostnameArg;
1043     portno   = portnoArg;
1044     return connect();
1049 #ifdef HAVE_SSL
1050 /*
1051 static int password_cb(char *buf, int bufLen, int rwflag, void *userdata)
1053     char *password = "password";
1054     if (bufLen < (int)(strlen(password)+1))
1055         return 0;
1057     strcpy(buf,password);
1058     int ret = strlen(password);
1059     return ret;
1062 static void infoCallback(const SSL *ssl, int where, int ret)
1064     switch (where)
1065         {
1066         case SSL_CB_ALERT:
1067             {
1068             printf("## %d SSL ALERT: %s\n",  where, SSL_alert_desc_string_long(ret));
1069             break;
1070             }
1071         default:
1072             {
1073             printf("## %d SSL: %s\n",  where, SSL_state_string_long(ssl));
1074             break;
1075             }
1076         }
1078 */
1079 #endif
1082 bool TcpSocket::startTls()
1084 #ifndef HAVE_SSL
1085     fprintf(stderr,
1086             "SSL starttls() error:  client not compiled with SSL enabled\n");
1087     return false;
1088 #endif /*HAVE_SSL*/
1090     sslStream  = NULL;
1091     sslContext = NULL;
1093     //SSL_METHOD *meth = SSLv23_method();
1094     //SSL_METHOD *meth = SSLv3_client_method();
1095     SSL_METHOD *meth = TLSv1_client_method();
1096     sslContext = SSL_CTX_new(meth);
1097     //SSL_CTX_set_info_callback(sslContext, infoCallback);
1099     /**
1100      * For now, let's accept all connections.  Ignore this
1101      * block of code     
1102      *       
1103     char *keyFile  = "client.pem";
1104     char *caList   = "root.pem";
1105     //#  Load our keys and certificates
1106     if (!(SSL_CTX_use_certificate_chain_file(sslContext, keyFile)))
1107         {
1108         fprintf(stderr, "Can't read certificate file\n");
1109         disconnect();
1110         return false;
1111         }
1113     SSL_CTX_set_default_passwd_cb(sslContext, password_cb);
1115     if (!(SSL_CTX_use_PrivateKey_file(sslContext, keyFile, SSL_FILETYPE_PEM)))
1116         {
1117         fprintf(stderr, "Can't read key file\n");
1118         disconnect();
1119         return false;
1120         }
1122     //## Load the CAs we trust
1123     if (!(SSL_CTX_load_verify_locations(sslContext, caList, 0)))
1124         {
1125         fprintf(stderr, "Can't read CA list\n");
1126         disconnect();
1127         return false;
1128         }
1129     */
1131     /* Connect the SSL socket */
1132     sslStream  = SSL_new(sslContext);
1133     SSL_set_fd(sslStream, sock);
1135     int ret = SSL_connect(sslStream);
1136     if (ret == 0)
1137         {
1138         fprintf(stderr, "SSL connection not successful\n");
1139         disconnect();
1140         return false;
1141         }
1142     else if (ret < 0)
1143         {
1144         int err = SSL_get_error(sslStream, ret);
1145         fprintf(stderr, "SSL connect error %d\n", err);
1146         disconnect();
1147         return false;
1148         }
1150     sslEnabled = true;
1151     return true;
1155 bool TcpSocket::connect()
1157     if (hostname.size()<1)
1158         {
1159         fprintf(stderr, "open: null hostname\n");
1160         return false;
1161         }
1163     if (portno<1)
1164         {
1165         fprintf(stderr, "open: bad port number\n");
1166         return false;
1167         }
1169     sock = socket(PF_INET, SOCK_STREAM, 0);
1170     if (sock < 0)
1171         {
1172         fprintf(stderr, "open: error creating socket\n");
1173         return false;
1174         }
1176     char *c_hostname = (char *)hostname.c_str();
1177     struct hostent *server = gethostbyname(c_hostname);
1178     if (!server)
1179         {
1180         fprintf(stderr, "open: could not locate host '%s'\n", c_hostname);
1181         return false;
1182         }
1184     struct sockaddr_in serv_addr;
1185     mybzero((char *) &serv_addr, sizeof(serv_addr));
1186     serv_addr.sin_family = AF_INET;
1187     mybcopy((char *)server->h_addr, (char *)&serv_addr.sin_addr.s_addr,
1188          server->h_length);
1189     serv_addr.sin_port = htons(portno);
1191     int ret = ::connect(sock, (const sockaddr *)&serv_addr, sizeof(serv_addr));
1192     if (ret < 0)
1193         {
1194         fprintf(stderr, "open: could not connect to host '%s'\n", c_hostname);
1195         return false;
1196         }
1198      if (sslEnabled)
1199         {
1200         if (!startTls())
1201             return false;
1202         }
1203     connected = true;
1204     return true;
1207 bool TcpSocket::disconnect()
1209     bool ret  = true;
1210     connected = false;
1211 #ifdef HAVE_SSL
1212     if (sslEnabled)
1213         {
1214         if (sslStream)
1215             {
1216             int r = SSL_shutdown(sslStream);
1217             switch(r)
1218                 {
1219                 case 1:
1220                     break; /* Success */
1221                 case 0:
1222                 case -1:
1223                 default:
1224                     //printf("Shutdown failed");
1225                     ret = false;
1226                 }
1227             SSL_free(sslStream);
1228             }
1229         if (sslContext)
1230             SSL_CTX_free(sslContext);
1231         }
1232     sslStream  = NULL;
1233     sslContext = NULL;
1234 #endif /*HAVE_SSL*/
1236 #ifdef __WIN32__
1237     closesocket(sock);
1238 #else
1239     ::close(sock);
1240 #endif
1241     sock = -1;
1242     sslEnabled = false;
1244     return ret;
1249 bool TcpSocket::setReceiveTimeout(unsigned long millis)
1251     receiveTimeout = millis;
1252     return true;
1255 /**
1256  * For normal sockets, return the number of bytes waiting to be received.
1257  * For SSL, just return >0 when something is ready to be read.
1258  */
1259 long TcpSocket::available()
1261     if (!isConnected())
1262         return -1;
1264     long count = 0;
1265 #ifdef __WIN32__
1266     if (ioctlsocket(sock, FIONREAD, (unsigned long *)&count) != 0)
1267         return -1;
1268 #else
1269     if (ioctl(sock, FIONREAD, &count) != 0)
1270         return -1;
1271 #endif
1272     if (count<=0 && sslEnabled)
1273         {
1274 #ifdef HAVE_SSL
1275         return SSL_pending(sslStream);
1276 #endif
1277         }
1278     return count;
1283 bool TcpSocket::write(int ch)
1285     if (!isConnected())
1286         {
1287         fprintf(stderr, "write: socket closed\n");
1288         return false;
1289         }
1290     unsigned char c = (unsigned char)ch;
1292     if (sslEnabled)
1293         {
1294 #ifdef HAVE_SSL
1295         int r = SSL_write(sslStream, &c, 1);
1296         if (r<=0)
1297             {
1298             switch(SSL_get_error(sslStream, r))
1299                 {
1300                 default:
1301                     fprintf(stderr, "SSL write problem");
1302                     return -1;
1303                 }
1304             }
1305 #endif
1306         }
1307     else
1308         {
1309         if (send(sock, (const char *)&c, 1, 0) < 0)
1310         //if (send(sock, &c, 1, 0) < 0)
1311             {
1312             fprintf(stderr, "write: could not send data\n");
1313             return false;
1314             }
1315         }
1316     return true;
1319 bool TcpSocket::write(char *str)
1321    if (!isConnected())
1322         {
1323         fprintf(stderr, "write(str): socket closed\n");
1324         return false;
1325         }
1326     int len = strlen(str);
1328     if (sslEnabled)
1329         {
1330 #ifdef HAVE_SSL
1331         int r = SSL_write(sslStream, (unsigned char *)str, len);
1332         if (r<=0)
1333             {
1334             switch(SSL_get_error(sslStream, r))
1335                 {
1336                 default:
1337                     fprintf(stderr, "SSL write problem");
1338                     return -1;
1339                 }
1340             }
1341 #endif
1342         }
1343     else
1344         {
1345         if (send(sock, str, len, 0) < 0)
1346         //if (send(sock, &c, 1, 0) < 0)
1347             {
1348             fprintf(stderr, "write: could not send data\n");
1349             return false;
1350             }
1351         }
1352     return true;
1355 bool TcpSocket::write(const std::string &str)
1357     return write((char *)str.c_str());
1360 int TcpSocket::read()
1362     if (!isConnected())
1363         return -1;
1365     //We'll use this loop for timeouts, so that SSL and plain sockets
1366     //will behave the same way
1367     if (receiveTimeout > 0)
1368         {
1369         unsigned long tim = 0;
1370         while (true)
1371             {
1372             int avail = available();
1373             if (avail > 0)
1374                 break;
1375             if (tim >= receiveTimeout)
1376                 return -2;
1377             Thread::sleep(20);
1378             tim += 20;
1379             }
1380         }
1382     //check again
1383     if (!isConnected())
1384         return -1;
1386     unsigned char ch;
1387     if (sslEnabled)
1388         {
1389 #ifdef HAVE_SSL
1390         if (!sslStream)
1391             return -1;
1392         int r = SSL_read(sslStream, &ch, 1);
1393         unsigned long err = SSL_get_error(sslStream, r);
1394         switch (err)
1395             {
1396             case SSL_ERROR_NONE:
1397                  break;
1398             case SSL_ERROR_ZERO_RETURN:
1399                 return -1;
1400             case SSL_ERROR_SYSCALL:
1401                 fprintf(stderr, "SSL read problem(syscall) %s\n",
1402                      ERR_error_string(ERR_get_error(), NULL));
1403                 return -1;
1404             default:
1405                 fprintf(stderr, "SSL read problem %s\n",
1406                      ERR_error_string(ERR_get_error(), NULL));
1407                 return -1;
1408             }
1409 #endif
1410         }
1411     else
1412         {
1413         if (recv(sock, (char *)&ch, 1, 0) <= 0)
1414             {
1415             fprintf(stderr, "read: could not receive data\n");
1416             disconnect();
1417             return -1;
1418             }
1419         }
1420     return (int)ch;
1423 std::string TcpSocket::readLine()
1425     std::string ret;
1427     while (isConnected())
1428         {
1429         int ch = read();
1430         if (ch<0)
1431             return ret;
1432         if (ch=='\r' || ch=='\n')
1433             return ret;
1434         ret.push_back((char)ch);
1435         }
1437     return ret;
1448 } //namespace Pedro
1449 //########################################################################
1450 //# E N D    O F     F I L E
1451 //########################################################################