Merge lp:~psiphon-inc/psiphon/psiphon-1.6 into lp:psiphon

Proposed by مندس جرثومي
Status: Needs review
Proposed branch: lp:~psiphon-inc/psiphon/psiphon-1.6
Merge into: lp:psiphon
Diff against target: 30229 lines (+29308/-0)
170 files modified
appWeb/CONFIGURE_DEBUG.TXT (+5/-0)
appWeb/CONFIGURE_RELEASE.TXT (+5/-0)
appWeb/openSslModule.cpp (+896/-0)
appWeb/thread.cpp (+768/-0)
appweb.cnf (+27/-0)
bake-w32.bat (+1/-0)
changes.txt (+99/-0)
common/CppSQLite3.cpp (+1383/-0)
common/CppSQLite3.h (+270/-0)
common/SHA1.cpp (+282/-0)
common/SHA1.h (+150/-0)
common/SetupInfo.cpp (+512/-0)
common/SetupInfo.h (+110/-0)
common/User.cpp (+598/-0)
common/User.h (+94/-0)
common/bookmarks.cpp (+213/-0)
common/bookmarks.h (+30/-0)
common/convert.cpp (+176/-0)
common/convert.h (+47/-0)
common/cookies.cpp (+947/-0)
common/cookies.h (+73/-0)
common/logDetails.cpp (+252/-0)
common/logDetails.h (+70/-0)
common/parsedUrl.cpp (+312/-0)
common/parsedUrl.h (+78/-0)
common/sessions.cpp (+134/-0)
common/sessions.h (+29/-0)
common/sqlite3.h (+1161/-0)
common/strfunc.cpp (+109/-0)
common/strfunc.h (+39/-0)
common/timefunc.h (+21/-0)
common/tracer.cpp (+89/-0)
common/tracer.h (+39/-0)
html/en/errors/403.html (+15/-0)
html/en/errors/404.html (+15/-0)
html/en/errors/504.html (+15/-0)
html/en/index.tpl.html (+1/-0)
html/en/language.ini (+1/-0)
html/en/login.tpl.html (+62/-0)
html/en/login_err_db_insert_sess.tpl.html (+62/-0)
html/en/login_err_db_update_sess.tpl.html (+62/-0)
html/en/login_err_no_match.tpl.html (+62/-0)
html/en/login_err_pwd.tpl.html (+62/-0)
html/en/login_err_user.tpl.html (+62/-0)
html/en/main.tpl.html (+15/-0)
html/en/reset_pwd.tpl.html (+66/-0)
html/en/reset_pwd_err_conf_fail_pwd.tpl.html (+66/-0)
html/en/reset_pwd_err_conf_pwd.tpl.html (+66/-0)
html/en/reset_pwd_err_cur_pwd.tpl.html (+66/-0)
html/en/reset_pwd_err_db_update.tpl.html (+66/-0)
html/en/reset_pwd_err_new_pwd.tpl.html (+66/-0)
html/en/reset_pwd_err_no_match.tpl.html (+66/-0)
html/en/reset_pwd_err_user.tpl.html (+66/-0)
html/en/reset_pwd_success.tpl.html (+27/-0)
html/en/topbar.tpl.html (+511/-0)
html/fr/errors/403.html (+15/-0)
html/fr/errors/404.html (+15/-0)
html/fr/errors/504.html (+15/-0)
html/fr/index.tpl.html (+1/-0)
html/fr/language.ini (+1/-0)
html/fr/login.tpl.html (+62/-0)
html/fr/login_err_db_insert_sess.tpl.html (+62/-0)
html/fr/login_err_db_update_sess.tpl.html (+62/-0)
html/fr/login_err_no_match.tpl.html (+62/-0)
html/fr/login_err_pwd.tpl.html (+62/-0)
html/fr/login_err_user.tpl.html (+62/-0)
html/fr/main.tpl.html (+15/-0)
html/fr/reset_pwd.tpl.html (+66/-0)
html/fr/reset_pwd_err_conf_fail_pwd.tpl.html (+66/-0)
html/fr/reset_pwd_err_conf_pwd.tpl.html (+66/-0)
html/fr/reset_pwd_err_cur_pwd.tpl.html (+66/-0)
html/fr/reset_pwd_err_db_update.tpl.html (+66/-0)
html/fr/reset_pwd_err_new_pwd.tpl.html (+66/-0)
html/fr/reset_pwd_err_no_match.tpl.html (+66/-0)
html/fr/reset_pwd_err_user.tpl.html (+66/-0)
html/fr/reset_pwd_success.tpl.html (+27/-0)
html/fr/topbar.tpl.html (+511/-0)
html/fr/topbar_text.tpl.html (+461/-0)
html/ru/language.ini (+1/-0)
html/ru/login.tpl.html (+62/-0)
html/ru/login_err_db_insert_sess.tpl.html (+62/-0)
html/ru/login_err_db_update_sess.tpl.html (+62/-0)
html/ru/login_err_no_match.tpl.html (+62/-0)
html/ru/login_err_pwd.tpl.html (+62/-0)
html/ru/login_err_user.tpl.html (+62/-0)
html/ru/reset_pwd.tpl.html (+66/-0)
html/ru/reset_pwd_err_conf_fail_pwd.tpl.html (+66/-0)
html/ru/reset_pwd_err_conf_pwd.tpl.html (+66/-0)
html/ru/reset_pwd_err_cur_pwd.tpl.html (+66/-0)
html/ru/reset_pwd_err_db_update.tpl.html (+66/-0)
html/ru/reset_pwd_err_new_pwd.tpl.html (+67/-0)
html/ru/reset_pwd_err_no_match.tpl.html (+66/-0)
html/ru/reset_pwd_err_user.tpl.html (+66/-0)
html/ru/reset_pwd_success.tpl.html (+27/-0)
html/ru/topbar.tpl.html (+517/-0)
install-ubuntu.txt (+98/-0)
install-w32.txt (+111/-0)
installer.aip (+221/-0)
mime.types (+110/-0)
psiphon.bkl (+296/-0)
psiphonHandler/CSSFlexLexer.h (+24/-0)
psiphonHandler/CSSLexer.l (+61/-0)
psiphonHandler/FlexLexer.h (+202/-0)
psiphonHandler/HTMLFlexLexer.h (+24/-0)
psiphonHandler/HTMLlexer.l (+315/-0)
psiphonHandler/lex.CSS.cpp (+1451/-0)
psiphonHandler/lex.HTML.cpp (+1852/-0)
psiphonHandler/myclient.cpp (+1084/-0)
psiphonHandler/myclient.h (+239/-0)
psiphonHandler/psiphonContFilter.cpp (+394/-0)
psiphonHandler/psiphonContFilter.h (+84/-0)
psiphonHandler/psiphonHandler.cpp (+1797/-0)
psiphonHandler/psiphonHandler.def (+3/-0)
psiphonHandler/psiphonHandler.h (+204/-0)
psiphonHandler/psiphonUrl.cpp (+293/-0)
psiphonHandler/psiphonUrl.h (+49/-0)
psiphonHandler/psiphonUtils.cpp (+390/-0)
psiphonHandler/psiphonUtils.h (+55/-0)
psiphonHandler/tokensDefs.h (+48/-0)
psiphonPanel/CertDlg.cpp (+309/-0)
psiphonPanel/CertDlg.h (+64/-0)
psiphonPanel/CodeCountry.cpp (+266/-0)
psiphonPanel/CodeCountry.h (+30/-0)
psiphonPanel/DownloadEvent.cpp (+96/-0)
psiphonPanel/DownloadEvent.h (+168/-0)
psiphonPanel/DownloadFile.cpp (+167/-0)
psiphonPanel/DownloadFile.h (+80/-0)
psiphonPanel/GetIP.cpp (+101/-0)
psiphonPanel/GetIP.h (+23/-0)
psiphonPanel/LinkDlg.cpp (+302/-0)
psiphonPanel/LinkDlg.h (+63/-0)
psiphonPanel/ListCtrlSort.cpp (+88/-0)
psiphonPanel/ListCtrlSort.h (+74/-0)
psiphonPanel/LogDlg.cpp (+223/-0)
psiphonPanel/LogDlg.h (+61/-0)
psiphonPanel/PrefDlg.cpp (+121/-0)
psiphonPanel/PrefDlg.h (+45/-0)
psiphonPanel/PsiphonApp.cpp (+99/-0)
psiphonPanel/PsiphonApp.h (+43/-0)
psiphonPanel/PsiphonDlg.cpp (+574/-0)
psiphonPanel/PsiphonDlg.h (+99/-0)
psiphonPanel/PsiphonLog.cpp (+51/-0)
psiphonPanel/PsiphonLog.h (+39/-0)
psiphonPanel/PsiphonNameDlg.cpp (+133/-0)
psiphonPanel/PsiphonNameDlg.h (+42/-0)
psiphonPanel/Server.cpp (+215/-0)
psiphonPanel/Server.h (+80/-0)
psiphonPanel/SetupDlg.cpp (+123/-0)
psiphonPanel/SetupDlg.h (+61/-0)
psiphonPanel/UpdateDlg.cpp (+292/-0)
psiphonPanel/UpdateDlg.h (+59/-0)
psiphonPanel/UserDetailsDlg.cpp (+230/-0)
psiphonPanel/UserDetailsDlg.h (+46/-0)
psiphonPanel/UserDlg.cpp (+336/-0)
psiphonPanel/UserDlg.h (+69/-0)
psiphonPanel/cert.cpp (+102/-0)
psiphonPanel/cert.h (+22/-0)
psiphonPanel/psiphonoff.xpm (+189/-0)
psiphonPanel/psiphonon.xpm (+189/-0)
psiphonPanel/resources.h (+33/-0)
psiphonPanel/sessionAccess.cpp (+172/-0)
psiphonPanel/sessionAccess.h (+35/-0)
psiphonPanel/stdwx.cpp (+19/-0)
psiphonPanel/stdwx.h (+53/-0)
psiphonPanel/taskbaricon.cpp (+91/-0)
psiphonPanel/taskbaricon.h (+39/-0)
psiphonPanel/update.cpp (+79/-0)
psiphonPanel/update.h (+20/-0)
psiphonPanel/wxPsiphon.rc (+23/-0)
userlicense.txt (+39/-0)
To merge this branch: bzr merge lp:~psiphon-inc/psiphon/psiphon-1.6
Reviewer Review Type Date Requested Status
Psiphon Inc. Pending
Review via email: mp+83096@code.launchpad.net
To post a comment you must log in.

Unmerged revisions

1. By jamyang <email address hidden>

psiphon-1.6

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== added file '.DS_Store'
0Binary files .DS_Store 1970-01-01 00:00:00 +0000 and .DS_Store 2011-11-23 01:01:25 +0000 differ0Binary files .DS_Store 1970-01-01 00:00:00 +0000 and .DS_Store 2011-11-23 01:01:25 +0000 differ
=== added directory 'appWeb'
=== added file 'appWeb/CONFIGURE_DEBUG.TXT'
--- appWeb/CONFIGURE_DEBUG.TXT 1970-01-01 00:00:00 +0000
+++ appWeb/CONFIGURE_DEBUG.TXT 2011-11-23 01:01:25 +0000
@@ -0,0 +1,5 @@
1./configure --reset
2./configure --disable-samples --without-upload --without-xdb --disable-test --type=DEBUG \
3--with-openssl=loadable \
4--with-openssl-dir=../../openssl \
5--with-openssl-libs="ssl crypto"
0\ No newline at end of file6\ No newline at end of file
17
=== added file 'appWeb/CONFIGURE_RELEASE.TXT'
--- appWeb/CONFIGURE_RELEASE.TXT 1970-01-01 00:00:00 +0000
+++ appWeb/CONFIGURE_RELEASE.TXT 2011-11-23 01:01:25 +0000
@@ -0,0 +1,5 @@
1./configure --reset
2./configure --disable-samples --without-upload --without-xdb --disable-test --type=RELEASE \
3--with-openssl=loadable \
4--with-openssl-dir=../../openssl \
5--with-openssl-libs="ssl crypto"
0\ No newline at end of file6\ No newline at end of file
17
=== added file 'appWeb/openSslModule.cpp'
--- appWeb/openSslModule.cpp 1970-01-01 00:00:00 +0000
+++ appWeb/openSslModule.cpp 2011-11-23 01:01:25 +0000
@@ -0,0 +1,896 @@
1///
2/// @file openSslModule.cpp
3/// @brief Support for secure sockets via OpenSSL
4/// @overview This module integrates support for OpenSSL into AppWeb
5/// via a dynamically loadable module.
6//
7/////////////////////////////////// Copyright //////////////////////////////////
8//
9// @copy default
10//
11// Copyright (c) Mbedthis Software LLC, 2003-2006. All Rights Reserved.
12// Copyright (c) Michael O'Brien, 1994-2006. All Rights Reserved.
13//
14// This software is distributed under commercial and open source licenses.
15// You may use the GPL open source license described below or you may acquire
16// a commercial license from Mbedthis Software. You agree to be fully bound
17// by the terms of either license. Consult the LICENSE.TXT distributed with
18// this software for full details.
19//
20// This software is open source; you can redistribute it and/or modify it
21// under the terms of the GNU General Public License as published by the
22// Free Software Foundation; either version 2 of the License, or (at your
23// option) any later version. See the GNU General Public License for more
24// details at: http://www.mbedthis.com/downloads/gplLicense.html
25//
26// This program is distributed WITHOUT ANY WARRANTY; without even the
27// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
28//
29// This GPL license does NOT permit incorporating this software into
30// proprietary programs. If you are unable to comply with the GPL, you must
31// acquire a commercial license to use this software. Commercial licenses
32// for this software and support services are available from Mbedthis
33// Software at http://www.mbedthis.com
34//
35// @end
36//
37////////////////////////////////// Includes ////////////////////////////////////
38
39#include "openSslModule.h"
40
41//////////////////////////////////// Locals ////////////////////////////////////
42#if BLD_FEATURE_OPENSSL_MODULE
43
44#include "openSslDh.h"
45
46#if BLD_FEATURE_MULTITHREAD
47static MprMutex **locks;
48static int numLocks;
49#endif
50
51////////////////////////////// Forward Declarations ////////////////////////////
52
53#if BLD_FEATURE_MULTITHREAD
54static DynLock *sslCreateDynLock(const char *file, int line);
55static void sslDynLock(int mode, DynLock *dl, const char *file, int line);
56static void sslDestroyDynLock(DynLock *dl, const char *file, int line);
57static void sslStaticLock(int mode, int n, const char *file, int line);
58static ulong sslThreadId();
59#endif
60
61static int configureCertificates(SSL_CTX *ctx, char *key, char *cert);
62static RSA *rsaCallback(SSL *ssl, int isExport, int keyLength);
63static DH *dhCallback(SSL *ssl, int isExport, int keyLength);
64static int verifyX509Certificate(int ok, X509_STORE_CTX *ctx);
65
66//////////////////////////////////// Locals ////////////////////////////////////
67
68static MaOpenSslModule *openSslModule;
69static MaOpenSslProvider *openSslProvider;
70
71////////////////////////////////////////////////////////////////////////////////
72/////////////////////////////// MaOpenSslModule ////////////////////////////////
73////////////////////////////////////////////////////////////////////////////////
74
75int mprOpenSslInit(void *handle)
76{
77 if (maGetHttp() == 0) {
78 return MPR_ERR_NOT_INITIALIZED;
79 }
80 new MaOpenSslModule(handle);
81 return 0;
82}
83
84////////////////////////////////////////////////////////////////////////////////
85
86MaOpenSslModule::MaOpenSslModule(void *handle) : MaModule("openSsl", handle)
87{
88 openSslModule = this;
89 openSslProvider = new MaOpenSslProvider("openSsl");
90}
91
92////////////////////////////////////////////////////////////////////////////////
93
94MaOpenSslModule::~MaOpenSslModule()
95{
96 delete openSslProvider;
97}
98
99////////////////////////////////////////////////////////////////////////////////
100//
101// This is called from Http::start after all the modules are loaded.
102// The code here is global for this handler and is not required per handler
103// instance.
104//
105int MaOpenSslModule::start()
106{
107 RandBuf randBuf;
108 static int once = 0;
109
110 //
111 // Depending on the order in the configuration file, we will get called
112 // by the module mechanism and by OpenSslConfig::start(). But we only
113 // want to run once.
114 //
115 if (once++ > 0) {
116 return 0;
117 }
118 randBuf.pid = getpid();
119 randBuf.time = time(0);
120 randBuf.msec = mprGetTime(0);
121 RAND_seed((void*) &randBuf, sizeof(randBuf));
122
123#if SOLARIS || LINUX || MACOSX
124 mprLog(6, "OpenSsl: Before calling RAND_load_file\n");
125 RAND_load_file("/dev/urandom", 256);
126 mprLog(6, "OpenSsl: After calling RAND_load_file\n");
127#endif
128
129#if BLD_FEATURE_MULTITHREAD
130 numLocks = CRYPTO_num_locks();
131 locks = (MprMutex**) mprMalloc(numLocks * sizeof(MprMutex*));
132 for (int i = 0; i < numLocks; i++) {
133 locks[i] = new MprMutex();
134 }
135 CRYPTO_set_id_callback(sslThreadId);
136 CRYPTO_set_locking_callback(sslStaticLock);
137
138 CRYPTO_set_dynlock_create_callback(sslCreateDynLock);
139 CRYPTO_set_dynlock_destroy_callback(sslDestroyDynLock);
140 CRYPTO_set_dynlock_lock_callback(sslDynLock);
141#endif
142
143#if WIN
144 // _fmode=_O_BINARY;
145 // CRYPTO_malloc_init();
146 // SSLC_add_all_algorithms();
147#else
148 OpenSSL_add_all_algorithms();
149#endif
150
151 SSL_library_init();
152 return 0;
153}
154
155////////////////////////////////////////////////////////////////////////////////
156
157void MaOpenSslModule::stop()
158{
159#if BLD_FEATURE_MULTITHREAD
160 int i;
161
162 if (locks) {
163 for (i = 0; i < numLocks; i++) {
164 delete locks[i];
165 }
166 mprFree(locks);
167 locks = 0;
168 numLocks = 0;
169
170 CRYPTO_set_id_callback(0);
171 CRYPTO_set_locking_callback(0);
172
173 CRYPTO_set_dynlock_create_callback(0);
174 CRYPTO_set_dynlock_destroy_callback(0);
175 CRYPTO_set_dynlock_lock_callback(0);
176 }
177#endif
178}
179
180////////////////////////////////////////////////////////////////////////////////
181/////////////////////////////// MaOpenSslProvider //////////////////////////////
182////////////////////////////////////////////////////////////////////////////////
183//
184// The SSL provider class implements and decouples the interface between
185// AppWeb and any SSL stack.
186//
187
188MaOpenSslProvider::MaOpenSslProvider(char *name) : MaSslProvider(name)
189{
190}
191
192////////////////////////////////////////////////////////////////////////////////
193
194MaOpenSslProvider::~MaOpenSslProvider()
195{
196}
197
198////////////////////////////////////////////////////////////////////////////////
199
200MaSslConfig *MaOpenSslProvider::newConfig(MaHost *host)
201{
202 return new MaOpenSslConfig(host);
203}
204
205////////////////////////////////////////////////////////////////////////////////
206//////////////////////////////// MaOpenSslConfig ///////////////////////////////
207////////////////////////////////////////////////////////////////////////////////
208//
209// An instance is created for each SSL server
210//
211
212MaOpenSslConfig::MaOpenSslConfig(MaHost *host) : MaSslConfig(host)
213{
214 context = 0;
215 dhKey512 = 0;
216 dhKey1024 = 0;
217 rsaKey512 = 0;
218 rsaKey1024 = 0;
219}
220
221////////////////////////////////////////////////////////////////////////////////
222
223MaOpenSslConfig::~MaOpenSslConfig()
224{
225 if (context != 0) {
226 SSL_CTX_free(context);
227 }
228 if (rsaKey512) {
229 RSA_free(rsaKey512);
230 }
231 if (rsaKey1024) {
232 RSA_free(rsaKey1024);
233 }
234 if (dhKey512) {
235 DH_free(dhKey512);
236 }
237 if (dhKey1024) {
238 DH_free(dhKey1024);
239 }
240}
241
242////////////////////////////////////////////////////////////////////////////////
243//
244// This method is called to open listening sockets using this SslConfig setup.
245//
246
247MprSocket *MaOpenSslConfig::newSocket()
248{
249 MaOpenSslSocket *socket;
250
251 socket = new MaOpenSslSocket(this);
252
253 return (MprSocket*) socket;
254}
255
256////////////////////////////////////////////////////////////////////////////////
257//
258// This is started for each SSL connection. With Keep-alive this may service
259// many requests.
260//
261
262int MaOpenSslConfig::start()
263{
264 SSL_METHOD *meth;
265 char *hostName;
266
267 if (keyFile == 0) {
268 mprError(MPR_L, MPR_LOG, "Cant start SSL: missing key file");
269 return MPR_ERR_CANT_INITIALIZE;
270 }
271 if (certFile == 0) {
272 mprError(MPR_L, MPR_LOG, "Cant start SSL: missing certificate file");
273 return MPR_ERR_CANT_INITIALIZE;
274 }
275
276 //
277 // Depending on the order in the configuration file, we may get called
278 // by sslModule::start() before OpenSslModule::start has run. So we
279 // must initialize here.
280 //
281 openSslModule->start();
282
283 hostName = host->getName();
284
285 if (protocols == MPR_HTTP_PROTO_SSLV2) {
286 meth = SSLv2_server_method();
287 } else {
288 meth = SSLv23_server_method();
289 }
290 context = SSL_CTX_new(meth);
291 mprAssert(context);
292 if (context == 0) {
293 mprError(MPR_L, MPR_LOG, "Unable to create SSL context");
294 return MPR_ERR_CANT_CREATE;
295 }
296
297 SSL_CTX_set_app_data(context, (void*) this);
298 SSL_CTX_set_quiet_shutdown(context, 1);
299 SSL_CTX_sess_set_cache_size(context, 512);
300
301 //
302 // Configure the certificate for this host
303 //
304 if (configureCertificates(context, keyFile, certFile) != 0) {
305 SSL_CTX_free(context);
306 context = 0;
307 return MPR_ERR_CANT_INITIALIZE;
308 }
309
310 mprLog(4, "SSL: %s: Using ciphers %s\n", hostName, ciphers);
311 SSL_CTX_set_cipher_list(context, ciphers);
312
313 //
314 // Configure the client verification certificate locations
315 //
316 if (verifyClient) {
317 if (caFile == 0 && caPath == 0) {
318 mprError(MPR_L, MPR_LOG,
319 "Must define CA certificates if using client verification");
320 SSL_CTX_free(context);
321 context = 0;
322 return MPR_ERR_BAD_STATE;
323 }
324 if (caFile || caPath) {
325 if ((!SSL_CTX_load_verify_locations(context, caFile, caPath)) ||
326 (!SSL_CTX_set_default_verify_paths(context))) {
327 mprError(MPR_L, MPR_LOG,
328 "Unable to set certificate locations");
329 SSL_CTX_free(context);
330 context = 0;
331 return MPR_ERR_CANT_ACCESS;
332 }
333 if (caFile) {
334 STACK_OF(X509_NAME) *certNames;
335 certNames = SSL_load_client_CA_file(caFile);
336 if (certNames == 0) {
337 } else {
338 //
339 // Define the list of CA certificates to send to the client
340 // before they send their client certificate for validation
341 //
342 SSL_CTX_set_client_CA_list(context, certNames);
343 }
344 }
345 }
346 mprLog(4, "SSL: %s: is verifying client connections\n", hostName);
347 if (caFile) {
348 mprLog(4, "SSL: %s: Using certificates from %s\n", hostName,
349 caFile);
350 } else if (caPath) {
351 mprLog(4, "SSL: %s: Using certificates from directory %s\n",
352 hostName, caPath);
353 }
354 SSL_CTX_set_verify(context,
355 SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
356 verifyX509Certificate);
357 SSL_CTX_set_verify_depth(context, verifyDepth);
358
359 } else {
360 SSL_CTX_set_verify(context, SSL_VERIFY_NONE, verifyX509Certificate);
361 }
362
363 //
364 // Define callbacks
365 //
366 SSL_CTX_set_tmp_rsa_callback(context, rsaCallback);
367 SSL_CTX_set_tmp_dh_callback(context, dhCallback);
368
369 //
370 // Enable all buggy client work-arounds
371 //
372 SSL_CTX_set_options(context, SSL_OP_ALL);
373
374 //
375 // Select the required protocols
376 //
377 if (!(protocols & MPR_HTTP_PROTO_SSLV2)) {
378 SSL_CTX_set_options(context, SSL_OP_NO_SSLv2);
379 mprLog(4, "SSL: %s: Disabling SSLv2\n", hostName);
380 }
381 if (!(protocols & MPR_HTTP_PROTO_SSLV3)) {
382 SSL_CTX_set_options(context, SSL_OP_NO_SSLv3);
383 mprLog(4, "SSL: %s: Disabling SSLv3\n", hostName);
384 }
385 if (!(protocols & MPR_HTTP_PROTO_TLSV1)) {
386 SSL_CTX_set_options(context, SSL_OP_NO_TLSv1);
387 mprLog(4, "SSL: %s: Disabling TLSv1\n", hostName);
388 }
389
390 //
391 // Ensure we generate a new private key for each connection
392 //
393 SSL_CTX_set_options(context, SSL_OP_SINGLE_DH_USE);
394
395 //
396 // Pre-generate some keys that are slow to compute
397 //
398 rsaKey512 = RSA_generate_key(512, RSA_F4, 0, 0);
399 rsaKey1024 = RSA_generate_key(1024, RSA_F4, 0, 0);
400
401 dhKey512 = get_dh512();
402 dhKey1024 = get_dh1024();
403
404 return 0;
405}
406
407////////////////////////////////////////////////////////////////////////////////
408
409void MaOpenSslConfig::stop()
410{
411}
412
413////////////////////////////////////////////////////////////////////////////////
414
415SSL_CTX *MaOpenSslConfig::getContext()
416{
417 return context;
418}
419
420////////////////////////////////////////////////////////////////////////////////
421
422///
423/// Called to verify X509 client certificates
424///
425static int verifyX509Certificate(int ok, X509_STORE_CTX *xContext)
426{
427 X509 *cert;
428 SSL *ssl;
429 MaOpenSslSocket *sslSocket;
430 MaOpenSslConfig *config;
431 char subject[260], issuer[260], peer[260];
432 int error, depth;
433
434 subject[0] = issuer[0] = '\0';
435
436 ssl = (SSL*) X509_STORE_CTX_get_app_data(xContext);
437 sslSocket = (MaOpenSslSocket*) SSL_get_app_data(ssl);
438 config = (MaOpenSslConfig*) sslSocket->getConfig();
439
440 cert = X509_STORE_CTX_get_current_cert(xContext);
441 depth = X509_STORE_CTX_get_error_depth(xContext);
442 error = X509_STORE_CTX_get_error(xContext);
443
444 if (X509_NAME_oneline(X509_get_subject_name(cert), subject,
445 sizeof(subject) - 1) < 0) {
446 ok = 0;
447 }
448 //
449 // FUTURE -- should compare subject name and host name. Need smart compare
450 //
451 if (X509_NAME_oneline(X509_get_issuer_name(xContext->current_cert), issuer,
452 sizeof(issuer) - 1) < 0) {
453 ok = 0;
454 }
455 if (X509_NAME_get_text_by_NID(X509_get_subject_name(xContext->current_cert),
456 NID_commonName, peer, sizeof(peer) - 1) < 0) {
457 ok = 0;
458 }
459
460 //
461 // Customizers: add your own code here to validate client certificates
462 //
463 if (ok && config->verifyDepth < depth) {
464 if (error == 0) {
465 error = X509_V_ERR_CERT_CHAIN_TOO_LONG;
466 }
467 ok = 0;
468 }
469
470 if (error != 0) {
471 mprAssert(!ok);
472 }
473
474#if UNUSED
475 switch (error) {
476 case X509_V_ERR_CERT_HAS_EXPIRED:
477 case X509_V_ERR_CERT_NOT_YET_VALID:
478 case X509_V_ERR_CERT_REJECTED:
479 case X509_V_ERR_CERT_SIGNATURE_FAILURE:
480 case X509_V_ERR_CERT_UNTRUSTED:
481 case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
482 case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
483 case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
484 case X509_V_ERR_INVALID_CA:
485 case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
486 case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
487 default:
488 ok = 0;
489 break;
490 }
491#endif
492
493 if (!ok) {
494 mprLog(0, "SSL: Certification failed: subject %s\n", subject);
495 mprLog(4, "SSL: Issuer: %s\n", issuer);
496 mprLog(4, "SSL: Peer: %s\n", peer);
497 mprLog(4, "SSL: Error: %d: %s\n", error,
498 X509_verify_cert_error_string(error));
499
500 } else {
501 mprLog(0, "SSL: Certificate verified: subject %s\n", subject);
502 mprLog(4, "SSL: Issuer: %s\n", issuer);
503 mprLog(4, "SSL: Peer: %s\n", peer);
504 }
505 return ok;
506}
507
508////////////////////////////////////////////////////////////////////////////////
509
510///
511/// Configure the SSL certificate information
512///
513
514static int configureCertificates(SSL_CTX *ctx, char *key, char *cert)
515{
516 mprAssert(ctx);
517 mprAssert(cert);
518
519 if (cert == 0) {
520 return 0;
521 }
522
523 if (SSL_CTX_use_certificate_file(ctx, cert, SSL_FILETYPE_PEM) <= 0){
524 mprError(MPR_L, MPR_LOG, "Can't define certificate file: %s", cert);
525 return -1;
526 }
527
528 key = (key == 0) ? cert : key;
529 if (SSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM) <= 0) {
530 mprError(MPR_L, MPR_LOG, "Can't define private key file: %s", key);
531 return -1;
532 }
533
534 if (!SSL_CTX_check_private_key(ctx)) {
535 mprError(MPR_L, MPR_LOG, "Check of private key file failed: %s", key);
536 return -1;
537 }
538 return 0;
539}
540
541////////////////////////////////////////////////////////////////////////////////
542//////////////////////////////// MaOpenSslSocket ///////////////////////////////
543////////////////////////////////////////////////////////////////////////////////
544
545MaOpenSslSocket::MaOpenSslSocket(MaOpenSslConfig *config) : MaSslSocket(config)
546{
547 ssl = 0;
548 bio = 0;
549 context = config->getContext();
550}
551
552////////////////////////////////////////////////////////////////////////////////
553
554MaOpenSslSocket::~MaOpenSslSocket()
555{
556 mprAssert(ssl == 0);
557 mprAssert(bio == 0);
558}
559
560////////////////////////////////////////////////////////////////////////////////
561//
562// Called to accept new connections. When a new connection arrives, this
563// method is called to create a new socket object using the same SSL "config"
564// as the listening socket.
565//
566
567MprSocket *MaOpenSslSocket::newSocket()
568{
569 MaOpenSslSocket *socket;
570
571 socket = new MaOpenSslSocket((MaOpenSslConfig*) config);
572
573 return (MprSocket*) socket;
574}
575
576////////////////////////////////////////////////////////////////////////////////
577//
578// initConnection is called on the first I/O on a new connection. It must
579// setup the SSL structures ready to exchange data.
580//
581// Init connection must return -1 on errors. It must also be able to reject
582// subsequent calls to read()/write(). On errors we leave bio == 0. This
583// will cause any calls to read() to error.
584//
585
586int MaOpenSslSocket::initConnection()
587{
588 BIO *bioSSL, *bioSock;
589
590 if (bio) {
591 return 0;
592 }
593 bio = BIO_new(BIO_f_buffer());
594 if (bio == 0) {
595 return MPR_ERR_CANT_INITIALIZE;
596 }
597
598 BIO_set_write_buffer_size(bio, 128);
599 ssl = (SSL*) SSL_new(context);
600 mprAssert(ssl);
601 if (ssl == 0) {
602 return MPR_ERR_CANT_INITIALIZE;
603 }
604 SSL_set_app_data(ssl, (void*) this);
605
606 SSL_set_session(ssl, 0);
607 bioSSL = BIO_new(BIO_f_ssl());
608 mprAssert(bioSSL);
609
610 bioSock = BIO_new_socket(sock, BIO_NOCLOSE);
611 mprAssert(bioSock);
612
613 SSL_set_bio(ssl, bioSock, bioSock);
614 SSL_set_accept_state(ssl);
615
616 BIO_set_ssl(bioSSL, ssl, BIO_CLOSE);
617 BIO_push(bio, bioSSL);
618 return 0;
619}
620
621////////////////////////////////////////////////////////////////////////////////
622
623bool MaOpenSslSocket::dispose()
624{
625 if (ssl) {
626 SSL_set_shutdown(ssl, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN);
627 ssl = 0;
628 }
629 if (bio) {
630 BIO_free_all(bio);
631 bio = 0;
632 }
633
634 //
635 // Disposing a socket is a thread-safe way of calling a destructor. It
636 // uses reference counting and will be deleted when the last reference
637 // is released.
638 //
639 return this->MprSocket::dispose();
640}
641
642////////////////////////////////////////////////////////////////////////////////
643
644void MaOpenSslSocket::close(int how)
645{
646 BIO_flush(bio);
647 this->MprSocket::close(how);
648}
649
650////////////////////////////////////////////////////////////////////////////////
651//
652// Write data. Return the number of bytes written or -1 on errors.
653//
654
655int MaOpenSslSocket::write(char *buf, int len)
656{
657 int rc, written, totalWritten;
658
659 if (bio == 0 || ssl == 0 || len < 0) {
660 return -1;
661 }
662 BIO_clear_retry_flags(bio);
663 totalWritten = 0;
664 do {
665 written = BIO_write(bio, buf, len);
666 mprLog(7, "written %d, len %d\n", written, len);
667 if (written >= 0) {
668 do {
669 rc = BIO_flush(bio);
670 mprLog(7, "BIO_flush rc %d\n", rc);
671 if (rc > 0) {
672 // Success
673 break;
674 }
675 //
676 // Nap to prevent busy waiting.
677 //
678 mprSleep(10);
679 } while (rc <= 0 && BIO_should_retry(bio));
680 totalWritten += written;
681 buf += written;
682 len -= written;
683 }
684 mprLog(7, "write: len %d, written %d, total %d, should_retry %d\n",
685 len, written, totalWritten, BIO_should_retry(bio));
686 } while (len > 0 && (written > 0 || BIO_should_retry(bio)));
687
688//AFF
689 if(written < 0 && BIO_should_retry(bio) == 0)
690 return -1;
691//
692
693 return totalWritten;
694}
695
696////////////////////////////////////////////////////////////////////////////////
697
698int MaOpenSslSocket::flush()
699{
700 return BIO_flush(bio);
701}
702
703////////////////////////////////////////////////////////////////////////////////
704
705int MaOpenSslSocket::read(char *buf, int len)
706{
707 int rc;
708
709 if (bio == 0 || ssl == 0) {
710 return -1;
711 }
712
713 rc = BIO_read(bio, buf, len);
714
715#if DEBUG
716 if (rc > 0 && !connTraced) {
717 X509_NAME *xSubject;
718 X509 *cert;
719 char subject[260], issuer[260], peer[260];
720
721 mprLog(4, "%d: SSL Connected using: \"%s\"\n",
722 sock, SSL_get_cipher(ssl));
723
724 cert = SSL_get_peer_certificate(ssl);
725 if (cert == 0) {
726 mprLog(4, "%d: SSL Details: client supplied no certificate\n",
727 sock);
728 } else {
729 xSubject = X509_get_subject_name(cert);
730 X509_NAME_oneline(xSubject, subject, sizeof(subject) -1);
731 X509_NAME_oneline(X509_get_issuer_name(cert), issuer,
732 sizeof(issuer) -1);
733 X509_NAME_get_text_by_NID(xSubject, NID_commonName, peer,
734 sizeof(peer) - 1);
735 mprLog(4, "%d: SSL Subject %s\n", sock, subject);
736 mprLog(4, "%d: SSL Issuer: %s\n", sock, issuer);
737 mprLog(4, "%d: SSL Peer: %s\n", sock, peer);
738 X509_free(cert);
739 }
740 connTraced = 1;
741 }
742#endif
743
744 if (rc > 0) {
745 return rc;
746
747 } else if (rc == 0) {
748 if (BIO_should_retry(bio)) {
749 return 0;
750 }
751 flags |= MPR_SOCKET_EOF;
752 return 0;
753 }
754 if (BIO_should_retry(bio)) {
755 return 0;
756 }
757 return rc;
758}
759
760////////////////////////////////////////////////////////////////////////////////
761#if UNUSED
762//
763// Return true if end of file
764//
765
766bool MaOpenSslSocket::getEof()
767{
768 bool rc;
769
770 rc = (BIO_eof(bio) != 0);
771 return rc;
772}
773
774#endif
775
776////////////////////////////////////////////////////////////////////////////////
777#if BLD_FEATURE_MULTITHREAD
778
779static ulong sslThreadId()
780{
781 return (long) mprGetCurrentThread();
782}
783
784////////////////////////////////////////////////////////////////////////////////
785
786static void sslStaticLock(int mode, int n, const char *file, int line)
787{
788 mprAssert(0 <= n && n < numLocks);
789 if (mode & CRYPTO_LOCK) {
790 locks[n]->lock();
791 } else {
792 locks[n]->unlock();
793 }
794}
795
796////////////////////////////////////////////////////////////////////////////////
797
798static DynLock *sslCreateDynLock(const char *file, int line)
799{
800 DynLock *dl;
801
802 dl = (DynLock*) mprMalloc(sizeof(DynLock));
803 dl->mutex = new MprMutex();
804 return dl;
805}
806
807////////////////////////////////////////////////////////////////////////////////
808
809static void sslDestroyDynLock(DynLock *dl, const char *file, int line)
810{
811 delete dl->mutex;
812 mprFree(dl);
813}
814
815////////////////////////////////////////////////////////////////////////////////
816
817static void sslDynLock(int mode, DynLock *dl, const char *file, int line)
818{
819 if (mode & CRYPTO_LOCK) {
820 dl->mutex->lock();
821 } else {
822 dl->mutex->unlock();
823 }
824}
825
826#endif // BLD_FEATURE_MULTITHREAD
827////////////////////////////////////////////////////////////////////////////////
828//
829// Used for ephemeral RSA keys
830//
831
832static RSA *rsaCallback(SSL *ssl, int isExport, int keyLength)
833{
834 MaOpenSslSocket *sslSocket;
835 MaOpenSslConfig *config;
836 RSA *key;
837
838 sslSocket = (MaOpenSslSocket*) SSL_get_app_data(ssl);
839 config = (MaOpenSslConfig*) sslSocket->getConfig();
840
841 key = 0;
842 switch (keyLength) {
843 case 512:
844 key = config->rsaKey512;
845 break;
846
847 case 1024:
848 default:
849 key = config->rsaKey1024;
850 }
851 return key;
852}
853
854
855////////////////////////////////////////////////////////////////////////////////
856//
857// Used for ephemeral DH keys
858//
859
860static DH *dhCallback(SSL *ssl, int isExport, int keyLength)
861{
862 MaOpenSslSocket *sslSocket;
863 MaOpenSslConfig *config;
864 DH *key;
865
866 sslSocket = (MaOpenSslSocket*) SSL_get_app_data(ssl);
867 config = (MaOpenSslConfig*) sslSocket->getConfig();
868
869 key = 0;
870 switch (keyLength) {
871 case 512:
872 key = config->dhKey512;
873 break;
874
875 case 1024:
876 default:
877 key = config->dhKey1024;
878 }
879 return key;
880}
881
882////////////////////////////////////////////////////////////////////////////////
883#else
884void mprOpenSslModuleDummy() {}
885
886#endif // BLD_FEATURE_OPENSSL_MODULE
887
888//
889// Local variables:
890// tab-width: 4
891// c-basic-offset: 4
892// End:
893// vim:tw=78
894// vim600: sw=4 ts=4 fdm=marker
895// vim<600: sw=4 ts=4
896//
0897
=== added file 'appWeb/thread.cpp'
--- appWeb/thread.cpp 1970-01-01 00:00:00 +0000
+++ appWeb/thread.cpp 2011-11-23 01:01:25 +0000
@@ -0,0 +1,768 @@
1///
2/// @file WIN/thread.cpp
3/// @brief Primitive multi-threading support for Linux
4/// @overview This module provides threading, mutex and condition
5/// variable APIs for Windows.
6//
7////////////////////////////////// Copyright ///////////////////////////////////
8//
9// @copy default
10//
11// Copyright (c) Mbedthis Software LLC, 2003-2006. All Rights Reserved.
12// Copyright (c) Michael O'Brien, 1994-2006. All Rights Reserved.
13//
14// This software is distributed under commercial and open source licenses.
15// You may use the GPL open source license described below or you may acquire
16// a commercial license from Mbedthis Software. You agree to be fully bound
17// by the terms of either license. Consult the LICENSE.TXT distributed with
18// this software for full details.
19//
20// This software is open source; you can redistribute it and/or modify it
21// under the terms of the GNU General Public License as published by the
22// Free Software Foundation; either version 2 of the License, or (at your
23// option) any later version. See the GNU General Public License for more
24// details at: http://www.mbedthis.com/downloads/gplLicense.html
25//
26// This program is distributed WITHOUT ANY WARRANTY; without even the
27// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
28//
29// This GPL license does NOT permit incorporating this software into
30// proprietary programs. If you are unable to comply with the GPL, you must
31// acquire a commercial license to use this software. Commercial licenses
32// for this software and support services are available from Mbedthis
33// Software at http://www.mbedthis.com
34//
35// @end
36//
37////////////////////////////////// Includes ///////////////////////////////////
38
39#include "mpr/mpr.h"
40
41//////////////////////////////////// Locals ///////////////////////////////////
42#if BLD_FEATURE_MULTITHREAD
43
44#if BLD_DEBUG
45CRITICAL_SECTION debugCs;
46static MprList mutexList;
47static int numMutex = -1; // Must initialize to -1 (see addMutex)
48MprList condList;
49
50#define DEBUG_TIME 0 // Spare[0] == time
51#define DEBUG_ID 1 // Spare[1] == thread id
52#endif
53
54//////////////////////////// Forward Declarations /////////////////////////////
55
56static uint __stdcall threadProcWrapper(void *arg);
57
58#if BLD_DEBUG
59#if UNUSED
60static void lockBuster(void *data, MprThread *tp);
61#endif
62static void removeMutex(MprMutex *mp);
63static void addMutex(MprMutex *mp);
64#endif
65
66///////////////////////////////////// Code ////////////////////////////////////
67//
68// Initialize thread service
69//
70//
71
72MprThreadService::MprThreadService()
73{
74 mutex = new MprMutex();
75
76 //
77 // Don't actually create the thread. Just create a thread object for this
78 // main thread.
79 //
80 mainThread = new MprThread(MPR_NORMAL_PRIORITY, "main");
81 mainThread->setId(GetCurrentThreadId());
82
83 insertThread(mainThread);
84}
85
86///////////////////////////////////////////////////////////////////////////////
87//
88// Terminate the thread service
89//
90
91MprThreadService::~MprThreadService()
92{
93 delete mainThread;
94
95#if BLD_DEBUG
96 if (threads.getNumItems() > 0) {
97 mprError(MPR_L, MPR_LOG, "Exiting with %d thread(s) unfreed",
98 threads.getNumItems());
99 }
100 if (condList.getNumItems() > 0) {
101 mprError(MPR_L, MPR_LOG, "Exiting with %d cond var(s) unfreed",
102 condList.getNumItems());
103 }
104 //
105 // We allow one open mutex for the log service which has not yet shutdown,
106 // and one for the libmpr DLL (malloc), we also need one for our mutex
107 // is freed below.
108 //
109 if (mutexList.getNumItems() > 3) {
110 mprError(MPR_L, MPR_LOG, "Exiting with %d mutex(es) unfreed",
111 mutexList.getNumItems() - 3);
112 }
113#endif
114 delete mutex;
115}
116
117////////////////////////////////////////////////////////////////////////////////
118//
119// Add a thread to the list
120//
121
122void MprThreadService::insertThread(MprThread *tp)
123{
124 lock();
125 threads.insert(tp);
126 unlock();
127}
128
129////////////////////////////////////////////////////////////////////////////////
130//
131// Remove a thread from the list
132//
133
134void MprThreadService::removeThread(MprThread *tp)
135{
136 lock();
137 threads.remove(tp);
138 unlock();
139}
140
141////////////////////////////////////////////////////////////////////////////////
142//
143// Nothing to do
144//
145
146int MprThreadService::start()
147{
148#if BLD_DEBUG && UNUSED
149 MprThread *tp;
150
151 if (!mprGetDebugMode()) {
152 tp = new MprThread(lockBuster, MPR_LOW_PRIORITY, 0, "watch");
153 tp->start();
154 }
155#endif
156 return 0;
157}
158
159////////////////////////////////////////////////////////////////////////////////
160//
161// Nothing to do. We expect the threads to be self terminating.
162//
163
164int MprThreadService::stop(int timeout)
165{
166 //
167 // Wait until all threads (except main thread) have exited
168 //
169 while (threads.getNumItems() > 1 && timeout > 0) {
170 mprSleep(10);
171 timeout -= 10;
172 }
173 return 0;
174}
175
176////////////////////////////////////////////////////////////////////////////////
177//
178// Return the current thread object
179//
180
181MprThread *MprThreadService::getCurrentThread()
182{
183 MprThread *tp;
184 int id;
185
186 lock();
187 id = (int) GetCurrentThreadId();
188 tp = (MprThread*) threads.getFirst();
189 while (tp) {
190 if (tp->getId() == id) {
191 unlock();
192 return tp;
193 }
194 tp = (MprThread*) threads.getNext(tp);
195 }
196 unlock();
197 return 0;
198}
199
200////////////////////////////////////////////////////////////////////////////////
201////////////////////////////////// MprThread ///////////////////////////////////
202////////////////////////////////////////////////////////////////////////////////
203//
204// Create a main thread
205//
206
207MprThread::MprThread(int priority, char *name)
208{
209 osThreadId = 0;
210 pid = getpid();
211 threadHandle = 0;
212 this->priority = priority;
213 entry = 0;
214 data = 0;
215 this->name = mprStrdup(name);
216
217 mutex = new MprMutex();
218 //
219 // Inserted into the thread list in MprThreadService()
220 //
221}
222
223////////////////////////////////////////////////////////////////////////////////
224//
225// Create a thread
226//
227
228MprThread::MprThread(MprThreadProc entry, int priority, void *data,
229 char *name, int stackSize)
230{
231 osThreadId = 0;
232 pid = getpid();
233 threadHandle = 0;
234 this->priority = priority;
235 this->entry = entry;
236 this->data = data;
237 this->name = mprStrdup(name);
238
239 mutex = new MprMutex();
240 mpr->threadService->insertThread(this);
241}
242
243////////////////////////////////////////////////////////////////////////////////
244//
245// Destroy a thread
246//
247
248MprThread::~MprThread()
249{
250 lock();
251 mprLog(MPR_INFO, "Thread exiting %s (%x)\n", name, osThreadId);
252
253 mpr->threadService->removeThread(this);
254 mprFree(name);
255 if (threadHandle) {
256 CloseHandle(threadHandle);
257 }
258 delete mutex;
259}
260
261////////////////////////////////////////////////////////////////////////////////
262//
263// Start a thread
264//
265
266int MprThread::start()
267{
268 HANDLE h;
269 uint threadId;
270
271 lock();
272 h = (HANDLE) _beginthreadex(NULL, 0, threadProcWrapper, (void*) this,
273 0, &threadId);
274 if (h == NULL) {
275 unlock();
276 return MPR_ERR_CANT_INITIALIZE;
277 }
278 osThreadId = (ulong) threadId;
279 threadHandle = (HANDLE) h;
280
281 setPriority(priority);
282 mprLog(MPR_INFO, "Created thread %s (%x)\n", name, threadId);
283 unlock();
284 return 0;
285}
286
287////////////////////////////////////////////////////////////////////////////////
288//
289// Thread entry function
290//
291
292static uint __stdcall threadProcWrapper(void *data)
293{
294//AFF gracefull crash, main app should exit
295#if BLD_DEBUG
296#else
297 try
298 {
299#endif
300 MprThread *tp;
301
302 tp = (MprThread*) data;
303 tp->threadProc();
304 delete tp;
305
306#if BLD_DEBUG
307#else
308 }
309 catch(...)
310 {
311 mprLog((char*)"ERROR: catch(...) threadProcWrapper crashed. terminating gracefully...");
312 mprGetMpr()->terminate(1);
313 }
314#endif
315
316 return 0;
317}
318
319////////////////////////////////////////////////////////////////////////////////
320//
321// Thread procedure
322//
323
324void MprThread::threadProc()
325{
326 osThreadId = GetCurrentThreadId();
327 pid = getpid();
328 (entry)(data, this);
329}
330
331////////////////////////////////////////////////////////////////////////////////
332
333void MprThread::setPriority(int newPriority)
334{
335 int osPri;
336
337 lock();
338 if (priority == newPriority) {
339 unlock();
340 return;
341 }
342
343 osPri = mapMprPriorityToOs(newPriority);
344 SetThreadPriority(threadHandle, osPri);
345 priority = newPriority;
346 unlock();
347}
348
349////////////////////////////////////////////////////////////////////////////////
350
351void MprThread::setId(int id)
352{
353 osThreadId = (ulong) id;
354}
355
356////////////////////////////////////////////////////////////////////////////////
357//
358// Map Mpr priority to Windows native priority. Windows priorities range from
359// -15 to +15 (zero is normal). Warning: +15 will not yield the CPU, -15 may
360// get starved. We should be very wary going above +11.
361//
362
363int MprThread::mapMprPriorityToOs(int mprPriority)
364{
365 mprAssert(mprPriority >= 0 && mprPriority <= 100);
366
367 if (mprPriority <= MPR_BACKGROUND_PRIORITY) {
368 return THREAD_PRIORITY_LOWEST;
369 } else if (mprPriority <= MPR_LOW_PRIORITY) {
370 return THREAD_PRIORITY_BELOW_NORMAL;
371 } else if (mprPriority <= MPR_NORMAL_PRIORITY) {
372 return THREAD_PRIORITY_NORMAL;
373 } else if (mprPriority <= MPR_HIGH_PRIORITY) {
374 return THREAD_PRIORITY_ABOVE_NORMAL;
375 } else {
376 return THREAD_PRIORITY_HIGHEST;
377 }
378}
379
380///////////////////////////////////////////////////////////////////////////////
381//
382// Map Windows priority to Mpr priority
383//
384
385int MprThread::mapOsPriorityToMpr(int nativePriority)
386{
387 int priority;
388
389 priority = (45 * nativePriority) + 50;
390 if (priority < 0) {
391 priority = 0;
392 }
393 if (priority >= 100) {
394 priority = 99;
395 }
396 return priority;
397}
398
399////////////////////////////////////////////////////////////////////////////////
400/////////////////////////////////// MprMutex ///////////////////////////////////
401////////////////////////////////////////////////////////////////////////////////
402//
403// Create a mutex
404//
405
406MprMutex::MprMutex()
407{
408 memset(&cs, 0, sizeof(cs));
409 InitializeCriticalSectionAndSpinCount(&cs, 5000);
410
411#if BLD_DEBUG
412 addMutex(this);
413 cs.DebugInfo->Spare[DEBUG_ID] = -1; // Thread ID goes here
414 cs.DebugInfo->Spare[DEBUG_TIME] = 0; // Time goes here
415#endif
416}
417
418///////////////////////////////////////////////////////////////////////////////
419//
420// Destroy a mutex. Must be locked on entrance.
421//
422
423MprMutex::~MprMutex()
424{
425 DeleteCriticalSection(&cs);
426#if BLD_DEBUG
427 removeMutex(this);
428#endif
429}
430
431///////////////////////////////////////////////////////////////////////////////
432//
433// Lock a mutex
434//
435
436void MprMutex::lock()
437{
438 EnterCriticalSection(&cs);
439
440#if BLD_DEBUG
441 mprAssert(cs.RecursionCount >= 0);
442 mprAssert(cs.RecursionCount < MPR_MAX_RECURSION);
443 mprAssert(cs.LockCount < MPR_MAX_BLOCKED_LOCKS);
444
445 cs.DebugInfo->Spare[DEBUG_ID] = (ulong) GetCurrentThreadId();
446 cs.DebugInfo->Spare[DEBUG_TIME] = GetTickCount();
447#endif
448}
449
450///////////////////////////////////////////////////////////////////////////////
451//
452// Try to lock a mutex. Do not block!
453//
454
455int MprMutex::tryLock()
456{
457 mprAssert(cs.RecursionCount >= 0);
458 if (TryEnterCriticalSection(&cs) == 0) {
459 return MPR_ERR_BUSY;
460 }
461#if BLD_DEBUG
462 cs.DebugInfo->Spare[DEBUG_ID] = (ulong) GetCurrentThreadId();
463 cs.DebugInfo->Spare[DEBUG_TIME] = GetTickCount();
464#endif
465 return 0;
466}
467
468///////////////////////////////////////////////////////////////////////////////
469//
470// Unlock a mutex. structure
471//
472
473void MprMutex::unlock()
474{
475#if BLD_DEBUG
476 mprAssert(cs.DebugInfo->Spare[DEBUG_ID] == (ulong) GetCurrentThreadId());
477 mprAssert(cs.RecursionCount > 0);
478 mprAssert(cs.RecursionCount < MPR_MAX_RECURSION);
479 mprAssert(cs.LockCount < MPR_MAX_LOCKS);
480 cs.DebugInfo->Spare[DEBUG_TIME] = GetTickCount();
481#endif
482 LeaveCriticalSection(&cs);
483}
484
485///////////////////////////////////////////////////////////////////////////////
486/////////////////////////////////// MprCond ////////////////////////////////////
487////////////////////////////////////////////////////////////////////////////////
488//
489// Create a condition variable for use by single or multiple waiters
490//
491
492MprCond::MprCond()
493{
494#if UNUSED
495 wakeAll = 0;
496 numWaiting = 0;
497#endif
498 triggered = 0;
499 mutex = new MprMutex();
500 cv = CreateEvent(NULL, FALSE, FALSE, NULL);
501}
502
503
504////////////////////////////////////////////////////////////////////////////////
505//
506// Destroy a condition variable
507//
508
509MprCond::~MprCond()
510{
511 mutex->lock();
512 CloseHandle(cv);
513 delete mutex;
514}
515
516////////////////////////////////////////////////////////////////////////////////
517//
518// Wait for the event to be triggered. Should only be used when there are
519// single waiters. If the event is already triggered, then it will return
520// immediately.
521//
522
523int MprCond::waitForCond(long timeout)
524{
525 if (timeout < 0) {
526 timeout = MAXINT;
527 }
528
529 if (WaitForSingleObject(cv, timeout) != WAIT_OBJECT_0) {
530 return -1;
531 }
532
533 //
534 // Reset the event
535 //
536 mutex->lock();
537 mprAssert(triggered != 0);
538 triggered = 0;
539 ResetEvent(cv);
540 mutex->unlock();
541
542 return 0;
543}
544
545////////////////////////////////////////////////////////////////////////////////
546#if UNUSED
547//
548// Wait for a condition variable to be signalled. Suitable for when there are
549// multiple waiters. It will work for single waiters, but is slower than
550// waitForCond() above. Depending on whether signalCond() or signalAll() is
551// used, a single waiter or multiple waiters may awake with one invocation of
552// signal. If the condition is already triggered, this routine will not block
553// for the first waiter. NOTE: the externalMutex must be defined and locked on
554// entry to this routine
555//
556
557int MprCond::multiWait(MprMutex *externalMutex, long timeout)
558{
559 int now, deadline;
560
561 if (timeout < 0) {
562 timeout = MAXINT;
563 }
564 now = mprGetTime(0);
565 deadline = now + timeout;
566
567 while (now <= deadline) {
568 mutex->lock();
569 numWaiting++;
570 mutex->unlock();
571
572 externalMutex->unlock();
573
574 if (WaitForSingleObject(cv, timeout) != WAIT_OBJECT_0) {
575 return -1;
576 }
577
578 mutex->lock();
579 --numWaiting;
580 if (wakeAll) {
581 //
582 // Last thread to awake must reset the event
583 //
584 if (numWaiting == 0) {
585 wakeAll = 0;
586 ResetEvent(cv);
587 }
588 mutex->unlock();
589 break;
590 }
591 if (triggered) {
592 triggered = 0;
593 ResetEvent(cv);
594 mutex->unlock();
595 break;
596 }
597 mutex->unlock();
598 now = mprGetTime(0);
599 }
600 externalMutex->lock();
601 return 0;
602}
603
604#endif
605////////////////////////////////////////////////////////////////////////////////
606//
607// Signal a condition and wakeup the waiter. Note: this may be called
608// prior to the waiter waiting.
609//
610
611void MprCond::signalCond()
612{
613 mutex->lock();
614 triggered = 1;
615#if UNUSED
616 wakeAll = 0;
617#endif
618 SetEvent(cv);
619 mutex->unlock();
620}
621
622///////////////////////////////////////////////////////////////////////////////
623#if UNUSED
624//
625// Signal all waiters. Note: this may be called prior to anyone waiting.
626//
627
628void MprCond::signalAll()
629{
630 mutex->lock();
631 triggered = 1;
632#if UNUSED
633 wakeAll = 1;
634#endif
635 SetEvent(cv);
636 mutex->unlock();
637}
638
639///////////////////////////////////////////////////////////////////////////////
640//
641// Use very carefully when you really know what you are doing. More dangerous
642// than it looks
643//
644
645void MprCond::reset()
646{
647 mutex->lock();
648 triggered = 0;
649#if UNUSED
650 wakeAll = 0;
651#endif
652 ResetEvent(cv);
653 mutex->unlock();
654}
655
656#endif
657///////////////////////////////////////////////////////////////////////////////
658////////////////////////////////////// Debug //////////////////////////////////
659///////////////////////////////////////////////////////////////////////////////
660#if BLD_DEBUG
661#if UNUSED
662
663static void lockBuster(void *data, MprThread *tp)
664{
665 MprMutex *mp;
666 int duration;
667 uint tid, whenLocked, ticks;
668
669 tid = (int) GetCurrentThreadId();
670 while (! mpr->isExiting()) {
671 if (numMutex > MPR_MAX_LOCKS) {
672 mprError(MPR_L, MPR_LOG, "Too many mutexes");
673 }
674
675 mp = (MprMutex*) mutexList.getFirst();
676 while (mp) {
677 whenLocked = mp->cs.DebugInfo->Spare[DEBUG_TIME];
678
679 if (mp->cs.RecursionCount > 0) {
680 ticks = GetTickCount();
681 if (ticks < whenLocked) {
682 duration = 0xFFFFFFFF - whenLocked + 1 + ticks;
683 } else {
684 duration = ticks - whenLocked;
685 }
686 if (duration > MPR_MAX_LOCK_TIME) {
687 mprError(MPR_L, MPR_LOG, "Mutex held too long");
688 // FUTURE -- could bust the lock here ... mp->unlock();
689 }
690 }
691 mp = (MprMutex*) mutexList.getNext(&mp->link);
692 }
693 mprSleep(500);
694 }
695}
696
697#endif // UNUSED
698///////////////////////////////////////////////////////////////////////////////
699//
700// Add this mutex to the list
701//
702
703static void addMutex(MprMutex *mp)
704{
705 //
706 // First time initialization
707 //
708 if (numMutex < 0) {
709 memset(&debugCs, 0, sizeof(debugCs));
710 InitializeCriticalSectionAndSpinCount(&debugCs, 4000);
711 }
712 EnterCriticalSection(&debugCs);
713 mutexList.insert(&mp->link);
714 numMutex++;
715 LeaveCriticalSection(&debugCs);
716}
717
718///////////////////////////////////////////////////////////////////////////////
719//
720// Remove this mutex from the list
721//
722
723static void removeMutex(MprMutex *mp)
724{
725 EnterCriticalSection(&debugCs);
726 numMutex--;
727 mutexList.remove(&mp->link);
728 LeaveCriticalSection(&debugCs);
729}
730
731///////////////////////////////////////////////////////////////////////////////
732//
733// Return the number of mutexes owned by this thread
734//
735
736int MprDebug::getMutexNum()
737{
738 MprMutex *mp;
739 int num;
740 uint tid;
741
742 tid = (uint) GetCurrentThreadId();
743
744 num = 0;
745 mp = (MprMutex*) mutexList.getFirst();
746 while (mp) {
747
748 if (mp->cs.DebugInfo->Spare[DEBUG_ID] == tid) {
749 num++;
750 }
751 mp = (MprMutex*) mutexList.getNext(&mp->link);
752 }
753 return num;
754}
755
756#endif // BLD_DEBUG
757#endif // BLD_FEATURE_MULTITHREAD
758///////////////////////////////////////////////////////////////////////////////
759
760//
761// Local variables:
762// tab-width: 4
763// c-basic-offset: 4
764// End:
765// vim:tw=78
766// vim600: sw=4 ts=4 fdm=marker
767// vim<600: sw=4 ts=4
768//
0769
=== added file 'appweb.cnf'
--- appweb.cnf 1970-01-01 00:00:00 +0000
+++ appweb.cnf 2011-11-23 01:01:25 +0000
@@ -0,0 +1,27 @@
1ServerRoot "."
2DocumentRoot "."
3
4LoadModulePath $SERVER_ROOT
5
6LoadModule psiphonHandler libpsiphonHandler
7LoadModule ssl libsslModule
8LoadModule openSsl libopenSslModule
9
10ThreadLimit 100
11KeepAlive on
12
13<VirtualHost *:*>
14 AddHandler psiphonHandler
15 DocumentRoot "."
16 SSLEngine on
17 SSLCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNULL
18 SSLProtocol ALL -SSLV2
19
20 SSLCertificateFile "$SERVER_ROOT/cert.pem"
21 SSLCertificateKeyFile "$SERVER_ROOT/key.pem"
22
23 <Location />
24 HttpChunking off
25 SetHandler psiphonHandler
26 </Location>
27</VirtualHost>
028
=== added file 'bake-w32.bat'
--- bake-w32.bat 1970-01-01 00:00:00 +0000
+++ bake-w32.bat 2011-11-23 01:01:25 +0000
@@ -0,0 +1,1 @@
1bakefile -f msvc6prj psiphon.bkl
0\ No newline at end of file2\ No newline at end of file
13
=== added file 'changes.txt'
--- changes.txt 1970-01-01 00:00:00 +0000
+++ changes.txt 2011-11-23 01:01:25 +0000
@@ -0,0 +1,99 @@
1-------------------------------------------
2Changes in version 1.6 (09 Mar 2007)
3- added fingerprint to SSL certificate page
4- added update downloading
5- minor code revisions
6
7-------------------------------------------
8Changes in version 1.5 (09 Feb 2007)
9
10- fixed '100% CPU usage' bug
11- added psiphon will find available port if 443 is not
12- added double click on a link in the log window opens it in default browser
13- added column sorting
14- added status icons
15- added choise for "Get My IP" server
16- added SLL country combo sorting
17- changed System Tray icon to be always available
18- minor GUI revisions
19- minor code revisions
20
21-------------------------------------------
22Changes in version 1.4 (26 Jan 2007)
23
24- added minimize to task bar
25- added single bakefile file for both platforms(WIN, LINUX)
26- added detailed build instructions for both platforms
27- fixed compatibility with Shaw Secure
28- improved HTML entities decoding
29- minor code revisions
30
31-------------------------------------------
32Changes in version 1.3 (29 Dec 2006)
33
34Added:
35- HTML entities decoding in the HTML filter
36
37Changed:
38- Improved CSS filtering
39
40- Improved error handling
41
42- Limited user input
43
44- Delete user related info when delete user
45
46- Password overwrite bug fixed
47
48- Switched to prepared SQL statements throughout the code
49
50- Minor code revisions
51
52-------------------------------------------
53Changes in version 1.2 (15 Dec 2006)
54
55Added:
56- Custom SSL certificate
57
58- Log level persistence
59
60- Log can be disabled
61
62Changed:
63- Image on/off handling through "Javascript:void(0);" in order to avoid extra HTTP requests
64
65- Updated wxWidgets framework to 2.8
66
67- Updated Advanced Installer to 4.6
68
69- Fixed several buffer overflow vulnerabilities
70
71-------------------------------------------
72Changes in version 1.1 (8 Dec 2006)
73
74Added:
75- psiphon access is forbidden (HTTP 403) to domains that resolve to localhost or
76 private network
77
78- Multiple network interface cards support
79
80- Our own external IP detection service
81
82- Version check on startup
83
84- Users can toggle images on/off in the blue bar
85
86Changed:
87- URLs in HTTP requests to psiphon must be prepended with psiphonode name
88 set by psiphon admin at setup, i.e. https://<IP>:<port>/<psiphonode>/login/..,
89 https://<IP>:<port>/<psiphonode>/fetch/.. etc.
90
91- Replacement tags (<%varname%>) added in HTML templates.
92
93- wxWidgets HTTP headers are replaced with generic headers
94
95- New database design in order to minimize SQLite locking
96
97- GUI changes
98
99- Minor bug fixes
0\ No newline at end of file100\ No newline at end of file
1101
=== added directory 'common'
=== added file 'common/CppSQLite3.cpp'
--- common/CppSQLite3.cpp 1970-01-01 00:00:00 +0000
+++ common/CppSQLite3.cpp 2011-11-23 01:01:25 +0000
@@ -0,0 +1,1383 @@
1////////////////////////////////////////////////////////////////////////////////
2// CppSQLite3 - A C++ wrapper around the SQLite3 embedded database library.
3//
4// Copyright (c) 2004 Rob Groves. All Rights Reserved. rob.groves@btinternet.com
5//
6// Permission to use, copy, modify, and distribute this software and its
7// documentation for any purpose, without fee, and without a written
8// agreement, is hereby granted, provided that the above copyright notice,
9// this paragraph and the following two paragraphs appear in all copies,
10// modifications, and distributions.
11//
12// IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT,
13// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST
14// PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION,
15// EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16//
17// THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
19// PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF
20// ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". THE AUTHOR HAS NO OBLIGATION
21// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
22//
23// V3.0 03/08/2004 -Initial Version for sqlite3
24//
25// V3.1 16/09/2004 -Implemented getXXXXField using sqlite3 functions
26// -Added CppSQLiteDB3::tableExists()
27////////////////////////////////////////////////////////////////////////////////
28#include "CppSQLite3.h"
29#include <cstdlib>
30
31// Named constant for passing to CppSQLite3Exception when passing it a string
32// that cannot be deleted.
33static const bool DONT_DELETE_MSG = false;
34
35////////////////////////////////////////////////////////////////////////////////
36// Prototypes for SQLite functions not included in SQLite DLL, but copied below
37// from SQLite encode.c
38////////////////////////////////////////////////////////////////////////////////
39int sqlite3_encode_binary(const unsigned char* in, int n, unsigned char* out);
40int sqlite3_decode_binary(const unsigned char* in, unsigned char* out);
41
42////////////////////////////////////////////////////////////////////////////////
43
44////////////////////////////////////////////////////////////////////////////////
45
46CppSQLite3Exception::CppSQLite3Exception(const int nErrCode, char* szErrMess, bool bDeleteMsg/*=true*/) : mnErrCode(nErrCode)
47{
48 mpszErrMess = sqlite3_mprintf("%s[%d]: %s", errorCodeAsString(nErrCode), nErrCode, szErrMess ? szErrMess : "");
49
50 if(bDeleteMsg && szErrMess)
51 {
52 sqlite3_free(szErrMess);
53 }
54}
55
56CppSQLite3Exception::CppSQLite3Exception(const CppSQLite3Exception& e) : mnErrCode(e.mnErrCode)
57{
58 mpszErrMess = 0;
59 if(e.mpszErrMess)
60 {
61 mpszErrMess = sqlite3_mprintf("%s", e.mpszErrMess);
62 }
63}
64
65const char* CppSQLite3Exception::errorCodeAsString(int nErrCode)
66{
67 switch(nErrCode)
68 {
69 case SQLITE_OK :
70 return "SQLITE_OK";
71 case SQLITE_ERROR :
72 return "SQLITE_ERROR";
73 case SQLITE_INTERNAL :
74 return "SQLITE_INTERNAL";
75 case SQLITE_PERM :
76 return "SQLITE_PERM";
77 case SQLITE_ABORT :
78 return "SQLITE_ABORT";
79 case SQLITE_BUSY :
80 return "SQLITE_BUSY";
81 case SQLITE_LOCKED :
82 return "SQLITE_LOCKED";
83 case SQLITE_NOMEM :
84 return "SQLITE_NOMEM";
85 case SQLITE_READONLY :
86 return "SQLITE_READONLY";
87 case SQLITE_INTERRUPT :
88 return "SQLITE_INTERRUPT";
89 case SQLITE_IOERR :
90 return "SQLITE_IOERR";
91 case SQLITE_CORRUPT :
92 return "SQLITE_CORRUPT";
93 case SQLITE_NOTFOUND :
94 return "SQLITE_NOTFOUND";
95 case SQLITE_FULL :
96 return "SQLITE_FULL";
97 case SQLITE_CANTOPEN :
98 return "SQLITE_CANTOPEN";
99 case SQLITE_PROTOCOL :
100 return "SQLITE_PROTOCOL";
101 case SQLITE_EMPTY :
102 return "SQLITE_EMPTY";
103 case SQLITE_SCHEMA :
104 return "SQLITE_SCHEMA";
105 case SQLITE_TOOBIG :
106 return "SQLITE_TOOBIG";
107 case SQLITE_CONSTRAINT :
108 return "SQLITE_CONSTRAINT";
109 case SQLITE_MISMATCH :
110 return "SQLITE_MISMATCH";
111 case SQLITE_MISUSE :
112 return "SQLITE_MISUSE";
113 case SQLITE_NOLFS :
114 return "SQLITE_NOLFS";
115 case SQLITE_AUTH :
116 return "SQLITE_AUTH";
117 case SQLITE_FORMAT :
118 return "SQLITE_FORMAT";
119 case SQLITE_RANGE :
120 return "SQLITE_RANGE";
121 case SQLITE_ROW :
122 return "SQLITE_ROW";
123 case SQLITE_DONE :
124 return "SQLITE_DONE";
125 case CPPSQLITE_ERROR :
126 return "CPPSQLITE_ERROR";
127 default:
128 return "UNKNOWN_ERROR";
129 }
130}
131
132CppSQLite3Exception::~CppSQLite3Exception()
133{
134 if(mpszErrMess)
135 {
136 sqlite3_free(mpszErrMess);
137 mpszErrMess = 0;
138 }
139}
140
141////////////////////////////////////////////////////////////////////////////////
142
143CppSQLite3Buffer::CppSQLite3Buffer()
144{
145 mpBuf = 0;
146}
147
148CppSQLite3Buffer::~CppSQLite3Buffer()
149{
150 clear();
151}
152
153void CppSQLite3Buffer::clear()
154{
155 if(mpBuf)
156 {
157 sqlite3_free(mpBuf);
158 mpBuf = 0;
159 }
160}
161
162const char* CppSQLite3Buffer::format(const char* szFormat, ...)
163{
164 clear();
165 va_list va;
166 va_start(va, szFormat);
167 mpBuf = sqlite3_vmprintf(szFormat, va);
168 va_end(va);
169 return mpBuf;
170}
171
172////////////////////////////////////////////////////////////////////////////////
173
174CppSQLite3Binary::CppSQLite3Binary() : mpBuf(0), mnBinaryLen(0), mnBufferLen(0), mnEncodedLen(0), mbEncoded(false)
175{
176}
177
178CppSQLite3Binary::~CppSQLite3Binary()
179{
180 clear();
181}
182
183void CppSQLite3Binary::setBinary(const unsigned char* pBuf, int nLen)
184{
185 mpBuf = allocBuffer(nLen);
186 memcpy(mpBuf, pBuf, nLen);
187}
188
189void CppSQLite3Binary::setEncoded(const unsigned char* pBuf)
190{
191 clear();
192
193 mnEncodedLen = strlen((const char*)pBuf);
194 mnBufferLen = mnEncodedLen + 1; // Allow for NULL terminator
195
196 mpBuf = (unsigned char*)malloc(mnBufferLen);
197
198 if(!mpBuf)
199 {
200 throw CppSQLite3Exception(CPPSQLITE_ERROR, "Cannot allocate memory", DONT_DELETE_MSG);
201 }
202
203 memcpy(mpBuf, pBuf, mnBufferLen);
204 mbEncoded = true;
205}
206
207const unsigned char* CppSQLite3Binary::getEncoded()
208{
209 if(!mbEncoded)
210 {
211 unsigned char* ptmp = (unsigned char*)malloc(mnBinaryLen);
212 memcpy(ptmp, mpBuf, mnBinaryLen);
213 mnEncodedLen = sqlite3_encode_binary(ptmp, mnBinaryLen, mpBuf);
214 free(ptmp);
215 mbEncoded = true;
216 }
217
218 return mpBuf;
219}
220
221const unsigned char* CppSQLite3Binary::getBinary()
222{
223 if(mbEncoded)
224 {
225 // in/out buffers can be the same
226 mnBinaryLen = sqlite3_decode_binary(mpBuf, mpBuf);
227
228 if(mnBinaryLen == -1)
229 {
230 throw CppSQLite3Exception(CPPSQLITE_ERROR, "Cannot decode binary", DONT_DELETE_MSG);
231 }
232
233 mbEncoded = false;
234 }
235
236 return mpBuf;
237}
238
239int CppSQLite3Binary::getBinaryLength()
240{
241 getBinary();
242 return mnBinaryLen;
243}
244
245unsigned char* CppSQLite3Binary::allocBuffer(int nLen)
246{
247 clear();
248
249 // Allow extra space for encoded binary as per comments in
250 // SQLite encode.c See bottom of this file for implementation
251 // of SQLite functions use 3 instead of 2 just to be sure ;-)
252 mnBinaryLen = nLen;
253 mnBufferLen = 3 + (257 * nLen) / 254;
254
255 mpBuf = (unsigned char*)malloc(mnBufferLen);
256
257 if(!mpBuf)
258 {
259 throw CppSQLite3Exception(CPPSQLITE_ERROR, "Cannot allocate memory", DONT_DELETE_MSG);
260 }
261
262 mbEncoded = false;
263
264 return mpBuf;
265}
266
267void CppSQLite3Binary::clear()
268{
269 if(mpBuf)
270 {
271 mnBinaryLen = 0;
272 mnBufferLen = 0;
273 free(mpBuf);
274 mpBuf = 0;
275 }
276}
277
278////////////////////////////////////////////////////////////////////////////////
279
280CppSQLite3Query::CppSQLite3Query()
281{
282 mpVM = 0;
283 mbEof = true;
284 mnCols = 0;
285 mbOwnVM = false;
286}
287
288CppSQLite3Query::CppSQLite3Query(const CppSQLite3Query& rQuery)
289{
290 mpVM = rQuery.mpVM;
291 // Only one object can own the VM
292 const_cast<CppSQLite3Query&>(rQuery).mpVM = 0;
293 mbEof = rQuery.mbEof;
294 mnCols = rQuery.mnCols;
295 mbOwnVM = rQuery.mbOwnVM;
296}
297
298CppSQLite3Query::CppSQLite3Query(sqlite3* pDB, sqlite3_stmt* pVM, bool bEof, bool bOwnVM/*=true*/)
299{
300 mpDB = pDB;
301 mpVM = pVM;
302 mbEof = bEof;
303 mnCols = sqlite3_column_count(mpVM);
304 mbOwnVM = bOwnVM;
305}
306
307CppSQLite3Query::~CppSQLite3Query()
308{
309 try
310 {
311 finalize();
312 }
313 catch(...)
314 {
315 }
316}
317
318CppSQLite3Query& CppSQLite3Query::operator=(const CppSQLite3Query& rQuery)
319{
320 try
321 {
322 finalize();
323 }
324 catch(...)
325 {
326 }
327 mpVM = rQuery.mpVM;
328 // Only one object can own the VM
329 const_cast<CppSQLite3Query&>(rQuery).mpVM = 0;
330 mbEof = rQuery.mbEof;
331 mnCols = rQuery.mnCols;
332 mbOwnVM = rQuery.mbOwnVM;
333 return *this;
334}
335
336int CppSQLite3Query::numFields()
337{
338 checkVM();
339 return mnCols;
340}
341
342const char* CppSQLite3Query::fieldValue(int nField)
343{
344 checkVM();
345
346 if(nField < 0 || nField > mnCols - 1)
347 {
348 throw CppSQLite3Exception(CPPSQLITE_ERROR, "Invalid field index requested", DONT_DELETE_MSG);
349 }
350
351 return (const char*)sqlite3_column_text(mpVM, nField);
352}
353
354const char* CppSQLite3Query::fieldValue(const char* szField)
355{
356 int nField = fieldIndex(szField);
357 return (const char*)sqlite3_column_text(mpVM, nField);
358}
359
360int CppSQLite3Query::getIntField(int nField, int nNullValue/*=0*/)
361{
362 if(fieldDataType(nField) == SQLITE_NULL)
363 {
364 return nNullValue;
365 }
366 else
367 {
368 return sqlite3_column_int(mpVM, nField);
369 }
370}
371
372int CppSQLite3Query::getIntField(const char* szField, int nNullValue/*=0*/)
373{
374 int nField = fieldIndex(szField);
375 return getIntField(nField, nNullValue);
376}
377
378double CppSQLite3Query::getFloatField(int nField, double fNullValue/*=0.0*/)
379{
380 if(fieldDataType(nField) == SQLITE_NULL)
381 {
382 return fNullValue;
383 }
384 else
385 {
386 return sqlite3_column_double(mpVM, nField);
387 }
388}
389
390double CppSQLite3Query::getFloatField(const char* szField, double fNullValue/*=0.0*/)
391{
392 int nField = fieldIndex(szField);
393 return getFloatField(nField, fNullValue);
394}
395
396const char* CppSQLite3Query::getStringField(int nField, const char* szNullValue/*=""*/)
397{
398 if(fieldDataType(nField) == SQLITE_NULL)
399 {
400 return szNullValue;
401 }
402 else
403 {
404 return (const char*)sqlite3_column_text(mpVM, nField);
405 }
406}
407
408const char* CppSQLite3Query::getStringField(const char* szField, const char* szNullValue/*=""*/)
409{
410 int nField = fieldIndex(szField);
411 return getStringField(nField, szNullValue);
412}
413
414const unsigned char* CppSQLite3Query::getBlobField(int nField, int& nLen)
415{
416 checkVM();
417
418 if(nField < 0 || nField > mnCols - 1)
419 {
420 throw CppSQLite3Exception(CPPSQLITE_ERROR, "Invalid field index requested", DONT_DELETE_MSG);
421 }
422
423 nLen = sqlite3_column_bytes(mpVM, nField);
424 return (const unsigned char*)sqlite3_column_blob(mpVM, nField);
425}
426
427const unsigned char* CppSQLite3Query::getBlobField(const char* szField, int& nLen)
428{
429 int nField = fieldIndex(szField);
430 return getBlobField(nField, nLen);
431}
432
433bool CppSQLite3Query::fieldIsNull(int nField)
434{
435 return (fieldDataType(nField) == SQLITE_NULL);
436}
437
438bool CppSQLite3Query::fieldIsNull(const char* szField)
439{
440 int nField = fieldIndex(szField);
441 return (fieldDataType(nField) == SQLITE_NULL);
442}
443
444int CppSQLite3Query::fieldIndex(const char* szField)
445{
446 checkVM();
447
448 if(szField)
449 {
450 for(int nField = 0;nField < mnCols;nField++)
451 {
452 const char* szTemp = sqlite3_column_name(mpVM, nField);
453
454 if(strcmp(szField, szTemp) == 0)
455 {
456 return nField;
457 }
458 }
459 }
460
461 throw CppSQLite3Exception(CPPSQLITE_ERROR, "Invalid field name requested", DONT_DELETE_MSG);
462}
463
464const char* CppSQLite3Query::fieldName(int nCol)
465{
466 checkVM();
467
468 if(nCol < 0 || nCol > mnCols - 1)
469 {
470 throw CppSQLite3Exception(CPPSQLITE_ERROR, "Invalid field index requested", DONT_DELETE_MSG);
471 }
472
473 return sqlite3_column_name(mpVM, nCol);
474}
475
476const char* CppSQLite3Query::fieldDeclType(int nCol)
477{
478 checkVM();
479
480 if(nCol < 0 || nCol > mnCols - 1)
481 {
482 throw CppSQLite3Exception(CPPSQLITE_ERROR, "Invalid field index requested", DONT_DELETE_MSG);
483 }
484
485 return sqlite3_column_decltype(mpVM, nCol);
486}
487
488int CppSQLite3Query::fieldDataType(int nCol)
489{
490 checkVM();
491
492 if(nCol < 0 || nCol > mnCols - 1)
493 {
494 throw CppSQLite3Exception(CPPSQLITE_ERROR, "Invalid field index requested", DONT_DELETE_MSG);
495 }
496
497 return sqlite3_column_type(mpVM, nCol);
498}
499
500bool CppSQLite3Query::eof()
501{
502 checkVM();
503 return mbEof;
504}
505
506void CppSQLite3Query::nextRow()
507{
508 checkVM();
509
510 int nRet = sqlite3_step(mpVM);
511
512 if(nRet == SQLITE_DONE)
513 {
514 // no rows
515 mbEof = true;
516 }
517 else if(nRet == SQLITE_ROW)
518 {
519 // more rows, nothing to do
520 }
521 else
522 {
523 nRet = sqlite3_finalize(mpVM);
524 mpVM = 0;
525 const char* szError = sqlite3_errmsg(mpDB);
526 throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG);
527 }
528}
529
530void CppSQLite3Query::finalize()
531{
532 if(mpVM && mbOwnVM)
533 {
534 int nRet = sqlite3_finalize(mpVM);
535 mpVM = 0;
536 if(nRet != SQLITE_OK)
537 {
538 const char* szError = sqlite3_errmsg(mpDB);
539 throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG);
540 }
541 }
542}
543
544void CppSQLite3Query::checkVM()
545{
546 if(mpVM == 0)
547 {
548 throw CppSQLite3Exception(CPPSQLITE_ERROR, "Null Virtual Machine pointer", DONT_DELETE_MSG);
549 }
550}
551
552////////////////////////////////////////////////////////////////////////////////
553
554CppSQLite3Table::CppSQLite3Table()
555{
556 mpaszResults = 0;
557 mnRows = 0;
558 mnCols = 0;
559 mnCurrentRow = 0;
560}
561
562CppSQLite3Table::CppSQLite3Table(const CppSQLite3Table& rTable)
563{
564 mpaszResults = rTable.mpaszResults;
565 // Only one object can own the results
566 const_cast<CppSQLite3Table&>(rTable).mpaszResults = 0;
567 mnRows = rTable.mnRows;
568 mnCols = rTable.mnCols;
569 mnCurrentRow = rTable.mnCurrentRow;
570}
571
572CppSQLite3Table::CppSQLite3Table(char** paszResults, int nRows, int nCols)
573{
574 mpaszResults = paszResults;
575 mnRows = nRows;
576 mnCols = nCols;
577 mnCurrentRow = 0;
578}
579
580CppSQLite3Table::~CppSQLite3Table()
581{
582 try
583 {
584 finalize();
585 }
586 catch(...)
587 {
588 }
589}
590
591CppSQLite3Table& CppSQLite3Table::operator=(const CppSQLite3Table& rTable)
592{
593 try
594 {
595 finalize();
596 }
597 catch(...)
598 {
599 }
600 mpaszResults = rTable.mpaszResults;
601 // Only one object can own the results
602 const_cast<CppSQLite3Table&>(rTable).mpaszResults = 0;
603 mnRows = rTable.mnRows;
604 mnCols = rTable.mnCols;
605 mnCurrentRow = rTable.mnCurrentRow;
606 return *this;
607}
608
609void CppSQLite3Table::finalize()
610{
611 if(mpaszResults)
612 {
613 sqlite3_free_table(mpaszResults);
614 mpaszResults = 0;
615 }
616}
617
618int CppSQLite3Table::numFields()
619{
620 checkResults();
621 return mnCols;
622}
623
624int CppSQLite3Table::numRows()
625{
626 checkResults();
627 return mnRows;
628}
629
630const char* CppSQLite3Table::fieldValue(int nField)
631{
632 checkResults();
633
634 if(nField < 0 || nField > mnCols - 1)
635 {
636 throw CppSQLite3Exception(CPPSQLITE_ERROR, "Invalid field index requested", DONT_DELETE_MSG);
637 }
638
639 int nIndex = (mnCurrentRow* mnCols) + mnCols + nField;
640 return mpaszResults[nIndex];
641}
642
643const char* CppSQLite3Table::fieldValue(const char* szField)
644{
645 checkResults();
646
647 if(szField)
648 {
649 for(int nField = 0;nField < mnCols;nField++)
650 {
651 if(strcmp(szField, mpaszResults[nField]) == 0)
652 {
653 int nIndex = (mnCurrentRow* mnCols) + mnCols + nField;
654 return mpaszResults[nIndex];
655 }
656 }
657 }
658
659 throw CppSQLite3Exception(CPPSQLITE_ERROR, "Invalid field name requested", DONT_DELETE_MSG);
660}
661
662int CppSQLite3Table::getIntField(int nField, int nNullValue/*=0*/)
663{
664 if(fieldIsNull(nField))
665 {
666 return nNullValue;
667 }
668 else
669 {
670 return atoi(fieldValue(nField));
671 }
672}
673
674int CppSQLite3Table::getIntField(const char* szField, int nNullValue/*=0*/)
675{
676 if(fieldIsNull(szField))
677 {
678 return nNullValue;
679 }
680 else
681 {
682 return atoi(fieldValue(szField));
683 }
684}
685
686double CppSQLite3Table::getFloatField(int nField, double fNullValue/*=0.0*/)
687{
688 if(fieldIsNull(nField))
689 {
690 return fNullValue;
691 }
692 else
693 {
694 return atof(fieldValue(nField));
695 }
696}
697
698double CppSQLite3Table::getFloatField(const char* szField, double fNullValue/*=0.0*/)
699{
700 if(fieldIsNull(szField))
701 {
702 return fNullValue;
703 }
704 else
705 {
706 return atof(fieldValue(szField));
707 }
708}
709
710const char* CppSQLite3Table::getStringField(int nField, const char* szNullValue/*=""*/)
711{
712 if(fieldIsNull(nField))
713 {
714 return szNullValue;
715 }
716 else
717 {
718 return fieldValue(nField);
719 }
720}
721
722const char* CppSQLite3Table::getStringField(const char* szField, const char* szNullValue/*=""*/)
723{
724 if(fieldIsNull(szField))
725 {
726 return szNullValue;
727 }
728 else
729 {
730 return fieldValue(szField);
731 }
732}
733
734bool CppSQLite3Table::fieldIsNull(int nField)
735{
736 checkResults();
737 return (fieldValue(nField) == 0);
738}
739
740bool CppSQLite3Table::fieldIsNull(const char* szField)
741{
742 checkResults();
743 return (fieldValue(szField) == 0);
744}
745
746const char* CppSQLite3Table::fieldName(int nCol)
747{
748 checkResults();
749
750 if(nCol < 0 || nCol > mnCols - 1)
751 {
752 throw CppSQLite3Exception(CPPSQLITE_ERROR, "Invalid field index requested", DONT_DELETE_MSG);
753 }
754
755 return mpaszResults[nCol];
756}
757
758void CppSQLite3Table::setRow(int nRow)
759{
760 checkResults();
761
762 if(nRow < 0 || nRow > mnRows - 1)
763 {
764 throw CppSQLite3Exception(CPPSQLITE_ERROR, "Invalid row index requested", DONT_DELETE_MSG);
765 }
766
767 mnCurrentRow = nRow;
768}
769
770void CppSQLite3Table::checkResults()
771{
772 if(mpaszResults == 0)
773 {
774 throw CppSQLite3Exception(CPPSQLITE_ERROR, "Null Results pointer", DONT_DELETE_MSG);
775 }
776}
777
778////////////////////////////////////////////////////////////////////////////////
779
780CppSQLite3Statement::CppSQLite3Statement()
781{
782 mpDB = 0;
783 mpVM = 0;
784}
785
786CppSQLite3Statement::CppSQLite3Statement(const CppSQLite3Statement& rStatement)
787{
788 mpDB = rStatement.mpDB;
789 mpVM = rStatement.mpVM;
790 // Only one object can own VM
791 const_cast<CppSQLite3Statement&>(rStatement).mpVM = 0;
792}
793
794CppSQLite3Statement::CppSQLite3Statement(sqlite3* pDB, sqlite3_stmt* pVM)
795{
796 mpDB = pDB;
797 mpVM = pVM;
798}
799
800CppSQLite3Statement::~CppSQLite3Statement()
801{
802 try
803 {
804 finalize();
805 }
806 catch(...)
807 {
808 }
809}
810
811CppSQLite3Statement& CppSQLite3Statement::operator=(const CppSQLite3Statement& rStatement)
812{
813 mpDB = rStatement.mpDB;
814 mpVM = rStatement.mpVM;
815 // Only one object can own VM
816 const_cast<CppSQLite3Statement&>(rStatement).mpVM = 0;
817 return *this;
818}
819
820int CppSQLite3Statement::execDML()
821{
822 checkDB();
823 checkVM();
824
825 const char* szError = 0;
826
827 int nRet = sqlite3_step(mpVM);
828
829 if(nRet == SQLITE_DONE)
830 {
831 int nRowsChanged = sqlite3_changes(mpDB);
832
833 nRet = sqlite3_reset(mpVM);
834
835 if(nRet != SQLITE_OK)
836 {
837 szError = sqlite3_errmsg(mpDB);
838 throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG);
839 }
840
841 return nRowsChanged;
842 }
843 else
844 {
845 nRet = sqlite3_reset(mpVM);
846 szError = sqlite3_errmsg(mpDB);
847 throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG);
848 }
849}
850
851CppSQLite3Query CppSQLite3Statement::execQuery()
852{
853 checkDB();
854 checkVM();
855
856 int nRet = sqlite3_step(mpVM);
857
858 if(nRet == SQLITE_DONE)
859 {
860 // no rows
861 return CppSQLite3Query(mpDB, mpVM, true/*eof*/, false);
862 }
863 else if(nRet == SQLITE_ROW)
864 {
865 // at least 1 row
866 return CppSQLite3Query(mpDB, mpVM, false/*eof*/, false);
867 }
868 else
869 {
870 nRet = sqlite3_reset(mpVM);
871 const char* szError = sqlite3_errmsg(mpDB);
872 throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG);
873 }
874}
875
876void CppSQLite3Statement::bind(int nParam, const char* szValue)
877{
878 checkVM();
879 int nRes = sqlite3_bind_text(mpVM, nParam, szValue, -1, SQLITE_TRANSIENT);
880
881 if(nRes != SQLITE_OK)
882 {
883 throw CppSQLite3Exception(nRes, "Error binding string param", DONT_DELETE_MSG);
884 }
885}
886
887void CppSQLite3Statement::bind(int nParam, const int nValue)
888{
889 checkVM();
890 int nRes = sqlite3_bind_int(mpVM, nParam, nValue);
891
892 if(nRes != SQLITE_OK)
893 {
894 throw CppSQLite3Exception(nRes, "Error binding int param", DONT_DELETE_MSG);
895 }
896}
897
898void CppSQLite3Statement::bind(int nParam, const double dValue)
899{
900 checkVM();
901 int nRes = sqlite3_bind_double(mpVM, nParam, dValue);
902
903 if(nRes != SQLITE_OK)
904 {
905 throw CppSQLite3Exception(nRes, "Error binding double param", DONT_DELETE_MSG);
906 }
907}
908
909void CppSQLite3Statement::bind(int nParam, const unsigned char* blobValue, int nLen)
910{
911 checkVM();
912 int nRes = sqlite3_bind_blob(mpVM, nParam, (const void*)blobValue, nLen, SQLITE_TRANSIENT);
913
914 if(nRes != SQLITE_OK)
915 {
916 throw CppSQLite3Exception(nRes, "Error binding blob param", DONT_DELETE_MSG);
917 }
918}
919
920void CppSQLite3Statement::bindNull(int nParam)
921{
922 checkVM();
923 int nRes = sqlite3_bind_null(mpVM, nParam);
924
925 if(nRes != SQLITE_OK)
926 {
927 throw CppSQLite3Exception(nRes, "Error binding NULL param", DONT_DELETE_MSG);
928 }
929}
930
931void CppSQLite3Statement::reset()
932{
933 if(mpVM)
934 {
935 int nRet = sqlite3_reset(mpVM);
936
937 if(nRet != SQLITE_OK)
938 {
939 const char* szError = sqlite3_errmsg(mpDB);
940 throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG);
941 }
942 }
943}
944
945void CppSQLite3Statement::finalize()
946{
947 if(mpVM)
948 {
949 int nRet = sqlite3_finalize(mpVM);
950 mpVM = 0;
951
952 if(nRet != SQLITE_OK)
953 {
954 const char* szError = sqlite3_errmsg(mpDB);
955 throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG);
956 }
957 }
958}
959
960void CppSQLite3Statement::checkDB()
961{
962 if(mpDB == 0)
963 {
964 throw CppSQLite3Exception(CPPSQLITE_ERROR, "Database not open", DONT_DELETE_MSG);
965 }
966}
967
968void CppSQLite3Statement::checkVM()
969{
970 if(mpVM == 0)
971 {
972 throw CppSQLite3Exception(CPPSQLITE_ERROR, "Null Virtual Machine pointer", DONT_DELETE_MSG);
973 }
974}
975
976////////////////////////////////////////////////////////////////////////////////
977
978CppSQLite3DB::CppSQLite3DB()
979{
980 mpDB = 0;
981 mnBusyTimeoutMs = 60000; // 60 seconds
982}
983
984CppSQLite3DB::CppSQLite3DB(const CppSQLite3DB& db)
985{
986 mpDB = db.mpDB;
987 mnBusyTimeoutMs = 60000; // 60 seconds
988}
989
990CppSQLite3DB::~CppSQLite3DB()
991{
992 Close();
993}
994
995CppSQLite3DB& CppSQLite3DB::operator=(const CppSQLite3DB& db)
996{
997 mpDB = db.mpDB;
998 mnBusyTimeoutMs = 60000; // 60 seconds
999 return *this;
1000}
1001
1002void CppSQLite3DB::Open(const char* szFile)
1003{
1004 int nRet = sqlite3_open(szFile, &mpDB);
1005
1006 if(nRet != SQLITE_OK)
1007 {
1008 const char* szError = sqlite3_errmsg(mpDB);
1009 throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG);
1010 }
1011
1012 setBusyTimeout(mnBusyTimeoutMs);
1013}
1014
1015void CppSQLite3DB::Close()
1016{
1017 if(mpDB)
1018 {
1019 sqlite3_close(mpDB);
1020 mpDB = 0;
1021 }
1022}
1023
1024CppSQLite3Statement CppSQLite3DB::compileStatement(const char* szSQL)
1025{
1026 checkDB();
1027
1028 sqlite3_stmt* pVM = compile(szSQL);
1029 return CppSQLite3Statement(mpDB, pVM);
1030}
1031
1032bool CppSQLite3DB::tableExists(const char* szTable)
1033{
1034 char szSQL[128];
1035 sprintf(szSQL, "select count(*) from sqlite_master where type='table' and name='%s'", szTable);
1036 int nRet = execScalar(szSQL);
1037 return (nRet > 0);
1038}
1039
1040int CppSQLite3DB::execDML(const char* szSQL)
1041{
1042 checkDB();
1043
1044 char* szError = 0;
1045
1046 int nRet = sqlite3_exec(mpDB, szSQL, 0, 0, &szError);
1047
1048 if(nRet == SQLITE_OK)
1049 {
1050 return sqlite3_changes(mpDB);
1051 }
1052 else
1053 {
1054 throw CppSQLite3Exception(nRet, szError);
1055 }
1056}
1057
1058CppSQLite3Query CppSQLite3DB::execQuery(const char* szSQL)
1059{
1060 checkDB();
1061
1062 sqlite3_stmt* pVM = compile(szSQL);
1063
1064 int nRet = sqlite3_step(pVM);
1065
1066 if(nRet == SQLITE_DONE)
1067 {
1068 // no rows
1069 return CppSQLite3Query(mpDB, pVM, true/*eof*/);
1070 }
1071 else if(nRet == SQLITE_ROW)
1072 {
1073 // at least 1 row
1074 return CppSQLite3Query(mpDB, pVM, false/*eof*/);
1075 }
1076 else
1077 {
1078 nRet = sqlite3_finalize(pVM);
1079 const char* szError = sqlite3_errmsg(mpDB);
1080 throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG);
1081 }
1082}
1083
1084int CppSQLite3DB::execScalar(const char* szSQL)
1085{
1086 CppSQLite3Query q = execQuery(szSQL);
1087
1088 if(q.eof() || q.numFields() < 1)
1089 {
1090 throw CppSQLite3Exception(CPPSQLITE_ERROR, "Invalid scalar query", DONT_DELETE_MSG);
1091 }
1092
1093 return atoi(q.fieldValue(0));
1094}
1095
1096CppSQLite3Table CppSQLite3DB::getTable(const char* szSQL)
1097{
1098 checkDB();
1099
1100 char* szError = 0;
1101 char** paszResults = 0;
1102 int nRet;
1103 int nRows(0);
1104 int nCols(0);
1105
1106 nRet = sqlite3_get_table(mpDB, szSQL, &paszResults, &nRows, &nCols, &szError);
1107
1108 if(nRet == SQLITE_OK)
1109 {
1110 return CppSQLite3Table(paszResults, nRows, nCols);
1111 }
1112 else
1113 {
1114 throw CppSQLite3Exception(nRet, szError);
1115 }
1116}
1117
1118sqlite_int64 CppSQLite3DB::lastRowId()
1119{
1120 return sqlite3_last_insert_rowid(mpDB);
1121}
1122
1123void CppSQLite3DB::setBusyTimeout(int nMillisecs)
1124{
1125 mnBusyTimeoutMs = nMillisecs;
1126 sqlite3_busy_timeout(mpDB, mnBusyTimeoutMs);
1127}
1128
1129void CppSQLite3DB::checkDB()
1130{
1131 if(!mpDB)
1132 {
1133 throw CppSQLite3Exception(CPPSQLITE_ERROR, "Database not open", DONT_DELETE_MSG);
1134 }
1135}
1136
1137sqlite3_stmt* CppSQLite3DB::compile(const char* szSQL)
1138{
1139 checkDB();
1140
1141 char* szError = 0;
1142 const char* szTail = 0;
1143 sqlite3_stmt* pVM;
1144
1145 int nRet = sqlite3_prepare(mpDB, szSQL, -1, &pVM, &szTail);
1146
1147 if(nRet != SQLITE_OK)
1148 {
1149 throw CppSQLite3Exception(nRet, szError);
1150 }
1151
1152 return pVM;
1153}
1154
1155////////////////////////////////////////////////////////////////////////////////
1156// SQLite encode.c reproduced here, containing implementation notes and source
1157// for sqlite3_encode_binary() and sqlite3_decode_binary()
1158////////////////////////////////////////////////////////////////////////////////
1159
1160/*
1161** 2002 April 25
1162**
1163** The author disclaims copyright to this source code. In place of
1164** a legal notice, here is a blessing:
1165**
1166** May you do good and not evil.
1167** May you find forgiveness for yourself and forgive others.
1168** May you share freely, never taking more than you give.
1169**
1170*************************************************************************
1171** This file contains helper routines used to translate binary data into
1172** a null-terminated string (suitable for use in SQLite) and back again.
1173** These are convenience routines for use by people who want to store binary
1174** data in an SQLite database. The code in this file is not used by any other
1175** part of the SQLite library.
1176**
1177** $Id: encode.c,v 1.10 2004/01/14 21:59:23 drh Exp $
1178*/
1179
1180/*
1181** How This Encoder Works
1182**
1183** The output is allowed to contain any character except 0x27 (') and
1184** 0x00. This is accomplished by using an escape character to encode
1185** 0x27 and 0x00 as a two-byte sequence. The escape character is always
1186** 0x01. An 0x00 is encoded as the two byte sequence 0x01 0x01. The
1187** 0x27 character is encoded as the two byte sequence 0x01 0x03. Finally,
1188** the escape character itself is encoded as the two-character sequence
1189** 0x01 0x02.
1190**
1191** To summarize, the encoder works by using an escape sequences as follows:
1192**
1193** 0x00 -> 0x01 0x01
1194** 0x01 -> 0x01 0x02
1195** 0x27 -> 0x01 0x03
1196**
1197** If that were all the encoder did, it would work, but in certain cases
1198** it could double the size of the encoded string. For example, to
1199** encode a string of 100 0x27 characters would require 100 instances of
1200** the 0x01 0x03 escape sequence resulting in a 200-character output.
1201** We would prefer to keep the size of the encoded string smaller than
1202** this.
1203**
1204** To minimize the encoding size, we first add a fixed offset value to each
1205** byte in the sequence. The addition is modulo 256. (That is to say, if
1206** the sum of the original character value and the offset exceeds 256, then
1207** the higher order bits are truncated.) The offset is chosen to minimize
1208** the number of characters in the string that need to be escaped. For
1209** example, in the case above where the string was composed of 100 0x27
1210** characters, the offset might be 0x01. Each of the 0x27 characters would
1211** then be converted into an 0x28 character which would not need to be
1212** escaped at all and so the 100 character input string would be converted
1213** into just 100 characters of output. Actually 101 characters of output -
1214** we have to record the offset used as the first byte in the sequence so
1215** that the string can be decoded. Since the offset value is stored as
1216** part of the output string and the output string is not allowed to contain
1217** characters 0x00 or 0x27, the offset cannot be 0x00 or 0x27.
1218**
1219** Here, then, are the encoding steps:
1220**
1221** (1) Choose an offset value and make it the first character of
1222** output.
1223**
1224** (2) Copy each input character into the output buffer, one by
1225** one, adding the offset value as you copy.
1226**
1227** (3) If the value of an input character plus offset is 0x00, replace
1228** that one character by the two-character sequence 0x01 0x01.
1229** If the sum is 0x01, replace it with 0x01 0x02. If the sum
1230** is 0x27, replace it with 0x01 0x03.
1231**
1232** (4) Put a 0x00 terminator at the end of the output.
1233**
1234** Decoding is obvious:
1235**
1236** (5) Copy encoded characters except the first into the decode
1237** buffer. Set the first encoded character aside for use as
1238** the offset in step 7 below.
1239**
1240** (6) Convert each 0x01 0x01 sequence into a single character 0x00.
1241** Convert 0x01 0x02 into 0x01. Convert 0x01 0x03 into 0x27.
1242**
1243** (7) Subtract the offset value that was the first character of
1244** the encoded buffer from all characters in the output buffer.
1245**
1246** The only tricky part is step (1) - how to compute an offset value to
1247** minimize the size of the output buffer. This is accomplished by testing
1248** all offset values and picking the one that results in the fewest number
1249** of escapes. To do that, we first scan the entire input and count the
1250** number of occurances of each character value in the input. Suppose
1251** the number of 0x00 characters is N(0), the number of occurances of 0x01
1252** is N(1), and so forth up to the number of occurances of 0xff is N(255).
1253** An offset of 0 is not allowed so we don't have to test it. The number
1254** of escapes required for an offset of 1 is N(1)+N(2)+N(40). The number
1255** of escapes required for an offset of 2 is N(2)+N(3)+N(41). And so forth.
1256** In this way we find the offset that gives the minimum number of escapes,
1257** and thus minimizes the length of the output string.
1258*/
1259
1260/*
1261** Encode a binary buffer "in" of size n bytes so that it contains
1262** no instances of characters '\'' or '\000'. The output is
1263** null-terminated and can be used as a string value in an INSERT
1264** or UPDATE statement. Use sqlite3_decode_binary() to convert the
1265** string back into its original binary.
1266**
1267** The result is written into a preallocated output buffer "out".
1268** "out" must be able to hold at least 2 +(257*n)/254 bytes.
1269** In other words, the output will be expanded by as much as 3
1270** bytes for every 254 bytes of input plus 2 bytes of fixed overhead.
1271** (This is approximately 2 + 1.0118*n or about a 1.2% size increase.)
1272**
1273** The return value is the number of characters in the encoded
1274** string, excluding the "\000" terminator.
1275*/
1276int sqlite3_encode_binary(const unsigned char* in, int n, unsigned char* out)
1277{
1278 int i = 0;
1279 int j = 0;
1280 int e = 0;
1281 int m = 0;
1282
1283 int cnt[256];
1284
1285 if(n <= 0)
1286 {
1287 out[0] = 'x';
1288 out[1] = 0;
1289 return 1;
1290 }
1291 memset(cnt, 0, sizeof(cnt));
1292 for(i = n - 1;i >= 0;i--)
1293 {
1294 cnt[in[i]]++;
1295 }
1296 m = n;
1297 for(i = 1;i < 256;i++)
1298 {
1299 int sum;
1300 if(i == '\'')
1301 continue;
1302 sum = cnt[i] + cnt[(i + 1) & 0xff] + cnt[(i + '\'') & 0xff];
1303 if(sum < m)
1304 {
1305 m = sum;
1306 e = i;
1307 if(m == 0)
1308 break;
1309 }
1310 }
1311 out[0] = e;
1312 j = 1;
1313 for(i = 0;i < n;i++)
1314 {
1315 int c = (in[i] - e) & 0xff;
1316 if(c == 0)
1317 {
1318 out[j++] = 1;
1319 out[j++] = 1;
1320 }
1321 else if(c == 1)
1322 {
1323 out[j++] = 1;
1324 out[j++] = 2;
1325 }
1326 else if(c == '\'')
1327 {
1328 out[j++] = 1;
1329 out[j++] = 3;
1330 }
1331 else
1332 {
1333 out[j++] = c;
1334 }
1335 }
1336 out[j] = 0;
1337 return j;
1338}
1339
1340/*
1341** Decode the string "in" into binary data and write it into "out".
1342** This routine reverses the encoding created by sqlite3_encode_binary().
1343** The output will always be a few bytes less than the input. The number
1344** of bytes of output is returned. If the input is not a well-formed
1345** encoding, -1 is returned.
1346**
1347** The "in" and "out" parameters may point to the same buffer in order
1348** to decode a string in place.
1349*/
1350int sqlite3_decode_binary(const unsigned char* in, unsigned char* out)
1351{
1352 int i = 0;
1353 int c = 0;
1354 int e = 0;
1355
1356 e = *(in++);
1357 i = 0;
1358 while((c = *(in++)) != 0)
1359 {
1360 if(c == 1)
1361 {
1362 c = *(in++);
1363 if(c == 1)
1364 {
1365 c = 0;
1366 }
1367 else if(c == 2)
1368 {
1369 c = 1;
1370 }
1371 else if(c == 3)
1372 {
1373 c = '\'';
1374 }
1375 else
1376 {
1377 return -1;
1378 }
1379 }
1380 out[i++] = (c + e) & 0xff;
1381 }
1382 return i;
1383}
01384
=== added file 'common/CppSQLite3.h'
--- common/CppSQLite3.h 1970-01-01 00:00:00 +0000
+++ common/CppSQLite3.h 2011-11-23 01:01:25 +0000
@@ -0,0 +1,270 @@
1#pragma once
2
3#include "sqlite3.h"
4#include <cstdio>
5#include <cstring>
6
7#define CPPSQLITE_ERROR 1000
8
9class CppSQLite3Exception
10{
11public:
12
13 CppSQLite3Exception(const int nErrCode,
14 char* szErrMess,
15 bool bDeleteMsg=true);
16
17 CppSQLite3Exception(const CppSQLite3Exception& e);
18
19 virtual ~CppSQLite3Exception();
20
21 const int errorCode() { return mnErrCode; }
22
23 const char* errorMessage() { return mpszErrMess; }
24
25 static const char* errorCodeAsString(int nErrCode);
26
27private:
28
29 int mnErrCode;
30 char* mpszErrMess;
31};
32
33class CppSQLite3Buffer
34{
35public:
36
37 CppSQLite3Buffer();
38
39 ~CppSQLite3Buffer();
40
41 const char* format(const char* szFormat, ...);
42
43 operator const char*() { return mpBuf; }
44
45 void clear();
46
47private:
48
49 char* mpBuf;
50};
51
52class CppSQLite3Binary
53{
54public:
55
56 CppSQLite3Binary();
57
58 ~CppSQLite3Binary();
59
60 void setBinary(const unsigned char* pBuf, int nLen);
61 void setEncoded(const unsigned char* pBuf);
62
63 const unsigned char* getEncoded();
64 const unsigned char* getBinary();
65
66 int getBinaryLength();
67
68 unsigned char* allocBuffer(int nLen);
69
70 void clear();
71
72private:
73
74 unsigned char* mpBuf;
75 int mnBinaryLen;
76 int mnBufferLen;
77 int mnEncodedLen;
78 bool mbEncoded;
79};
80
81class CppSQLite3Query
82{
83public:
84
85 CppSQLite3Query();
86
87 CppSQLite3Query(const CppSQLite3Query& rQuery);
88
89 CppSQLite3Query(sqlite3* pDB,
90 sqlite3_stmt* pVM,
91 bool bEof,
92 bool bOwnVM=true);
93
94 CppSQLite3Query& operator=(const CppSQLite3Query& rQuery);
95
96 virtual ~CppSQLite3Query();
97
98 int numFields();
99
100 int fieldIndex(const char* szField);
101 const char* fieldName(int nCol);
102
103 const char* fieldDeclType(int nCol);
104 int fieldDataType(int nCol);
105
106 const char* fieldValue(int nField);
107 const char* fieldValue(const char* szField);
108
109 int getIntField(int nField, int nNullValue=0);
110 int getIntField(const char* szField, int nNullValue=0);
111
112 double getFloatField(int nField, double fNullValue=0.0);
113 double getFloatField(const char* szField, double fNullValue=0.0);
114
115 const char* getStringField(int nField, const char* szNullValue="");
116 const char* getStringField(const char* szField, const char* szNullValue="");
117
118 const unsigned char* getBlobField(int nField, int& nLen);
119 const unsigned char* getBlobField(const char* szField, int& nLen);
120
121 bool fieldIsNull(int nField);
122 bool fieldIsNull(const char* szField);
123
124 bool eof();
125
126 void nextRow();
127
128 void finalize();
129
130private:
131
132 void checkVM();
133
134 sqlite3* mpDB;
135 sqlite3_stmt* mpVM;
136 bool mbEof;
137 int mnCols;
138 bool mbOwnVM;
139};
140
141class CppSQLite3Table
142{
143public:
144
145 CppSQLite3Table();
146
147 CppSQLite3Table(const CppSQLite3Table& rTable);
148
149 CppSQLite3Table(char** paszResults, int nRows, int nCols);
150
151 virtual ~CppSQLite3Table();
152
153 CppSQLite3Table& operator=(const CppSQLite3Table& rTable);
154
155 int numFields();
156
157 int numRows();
158
159 const char* fieldName(int nCol);
160
161 const char* fieldValue(int nField);
162 const char* fieldValue(const char* szField);
163
164 int getIntField(int nField, int nNullValue=0);
165 int getIntField(const char* szField, int nNullValue=0);
166
167 double getFloatField(int nField, double fNullValue=0.0);
168 double getFloatField(const char* szField, double fNullValue=0.0);
169
170 const char* getStringField(int nField, const char* szNullValue="");
171 const char* getStringField(const char* szField, const char* szNullValue="");
172
173 bool fieldIsNull(int nField);
174 bool fieldIsNull(const char* szField);
175
176 void setRow(int nRow);
177
178 void finalize();
179
180private:
181
182 void checkResults();
183
184 int mnCols;
185 int mnRows;
186 int mnCurrentRow;
187 char** mpaszResults;
188};
189
190class CppSQLite3Statement
191{
192public:
193
194 CppSQLite3Statement();
195
196 CppSQLite3Statement(const CppSQLite3Statement& rStatement);
197
198 CppSQLite3Statement(sqlite3* pDB, sqlite3_stmt* pVM);
199
200 virtual ~CppSQLite3Statement();
201
202 CppSQLite3Statement& operator=(const CppSQLite3Statement& rStatement);
203
204 int execDML();
205
206 CppSQLite3Query execQuery();
207
208 void bind(int nParam, const char* szValue);
209 void bind(int nParam, const int nValue);
210 void bind(int nParam, const double dwValue);
211 void bind(int nParam, const unsigned char* blobValue, int nLen);
212 void bindNull(int nParam);
213
214 void reset();
215
216 void finalize();
217
218private:
219
220 void checkDB();
221 void checkVM();
222
223 sqlite3* mpDB;
224 sqlite3_stmt* mpVM;
225};
226
227class CppSQLite3DB
228{
229public:
230
231 CppSQLite3DB();
232
233 virtual ~CppSQLite3DB();
234
235 void Open(const char* szFile);
236
237 void Close();
238
239 bool tableExists(const char* szTable);
240
241 int execDML(const char* szSQL);
242
243 CppSQLite3Query execQuery(const char* szSQL);
244
245 int execScalar(const char* szSQL);
246
247 CppSQLite3Table getTable(const char* szSQL);
248
249 CppSQLite3Statement compileStatement(const char* szSQL);
250
251 sqlite_int64 lastRowId();
252
253 void interrupt() { sqlite3_interrupt(mpDB); }
254
255 void setBusyTimeout(int nMillisecs);
256
257 static const char* SQLiteVersion() { return SQLITE_VERSION; }
258
259private:
260
261 CppSQLite3DB(const CppSQLite3DB& db);
262 CppSQLite3DB& operator=(const CppSQLite3DB& db);
263
264 sqlite3_stmt* compile(const char* szSQL);
265
266 void checkDB();
267
268 sqlite3* mpDB;
269 int mnBusyTimeoutMs;
270};
0271
=== added file 'common/SHA1.cpp'
--- common/SHA1.cpp 1970-01-01 00:00:00 +0000
+++ common/SHA1.cpp 2011-11-23 01:01:25 +0000
@@ -0,0 +1,282 @@
1/*
2 100% free public domain implementation of the SHA-1 algorithm
3 by Dominik Reichl <dominik.reichl@t-online.de>
4 Web: http://www.dominik-reichl.de/
5
6 Version 1.6 - 2005-02-07 (thanks to Howard Kapustein for patches)
7 - You can set the endianness in your files, no need to modify the
8 header file of the CSHA1 class any more
9 - Aligned data support
10 - Made support/compilation of the utility functions (ReportHash
11 and HashFile) optional (useful, if bytes count, for example in
12 embedded environments)
13
14 Version 1.5 - 2005-01-01
15 - 64-bit compiler compatibility added
16 - Made variable wiping optional (define SHA1_WIPE_VARIABLES)
17 - Removed unnecessary variable initializations
18 - ROL32 improvement for the Microsoft compiler (using _rotl)
19
20 ======== Test Vectors (from FIPS PUB 180-1) ========
21
22 SHA1("abc") =
23 A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
24
25 SHA1("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") =
26 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
27
28 SHA1(A million repetitions of "a") =
29 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
30*/
31
32#include "SHA1.h"
33
34#ifdef SHA1_UTILITY_FUNCTIONS
35#define SHA1_MAX_FILE_BUFFER 8000
36#endif
37
38// Rotate x bits to the left
39#ifndef ROL32
40#ifdef _MSC_VER
41#define ROL32(_val32, _nBits) _rotl(_val32, _nBits)
42#else
43#define ROL32(_val32, _nBits) (((_val32)<<(_nBits))|((_val32)>>(32-(_nBits))))
44#endif
45#endif
46
47#ifdef SHA1_LITTLE_ENDIAN
48#define SHABLK0(i) (m_block->l[i] = \
49 (ROL32(m_block->l[i],24) & 0xFF00FF00) | (ROL32(m_block->l[i],8) & 0x00FF00FF))
50#else
51#define SHABLK0(i) (m_block->l[i])
52#endif
53
54#define SHABLK(i) (m_block->l[i&15] = ROL32(m_block->l[(i+13)&15] ^ m_block->l[(i+8)&15] \
55 ^ m_block->l[(i+2)&15] ^ m_block->l[i&15],1))
56
57// SHA-1 rounds
58#define _R0(v,w,x,y,z,i) { z+=((w&(x^y))^y)+SHABLK0(i)+0x5A827999+ROL32(v,5); w=ROL32(w,30); }
59#define _R1(v,w,x,y,z,i) { z+=((w&(x^y))^y)+SHABLK(i)+0x5A827999+ROL32(v,5); w=ROL32(w,30); }
60#define _R2(v,w,x,y,z,i) { z+=(w^x^y)+SHABLK(i)+0x6ED9EBA1+ROL32(v,5); w=ROL32(w,30); }
61#define _R3(v,w,x,y,z,i) { z+=(((w|x)&y)|(w&x))+SHABLK(i)+0x8F1BBCDC+ROL32(v,5); w=ROL32(w,30); }
62#define _R4(v,w,x,y,z,i) { z+=(w^x^y)+SHABLK(i)+0xCA62C1D6+ROL32(v,5); w=ROL32(w,30); }
63
64CSHA1::CSHA1()
65{
66 m_block = (SHA1_WORKSPACE_BLOCK *)m_workspace;
67
68 Reset();
69}
70
71CSHA1::~CSHA1()
72{
73 Reset();
74}
75
76void CSHA1::Reset()
77{
78 // SHA1 initialization constants
79 m_state[0] = 0x67452301;
80 m_state[1] = 0xEFCDAB89;
81 m_state[2] = 0x98BADCFE;
82 m_state[3] = 0x10325476;
83 m_state[4] = 0xC3D2E1F0;
84
85 m_count[0] = 0;
86 m_count[1] = 0;
87}
88
89void CSHA1::Transform(UINT_32* state, UINT_8* buffer)
90{
91 // Copy state[] to working vars
92 UINT_32 a = state[0], b = state[1], c = state[2], d = state[3], e = state[4];
93
94 memcpy(m_block, buffer, 64);
95
96 // 4 rounds of 20 operations each. Loop unrolled.
97 _R0(a, b, c, d, e, 0); _R0(e, a, b, c, d, 1); _R0(d, e, a, b, c, 2); _R0(c, d, e, a, b, 3);
98 _R0(b, c, d, e, a, 4); _R0(a, b, c, d, e, 5); _R0(e, a, b, c, d, 6); _R0(d, e, a, b, c, 7);
99 _R0(c, d, e, a, b, 8); _R0(b, c, d, e, a, 9); _R0(a, b, c, d, e, 10); _R0(e, a, b, c, d, 11);
100 _R0(d, e, a, b, c, 12); _R0(c, d, e, a, b, 13); _R0(b, c, d, e, a, 14); _R0(a, b, c, d, e, 15);
101 _R1(e, a, b, c, d, 16); _R1(d, e, a, b, c, 17); _R1(c, d, e, a, b, 18); _R1(b, c, d, e, a, 19);
102 _R2(a, b, c, d, e, 20); _R2(e, a, b, c, d, 21); _R2(d, e, a, b, c, 22); _R2(c, d, e, a, b, 23);
103 _R2(b, c, d, e, a, 24); _R2(a, b, c, d, e, 25); _R2(e, a, b, c, d, 26); _R2(d, e, a, b, c, 27);
104 _R2(c, d, e, a, b, 28); _R2(b, c, d, e, a, 29); _R2(a, b, c, d, e, 30); _R2(e, a, b, c, d, 31);
105 _R2(d, e, a, b, c, 32); _R2(c, d, e, a, b, 33); _R2(b, c, d, e, a, 34); _R2(a, b, c, d, e, 35);
106 _R2(e, a, b, c, d, 36); _R2(d, e, a, b, c, 37); _R2(c, d, e, a, b, 38); _R2(b, c, d, e, a, 39);
107 _R3(a, b, c, d, e, 40); _R3(e, a, b, c, d, 41); _R3(d, e, a, b, c, 42); _R3(c, d, e, a, b, 43);
108 _R3(b, c, d, e, a, 44); _R3(a, b, c, d, e, 45); _R3(e, a, b, c, d, 46); _R3(d, e, a, b, c, 47);
109 _R3(c, d, e, a, b, 48); _R3(b, c, d, e, a, 49); _R3(a, b, c, d, e, 50); _R3(e, a, b, c, d, 51);
110 _R3(d, e, a, b, c, 52); _R3(c, d, e, a, b, 53); _R3(b, c, d, e, a, 54); _R3(a, b, c, d, e, 55);
111 _R3(e, a, b, c, d, 56); _R3(d, e, a, b, c, 57); _R3(c, d, e, a, b, 58); _R3(b, c, d, e, a, 59);
112 _R4(a, b, c, d, e, 60); _R4(e, a, b, c, d, 61); _R4(d, e, a, b, c, 62); _R4(c, d, e, a, b, 63);
113 _R4(b, c, d, e, a, 64); _R4(a, b, c, d, e, 65); _R4(e, a, b, c, d, 66); _R4(d, e, a, b, c, 67);
114 _R4(c, d, e, a, b, 68); _R4(b, c, d, e, a, 69); _R4(a, b, c, d, e, 70); _R4(e, a, b, c, d, 71);
115 _R4(d, e, a, b, c, 72); _R4(c, d, e, a, b, 73); _R4(b, c, d, e, a, 74); _R4(a, b, c, d, e, 75);
116 _R4(e, a, b, c, d, 76); _R4(d, e, a, b, c, 77); _R4(c, d, e, a, b, 78); _R4(b, c, d, e, a, 79);
117
118 // Add the working vars back into state
119 state[0] += a;
120 state[1] += b;
121 state[2] += c;
122 state[3] += d;
123 state[4] += e;
124
125 // Wipe variables
126#ifdef SHA1_WIPE_VARIABLES
127 a = b = c = d = e = 0;
128#endif
129}
130
131// Use this function to hash in binary data and strings
132void CSHA1::Update(UINT_8* data, UINT_32 len)
133{
134 UINT_32 i, j;
135
136 j = (m_count[0] >> 3) & 63;
137
138 if((m_count[0] += len << 3) < (len << 3))
139 m_count[1]++;
140
141 m_count[1] += (len >> 29);
142
143 if((j + len) > 63)
144 {
145 i = 64 - j;
146 memcpy(&m_buffer[j], data, i);
147 Transform(m_state, m_buffer);
148
149 for(;i + 63 < len;i += 64)
150 Transform(m_state, &data[i]);
151
152 j = 0;
153 }
154 else
155 i = 0;
156
157 memcpy(&m_buffer[j], &data[i], len - i);
158}
159
160#ifdef SHA1_UTILITY_FUNCTIONS
161// Hash in file contents
162bool CSHA1::HashFile(char* szFileName)
163{
164 unsigned long ulFileSize, ulRest, ulBlocks;
165 unsigned long i;
166 UINT_8 uData[SHA1_MAX_FILE_BUFFER];
167 FILE* fIn;
168
169 if(szFileName == NULL)
170 return false;
171
172 fIn = fopen(szFileName, "rb");
173 if(fIn == NULL)
174 return false;
175
176 fseek(fIn, 0, SEEK_END);
177 ulFileSize = (unsigned long)ftell(fIn);
178 fseek(fIn, 0, SEEK_SET);
179
180 if(ulFileSize != 0)
181 {
182 ulBlocks = ulFileSize / SHA1_MAX_FILE_BUFFER;
183 ulRest = ulFileSize % SHA1_MAX_FILE_BUFFER;
184 }
185 else
186 {
187 ulBlocks = 0;
188 ulRest = 0;
189 }
190
191 for(i = 0;i < ulBlocks;i++)
192 {
193 fread(uData, 1, SHA1_MAX_FILE_BUFFER, fIn);
194 Update((UINT_8 *)uData, SHA1_MAX_FILE_BUFFER);
195 }
196
197 if(ulRest != 0)
198 {
199 fread(uData, 1, ulRest, fIn);
200 Update((UINT_8 *)uData, ulRest);
201 }
202
203 fclose(fIn); fIn = NULL;
204 return true;
205}
206
207#endif
208
209void CSHA1::Final()
210{
211 UINT_32 i;
212 UINT_8 finalcount[8];
213
214 for(i = 0;i < 8;i++)
215 finalcount[i] = (UINT_8)((m_count[((i >= 4) ? 0 : 1)] >> ((3 - (i & 3)) * 8)) & 255); // Endian independent
216
217 Update((UINT_8 *)"\200", 1);
218
219 while((m_count[0] & 504) != 448)
220 Update((UINT_8 *)"\0", 1);
221
222 Update(finalcount, 8); // Cause a SHA1Transform()
223
224 for(i = 0;i < 20;i++)
225 {
226 m_digest[i] = (UINT_8)((m_state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255);
227 }
228
229 // Wipe variables for security reasons
230#ifdef SHA1_WIPE_VARIABLES
231 i = 0;
232 memset(m_buffer, 0, 64);
233 memset(m_state, 0, 20);
234 memset(m_count, 0, 8);
235 memset(finalcount, 0, 8);
236 Transform(m_state, m_buffer);
237#endif
238}
239
240#ifdef SHA1_UTILITY_FUNCTIONS
241// Get the final hash as a pre-formatted string
242void CSHA1::ReportHash(char* szReport, unsigned char uReportType)
243{
244 unsigned char i;
245 char szTemp[16];
246
247 if(szReport == NULL)
248 return;
249
250 if(uReportType == REPORT_HEX)
251 {
252 sprintf(szTemp, "%02X", m_digest[0]);
253 strcat(szReport, szTemp);
254
255 for(i = 1;i < 20;i++)
256 {
257 sprintf(szTemp, " %02X", m_digest[i]);
258 strcat(szReport, szTemp);
259 }
260 }
261 else if(uReportType == REPORT_DIGIT)
262 {
263 sprintf(szTemp, "%u", m_digest[0]);
264 strcat(szReport, szTemp);
265
266 for(i = 1;i < 20;i++)
267 {
268 sprintf(szTemp, " %u", m_digest[i]);
269 strcat(szReport, szTemp);
270 }
271 }
272 else
273 strcpy(szReport, "Error: Unknown report type!");
274}
275
276#endif
277
278// Get the raw message digest
279void CSHA1::GetHash(UINT_8* puDest)
280{
281 memcpy(puDest, m_digest, 20);
282}
0283
=== added file 'common/SHA1.h'
--- common/SHA1.h 1970-01-01 00:00:00 +0000
+++ common/SHA1.h 2011-11-23 01:01:25 +0000
@@ -0,0 +1,150 @@
1/*
2 100% free public domain implementation of the SHA-1 algorithm
3 by Dominik Reichl <dominik.reichl@t-online.de>
4 Web: http://www.dominik-reichl.de/
5
6 Version 1.6 - 2005-02-07 (thanks to Howard Kapustein for patches)
7 - You can set the endianness in your files, no need to modify the
8 header file of the CSHA1 class any more
9 - Aligned data support
10 - Made support/compilation of the utility functions (ReportHash
11 and HashFile) optional (useful, if bytes count, for example in
12 embedded environments)
13
14 Version 1.5 - 2005-01-01
15 - 64-bit compiler compatibility added
16 - Made variable wiping optional (define SHA1_WIPE_VARIABLES)
17 - Removed unnecessary variable initializations
18 - ROL32 improvement for the Microsoft compiler (using _rotl)
19
20 ======== Test Vectors (from FIPS PUB 180-1) ========
21
22 SHA1("abc") =
23 A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
24
25 SHA1("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") =
26 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
27
28 SHA1(A million repetitions of "a") =
29 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
30*/
31
32#ifndef ___SHA1_HDR___
33#define ___SHA1_HDR___
34
35#if !defined(SHA1_UTILITY_FUNCTIONS) && !defined(SHA1_NO_UTILITY_FUNCTIONS)
36#define SHA1_UTILITY_FUNCTIONS
37#endif
38
39#include <memory.h> // Needed for memset and memcpy