summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/compat/win32.cpp22
-rw-r--r--src/compat/win32.h2
-rw-r--r--src/md5.cpp323
-rw-r--r--src/md5.h17
-rw-r--r--src/plugger.cpp4
-rw-r--r--src/plugger.h107
-rw-r--r--src/tcpsocket.h1
-rw-r--r--src/tests/udpsocket.cpp86
-rw-r--r--src/udpsocket.cpp240
-rw-r--r--src/udpsocket.h81
-rw-r--r--src/unit/md5.unit82
11 files changed, 796 insertions, 169 deletions
diff --git a/src/compat/win32.cpp b/src/compat/win32.cpp
index 2a43ff9..b689322 100644
--- a/src/compat/win32.cpp
+++ b/src/compat/win32.cpp
@@ -162,5 +162,27 @@ int Bu::Winsock2::__WSAFDIsSet( SOCKET s, fd_set *set ) {
162 return (*Bu::Winsock2::_fnptr___WSAFDIsSet)( s, set ); 162 return (*Bu::Winsock2::_fnptr___WSAFDIsSet)( s, set );
163} 163}
164 164
165Bu::String Bu::getLastWinError()
166{
167 LPVOID lpMsgBuf;
168 DWORD dw = GetLastError();
169
170 FormatMessageA(
171 FORMAT_MESSAGE_ALLOCATE_BUFFER |
172 FORMAT_MESSAGE_FROM_SYSTEM |
173 FORMAT_MESSAGE_IGNORE_INSERTS,
174 NULL,
175 dw,
176 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
177 (LPSTR) &lpMsgBuf,
178 0, NULL );
179
180 Bu::String sRet( (char *)lpMsgBuf );
181
182 LocalFree(lpMsgBuf);
183
184 return sRet;
185}
186
165#endif 187#endif
166 188
diff --git a/src/compat/win32.h b/src/compat/win32.h
index 67d80d3..1d82fbe 100644
--- a/src/compat/win32.h
+++ b/src/compat/win32.h
@@ -89,6 +89,8 @@ namespace Bu
89 static char scode[15]; 89 static char scode[15];
90 static char *gai_strerror( int iCode ); 90 static char *gai_strerror( int iCode );
91 }; 91 };
92
93 Bu::String getLastWinError();
92}; 94};
93 95
94#ifdef FD_ISSET 96#ifdef FD_ISSET
diff --git a/src/md5.cpp b/src/md5.cpp
index f971f23..71f17a0 100644
--- a/src/md5.cpp
+++ b/src/md5.cpp
@@ -11,31 +11,11 @@
11#include "bu/md5.h" 11#include "bu/md5.h"
12#include "bu/stream.h" 12#include "bu/stream.h"
13 13
14 14#ifdef SYSTEM_BIG_ENDIAN
15// This performs a wrapping bitwise shift, kinda' fun! 15# define toLittleEndian( a, b ) _toLittleEndian( a, b )
16 16#else
17#define bit_roll( num, cnt ) \ 17# define toLittleEndian( a, b ) (void)0
18 (((num) << (cnt)) | (((num) >> (32 - (cnt))) & ~(-1<<(cnt)))) 18#endif
19
20//#define md5_cmn( q, a, b, x, s, t ) (bit_roll((a + q + x + t), s) + b)
21
22// The following are handy wrappers for the cmn function
23#define md5_ff( a, b, c, d, x, s, t ) \
24 (md5_cmn((b & c) | ((~b) & d), a, b, x, s, t))
25
26#define md5_gg( a, b, c, d, x, s, t ) \
27 (md5_cmn((b & d) | (c & (~d)), a, b, x, s, t))
28
29#define md5_hh( a, b, c, d, x, s, t ) \
30 (md5_cmn(b ^ c ^ d, a, b, x, s, t))
31
32#define md5_ii( a, b, c, d, x, s, t ) \
33 (md5_cmn(c ^ (b | (~d)), a, b, x, s, t))
34
35inline long md5_cmn( long q, long a, long b, long x, long s, long t )
36{
37 return bit_roll((a + q + x + t), s) + b;
38}
39 19
40Bu::Md5::Md5() 20Bu::Md5::Md5()
41{ 21{
@@ -50,14 +30,13 @@ void Bu::Md5::reset()
50{ 30{
51 // These are the magic seed numbers... 31 // These are the magic seed numbers...
52 32
53 sum[0] = 1732584193; 33 sum[0] = 0x67452301U;
54 sum[1] = -271733879; 34 sum[1] = 0xEFCDAB89U;
55 sum[2] = -1732584194; 35 sum[2] = 0x98BADCFEU;
56 sum[3] = 271733878; 36 sum[3] = 0x10325476U;
57 37
58 iBytes = 0; 38 uBits[0] = 0;
59 memset( inbuf, 0, 4*16 ); 39 uBits[1] = 0;
60 iFill = 0;
61} 40}
62 41
63void Bu::Md5::setSalt( const Bu::String & /*sSalt*/ ) 42void Bu::Md5::setSalt( const Bu::String & /*sSalt*/ )
@@ -67,137 +46,201 @@ void Bu::Md5::setSalt( const Bu::String & /*sSalt*/ )
67void Bu::Md5::addData( const void *sVData, int iSize ) 46void Bu::Md5::addData( const void *sVData, int iSize )
68{ 47{
69 const char *sData = (const char *)sVData; 48 const char *sData = (const char *)sVData;
49 uint32_t t;
50
51 t = uBits[0];
52 if( (uBits[0] = t + ((uint32_t)iSize << 3)) < t )
53 uBits[1]++;
54 uBits[1] += iSize >> 29;
70 55
71 int iInPos = 0; 56 t = (t >> 3) & 0x3f; /* How many bytes we have buffered */
72 for(;;) 57
58 /* Handle any leading odd-sized chunks */
59 if( t )
73 { 60 {
74 for( ; iFill < 16*4 && iInPos < iSize; iFill++, iInPos++ ) 61 unsigned char *p = (unsigned char *) inbuf + t;
75 { 62
76 inbuf[iFill>>2] |= ((long)sData[iInPos]) << ((iFill*8)%32); 63 t = 64 - t;
64 if( iSize < t ) {
65 memcpy( p, sData, iSize );
66 return;
77 } 67 }
78 if( iFill < 16*4 ) 68 memcpy( p, sData, t );
79 break; 69 toLittleEndian( inbuf, 16 );
80 compBlock( inbuf, sum ); 70 compBlock( sum, (uint32_t *)inbuf );
81 memset( inbuf, 0, 4*16 ); 71 sData += t;
82 iFill = 0; 72 iSize -= t;
83 } 73 }
84 iBytes += iSize; 74
75 /* Process data in 64-byte chunks */
76 while( iSize >= 64 )
77 {
78 memcpy( inbuf, sData, 64 );
79 toLittleEndian( inbuf, 16 );
80 compBlock( sum, (uint32_t *)inbuf );
81 sData += 64;
82 iSize -= 64;
83 }
84
85 /* Handle any remaining bytes of data. */
86 memcpy( inbuf, sData, iSize );
85} 87}
86 88
87Bu::String Bu::Md5::getResult() 89Bu::String Bu::Md5::getResult()
88{ 90{
89 long lsum[4]; 91 uint32_t lsum[4];
90 compCap( lsum ); 92 compCap( lsum );
91 return Bu::String( (const char *)lsum, 4*4 ); 93 return Bu::String( (const char *)lsum, 4*4 );
92} 94}
93 95
94void Bu::Md5::writeResult( Bu::Stream &sOut ) 96void Bu::Md5::writeResult( Bu::Stream &sOut )
95{ 97{
96 long lsum[4]; 98 uint32_t lsum[4];
97 compCap( lsum ); 99 compCap( lsum );
98 sOut.write( lsum, 4*4 ); 100 sOut.write( lsum, 4*4 );
99} 101}
100 102
101void Bu::Md5::compCap( long *sumout ) 103void Bu::Md5::compCap( uint32_t *sumout )
102{ 104{
105 uint8_t tmpbuf[64];
103 memcpy( sumout, sum, 4*4 ); 106 memcpy( sumout, sum, 4*4 );
104 long lbuf[16]; 107 memcpy( tmpbuf, inbuf, 64 );
105 memcpy( lbuf, inbuf, 4*16 ); 108
106 109 uint32_t count;
107 lbuf[iFill>>2] |= 0x80 << ((iFill*8)%32); 110 uint8_t *p;
108 uint64_t iBits = iBytes*8; 111
109 if( iBytes > 0 && iFill>>2 >= 14 ) 112 /* Compute number of bytes mod 64 */
110 { 113 count = (uBits[0] >> 3) & 0x3F;
111 compBlock( lbuf, sumout ); 114
112 memset( lbuf, 0, 4*16 ); 115 /* Set the first char of padding to 0x80. This is safe since there is
113 memcpy( lbuf+14, &iBits, 8 ); 116 always at least one byte free */
114 compBlock( lbuf, sumout ); 117 p = tmpbuf + count;
115 } 118 *p++ = 0x80;
116 else 119
117 { 120 /* Bytes of padding needed to make 64 bytes */
118 memcpy( lbuf+14, &iBits, 8 ); 121 count = 64 - 1 - count;
119 compBlock( lbuf, sumout ); 122
123 /* Pad out to 56 mod 64 */
124 if (count < 8) {
125 /* Two lots of padding: Pad the first block to 64 bytes */
126 memset( p, 0, count );
127 toLittleEndian( tmpbuf, 16 );
128 compBlock( sumout, (uint32_t *)tmpbuf );
129
130 /* Now fill the next block with 56 bytes */
131 memset( tmpbuf, 0, 56);
132 } else {
133 /* Pad block to 56 bytes */
134 memset( p, 0, count - 8);
120 } 135 }
136 toLittleEndian( tmpbuf, 14 );
137
138 /* Append length in bits and transform */
139 ((uint32_t *) tmpbuf)[14] = uBits[0];
140 ((uint32_t *) tmpbuf)[15] = uBits[1];
141
142 compBlock( sumout, (uint32_t *)tmpbuf );
143 toLittleEndian((unsigned char *)sumout, 4);
121} 144}
122 145
123void Bu::Md5::compBlock( long *x, long *lsum ) 146#define F1(x, y, z) (z ^ (x & (y ^ z)))
147#define F2(x, y, z) F1(z, x, y)
148#define F3(x, y, z) (x ^ y ^ z)
149#define F4(x, y, z) (y ^ (x | ~z))
150
151/* This is the central step in the MD5 algorithm. */
152#define MD5STEP(f, w, x, y, z, data, s) \
153 ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
154
155void Bu::Md5::compBlock( uint32_t *lsum, uint32_t *x )
124{ 156{
125 long a = lsum[0]; 157 register uint32_t a, b, c, d;
126 long b = lsum[1]; 158 a = lsum[0];
127 long c = lsum[2]; 159 b = lsum[1];
128 long d = lsum[3]; 160 c = lsum[2];
129 161 d = lsum[3];
130 a = md5_ff(a, b, c, d, x[ 0], 7 , -680876936); 162
131 d = md5_ff(d, a, b, c, x[ 1], 12, -389564586); 163 MD5STEP(F1, a, b, c, d, x[0] + 0xd76aa478, 7);
132 c = md5_ff(c, d, a, b, x[ 2], 17, 606105819); 164 MD5STEP(F1, d, a, b, c, x[1] + 0xe8c7b756, 12);
133 b = md5_ff(b, c, d, a, x[ 3], 22, -1044525330); 165 MD5STEP(F1, c, d, a, b, x[2] + 0x242070db, 17);
134 a = md5_ff(a, b, c, d, x[ 4], 7 , -176418897); 166 MD5STEP(F1, b, c, d, a, x[3] + 0xc1bdceee, 22);
135 d = md5_ff(d, a, b, c, x[ 5], 12, 1200080426); 167 MD5STEP(F1, a, b, c, d, x[4] + 0xf57c0faf, 7);
136 c = md5_ff(c, d, a, b, x[ 6], 17, -1473231341); 168 MD5STEP(F1, d, a, b, c, x[5] + 0x4787c62a, 12);
137 b = md5_ff(b, c, d, a, x[ 7], 22, -45705983); 169 MD5STEP(F1, c, d, a, b, x[6] + 0xa8304613, 17);
138 a = md5_ff(a, b, c, d, x[ 8], 7 , 1770035416); 170 MD5STEP(F1, b, c, d, a, x[7] + 0xfd469501, 22);
139 d = md5_ff(d, a, b, c, x[ 9], 12, -1958414417); 171 MD5STEP(F1, a, b, c, d, x[8] + 0x698098d8, 7);
140 c = md5_ff(c, d, a, b, x[10], 17, -42063); 172 MD5STEP(F1, d, a, b, c, x[9] + 0x8b44f7af, 12);
141 b = md5_ff(b, c, d, a, x[11], 22, -1990404162); 173 MD5STEP(F1, c, d, a, b, x[10] + 0xffff5bb1, 17);
142 a = md5_ff(a, b, c, d, x[12], 7 , 1804603682); 174 MD5STEP(F1, b, c, d, a, x[11] + 0x895cd7be, 22);
143 d = md5_ff(d, a, b, c, x[13], 12, -40341101); 175 MD5STEP(F1, a, b, c, d, x[12] + 0x6b901122, 7);
144 c = md5_ff(c, d, a, b, x[14], 17, -1502002290); 176 MD5STEP(F1, d, a, b, c, x[13] + 0xfd987193, 12);
145 b = md5_ff(b, c, d, a, x[15], 22, 1236535329); 177 MD5STEP(F1, c, d, a, b, x[14] + 0xa679438e, 17);
146 178 MD5STEP(F1, b, c, d, a, x[15] + 0x49b40821, 22);
147 a = md5_gg(a, b, c, d, x[ 1], 5 , -165796510); 179
148 d = md5_gg(d, a, b, c, x[ 6], 9 , -1069501632); 180 MD5STEP(F2, a, b, c, d, x[1] + 0xf61e2562, 5);
149 c = md5_gg(c, d, a, b, x[11], 14, 643717713); 181 MD5STEP(F2, d, a, b, c, x[6] + 0xc040b340, 9);
150 b = md5_gg(b, c, d, a, x[ 0], 20, -373897302); 182 MD5STEP(F2, c, d, a, b, x[11] + 0x265e5a51, 14);
151 a = md5_gg(a, b, c, d, x[ 5], 5 , -701558691); 183 MD5STEP(F2, b, c, d, a, x[0] + 0xe9b6c7aa, 20);
152 d = md5_gg(d, a, b, c, x[10], 9 , 38016083); 184 MD5STEP(F2, a, b, c, d, x[5] + 0xd62f105d, 5);
153 c = md5_gg(c, d, a, b, x[15], 14, -660478335); 185 MD5STEP(F2, d, a, b, c, x[10] + 0x02441453, 9);
154 b = md5_gg(b, c, d, a, x[ 4], 20, -405537848); 186 MD5STEP(F2, c, d, a, b, x[15] + 0xd8a1e681, 14);
155 a = md5_gg(a, b, c, d, x[ 9], 5 , 568446438); 187 MD5STEP(F2, b, c, d, a, x[4] + 0xe7d3fbc8, 20);
156 d = md5_gg(d, a, b, c, x[14], 9 , -1019803690); 188 MD5STEP(F2, a, b, c, d, x[9] + 0x21e1cde6, 5);
157 c = md5_gg(c, d, a, b, x[ 3], 14, -187363961); 189 MD5STEP(F2, d, a, b, c, x[14] + 0xc33707d6, 9);
158 b = md5_gg(b, c, d, a, x[ 8], 20, 1163531501); 190 MD5STEP(F2, c, d, a, b, x[3] + 0xf4d50d87, 14);
159 a = md5_gg(a, b, c, d, x[13], 5 , -1444681467); 191 MD5STEP(F2, b, c, d, a, x[8] + 0x455a14ed, 20);
160 d = md5_gg(d, a, b, c, x[ 2], 9 , -51403784); 192 MD5STEP(F2, a, b, c, d, x[13] + 0xa9e3e905, 5);
161 c = md5_gg(c, d, a, b, x[ 7], 14, 1735328473); 193 MD5STEP(F2, d, a, b, c, x[2] + 0xfcefa3f8, 9);
162 b = md5_gg(b, c, d, a, x[12], 20, -1926607734); 194 MD5STEP(F2, c, d, a, b, x[7] + 0x676f02d9, 14);
163 195 MD5STEP(F2, b, c, d, a, x[12] + 0x8d2a4c8a, 20);
164 a = md5_hh(a, b, c, d, x[ 5], 4 , -378558); 196
165 d = md5_hh(d, a, b, c, x[ 8], 11, -2022574463); 197 MD5STEP(F3, a, b, c, d, x[5] + 0xfffa3942, 4);
166 c = md5_hh(c, d, a, b, x[11], 16, 1839030562); 198 MD5STEP(F3, d, a, b, c, x[8] + 0x8771f681, 11);
167 b = md5_hh(b, c, d, a, x[14], 23, -35309556); 199 MD5STEP(F3, c, d, a, b, x[11] + 0x6d9d6122, 16);
168 a = md5_hh(a, b, c, d, x[ 1], 4 , -1530992060); 200 MD5STEP(F3, b, c, d, a, x[14] + 0xfde5380c, 23);
169 d = md5_hh(d, a, b, c, x[ 4], 11, 1272893353); 201 MD5STEP(F3, a, b, c, d, x[1] + 0xa4beea44, 4);
170 c = md5_hh(c, d, a, b, x[ 7], 16, -155497632); 202 MD5STEP(F3, d, a, b, c, x[4] + 0x4bdecfa9, 11);
171 b = md5_hh(b, c, d, a, x[10], 23, -1094730640); 203 MD5STEP(F3, c, d, a, b, x[7] + 0xf6bb4b60, 16);
172 a = md5_hh(a, b, c, d, x[13], 4 , 681279174); 204 MD5STEP(F3, b, c, d, a, x[10] + 0xbebfbc70, 23);
173 d = md5_hh(d, a, b, c, x[ 0], 11, -358537222); 205 MD5STEP(F3, a, b, c, d, x[13] + 0x289b7ec6, 4);
174 c = md5_hh(c, d, a, b, x[ 3], 16, -722521979); 206 MD5STEP(F3, d, a, b, c, x[0] + 0xeaa127fa, 11);
175 b = md5_hh(b, c, d, a, x[ 6], 23, 76029189); 207 MD5STEP(F3, c, d, a, b, x[3] + 0xd4ef3085, 16);
176 a = md5_hh(a, b, c, d, x[ 9], 4 , -640364487); 208 MD5STEP(F3, b, c, d, a, x[6] + 0x04881d05, 23);
177 d = md5_hh(d, a, b, c, x[12], 11, -421815835); 209 MD5STEP(F3, a, b, c, d, x[9] + 0xd9d4d039, 4);
178 c = md5_hh(c, d, a, b, x[15], 16, 530742520); 210 MD5STEP(F3, d, a, b, c, x[12] + 0xe6db99e5, 11);
179 b = md5_hh(b, c, d, a, x[ 2], 23, -995338651); 211 MD5STEP(F3, c, d, a, b, x[15] + 0x1fa27cf8, 16);
180 212 MD5STEP(F3, b, c, d, a, x[2] + 0xc4ac5665, 23);
181 a = md5_ii(a, b, c, d, x[ 0], 6 , -198630844); 213
182 d = md5_ii(d, a, b, c, x[ 7], 10, 1126891415); 214 MD5STEP(F4, a, b, c, d, x[0] + 0xf4292244, 6);
183 c = md5_ii(c, d, a, b, x[14], 15, -1416354905); 215 MD5STEP(F4, d, a, b, c, x[7] + 0x432aff97, 10);
184 b = md5_ii(b, c, d, a, x[ 5], 21, -57434055); 216 MD5STEP(F4, c, d, a, b, x[14] + 0xab9423a7, 15);
185 a = md5_ii(a, b, c, d, x[12], 6 , 1700485571); 217 MD5STEP(F4, b, c, d, a, x[5] + 0xfc93a039, 21);
186 d = md5_ii(d, a, b, c, x[ 3], 10, -1894986606); 218 MD5STEP(F4, a, b, c, d, x[12] + 0x655b59c3, 6);
187 c = md5_ii(c, d, a, b, x[10], 15, -1051523); 219 MD5STEP(F4, d, a, b, c, x[3] + 0x8f0ccc92, 10);
188 b = md5_ii(b, c, d, a, x[ 1], 21, -2054922799); 220 MD5STEP(F4, c, d, a, b, x[10] + 0xffeff47d, 15);
189 a = md5_ii(a, b, c, d, x[ 8], 6 , 1873313359); 221 MD5STEP(F4, b, c, d, a, x[1] + 0x85845dd1, 21);
190 d = md5_ii(d, a, b, c, x[15], 10, -30611744); 222 MD5STEP(F4, a, b, c, d, x[8] + 0x6fa87e4f, 6);
191 c = md5_ii(c, d, a, b, x[ 6], 15, -1560198380); 223 MD5STEP(F4, d, a, b, c, x[15] + 0xfe2ce6e0, 10);
192 b = md5_ii(b, c, d, a, x[13], 21, 1309151649); 224 MD5STEP(F4, c, d, a, b, x[6] + 0xa3014314, 15);
193 a = md5_ii(a, b, c, d, x[ 4], 6 , -145523070); 225 MD5STEP(F4, b, c, d, a, x[13] + 0x4e0811a1, 21);
194 d = md5_ii(d, a, b, c, x[11], 10, -1120210379); 226 MD5STEP(F4, a, b, c, d, x[4] + 0xf7537e82, 6);
195 c = md5_ii(c, d, a, b, x[ 2], 15, 718787259); 227 MD5STEP(F4, d, a, b, c, x[11] + 0xbd3af235, 10);
196 b = md5_ii(b, c, d, a, x[ 9], 21, -343485551); 228 MD5STEP(F4, c, d, a, b, x[2] + 0x2ad7d2bb, 15);
197 229 MD5STEP(F4, b, c, d, a, x[9] + 0xeb86d391, 21);
198 lsum[0] = a + lsum[0]; 230
199 lsum[1] = b + lsum[1]; 231 lsum[0] += a;
200 lsum[2] = c + lsum[2]; 232 lsum[1] += b;
201 lsum[3] = d + lsum[3]; 233 lsum[2] += c;
234 lsum[3] += d;
202} 235}
203 236
237void Bu::Md5::_toLittleEndian( uint8_t *buf, uint32_t count )
238{
239 uint32_t t;
240 do {
241 t = (uint32_t) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
242 ((unsigned) buf[1] << 8 | buf[0]);
243 *(uint32_t *) buf = t;
244 buf += 4;
245 } while( --count );
246}
diff --git a/src/md5.h b/src/md5.h
index d4a82ec..b7597fd 100644
--- a/src/md5.h
+++ b/src/md5.h
@@ -14,6 +14,8 @@ namespace Bu
14{ 14{
15 /** 15 /**
16 * Class for easily calculating MD5 sums of just about any data. 16 * Class for easily calculating MD5 sums of just about any data.
17 * This code is based on some public domain code written by Colin Plumb in
18 * 1993.
17 *@author Mike Buland 19 *@author Mike Buland
18 */ 20 */
19 class Md5 : public Bu::CryptoHash 21 class Md5 : public Bu::CryptoHash
@@ -36,13 +38,16 @@ namespace Bu
36 /** 38 /**
37 * Compute one block of input data. 39 * Compute one block of input data.
38 */ 40 */
39 void compBlock( long *x, long *lsum ); 41 void compBlock( uint32_t *lsum, uint32_t *x );
40 void compCap( long *sumout ); 42 void compCap( uint32_t *sumout );
43
44 void _addData( uint8_t *target, int &iCurFill, const void *sData,
45 int iSize );
46 void _toLittleEndian( uint8_t *buf, uint32_t count );
41 47
42 long inbuf[16]; 48 uint8_t inbuf[64];
43 long iFill; 49 uint32_t sum[4];
44 long sum[4]; 50 uint32_t uBits[2];
45 uint64_t iBytes;
46 }; 51 };
47}; 52};
48 53
diff --git a/src/plugger.cpp b/src/plugger.cpp
index 6e49b4e..fb6850a 100644
--- a/src/plugger.cpp
+++ b/src/plugger.cpp
@@ -7,9 +7,5 @@
7 7
8#include "bu/plugger.h" 8#include "bu/plugger.h"
9 9
10#ifndef WIN32
11
12namespace Bu { subExceptionDef( PluginException ) } 10namespace Bu { subExceptionDef( PluginException ) }
13 11
14#endif
15
diff --git a/src/plugger.h b/src/plugger.h
index 65ac4bb..2ba7b4b 100644
--- a/src/plugger.h
+++ b/src/plugger.h
@@ -8,15 +8,20 @@
8#ifndef BU_PLUGGER_H 8#ifndef BU_PLUGGER_H
9#define BU_PLUGGER_H 9#define BU_PLUGGER_H
10 10
11#ifndef WIN32 //yeah, this one is going to take some work...
12
13#include "bu/hash.h" 11#include "bu/hash.h"
14#include "bu/list.h" 12#include "bu/list.h"
15#include <dlfcn.h>
16#include "bu/exceptionbase.h" 13#include "bu/exceptionbase.h"
17#include "bu/string.h" 14#include "bu/string.h"
18#include <stddef.h> 15#include <stddef.h>
19 16
17#include "bu/config.h"
18
19#ifdef WIN32
20# include <windows.h>
21#else
22# include <dlfcn.h>
23#endif
24
20namespace Bu 25namespace Bu
21{ 26{
22 subExceptionDecl( PluginException ); 27 subExceptionDecl( PluginException );
@@ -34,7 +39,11 @@ namespace Bu
34 typedef struct PluginReg 39 typedef struct PluginReg
35 { 40 {
36 bool bBuiltin; 41 bool bBuiltin;
42#ifdef WIN32
43 HMODULE dlHandle;
44#else
37 void *dlHandle; 45 void *dlHandle;
46#endif
38 PluginInfo *pInfo; 47 PluginInfo *pInfo;
39 } PluginReg; 48 } PluginReg;
40 49
@@ -69,6 +78,20 @@ namespace Bu
69 (void (*)( void * ))(destroy ##classname) }; \ 78 (void (*)( void * ))(destroy ##classname) }; \
70 } 79 }
71 80
81//
82// This is probably the main interface to use, I'll describe it some here...
83// structname - The name of the structure, this is what you have to pass to
84// register. Depending on how you build your dll/so files this
85// will need to be unique (generally not)
86// pluginname - This is what will be used by the plugin system to refer to
87// your plugin once it's loaded. This should be unique, but not
88// a string
89// classname - The name of the class that is the plugin
90// baseclass - The name of the base class that is the parent of the plugin
91// name - The name of the author of this class (or company)
92// ver - an integer version number for the plugin
93// rev - an integer revision number for the plugin
94//
72#define PluginInterface3( structname, pluginname, classname, baseclass, name, ver, rev ) \ 95#define PluginInterface3( structname, pluginname, classname, baseclass, name, ver, rev ) \
73 extern "C" { \ 96 extern "C" { \
74 baseclass *create ##classname() \ 97 baseclass *create ##classname() \
@@ -85,6 +108,38 @@ namespace Bu
85 (void (*)( void * ))(destroy ##classname) }; \ 108 (void (*)( void * ))(destroy ##classname) }; \
86 } 109 }
87 110
111 /**
112 * A complete dynamic plugin manager system. This will allow you to design
113 * and use plugins that are compiled into your program and dynamically
114 * linked to your program interchangably. It works on windows and on *nix
115 * and bsd type systems (anything that supports dlopen). Basically you
116 * create a base class that will be the basic interface of your plugins.
117 * Then you create some classes that inherit from it, and use the
118 * PluginInterface3 macro to create the required data structures for it.
119 *
120 * Once you have plugins you can create a Plugger, by passing in the base
121 * class as it's template parameter. Once it's created, you can register
122 * plugins. To register a plugin that is builtin, you just need to pass
123 * a pointer to it's interface structure to the registerBuiltinPlugin
124 * function. To register a plugin that is in a shared object or dll file
125 * you just pass the filename (with path, probably), and the name of the
126 * structure to load and you're all set.
127 *
128 * To instantiate an object from a plugin simply call instantiate with the
129 * name of the plugin as specified in the interface macro. To destroy an
130 * object crated with the plugger do not delete it, instead pass it into
131 * Plugger's destroy function.
132 *
133 * Any objects not destroyed when the plugger is deleted will be destroyed
134 * automatically.
135 *
136 * It is important to note that some systems (linux at least) partition off
137 * the memory allocated by objects linked in at run time into a seperate
138 * segment that, while it can be accessed by the main program, cannot be
139 * safely or reliably freed by the main program. With that in mind it is
140 * a good idea to free all memory allocated by a plugin object in the plugin
141 * object and not allow the calling program to delete it.
142 */
88 template<class T> 143 template<class T>
89 class Plugger 144 class Plugger
90 { 145 {
@@ -111,7 +166,11 @@ namespace Bu
111 { 166 {
112 if( (*i)->bBuiltin == false ) 167 if( (*i)->bBuiltin == false )
113 { 168 {
169#ifdef WIN32
170 FreeLibrary( (*i)->dlHandle );
171#else
114 dlclose( (*i)->dlHandle ); 172 dlclose( (*i)->dlHandle );
173#endif
115 } 174 }
116 delete (*i); 175 delete (*i);
117 } 176 }
@@ -129,32 +188,42 @@ namespace Bu
129 const Bu::String &sPluginName ) 188 const Bu::String &sPluginName )
130 { 189 {
131 PluginReg *pReg; 190 PluginReg *pReg;
132 try { 191 if( hPlugin.has( sPluginName ) )
133 pReg = (PluginReg *)hPlugin[sPluginName]; 192 throw Bu::ExceptionBase("A plugin with name '%s' is already "
134 hPlugin.erase( sPluginName ); 193 "loaded.", sPluginName.getStr() );
135 dlclose( pReg->dlHandle );
136 delete pReg;
137 pReg = NULL;
138 } catch( Bu::HashException &e )
139 {
140 }
141 194
142 pReg = new PluginReg; 195 pReg = new PluginReg;
143 196
144 pReg->bBuiltin = false; 197 pReg->bBuiltin = false;
198#ifdef WIN32
199 pReg->dlHandle = LoadLibrary( sFName.getStr() );
200 if( pReg->dlHandle == NULL )
201 {
202 throw PluginException( 1, "Error opening %s: %s",
203 sFName.getStr(), Bu::getLastWinError().getStr() );
204 }
205 pReg->pInfo = (PluginInfo *)GetProcAddress( pReg->dlHandle,
206 sPluginName.getStr() );
207 if( pReg->pInfo == NULL )
208 {
209 throw PluginException( 2, "Error mapping %s: %s",
210 sFName.getStr(), Bu::getLastWinError().getStr() );
211 }
212#else
145 pReg->dlHandle = dlopen( sFName.getStr(), RTLD_NOW ); 213 pReg->dlHandle = dlopen( sFName.getStr(), RTLD_NOW );
146 if( pReg->dlHandle == NULL ) 214 if( pReg->dlHandle == NULL )
147 { 215 {
148 throw PluginException( 1, "Error on %s: %s", sFName.getStr(), 216 throw PluginException( 1, "Error opening %s: %s",
149 dlerror() ); 217 sFName.getStr(), dlerror() );
150 } 218 }
151 pReg->pInfo = (PluginInfo *)dlsym( pReg->dlHandle, 219 pReg->pInfo = (PluginInfo *)dlsym( pReg->dlHandle,
152 sPluginName.getStr() ); 220 sPluginName.getStr() );
153 if( pReg->pInfo == NULL ) 221 if( pReg->pInfo == NULL )
154 { 222 {
155 throw PluginException( 2, "Error on %s: %s", sFName.getStr(), 223 throw PluginException( 2, "Error mapping %s: %s",
156 dlerror() ); 224 sFName.getStr(), dlerror() );
157 } 225 }
226#endif
158 hPlugin.insert( pReg->pInfo->sID, pReg ); 227 hPlugin.insert( pReg->pInfo->sID, pReg );
159 } 228 }
160 229
@@ -195,7 +264,11 @@ namespace Bu
195 { 264 {
196 if( (*i)->bBuiltin == false ) 265 if( (*i)->bBuiltin == false )
197 { 266 {
267#ifdef WIN32
268 FreeLibrary( (*i)->dlHandle );
269#else
198 dlclose( (*i)->dlHandle ); 270 dlclose( (*i)->dlHandle );
271#endif
199 } 272 }
200 delete (*i); 273 delete (*i);
201 } 274 }
@@ -213,6 +286,4 @@ namespace Bu
213 }; 286 };
214} 287}
215 288
216#endif //#ifndef WIN32 //yeah, this one is going to take some work...
217
218#endif 289#endif
diff --git a/src/tcpsocket.h b/src/tcpsocket.h
index a05580a..dbaaa5e 100644
--- a/src/tcpsocket.h
+++ b/src/tcpsocket.h
@@ -66,7 +66,6 @@ namespace Bu
66 virtual ~TcpSocket(); 66 virtual ~TcpSocket();
67 67
68 virtual void close(); 68 virtual void close();
69 //virtual void read();
70 virtual size read( void *pBuf, size nBytes ); 69 virtual size read( void *pBuf, size nBytes );
71 virtual size read( void *pBuf, size nBytes, 70 virtual size read( void *pBuf, size nBytes,
72 uint32_t nSec, uint32_t nUSec=0 ); 71 uint32_t nSec, uint32_t nUSec=0 );
diff --git a/src/tests/udpsocket.cpp b/src/tests/udpsocket.cpp
new file mode 100644
index 0000000..2a74acf
--- /dev/null
+++ b/src/tests/udpsocket.cpp
@@ -0,0 +1,86 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/udpsocket.h"
9#include "bu/sio.h"
10
11#include <errno.h>
12#include <arpa/inet.h>
13#include <sys/socket.h>
14#include <netinet/in.h>
15#include <sys/utsname.h>
16
17using namespace Bu;
18
19int main( int argc, char *argv[] )
20{
21 sio << Fmt::hex(8) << INADDR_ANY << sio.nl << Fmt::hex(8) << inet_addr("0.0.0.0") << sio.nl;
22 if( argc == 1 )
23 {
24 sio << "Options are 'l' for listening and 'b' for broadcasting."
25 << sio.nl;
26 }
27 else if( argv[1][0] == 'l' )
28 {
29 sio << "Listening..." << sio.nl;
30 Bu::UdpSocket udp( "0.0.0.0", 6688, UdpSocket::Read|UdpSocket::Broadcast );
31
32 for(;;)
33 {
34 char buf[1501];
35 int iRead = udp.read( buf, 1500 );
36 if( iRead >= 0 )
37 {
38 buf[iRead] = '\0';
39 sio << "Read(" << iRead << "): '" << buf << "'" << sio.nl;
40 }
41 else
42 {
43 sio << "Got " << iRead << ": " << strerror( errno ) << sio.nl;
44 }
45 }
46 }
47 else if( argv[1][0] == 'L' )
48 {
49 sio << "Listening..." << sio.nl;
50 Bu::UdpSocket udp( "0.0.0.0", 6688, UdpSocket::Read|UdpSocket::Broadcast );
51
52 for(;;)
53 {
54 char buf[1501];
55 Bu::UdpSocket::addr aHost;
56 int iPort;
57 int iRead = udp.read( buf, 1500, aHost, iPort );
58 if( iRead >= 0 )
59 {
60 buf[iRead] = '\0';
61 sio << "Read(" << iRead << ") from " << Bu::UdpSocket::addrToStr( aHost ) << ":" << iPort << ": '" << buf << "'" << sio.nl;
62 }
63 }
64 }
65 else if( argv[1][0] == 'b' )
66 {
67 sio << "Broadcasting..." << sio.nl;
68 Bu::UdpSocket udp("255.255.255.255", 6688,
69 UdpSocket::Write|UdpSocket::Broadcast );
70
71 for(;;)
72 {
73 int iWrote = udp.write("hello", 5 );
74 sio << "Wrote(" << iWrote << "): " << strerror( errno ) << sio.nl;
75 usleep( 250000 );
76 }
77 }
78 else
79 {
80 sio << "Options are 'l' for listening and 'b' for broadcasting."
81 << sio.nl;
82 }
83
84 return 0;
85}
86
diff --git a/src/udpsocket.cpp b/src/udpsocket.cpp
new file mode 100644
index 0000000..91e04c1
--- /dev/null
+++ b/src/udpsocket.cpp
@@ -0,0 +1,240 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/udpsocket.h"
9
10#include "bu/sio.h"
11using namespace Bu;
12#include <fcntl.h>
13
14#include <errno.h>
15#include <arpa/inet.h>
16#include <sys/socket.h>
17#include <netinet/in.h>
18#include <sys/utsname.h>
19
20namespace Bu { subExceptionDef( UdpSocketException ) }
21
22#define saTarget ( *((struct sockaddr_in *)paTarget) )
23
24Bu::UdpSocket::UdpSocket( int iUdpSocket ) :
25 iUdpSocket( iUdpSocket ),
26 paTarget( NULL ),
27 bBound( false )
28{
29}
30
31Bu::UdpSocket::UdpSocket( const Bu::String &sAddr, int iPort, int iFlags ) :
32 iUdpSocket( 0 ),
33 paTarget( NULL ),
34 bBound( false )
35{
36 iUdpSocket = socket( PF_INET, SOCK_DGRAM, 0 );
37 if( iUdpSocket < 0 )
38 {
39 throw UdpSocketException("Couldn't open udp socket: %s",
40 strerror( errno )
41 );
42 }
43
44 if( (iFlags&Broadcast) )
45 {
46 int broadcast = 1;
47 if( (setsockopt( iUdpSocket, SOL_SOCKET, SO_BROADCAST,
48 &broadcast, sizeof(broadcast) )) == -1)
49 {
50 throw UdpSocketException("Couldn't set udp socket to broadcast: %s",
51 strerror( errno )
52 );
53 }
54 }
55
56 paTarget = new struct sockaddr_in;
57 saTarget.sin_family = AF_INET;
58 saTarget.sin_port = htons( iPort );
59 saTarget.sin_addr.s_addr = inet_addr( sAddr.getStr() ); // INADDR_ANY;
60 memset( saTarget.sin_zero, '\0', sizeof(saTarget.sin_zero) );
61
62 if( (iFlags&Read) )
63 {
64 if( bind( iUdpSocket, (struct sockaddr*)paTarget, sizeof(struct sockaddr_in) )
65 == -1 )
66 {
67 throw UdpSocketException("Couldn't bind port to udp socket: %s",
68 strerror( errno )
69 );
70 }
71 bBound = true;
72 }
73}
74
75Bu::UdpSocket::~UdpSocket()
76{
77 close();
78 delete (struct sockaddr_in *)paTarget;
79 paTarget = NULL;
80}
81
82Bu::String Bu::UdpSocket::addrToStr( const addr &a )
83{
84 Bu::String sOut;
85 sOut.format("%d.%d.%d.%d",
86 (a&0xff),
87 (a&0xff00)>>8,
88 (a&0xff0000)>>16,
89 (a&0xff000000)>>24
90 );
91
92 return sOut;
93}
94
95void Bu::UdpSocket::close()
96{
97 ::close( iUdpSocket );
98}
99
100Bu::size Bu::UdpSocket::read( void *pBuf, Bu::size nBytes )
101{
102 return recv( iUdpSocket, pBuf, nBytes, 0 );
103}
104
105Bu::size Bu::UdpSocket::read( void *pBuf, Bu::size nBytes,
106 Bu::UdpSocket::addr &aHost, int &iPort )
107{
108 sockaddr_in name;
109 size_t size = sizeof(name);
110 Bu::size ret = recvfrom( iUdpSocket, pBuf, nBytes, 0,
111 (struct sockaddr *)&name, &size );
112 aHost = name.sin_addr.s_addr;
113 iPort = ntohs(name.sin_port);
114 return ret;
115}
116
117Bu::size Bu::UdpSocket::write( const void *pBuf, Bu::size nBytes )
118{
119 if( bBound )
120 {
121 return sendto( iUdpSocket, pBuf, nBytes, 0, NULL, 0 );
122 }
123 else
124 {
125 return sendto( iUdpSocket, pBuf, nBytes, 0,
126 (struct sockaddr*)paTarget, sizeof(struct sockaddr_in) );
127 }
128}
129
130Bu::size Bu::UdpSocket::tell()
131{
132 throw Bu::UnsupportedException();
133}
134
135void Bu::UdpSocket::seek( Bu::size )
136{
137 throw Bu::UnsupportedException();
138}
139
140void Bu::UdpSocket::setPos( Bu::size )
141{
142 throw Bu::UnsupportedException();
143}
144
145void Bu::UdpSocket::setPosEnd( Bu::size )
146{
147 throw Bu::UnsupportedException();
148}
149
150bool Bu::UdpSocket::isEos()
151{
152 return false;
153}
154
155bool Bu::UdpSocket::isOpen()
156{
157 return true;
158}
159
160void Bu::UdpSocket::flush()
161{
162}
163
164bool Bu::UdpSocket::canRead()
165{
166 return bBound;
167}
168
169bool Bu::UdpSocket::canWrite()
170{
171 return true;
172}
173
174bool Bu::UdpSocket::isReadable()
175{
176 return bBound;
177}
178
179bool Bu::UdpSocket::isWritable()
180{
181 return true;
182}
183
184bool Bu::UdpSocket::isSeekable()
185{
186 return false;
187}
188
189bool Bu::UdpSocket::isBlocking()
190{
191 return true;
192}
193
194void Bu::UdpSocket::setBlocking( bool bBlocking )
195{
196#ifndef WIN32
197 if( bBlocking )
198 {
199 fcntl( iUdpSocket, F_SETFL, fcntl( iUdpSocket, F_GETFL, 0 ) & (~O_NONBLOCK) );
200 }
201 else
202 {
203 fcntl( iUdpSocket, F_SETFL, fcntl( iUdpSocket, F_GETFL, 0 ) | O_NONBLOCK );
204 }
205#else
206 u_long iMode;
207 if( bBlocking )
208 iMode = 0;
209 else
210 iMode = 1;
211 //-------------------------
212 // Set the socket I/O mode: In this case FIONBIO
213 // enables or disables the blocking mode for the
214 // socket based on the numerical value of iMode.
215 // If iMode = 0, blocking is enabled;
216 // If iMode != 0, non-blocking mode is enabled.
217 bu_ioctlsocket(iUdpSocket, FIONBIO, &iMode);
218#endif
219}
220
221void Bu::UdpSocket::setSize( Bu::size )
222{
223 throw Bu::UnsupportedException();
224}
225
226Bu::size Bu::UdpSocket::getSize() const
227{
228 throw Bu::UnsupportedException();
229}
230
231Bu::size Bu::UdpSocket::getBlockSize() const
232{
233 return 1500;
234}
235
236Bu::String Bu::UdpSocket::getLocation() const
237{
238 throw Bu::UnsupportedException();
239}
240
diff --git a/src/udpsocket.h b/src/udpsocket.h
new file mode 100644
index 0000000..8fe114d
--- /dev/null
+++ b/src/udpsocket.h
@@ -0,0 +1,81 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_UDP_SOCKET_H
9#define BU_UDP_SOCKET_H
10
11#include <stdint.h>
12
13#include "bu/stream.h"
14
15namespace Bu
16{
17 subExceptionDecl( UdpSocketException );
18
19 class UdpSocket : public Stream
20 {
21 public:
22 UdpSocket( int iUdpSocket );
23 UdpSocket( const Bu::String &sAddr, int iPort, int iFlags );
24 virtual ~UdpSocket();
25
26 typedef uint32_t addr;
27
28 static Bu::String addrToStr( const addr &a );
29
30 virtual void close();
31 virtual Bu::size read( void *pBuf, Bu::size nBytes );
32 virtual Bu::size read( void *pBuf, Bu::size nBytes,
33 addr &sHost, int &iPort );
34 virtual Bu::size write( const void *pBuf, Bu::size nBytes );
35 using Stream::write;
36
37 virtual Bu::size tell();
38 virtual void seek( Bu::size offset );
39 virtual void setPos( Bu::size pos );
40 virtual void setPosEnd( Bu::size pos );
41 virtual bool isEos();
42 virtual bool isOpen();
43
44 virtual void flush();
45
46 virtual bool canRead();
47 virtual bool canWrite();
48
49 virtual bool isReadable();
50 virtual bool isWritable();
51 virtual bool isSeekable();
52
53 virtual bool isBlocking();
54 virtual void setBlocking( bool bBlocking=true );
55
56 virtual void setSize( Bu::size iSize );
57
58 enum {
59 // Flags
60 Read = 0x01, ///< Open udp socket for reading
61 Write = 0x02, ///< Open udp socket for writing
62 ReadWrite = 0x03, ///< Open for both read and write
63 Broadcast = 0x04, ///< Open for broadcast
64 };
65
66 virtual size getSize() const;
67 virtual size getBlockSize() const;
68 virtual Bu::String getLocation() const;
69
70 private:
71#ifdef WIN32
72 unsigned int iUdpSocket;
73#else
74 int iUdpSocket;
75#endif
76 void *paTarget;
77 bool bBound;
78 };
79};
80
81#endif
diff --git a/src/unit/md5.unit b/src/unit/md5.unit
new file mode 100644
index 0000000..248aaaf
--- /dev/null
+++ b/src/unit/md5.unit
@@ -0,0 +1,82 @@
1// vim: syntax=cpp
2/*
3 * Copyright (C) 2007-2010 Xagasoft, All rights reserved.
4 *
5 * This file is part of the libbu++ library and is released under the
6 * terms of the license contained in the file LICENSE.
7 */
8
9#include "bu/md5.h"
10
11#include <stdlib.h>
12
13suite Md5
14{
15 test basics
16 {
17#define tryStr( a, b ) \
18 { Bu::Md5 m; m.addData(a); unitTest( m.getHexResult() == b ); } (void)0
19 tryStr("", "d41d8cd98f00b204e9800998ecf8427e");
20 tryStr("a", "0cc175b9c0f1b6a831c399e269772661");
21 tryStr("abc", "900150983cd24fb0d6963f7d28e17f72");
22 tryStr("message digest", "f96b697d7cb7938d525a2f31aaf161d0");
23 tryStr("abcdefghijklmnopqrstuvwxyz",
24 "c3fcd3d76192e4007dfb496cca67e13b");
25 tryStr("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
26 "d174ab98d277d9f5a5611c2c9f419d9f");
27 tryStr("12345678901234567890123456789012345"
28 "678901234567890123456789012345678901234567890",
29 "57edf4a22be3c955ac49da2e2107b67a");
30 }
31
32 test twoChunks
33 {
34 Bu::Md5 m;
35 m.addData("12345678901234567890123456789012345");
36 m.addData("678901234567890123456789012345678901234567890");
37 unitTest( m.getHexResult() == "57edf4a22be3c955ac49da2e2107b67a" );
38 }
39
40 test biggerBlocks
41 {
42 const char *sums[33] = {
43 "75fcf199abe516903321095a588b938d",
44 "e26a863c96d6bdba6601175aedaae108",
45 "2b207fdcb222078d3ebfeb8d5e7c9315",
46 "b08683aaa465add72cc2b43ae42f4f70",
47 "638bb73963b2d925771c3579ccb5e879",
48 "c727bd4b48a88e3df5924a2604de0790",
49 "f33d21203c80490f7342e5853c5550eb",
50 "db449faca66a177aae59b1e36a19d053",
51 "c800d429afb5f5c820f75c2c94e2e2bb",
52 "43b79c70b9a6a11e823ffbfa0f45a4db",
53 "0177ffc483cf598ae3966b3a5ae00c8c",
54 "1a68fdf4b17a3820d48d101e9355a818"
55 };
56
57 char block[128];
58 for( int i = 0; i < 128; i++ )
59 block[i] = i*2;
60
61 const char **curSum = sums;
62 for( int j = 1; j < 4096; j*=2 )
63 {
64 /*
65 Bu::File fOut("temp", Bu::File::WriteNew );
66 for( int b = 0; b < j; b++ )
67 {
68 fOut.write( block, 128 );
69 }
70 fOut.close();
71 system("md5sum -b temp");
72 */
73 Bu::Md5 m;
74 for( int b = 0; b < j; b++ )
75 {
76 m.addData( block, 128 );
77 }
78 unitTest( m.getHexResult() == *curSum );
79 curSum++;
80 }
81 }
82}