Merge lp:~psiphon-inc/psiphon/psiphon-1.6 into lp:psiphon
- psiphon-1.6
- Merge into trunk
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 |
Related bugs: | |
Related blueprints: |
Psiphon 2 Design Overview
(Undefined)
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Psiphon Inc. | Pending | ||
Review via email: mp+83096@code.launchpad.net |
Commit message
Description of the change
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
1 | === added file '.DS_Store' |
2 | Binary files .DS_Store 1970-01-01 00:00:00 +0000 and .DS_Store 2011-11-23 01:01:25 +0000 differ |
3 | === added directory 'appWeb' |
4 | === added file 'appWeb/CONFIGURE_DEBUG.TXT' |
5 | --- appWeb/CONFIGURE_DEBUG.TXT 1970-01-01 00:00:00 +0000 |
6 | +++ appWeb/CONFIGURE_DEBUG.TXT 2011-11-23 01:01:25 +0000 |
7 | @@ -0,0 +1,5 @@ |
8 | +./configure --reset |
9 | +./configure --disable-samples --without-upload --without-xdb --disable-test --type=DEBUG \ |
10 | +--with-openssl=loadable \ |
11 | +--with-openssl-dir=../../openssl \ |
12 | +--with-openssl-libs="ssl crypto" |
13 | \ No newline at end of file |
14 | |
15 | === added file 'appWeb/CONFIGURE_RELEASE.TXT' |
16 | --- appWeb/CONFIGURE_RELEASE.TXT 1970-01-01 00:00:00 +0000 |
17 | +++ appWeb/CONFIGURE_RELEASE.TXT 2011-11-23 01:01:25 +0000 |
18 | @@ -0,0 +1,5 @@ |
19 | +./configure --reset |
20 | +./configure --disable-samples --without-upload --without-xdb --disable-test --type=RELEASE \ |
21 | +--with-openssl=loadable \ |
22 | +--with-openssl-dir=../../openssl \ |
23 | +--with-openssl-libs="ssl crypto" |
24 | \ No newline at end of file |
25 | |
26 | === added file 'appWeb/openSslModule.cpp' |
27 | --- appWeb/openSslModule.cpp 1970-01-01 00:00:00 +0000 |
28 | +++ appWeb/openSslModule.cpp 2011-11-23 01:01:25 +0000 |
29 | @@ -0,0 +1,896 @@ |
30 | +/// |
31 | +/// @file openSslModule.cpp |
32 | +/// @brief Support for secure sockets via OpenSSL |
33 | +/// @overview This module integrates support for OpenSSL into AppWeb |
34 | +/// via a dynamically loadable module. |
35 | +// |
36 | +/////////////////////////////////// Copyright ////////////////////////////////// |
37 | +// |
38 | +// @copy default |
39 | +// |
40 | +// Copyright (c) Mbedthis Software LLC, 2003-2006. All Rights Reserved. |
41 | +// Copyright (c) Michael O'Brien, 1994-2006. All Rights Reserved. |
42 | +// |
43 | +// This software is distributed under commercial and open source licenses. |
44 | +// You may use the GPL open source license described below or you may acquire |
45 | +// a commercial license from Mbedthis Software. You agree to be fully bound |
46 | +// by the terms of either license. Consult the LICENSE.TXT distributed with |
47 | +// this software for full details. |
48 | +// |
49 | +// This software is open source; you can redistribute it and/or modify it |
50 | +// under the terms of the GNU General Public License as published by the |
51 | +// Free Software Foundation; either version 2 of the License, or (at your |
52 | +// option) any later version. See the GNU General Public License for more |
53 | +// details at: http://www.mbedthis.com/downloads/gplLicense.html |
54 | +// |
55 | +// This program is distributed WITHOUT ANY WARRANTY; without even the |
56 | +// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
57 | +// |
58 | +// This GPL license does NOT permit incorporating this software into |
59 | +// proprietary programs. If you are unable to comply with the GPL, you must |
60 | +// acquire a commercial license to use this software. Commercial licenses |
61 | +// for this software and support services are available from Mbedthis |
62 | +// Software at http://www.mbedthis.com |
63 | +// |
64 | +// @end |
65 | +// |
66 | +////////////////////////////////// Includes //////////////////////////////////// |
67 | + |
68 | +#include "openSslModule.h" |
69 | + |
70 | +//////////////////////////////////// Locals //////////////////////////////////// |
71 | +#if BLD_FEATURE_OPENSSL_MODULE |
72 | + |
73 | +#include "openSslDh.h" |
74 | + |
75 | +#if BLD_FEATURE_MULTITHREAD |
76 | +static MprMutex **locks; |
77 | +static int numLocks; |
78 | +#endif |
79 | + |
80 | +////////////////////////////// Forward Declarations //////////////////////////// |
81 | + |
82 | +#if BLD_FEATURE_MULTITHREAD |
83 | +static DynLock *sslCreateDynLock(const char *file, int line); |
84 | +static void sslDynLock(int mode, DynLock *dl, const char *file, int line); |
85 | +static void sslDestroyDynLock(DynLock *dl, const char *file, int line); |
86 | +static void sslStaticLock(int mode, int n, const char *file, int line); |
87 | +static ulong sslThreadId(); |
88 | +#endif |
89 | + |
90 | +static int configureCertificates(SSL_CTX *ctx, char *key, char *cert); |
91 | +static RSA *rsaCallback(SSL *ssl, int isExport, int keyLength); |
92 | +static DH *dhCallback(SSL *ssl, int isExport, int keyLength); |
93 | +static int verifyX509Certificate(int ok, X509_STORE_CTX *ctx); |
94 | + |
95 | +//////////////////////////////////// Locals //////////////////////////////////// |
96 | + |
97 | +static MaOpenSslModule *openSslModule; |
98 | +static MaOpenSslProvider *openSslProvider; |
99 | + |
100 | +//////////////////////////////////////////////////////////////////////////////// |
101 | +/////////////////////////////// MaOpenSslModule //////////////////////////////// |
102 | +//////////////////////////////////////////////////////////////////////////////// |
103 | + |
104 | +int mprOpenSslInit(void *handle) |
105 | +{ |
106 | + if (maGetHttp() == 0) { |
107 | + return MPR_ERR_NOT_INITIALIZED; |
108 | + } |
109 | + new MaOpenSslModule(handle); |
110 | + return 0; |
111 | +} |
112 | + |
113 | +//////////////////////////////////////////////////////////////////////////////// |
114 | + |
115 | +MaOpenSslModule::MaOpenSslModule(void *handle) : MaModule("openSsl", handle) |
116 | +{ |
117 | + openSslModule = this; |
118 | + openSslProvider = new MaOpenSslProvider("openSsl"); |
119 | +} |
120 | + |
121 | +//////////////////////////////////////////////////////////////////////////////// |
122 | + |
123 | +MaOpenSslModule::~MaOpenSslModule() |
124 | +{ |
125 | + delete openSslProvider; |
126 | +} |
127 | + |
128 | +//////////////////////////////////////////////////////////////////////////////// |
129 | +// |
130 | +// This is called from Http::start after all the modules are loaded. |
131 | +// The code here is global for this handler and is not required per handler |
132 | +// instance. |
133 | +// |
134 | +int MaOpenSslModule::start() |
135 | +{ |
136 | + RandBuf randBuf; |
137 | + static int once = 0; |
138 | + |
139 | + // |
140 | + // Depending on the order in the configuration file, we will get called |
141 | + // by the module mechanism and by OpenSslConfig::start(). But we only |
142 | + // want to run once. |
143 | + // |
144 | + if (once++ > 0) { |
145 | + return 0; |
146 | + } |
147 | + randBuf.pid = getpid(); |
148 | + randBuf.time = time(0); |
149 | + randBuf.msec = mprGetTime(0); |
150 | + RAND_seed((void*) &randBuf, sizeof(randBuf)); |
151 | + |
152 | +#if SOLARIS || LINUX || MACOSX |
153 | + mprLog(6, "OpenSsl: Before calling RAND_load_file\n"); |
154 | + RAND_load_file("/dev/urandom", 256); |
155 | + mprLog(6, "OpenSsl: After calling RAND_load_file\n"); |
156 | +#endif |
157 | + |
158 | +#if BLD_FEATURE_MULTITHREAD |
159 | + numLocks = CRYPTO_num_locks(); |
160 | + locks = (MprMutex**) mprMalloc(numLocks * sizeof(MprMutex*)); |
161 | + for (int i = 0; i < numLocks; i++) { |
162 | + locks[i] = new MprMutex(); |
163 | + } |
164 | + CRYPTO_set_id_callback(sslThreadId); |
165 | + CRYPTO_set_locking_callback(sslStaticLock); |
166 | + |
167 | + CRYPTO_set_dynlock_create_callback(sslCreateDynLock); |
168 | + CRYPTO_set_dynlock_destroy_callback(sslDestroyDynLock); |
169 | + CRYPTO_set_dynlock_lock_callback(sslDynLock); |
170 | +#endif |
171 | + |
172 | +#if WIN |
173 | + // _fmode=_O_BINARY; |
174 | + // CRYPTO_malloc_init(); |
175 | + // SSLC_add_all_algorithms(); |
176 | +#else |
177 | + OpenSSL_add_all_algorithms(); |
178 | +#endif |
179 | + |
180 | + SSL_library_init(); |
181 | + return 0; |
182 | +} |
183 | + |
184 | +//////////////////////////////////////////////////////////////////////////////// |
185 | + |
186 | +void MaOpenSslModule::stop() |
187 | +{ |
188 | +#if BLD_FEATURE_MULTITHREAD |
189 | + int i; |
190 | + |
191 | + if (locks) { |
192 | + for (i = 0; i < numLocks; i++) { |
193 | + delete locks[i]; |
194 | + } |
195 | + mprFree(locks); |
196 | + locks = 0; |
197 | + numLocks = 0; |
198 | + |
199 | + CRYPTO_set_id_callback(0); |
200 | + CRYPTO_set_locking_callback(0); |
201 | + |
202 | + CRYPTO_set_dynlock_create_callback(0); |
203 | + CRYPTO_set_dynlock_destroy_callback(0); |
204 | + CRYPTO_set_dynlock_lock_callback(0); |
205 | + } |
206 | +#endif |
207 | +} |
208 | + |
209 | +//////////////////////////////////////////////////////////////////////////////// |
210 | +/////////////////////////////// MaOpenSslProvider ////////////////////////////// |
211 | +//////////////////////////////////////////////////////////////////////////////// |
212 | +// |
213 | +// The SSL provider class implements and decouples the interface between |
214 | +// AppWeb and any SSL stack. |
215 | +// |
216 | + |
217 | +MaOpenSslProvider::MaOpenSslProvider(char *name) : MaSslProvider(name) |
218 | +{ |
219 | +} |
220 | + |
221 | +//////////////////////////////////////////////////////////////////////////////// |
222 | + |
223 | +MaOpenSslProvider::~MaOpenSslProvider() |
224 | +{ |
225 | +} |
226 | + |
227 | +//////////////////////////////////////////////////////////////////////////////// |
228 | + |
229 | +MaSslConfig *MaOpenSslProvider::newConfig(MaHost *host) |
230 | +{ |
231 | + return new MaOpenSslConfig(host); |
232 | +} |
233 | + |
234 | +//////////////////////////////////////////////////////////////////////////////// |
235 | +//////////////////////////////// MaOpenSslConfig /////////////////////////////// |
236 | +//////////////////////////////////////////////////////////////////////////////// |
237 | +// |
238 | +// An instance is created for each SSL server |
239 | +// |
240 | + |
241 | +MaOpenSslConfig::MaOpenSslConfig(MaHost *host) : MaSslConfig(host) |
242 | +{ |
243 | + context = 0; |
244 | + dhKey512 = 0; |
245 | + dhKey1024 = 0; |
246 | + rsaKey512 = 0; |
247 | + rsaKey1024 = 0; |
248 | +} |
249 | + |
250 | +//////////////////////////////////////////////////////////////////////////////// |
251 | + |
252 | +MaOpenSslConfig::~MaOpenSslConfig() |
253 | +{ |
254 | + if (context != 0) { |
255 | + SSL_CTX_free(context); |
256 | + } |
257 | + if (rsaKey512) { |
258 | + RSA_free(rsaKey512); |
259 | + } |
260 | + if (rsaKey1024) { |
261 | + RSA_free(rsaKey1024); |
262 | + } |
263 | + if (dhKey512) { |
264 | + DH_free(dhKey512); |
265 | + } |
266 | + if (dhKey1024) { |
267 | + DH_free(dhKey1024); |
268 | + } |
269 | +} |
270 | + |
271 | +//////////////////////////////////////////////////////////////////////////////// |
272 | +// |
273 | +// This method is called to open listening sockets using this SslConfig setup. |
274 | +// |
275 | + |
276 | +MprSocket *MaOpenSslConfig::newSocket() |
277 | +{ |
278 | + MaOpenSslSocket *socket; |
279 | + |
280 | + socket = new MaOpenSslSocket(this); |
281 | + |
282 | + return (MprSocket*) socket; |
283 | +} |
284 | + |
285 | +//////////////////////////////////////////////////////////////////////////////// |
286 | +// |
287 | +// This is started for each SSL connection. With Keep-alive this may service |
288 | +// many requests. |
289 | +// |
290 | + |
291 | +int MaOpenSslConfig::start() |
292 | +{ |
293 | + SSL_METHOD *meth; |
294 | + char *hostName; |
295 | + |
296 | + if (keyFile == 0) { |
297 | + mprError(MPR_L, MPR_LOG, "Cant start SSL: missing key file"); |
298 | + return MPR_ERR_CANT_INITIALIZE; |
299 | + } |
300 | + if (certFile == 0) { |
301 | + mprError(MPR_L, MPR_LOG, "Cant start SSL: missing certificate file"); |
302 | + return MPR_ERR_CANT_INITIALIZE; |
303 | + } |
304 | + |
305 | + // |
306 | + // Depending on the order in the configuration file, we may get called |
307 | + // by sslModule::start() before OpenSslModule::start has run. So we |
308 | + // must initialize here. |
309 | + // |
310 | + openSslModule->start(); |
311 | + |
312 | + hostName = host->getName(); |
313 | + |
314 | + if (protocols == MPR_HTTP_PROTO_SSLV2) { |
315 | + meth = SSLv2_server_method(); |
316 | + } else { |
317 | + meth = SSLv23_server_method(); |
318 | + } |
319 | + context = SSL_CTX_new(meth); |
320 | + mprAssert(context); |
321 | + if (context == 0) { |
322 | + mprError(MPR_L, MPR_LOG, "Unable to create SSL context"); |
323 | + return MPR_ERR_CANT_CREATE; |
324 | + } |
325 | + |
326 | + SSL_CTX_set_app_data(context, (void*) this); |
327 | + SSL_CTX_set_quiet_shutdown(context, 1); |
328 | + SSL_CTX_sess_set_cache_size(context, 512); |
329 | + |
330 | + // |
331 | + // Configure the certificate for this host |
332 | + // |
333 | + if (configureCertificates(context, keyFile, certFile) != 0) { |
334 | + SSL_CTX_free(context); |
335 | + context = 0; |
336 | + return MPR_ERR_CANT_INITIALIZE; |
337 | + } |
338 | + |
339 | + mprLog(4, "SSL: %s: Using ciphers %s\n", hostName, ciphers); |
340 | + SSL_CTX_set_cipher_list(context, ciphers); |
341 | + |
342 | + // |
343 | + // Configure the client verification certificate locations |
344 | + // |
345 | + if (verifyClient) { |
346 | + if (caFile == 0 && caPath == 0) { |
347 | + mprError(MPR_L, MPR_LOG, |
348 | + "Must define CA certificates if using client verification"); |
349 | + SSL_CTX_free(context); |
350 | + context = 0; |
351 | + return MPR_ERR_BAD_STATE; |
352 | + } |
353 | + if (caFile || caPath) { |
354 | + if ((!SSL_CTX_load_verify_locations(context, caFile, caPath)) || |
355 | + (!SSL_CTX_set_default_verify_paths(context))) { |
356 | + mprError(MPR_L, MPR_LOG, |
357 | + "Unable to set certificate locations"); |
358 | + SSL_CTX_free(context); |
359 | + context = 0; |
360 | + return MPR_ERR_CANT_ACCESS; |
361 | + } |
362 | + if (caFile) { |
363 | + STACK_OF(X509_NAME) *certNames; |
364 | + certNames = SSL_load_client_CA_file(caFile); |
365 | + if (certNames == 0) { |
366 | + } else { |
367 | + // |
368 | + // Define the list of CA certificates to send to the client |
369 | + // before they send their client certificate for validation |
370 | + // |
371 | + SSL_CTX_set_client_CA_list(context, certNames); |
372 | + } |
373 | + } |
374 | + } |
375 | + mprLog(4, "SSL: %s: is verifying client connections\n", hostName); |
376 | + if (caFile) { |
377 | + mprLog(4, "SSL: %s: Using certificates from %s\n", hostName, |
378 | + caFile); |
379 | + } else if (caPath) { |
380 | + mprLog(4, "SSL: %s: Using certificates from directory %s\n", |
381 | + hostName, caPath); |
382 | + } |
383 | + SSL_CTX_set_verify(context, |
384 | + SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, |
385 | + verifyX509Certificate); |
386 | + SSL_CTX_set_verify_depth(context, verifyDepth); |
387 | + |
388 | + } else { |
389 | + SSL_CTX_set_verify(context, SSL_VERIFY_NONE, verifyX509Certificate); |
390 | + } |
391 | + |
392 | + // |
393 | + // Define callbacks |
394 | + // |
395 | + SSL_CTX_set_tmp_rsa_callback(context, rsaCallback); |
396 | + SSL_CTX_set_tmp_dh_callback(context, dhCallback); |
397 | + |
398 | + // |
399 | + // Enable all buggy client work-arounds |
400 | + // |
401 | + SSL_CTX_set_options(context, SSL_OP_ALL); |
402 | + |
403 | + // |
404 | + // Select the required protocols |
405 | + // |
406 | + if (!(protocols & MPR_HTTP_PROTO_SSLV2)) { |
407 | + SSL_CTX_set_options(context, SSL_OP_NO_SSLv2); |
408 | + mprLog(4, "SSL: %s: Disabling SSLv2\n", hostName); |
409 | + } |
410 | + if (!(protocols & MPR_HTTP_PROTO_SSLV3)) { |
411 | + SSL_CTX_set_options(context, SSL_OP_NO_SSLv3); |
412 | + mprLog(4, "SSL: %s: Disabling SSLv3\n", hostName); |
413 | + } |
414 | + if (!(protocols & MPR_HTTP_PROTO_TLSV1)) { |
415 | + SSL_CTX_set_options(context, SSL_OP_NO_TLSv1); |
416 | + mprLog(4, "SSL: %s: Disabling TLSv1\n", hostName); |
417 | + } |
418 | + |
419 | + // |
420 | + // Ensure we generate a new private key for each connection |
421 | + // |
422 | + SSL_CTX_set_options(context, SSL_OP_SINGLE_DH_USE); |
423 | + |
424 | + // |
425 | + // Pre-generate some keys that are slow to compute |
426 | + // |
427 | + rsaKey512 = RSA_generate_key(512, RSA_F4, 0, 0); |
428 | + rsaKey1024 = RSA_generate_key(1024, RSA_F4, 0, 0); |
429 | + |
430 | + dhKey512 = get_dh512(); |
431 | + dhKey1024 = get_dh1024(); |
432 | + |
433 | + return 0; |
434 | +} |
435 | + |
436 | +//////////////////////////////////////////////////////////////////////////////// |
437 | + |
438 | +void MaOpenSslConfig::stop() |
439 | +{ |
440 | +} |
441 | + |
442 | +//////////////////////////////////////////////////////////////////////////////// |
443 | + |
444 | +SSL_CTX *MaOpenSslConfig::getContext() |
445 | +{ |
446 | + return context; |
447 | +} |
448 | + |
449 | +//////////////////////////////////////////////////////////////////////////////// |
450 | + |
451 | +/// |
452 | +/// Called to verify X509 client certificates |
453 | +/// |
454 | +static int verifyX509Certificate(int ok, X509_STORE_CTX *xContext) |
455 | +{ |
456 | + X509 *cert; |
457 | + SSL *ssl; |
458 | + MaOpenSslSocket *sslSocket; |
459 | + MaOpenSslConfig *config; |
460 | + char subject[260], issuer[260], peer[260]; |
461 | + int error, depth; |
462 | + |
463 | + subject[0] = issuer[0] = '\0'; |
464 | + |
465 | + ssl = (SSL*) X509_STORE_CTX_get_app_data(xContext); |
466 | + sslSocket = (MaOpenSslSocket*) SSL_get_app_data(ssl); |
467 | + config = (MaOpenSslConfig*) sslSocket->getConfig(); |
468 | + |
469 | + cert = X509_STORE_CTX_get_current_cert(xContext); |
470 | + depth = X509_STORE_CTX_get_error_depth(xContext); |
471 | + error = X509_STORE_CTX_get_error(xContext); |
472 | + |
473 | + if (X509_NAME_oneline(X509_get_subject_name(cert), subject, |
474 | + sizeof(subject) - 1) < 0) { |
475 | + ok = 0; |
476 | + } |
477 | + // |
478 | + // FUTURE -- should compare subject name and host name. Need smart compare |
479 | + // |
480 | + if (X509_NAME_oneline(X509_get_issuer_name(xContext->current_cert), issuer, |
481 | + sizeof(issuer) - 1) < 0) { |
482 | + ok = 0; |
483 | + } |
484 | + if (X509_NAME_get_text_by_NID(X509_get_subject_name(xContext->current_cert), |
485 | + NID_commonName, peer, sizeof(peer) - 1) < 0) { |
486 | + ok = 0; |
487 | + } |
488 | + |
489 | + // |
490 | + // Customizers: add your own code here to validate client certificates |
491 | + // |
492 | + if (ok && config->verifyDepth < depth) { |
493 | + if (error == 0) { |
494 | + error = X509_V_ERR_CERT_CHAIN_TOO_LONG; |
495 | + } |
496 | + ok = 0; |
497 | + } |
498 | + |
499 | + if (error != 0) { |
500 | + mprAssert(!ok); |
501 | + } |
502 | + |
503 | +#if UNUSED |
504 | + switch (error) { |
505 | + case X509_V_ERR_CERT_HAS_EXPIRED: |
506 | + case X509_V_ERR_CERT_NOT_YET_VALID: |
507 | + case X509_V_ERR_CERT_REJECTED: |
508 | + case X509_V_ERR_CERT_SIGNATURE_FAILURE: |
509 | + case X509_V_ERR_CERT_UNTRUSTED: |
510 | + case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: |
511 | + case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: |
512 | + case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: |
513 | + case X509_V_ERR_INVALID_CA: |
514 | + case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: |
515 | + case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: |
516 | + default: |
517 | + ok = 0; |
518 | + break; |
519 | + } |
520 | +#endif |
521 | + |
522 | + if (!ok) { |
523 | + mprLog(0, "SSL: Certification failed: subject %s\n", subject); |
524 | + mprLog(4, "SSL: Issuer: %s\n", issuer); |
525 | + mprLog(4, "SSL: Peer: %s\n", peer); |
526 | + mprLog(4, "SSL: Error: %d: %s\n", error, |
527 | + X509_verify_cert_error_string(error)); |
528 | + |
529 | + } else { |
530 | + mprLog(0, "SSL: Certificate verified: subject %s\n", subject); |
531 | + mprLog(4, "SSL: Issuer: %s\n", issuer); |
532 | + mprLog(4, "SSL: Peer: %s\n", peer); |
533 | + } |
534 | + return ok; |
535 | +} |
536 | + |
537 | +//////////////////////////////////////////////////////////////////////////////// |
538 | + |
539 | +/// |
540 | +/// Configure the SSL certificate information |
541 | +/// |
542 | + |
543 | +static int configureCertificates(SSL_CTX *ctx, char *key, char *cert) |
544 | +{ |
545 | + mprAssert(ctx); |
546 | + mprAssert(cert); |
547 | + |
548 | + if (cert == 0) { |
549 | + return 0; |
550 | + } |
551 | + |
552 | + if (SSL_CTX_use_certificate_file(ctx, cert, SSL_FILETYPE_PEM) <= 0){ |
553 | + mprError(MPR_L, MPR_LOG, "Can't define certificate file: %s", cert); |
554 | + return -1; |
555 | + } |
556 | + |
557 | + key = (key == 0) ? cert : key; |
558 | + if (SSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM) <= 0) { |
559 | + mprError(MPR_L, MPR_LOG, "Can't define private key file: %s", key); |
560 | + return -1; |
561 | + } |
562 | + |
563 | + if (!SSL_CTX_check_private_key(ctx)) { |
564 | + mprError(MPR_L, MPR_LOG, "Check of private key file failed: %s", key); |
565 | + return -1; |
566 | + } |
567 | + return 0; |
568 | +} |
569 | + |
570 | +//////////////////////////////////////////////////////////////////////////////// |
571 | +//////////////////////////////// MaOpenSslSocket /////////////////////////////// |
572 | +//////////////////////////////////////////////////////////////////////////////// |
573 | + |
574 | +MaOpenSslSocket::MaOpenSslSocket(MaOpenSslConfig *config) : MaSslSocket(config) |
575 | +{ |
576 | + ssl = 0; |
577 | + bio = 0; |
578 | + context = config->getContext(); |
579 | +} |
580 | + |
581 | +//////////////////////////////////////////////////////////////////////////////// |
582 | + |
583 | +MaOpenSslSocket::~MaOpenSslSocket() |
584 | +{ |
585 | + mprAssert(ssl == 0); |
586 | + mprAssert(bio == 0); |
587 | +} |
588 | + |
589 | +//////////////////////////////////////////////////////////////////////////////// |
590 | +// |
591 | +// Called to accept new connections. When a new connection arrives, this |
592 | +// method is called to create a new socket object using the same SSL "config" |
593 | +// as the listening socket. |
594 | +// |
595 | + |
596 | +MprSocket *MaOpenSslSocket::newSocket() |
597 | +{ |
598 | + MaOpenSslSocket *socket; |
599 | + |
600 | + socket = new MaOpenSslSocket((MaOpenSslConfig*) config); |
601 | + |
602 | + return (MprSocket*) socket; |
603 | +} |
604 | + |
605 | +//////////////////////////////////////////////////////////////////////////////// |
606 | +// |
607 | +// initConnection is called on the first I/O on a new connection. It must |
608 | +// setup the SSL structures ready to exchange data. |
609 | +// |
610 | +// Init connection must return -1 on errors. It must also be able to reject |
611 | +// subsequent calls to read()/write(). On errors we leave bio == 0. This |
612 | +// will cause any calls to read() to error. |
613 | +// |
614 | + |
615 | +int MaOpenSslSocket::initConnection() |
616 | +{ |
617 | + BIO *bioSSL, *bioSock; |
618 | + |
619 | + if (bio) { |
620 | + return 0; |
621 | + } |
622 | + bio = BIO_new(BIO_f_buffer()); |
623 | + if (bio == 0) { |
624 | + return MPR_ERR_CANT_INITIALIZE; |
625 | + } |
626 | + |
627 | + BIO_set_write_buffer_size(bio, 128); |
628 | + ssl = (SSL*) SSL_new(context); |
629 | + mprAssert(ssl); |
630 | + if (ssl == 0) { |
631 | + return MPR_ERR_CANT_INITIALIZE; |
632 | + } |
633 | + SSL_set_app_data(ssl, (void*) this); |
634 | + |
635 | + SSL_set_session(ssl, 0); |
636 | + bioSSL = BIO_new(BIO_f_ssl()); |
637 | + mprAssert(bioSSL); |
638 | + |
639 | + bioSock = BIO_new_socket(sock, BIO_NOCLOSE); |
640 | + mprAssert(bioSock); |
641 | + |
642 | + SSL_set_bio(ssl, bioSock, bioSock); |
643 | + SSL_set_accept_state(ssl); |
644 | + |
645 | + BIO_set_ssl(bioSSL, ssl, BIO_CLOSE); |
646 | + BIO_push(bio, bioSSL); |
647 | + return 0; |
648 | +} |
649 | + |
650 | +//////////////////////////////////////////////////////////////////////////////// |
651 | + |
652 | +bool MaOpenSslSocket::dispose() |
653 | +{ |
654 | + if (ssl) { |
655 | + SSL_set_shutdown(ssl, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN); |
656 | + ssl = 0; |
657 | + } |
658 | + if (bio) { |
659 | + BIO_free_all(bio); |
660 | + bio = 0; |
661 | + } |
662 | + |
663 | + // |
664 | + // Disposing a socket is a thread-safe way of calling a destructor. It |
665 | + // uses reference counting and will be deleted when the last reference |
666 | + // is released. |
667 | + // |
668 | + return this->MprSocket::dispose(); |
669 | +} |
670 | + |
671 | +//////////////////////////////////////////////////////////////////////////////// |
672 | + |
673 | +void MaOpenSslSocket::close(int how) |
674 | +{ |
675 | + BIO_flush(bio); |
676 | + this->MprSocket::close(how); |
677 | +} |
678 | + |
679 | +//////////////////////////////////////////////////////////////////////////////// |
680 | +// |
681 | +// Write data. Return the number of bytes written or -1 on errors. |
682 | +// |
683 | + |
684 | +int MaOpenSslSocket::write(char *buf, int len) |
685 | +{ |
686 | + int rc, written, totalWritten; |
687 | + |
688 | + if (bio == 0 || ssl == 0 || len < 0) { |
689 | + return -1; |
690 | + } |
691 | + BIO_clear_retry_flags(bio); |
692 | + totalWritten = 0; |
693 | + do { |
694 | + written = BIO_write(bio, buf, len); |
695 | + mprLog(7, "written %d, len %d\n", written, len); |
696 | + if (written >= 0) { |
697 | + do { |
698 | + rc = BIO_flush(bio); |
699 | + mprLog(7, "BIO_flush rc %d\n", rc); |
700 | + if (rc > 0) { |
701 | + // Success |
702 | + break; |
703 | + } |
704 | + // |
705 | + // Nap to prevent busy waiting. |
706 | + // |
707 | + mprSleep(10); |
708 | + } while (rc <= 0 && BIO_should_retry(bio)); |
709 | + totalWritten += written; |
710 | + buf += written; |
711 | + len -= written; |
712 | + } |
713 | + mprLog(7, "write: len %d, written %d, total %d, should_retry %d\n", |
714 | + len, written, totalWritten, BIO_should_retry(bio)); |
715 | + } while (len > 0 && (written > 0 || BIO_should_retry(bio))); |
716 | + |
717 | +//AFF |
718 | + if(written < 0 && BIO_should_retry(bio) == 0) |
719 | + return -1; |
720 | +// |
721 | + |
722 | + return totalWritten; |
723 | +} |
724 | + |
725 | +//////////////////////////////////////////////////////////////////////////////// |
726 | + |
727 | +int MaOpenSslSocket::flush() |
728 | +{ |
729 | + return BIO_flush(bio); |
730 | +} |
731 | + |
732 | +//////////////////////////////////////////////////////////////////////////////// |
733 | + |
734 | +int MaOpenSslSocket::read(char *buf, int len) |
735 | +{ |
736 | + int rc; |
737 | + |
738 | + if (bio == 0 || ssl == 0) { |
739 | + return -1; |
740 | + } |
741 | + |
742 | + rc = BIO_read(bio, buf, len); |
743 | + |
744 | +#if DEBUG |
745 | + if (rc > 0 && !connTraced) { |
746 | + X509_NAME *xSubject; |
747 | + X509 *cert; |
748 | + char subject[260], issuer[260], peer[260]; |
749 | + |
750 | + mprLog(4, "%d: SSL Connected using: \"%s\"\n", |
751 | + sock, SSL_get_cipher(ssl)); |
752 | + |
753 | + cert = SSL_get_peer_certificate(ssl); |
754 | + if (cert == 0) { |
755 | + mprLog(4, "%d: SSL Details: client supplied no certificate\n", |
756 | + sock); |
757 | + } else { |
758 | + xSubject = X509_get_subject_name(cert); |
759 | + X509_NAME_oneline(xSubject, subject, sizeof(subject) -1); |
760 | + X509_NAME_oneline(X509_get_issuer_name(cert), issuer, |
761 | + sizeof(issuer) -1); |
762 | + X509_NAME_get_text_by_NID(xSubject, NID_commonName, peer, |
763 | + sizeof(peer) - 1); |
764 | + mprLog(4, "%d: SSL Subject %s\n", sock, subject); |
765 | + mprLog(4, "%d: SSL Issuer: %s\n", sock, issuer); |
766 | + mprLog(4, "%d: SSL Peer: %s\n", sock, peer); |
767 | + X509_free(cert); |
768 | + } |
769 | + connTraced = 1; |
770 | + } |
771 | +#endif |
772 | + |
773 | + if (rc > 0) { |
774 | + return rc; |
775 | + |
776 | + } else if (rc == 0) { |
777 | + if (BIO_should_retry(bio)) { |
778 | + return 0; |
779 | + } |
780 | + flags |= MPR_SOCKET_EOF; |
781 | + return 0; |
782 | + } |
783 | + if (BIO_should_retry(bio)) { |
784 | + return 0; |
785 | + } |
786 | + return rc; |
787 | +} |
788 | + |
789 | +//////////////////////////////////////////////////////////////////////////////// |
790 | +#if UNUSED |
791 | +// |
792 | +// Return true if end of file |
793 | +// |
794 | + |
795 | +bool MaOpenSslSocket::getEof() |
796 | +{ |
797 | + bool rc; |
798 | + |
799 | + rc = (BIO_eof(bio) != 0); |
800 | + return rc; |
801 | +} |
802 | + |
803 | +#endif |
804 | + |
805 | +//////////////////////////////////////////////////////////////////////////////// |
806 | +#if BLD_FEATURE_MULTITHREAD |
807 | + |
808 | +static ulong sslThreadId() |
809 | +{ |
810 | + return (long) mprGetCurrentThread(); |
811 | +} |
812 | + |
813 | +//////////////////////////////////////////////////////////////////////////////// |
814 | + |
815 | +static void sslStaticLock(int mode, int n, const char *file, int line) |
816 | +{ |
817 | + mprAssert(0 <= n && n < numLocks); |
818 | + if (mode & CRYPTO_LOCK) { |
819 | + locks[n]->lock(); |
820 | + } else { |
821 | + locks[n]->unlock(); |
822 | + } |
823 | +} |
824 | + |
825 | +//////////////////////////////////////////////////////////////////////////////// |
826 | + |
827 | +static DynLock *sslCreateDynLock(const char *file, int line) |
828 | +{ |
829 | + DynLock *dl; |
830 | + |
831 | + dl = (DynLock*) mprMalloc(sizeof(DynLock)); |
832 | + dl->mutex = new MprMutex(); |
833 | + return dl; |
834 | +} |
835 | + |
836 | +//////////////////////////////////////////////////////////////////////////////// |
837 | + |
838 | +static void sslDestroyDynLock(DynLock *dl, const char *file, int line) |
839 | +{ |
840 | + delete dl->mutex; |
841 | + mprFree(dl); |
842 | +} |
843 | + |
844 | +//////////////////////////////////////////////////////////////////////////////// |
845 | + |
846 | +static void sslDynLock(int mode, DynLock *dl, const char *file, int line) |
847 | +{ |
848 | + if (mode & CRYPTO_LOCK) { |
849 | + dl->mutex->lock(); |
850 | + } else { |
851 | + dl->mutex->unlock(); |
852 | + } |
853 | +} |
854 | + |
855 | +#endif // BLD_FEATURE_MULTITHREAD |
856 | +//////////////////////////////////////////////////////////////////////////////// |
857 | +// |
858 | +// Used for ephemeral RSA keys |
859 | +// |
860 | + |
861 | +static RSA *rsaCallback(SSL *ssl, int isExport, int keyLength) |
862 | +{ |
863 | + MaOpenSslSocket *sslSocket; |
864 | + MaOpenSslConfig *config; |
865 | + RSA *key; |
866 | + |
867 | + sslSocket = (MaOpenSslSocket*) SSL_get_app_data(ssl); |
868 | + config = (MaOpenSslConfig*) sslSocket->getConfig(); |
869 | + |
870 | + key = 0; |
871 | + switch (keyLength) { |
872 | + case 512: |
873 | + key = config->rsaKey512; |
874 | + break; |
875 | + |
876 | + case 1024: |
877 | + default: |
878 | + key = config->rsaKey1024; |
879 | + } |
880 | + return key; |
881 | +} |
882 | + |
883 | + |
884 | +//////////////////////////////////////////////////////////////////////////////// |
885 | +// |
886 | +// Used for ephemeral DH keys |
887 | +// |
888 | + |
889 | +static DH *dhCallback(SSL *ssl, int isExport, int keyLength) |
890 | +{ |
891 | + MaOpenSslSocket *sslSocket; |
892 | + MaOpenSslConfig *config; |
893 | + DH *key; |
894 | + |
895 | + sslSocket = (MaOpenSslSocket*) SSL_get_app_data(ssl); |
896 | + config = (MaOpenSslConfig*) sslSocket->getConfig(); |
897 | + |
898 | + key = 0; |
899 | + switch (keyLength) { |
900 | + case 512: |
901 | + key = config->dhKey512; |
902 | + break; |
903 | + |
904 | + case 1024: |
905 | + default: |
906 | + key = config->dhKey1024; |
907 | + } |
908 | + return key; |
909 | +} |
910 | + |
911 | +//////////////////////////////////////////////////////////////////////////////// |
912 | +#else |
913 | +void mprOpenSslModuleDummy() {} |
914 | + |
915 | +#endif // BLD_FEATURE_OPENSSL_MODULE |
916 | + |
917 | +// |
918 | +// Local variables: |
919 | +// tab-width: 4 |
920 | +// c-basic-offset: 4 |
921 | +// End: |
922 | +// vim:tw=78 |
923 | +// vim600: sw=4 ts=4 fdm=marker |
924 | +// vim<600: sw=4 ts=4 |
925 | +// |
926 | |
927 | === added file 'appWeb/thread.cpp' |
928 | --- appWeb/thread.cpp 1970-01-01 00:00:00 +0000 |
929 | +++ appWeb/thread.cpp 2011-11-23 01:01:25 +0000 |
930 | @@ -0,0 +1,768 @@ |
931 | +/// |
932 | +/// @file WIN/thread.cpp |
933 | +/// @brief Primitive multi-threading support for Linux |
934 | +/// @overview This module provides threading, mutex and condition |
935 | +/// variable APIs for Windows. |
936 | +// |
937 | +////////////////////////////////// Copyright /////////////////////////////////// |
938 | +// |
939 | +// @copy default |
940 | +// |
941 | +// Copyright (c) Mbedthis Software LLC, 2003-2006. All Rights Reserved. |
942 | +// Copyright (c) Michael O'Brien, 1994-2006. All Rights Reserved. |
943 | +// |
944 | +// This software is distributed under commercial and open source licenses. |
945 | +// You may use the GPL open source license described below or you may acquire |
946 | +// a commercial license from Mbedthis Software. You agree to be fully bound |
947 | +// by the terms of either license. Consult the LICENSE.TXT distributed with |
948 | +// this software for full details. |
949 | +// |
950 | +// This software is open source; you can redistribute it and/or modify it |
951 | +// under the terms of the GNU General Public License as published by the |
952 | +// Free Software Foundation; either version 2 of the License, or (at your |
953 | +// option) any later version. See the GNU General Public License for more |
954 | +// details at: http://www.mbedthis.com/downloads/gplLicense.html |
955 | +// |
956 | +// This program is distributed WITHOUT ANY WARRANTY; without even the |
957 | +// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
958 | +// |
959 | +// This GPL license does NOT permit incorporating this software into |
960 | +// proprietary programs. If you are unable to comply with the GPL, you must |
961 | +// acquire a commercial license to use this software. Commercial licenses |
962 | +// for this software and support services are available from Mbedthis |
963 | +// Software at http://www.mbedthis.com |
964 | +// |
965 | +// @end |
966 | +// |
967 | +////////////////////////////////// Includes /////////////////////////////////// |
968 | + |
969 | +#include "mpr/mpr.h" |
970 | + |
971 | +//////////////////////////////////// Locals /////////////////////////////////// |
972 | +#if BLD_FEATURE_MULTITHREAD |
973 | + |
974 | +#if BLD_DEBUG |
975 | +CRITICAL_SECTION debugCs; |
976 | +static MprList mutexList; |
977 | +static int numMutex = -1; // Must initialize to -1 (see addMutex) |
978 | +MprList condList; |
979 | + |
980 | +#define DEBUG_TIME 0 // Spare[0] == time |
981 | +#define DEBUG_ID 1 // Spare[1] == thread id |
982 | +#endif |
983 | + |
984 | +//////////////////////////// Forward Declarations ///////////////////////////// |
985 | + |
986 | +static uint __stdcall threadProcWrapper(void *arg); |
987 | + |
988 | +#if BLD_DEBUG |
989 | +#if UNUSED |
990 | +static void lockBuster(void *data, MprThread *tp); |
991 | +#endif |
992 | +static void removeMutex(MprMutex *mp); |
993 | +static void addMutex(MprMutex *mp); |
994 | +#endif |
995 | + |
996 | +///////////////////////////////////// Code //////////////////////////////////// |
997 | +// |
998 | +// Initialize thread service |
999 | +// |
1000 | +// |
1001 | + |
1002 | +MprThreadService::MprThreadService() |
1003 | +{ |
1004 | + mutex = new MprMutex(); |
1005 | + |
1006 | + // |
1007 | + // Don't actually create the thread. Just create a thread object for this |
1008 | + // main thread. |
1009 | + // |
1010 | + mainThread = new MprThread(MPR_NORMAL_PRIORITY, "main"); |
1011 | + mainThread->setId(GetCurrentThreadId()); |
1012 | + |
1013 | + insertThread(mainThread); |
1014 | +} |
1015 | + |
1016 | +/////////////////////////////////////////////////////////////////////////////// |
1017 | +// |
1018 | +// Terminate the thread service |
1019 | +// |
1020 | + |
1021 | +MprThreadService::~MprThreadService() |
1022 | +{ |
1023 | + delete mainThread; |
1024 | + |
1025 | +#if BLD_DEBUG |
1026 | + if (threads.getNumItems() > 0) { |
1027 | + mprError(MPR_L, MPR_LOG, "Exiting with %d thread(s) unfreed", |
1028 | + threads.getNumItems()); |
1029 | + } |
1030 | + if (condList.getNumItems() > 0) { |
1031 | + mprError(MPR_L, MPR_LOG, "Exiting with %d cond var(s) unfreed", |
1032 | + condList.getNumItems()); |
1033 | + } |
1034 | + // |
1035 | + // We allow one open mutex for the log service which has not yet shutdown, |
1036 | + // and one for the libmpr DLL (malloc), we also need one for our mutex |
1037 | + // is freed below. |
1038 | + // |
1039 | + if (mutexList.getNumItems() > 3) { |
1040 | + mprError(MPR_L, MPR_LOG, "Exiting with %d mutex(es) unfreed", |
1041 | + mutexList.getNumItems() - 3); |
1042 | + } |
1043 | +#endif |
1044 | + delete mutex; |
1045 | +} |
1046 | + |
1047 | +//////////////////////////////////////////////////////////////////////////////// |
1048 | +// |
1049 | +// Add a thread to the list |
1050 | +// |
1051 | + |
1052 | +void MprThreadService::insertThread(MprThread *tp) |
1053 | +{ |
1054 | + lock(); |
1055 | + threads.insert(tp); |
1056 | + unlock(); |
1057 | +} |
1058 | + |
1059 | +//////////////////////////////////////////////////////////////////////////////// |
1060 | +// |
1061 | +// Remove a thread from the list |
1062 | +// |
1063 | + |
1064 | +void MprThreadService::removeThread(MprThread *tp) |
1065 | +{ |
1066 | + lock(); |
1067 | + threads.remove(tp); |
1068 | + unlock(); |
1069 | +} |
1070 | + |
1071 | +//////////////////////////////////////////////////////////////////////////////// |
1072 | +// |
1073 | +// Nothing to do |
1074 | +// |
1075 | + |
1076 | +int MprThreadService::start() |
1077 | +{ |
1078 | +#if BLD_DEBUG && UNUSED |
1079 | + MprThread *tp; |
1080 | + |
1081 | + if (!mprGetDebugMode()) { |
1082 | + tp = new MprThread(lockBuster, MPR_LOW_PRIORITY, 0, "watch"); |
1083 | + tp->start(); |
1084 | + } |
1085 | +#endif |
1086 | + return 0; |
1087 | +} |
1088 | + |
1089 | +//////////////////////////////////////////////////////////////////////////////// |
1090 | +// |
1091 | +// Nothing to do. We expect the threads to be self terminating. |
1092 | +// |
1093 | + |
1094 | +int MprThreadService::stop(int timeout) |
1095 | +{ |
1096 | + // |
1097 | + // Wait until all threads (except main thread) have exited |
1098 | + // |
1099 | + while (threads.getNumItems() > 1 && timeout > 0) { |
1100 | + mprSleep(10); |
1101 | + timeout -= 10; |
1102 | + } |
1103 | + return 0; |
1104 | +} |
1105 | + |
1106 | +//////////////////////////////////////////////////////////////////////////////// |
1107 | +// |
1108 | +// Return the current thread object |
1109 | +// |
1110 | + |
1111 | +MprThread *MprThreadService::getCurrentThread() |
1112 | +{ |
1113 | + MprThread *tp; |
1114 | + int id; |
1115 | + |
1116 | + lock(); |
1117 | + id = (int) GetCurrentThreadId(); |
1118 | + tp = (MprThread*) threads.getFirst(); |
1119 | + while (tp) { |
1120 | + if (tp->getId() == id) { |
1121 | + unlock(); |
1122 | + return tp; |
1123 | + } |
1124 | + tp = (MprThread*) threads.getNext(tp); |
1125 | + } |
1126 | + unlock(); |
1127 | + return 0; |
1128 | +} |
1129 | + |
1130 | +//////////////////////////////////////////////////////////////////////////////// |
1131 | +////////////////////////////////// MprThread /////////////////////////////////// |
1132 | +//////////////////////////////////////////////////////////////////////////////// |
1133 | +// |
1134 | +// Create a main thread |
1135 | +// |
1136 | + |
1137 | +MprThread::MprThread(int priority, char *name) |
1138 | +{ |
1139 | + osThreadId = 0; |
1140 | + pid = getpid(); |
1141 | + threadHandle = 0; |
1142 | + this->priority = priority; |
1143 | + entry = 0; |
1144 | + data = 0; |
1145 | + this->name = mprStrdup(name); |
1146 | + |
1147 | + mutex = new MprMutex(); |
1148 | + // |
1149 | + // Inserted into the thread list in MprThreadService() |
1150 | + // |
1151 | +} |
1152 | + |
1153 | +//////////////////////////////////////////////////////////////////////////////// |
1154 | +// |
1155 | +// Create a thread |
1156 | +// |
1157 | + |
1158 | +MprThread::MprThread(MprThreadProc entry, int priority, void *data, |
1159 | + char *name, int stackSize) |
1160 | +{ |
1161 | + osThreadId = 0; |
1162 | + pid = getpid(); |
1163 | + threadHandle = 0; |
1164 | + this->priority = priority; |
1165 | + this->entry = entry; |
1166 | + this->data = data; |
1167 | + this->name = mprStrdup(name); |
1168 | + |
1169 | + mutex = new MprMutex(); |
1170 | + mpr->threadService->insertThread(this); |
1171 | +} |
1172 | + |
1173 | +//////////////////////////////////////////////////////////////////////////////// |
1174 | +// |
1175 | +// Destroy a thread |
1176 | +// |
1177 | + |
1178 | +MprThread::~MprThread() |
1179 | +{ |
1180 | + lock(); |
1181 | + mprLog(MPR_INFO, "Thread exiting %s (%x)\n", name, osThreadId); |
1182 | + |
1183 | + mpr->threadService->removeThread(this); |
1184 | + mprFree(name); |
1185 | + if (threadHandle) { |
1186 | + CloseHandle(threadHandle); |
1187 | + } |
1188 | + delete mutex; |
1189 | +} |
1190 | + |
1191 | +//////////////////////////////////////////////////////////////////////////////// |
1192 | +// |
1193 | +// Start a thread |
1194 | +// |
1195 | + |
1196 | +int MprThread::start() |
1197 | +{ |
1198 | + HANDLE h; |
1199 | + uint threadId; |
1200 | + |
1201 | + lock(); |
1202 | + h = (HANDLE) _beginthreadex(NULL, 0, threadProcWrapper, (void*) this, |
1203 | + 0, &threadId); |
1204 | + if (h == NULL) { |
1205 | + unlock(); |
1206 | + return MPR_ERR_CANT_INITIALIZE; |
1207 | + } |
1208 | + osThreadId = (ulong) threadId; |
1209 | + threadHandle = (HANDLE) h; |
1210 | + |
1211 | + setPriority(priority); |
1212 | + mprLog(MPR_INFO, "Created thread %s (%x)\n", name, threadId); |
1213 | + unlock(); |
1214 | + return 0; |
1215 | +} |
1216 | + |
1217 | +//////////////////////////////////////////////////////////////////////////////// |
1218 | +// |
1219 | +// Thread entry function |
1220 | +// |
1221 | + |
1222 | +static uint __stdcall threadProcWrapper(void *data) |
1223 | +{ |
1224 | +//AFF gracefull crash, main app should exit |
1225 | +#if BLD_DEBUG |
1226 | +#else |
1227 | + try |
1228 | + { |
1229 | +#endif |
1230 | + MprThread *tp; |
1231 | + |
1232 | + tp = (MprThread*) data; |
1233 | + tp->threadProc(); |
1234 | + delete tp; |
1235 | + |
1236 | +#if BLD_DEBUG |
1237 | +#else |
1238 | + } |
1239 | + catch(...) |
1240 | + { |
1241 | + mprLog((char*)"ERROR: catch(...) threadProcWrapper crashed. terminating gracefully..."); |
1242 | + mprGetMpr()->terminate(1); |
1243 | + } |
1244 | +#endif |
1245 | + |
1246 | + return 0; |
1247 | +} |
1248 | + |
1249 | +//////////////////////////////////////////////////////////////////////////////// |
1250 | +// |
1251 | +// Thread procedure |
1252 | +// |
1253 | + |
1254 | +void MprThread::threadProc() |
1255 | +{ |
1256 | + osThreadId = GetCurrentThreadId(); |
1257 | + pid = getpid(); |
1258 | + (entry)(data, this); |
1259 | +} |
1260 | + |
1261 | +//////////////////////////////////////////////////////////////////////////////// |
1262 | + |
1263 | +void MprThread::setPriority(int newPriority) |
1264 | +{ |
1265 | + int osPri; |
1266 | + |
1267 | + lock(); |
1268 | + if (priority == newPriority) { |
1269 | + unlock(); |
1270 | + return; |
1271 | + } |
1272 | + |
1273 | + osPri = mapMprPriorityToOs(newPriority); |
1274 | + SetThreadPriority(threadHandle, osPri); |
1275 | + priority = newPriority; |
1276 | + unlock(); |
1277 | +} |
1278 | + |
1279 | +//////////////////////////////////////////////////////////////////////////////// |
1280 | + |
1281 | +void MprThread::setId(int id) |
1282 | +{ |
1283 | + osThreadId = (ulong) id; |
1284 | +} |
1285 | + |
1286 | +//////////////////////////////////////////////////////////////////////////////// |
1287 | +// |
1288 | +// Map Mpr priority to Windows native priority. Windows priorities range from |
1289 | +// -15 to +15 (zero is normal). Warning: +15 will not yield the CPU, -15 may |
1290 | +// get starved. We should be very wary going above +11. |
1291 | +// |
1292 | + |
1293 | +int MprThread::mapMprPriorityToOs(int mprPriority) |
1294 | +{ |
1295 | + mprAssert(mprPriority >= 0 && mprPriority <= 100); |
1296 | + |
1297 | + if (mprPriority <= MPR_BACKGROUND_PRIORITY) { |
1298 | + return THREAD_PRIORITY_LOWEST; |
1299 | + } else if (mprPriority <= MPR_LOW_PRIORITY) { |
1300 | + return THREAD_PRIORITY_BELOW_NORMAL; |
1301 | + } else if (mprPriority <= MPR_NORMAL_PRIORITY) { |
1302 | + return THREAD_PRIORITY_NORMAL; |
1303 | + } else if (mprPriority <= MPR_HIGH_PRIORITY) { |
1304 | + return THREAD_PRIORITY_ABOVE_NORMAL; |
1305 | + } else { |
1306 | + return THREAD_PRIORITY_HIGHEST; |
1307 | + } |
1308 | +} |
1309 | + |
1310 | +/////////////////////////////////////////////////////////////////////////////// |
1311 | +// |
1312 | +// Map Windows priority to Mpr priority |
1313 | +// |
1314 | + |
1315 | +int MprThread::mapOsPriorityToMpr(int nativePriority) |
1316 | +{ |
1317 | + int priority; |
1318 | + |
1319 | + priority = (45 * nativePriority) + 50; |
1320 | + if (priority < 0) { |
1321 | + priority = 0; |
1322 | + } |
1323 | + if (priority >= 100) { |
1324 | + priority = 99; |
1325 | + } |
1326 | + return priority; |
1327 | +} |
1328 | + |
1329 | +//////////////////////////////////////////////////////////////////////////////// |
1330 | +/////////////////////////////////// MprMutex /////////////////////////////////// |
1331 | +//////////////////////////////////////////////////////////////////////////////// |
1332 | +// |
1333 | +// Create a mutex |
1334 | +// |
1335 | + |
1336 | +MprMutex::MprMutex() |
1337 | +{ |
1338 | + memset(&cs, 0, sizeof(cs)); |
1339 | + InitializeCriticalSectionAndSpinCount(&cs, 5000); |
1340 | + |
1341 | +#if BLD_DEBUG |
1342 | + addMutex(this); |
1343 | + cs.DebugInfo->Spare[DEBUG_ID] = -1; // Thread ID goes here |
1344 | + cs.DebugInfo->Spare[DEBUG_TIME] = 0; // Time goes here |
1345 | +#endif |
1346 | +} |
1347 | + |
1348 | +/////////////////////////////////////////////////////////////////////////////// |
1349 | +// |
1350 | +// Destroy a mutex. Must be locked on entrance. |
1351 | +// |
1352 | + |
1353 | +MprMutex::~MprMutex() |
1354 | +{ |
1355 | + DeleteCriticalSection(&cs); |
1356 | +#if BLD_DEBUG |
1357 | + removeMutex(this); |
1358 | +#endif |
1359 | +} |
1360 | + |
1361 | +/////////////////////////////////////////////////////////////////////////////// |
1362 | +// |
1363 | +// Lock a mutex |
1364 | +// |
1365 | + |
1366 | +void MprMutex::lock() |
1367 | +{ |
1368 | + EnterCriticalSection(&cs); |
1369 | + |
1370 | +#if BLD_DEBUG |
1371 | + mprAssert(cs.RecursionCount >= 0); |
1372 | + mprAssert(cs.RecursionCount < MPR_MAX_RECURSION); |
1373 | + mprAssert(cs.LockCount < MPR_MAX_BLOCKED_LOCKS); |
1374 | + |
1375 | + cs.DebugInfo->Spare[DEBUG_ID] = (ulong) GetCurrentThreadId(); |
1376 | + cs.DebugInfo->Spare[DEBUG_TIME] = GetTickCount(); |
1377 | +#endif |
1378 | +} |
1379 | + |
1380 | +/////////////////////////////////////////////////////////////////////////////// |
1381 | +// |
1382 | +// Try to lock a mutex. Do not block! |
1383 | +// |
1384 | + |
1385 | +int MprMutex::tryLock() |
1386 | +{ |
1387 | + mprAssert(cs.RecursionCount >= 0); |
1388 | + if (TryEnterCriticalSection(&cs) == 0) { |
1389 | + return MPR_ERR_BUSY; |
1390 | + } |
1391 | +#if BLD_DEBUG |
1392 | + cs.DebugInfo->Spare[DEBUG_ID] = (ulong) GetCurrentThreadId(); |
1393 | + cs.DebugInfo->Spare[DEBUG_TIME] = GetTickCount(); |
1394 | +#endif |
1395 | + return 0; |
1396 | +} |
1397 | + |
1398 | +/////////////////////////////////////////////////////////////////////////////// |
1399 | +// |
1400 | +// Unlock a mutex. structure |
1401 | +// |
1402 | + |
1403 | +void MprMutex::unlock() |
1404 | +{ |
1405 | +#if BLD_DEBUG |
1406 | + mprAssert(cs.DebugInfo->Spare[DEBUG_ID] == (ulong) GetCurrentThreadId()); |
1407 | + mprAssert(cs.RecursionCount > 0); |
1408 | + mprAssert(cs.RecursionCount < MPR_MAX_RECURSION); |
1409 | + mprAssert(cs.LockCount < MPR_MAX_LOCKS); |
1410 | + cs.DebugInfo->Spare[DEBUG_TIME] = GetTickCount(); |
1411 | +#endif |
1412 | + LeaveCriticalSection(&cs); |
1413 | +} |
1414 | + |
1415 | +/////////////////////////////////////////////////////////////////////////////// |
1416 | +/////////////////////////////////// MprCond //////////////////////////////////// |
1417 | +//////////////////////////////////////////////////////////////////////////////// |
1418 | +// |
1419 | +// Create a condition variable for use by single or multiple waiters |
1420 | +// |
1421 | + |
1422 | +MprCond::MprCond() |
1423 | +{ |
1424 | +#if UNUSED |
1425 | + wakeAll = 0; |
1426 | + numWaiting = 0; |
1427 | +#endif |
1428 | + triggered = 0; |
1429 | + mutex = new MprMutex(); |
1430 | + cv = CreateEvent(NULL, FALSE, FALSE, NULL); |
1431 | +} |
1432 | + |
1433 | + |
1434 | +//////////////////////////////////////////////////////////////////////////////// |
1435 | +// |
1436 | +// Destroy a condition variable |
1437 | +// |
1438 | + |
1439 | +MprCond::~MprCond() |
1440 | +{ |
1441 | + mutex->lock(); |
1442 | + CloseHandle(cv); |
1443 | + delete mutex; |
1444 | +} |
1445 | + |
1446 | +//////////////////////////////////////////////////////////////////////////////// |
1447 | +// |
1448 | +// Wait for the event to be triggered. Should only be used when there are |
1449 | +// single waiters. If the event is already triggered, then it will return |
1450 | +// immediately. |
1451 | +// |
1452 | + |
1453 | +int MprCond::waitForCond(long timeout) |
1454 | +{ |
1455 | + if (timeout < 0) { |
1456 | + timeout = MAXINT; |
1457 | + } |
1458 | + |
1459 | + if (WaitForSingleObject(cv, timeout) != WAIT_OBJECT_0) { |
1460 | + return -1; |
1461 | + } |
1462 | + |
1463 | + // |
1464 | + // Reset the event |
1465 | + // |
1466 | + mutex->lock(); |
1467 | + mprAssert(triggered != 0); |
1468 | + triggered = 0; |
1469 | + ResetEvent(cv); |
1470 | + mutex->unlock(); |
1471 | + |
1472 | + return 0; |
1473 | +} |
1474 | + |
1475 | +//////////////////////////////////////////////////////////////////////////////// |
1476 | +#if UNUSED |
1477 | +// |
1478 | +// Wait for a condition variable to be signalled. Suitable for when there are |
1479 | +// multiple waiters. It will work for single waiters, but is slower than |
1480 | +// waitForCond() above. Depending on whether signalCond() or signalAll() is |
1481 | +// used, a single waiter or multiple waiters may awake with one invocation of |
1482 | +// signal. If the condition is already triggered, this routine will not block |
1483 | +// for the first waiter. NOTE: the externalMutex must be defined and locked on |
1484 | +// entry to this routine |
1485 | +// |
1486 | + |
1487 | +int MprCond::multiWait(MprMutex *externalMutex, long timeout) |
1488 | +{ |
1489 | + int now, deadline; |
1490 | + |
1491 | + if (timeout < 0) { |
1492 | + timeout = MAXINT; |
1493 | + } |
1494 | + now = mprGetTime(0); |
1495 | + deadline = now + timeout; |
1496 | + |
1497 | + while (now <= deadline) { |
1498 | + mutex->lock(); |
1499 | + numWaiting++; |
1500 | + mutex->unlock(); |
1501 | + |
1502 | + externalMutex->unlock(); |
1503 | + |
1504 | + if (WaitForSingleObject(cv, timeout) != WAIT_OBJECT_0) { |
1505 | + return -1; |
1506 | + } |
1507 | + |
1508 | + mutex->lock(); |
1509 | + --numWaiting; |
1510 | + if (wakeAll) { |
1511 | + // |
1512 | + // Last thread to awake must reset the event |
1513 | + // |
1514 | + if (numWaiting == 0) { |
1515 | + wakeAll = 0; |
1516 | + ResetEvent(cv); |
1517 | + } |
1518 | + mutex->unlock(); |
1519 | + break; |
1520 | + } |
1521 | + if (triggered) { |
1522 | + triggered = 0; |
1523 | + ResetEvent(cv); |
1524 | + mutex->unlock(); |
1525 | + break; |
1526 | + } |
1527 | + mutex->unlock(); |
1528 | + now = mprGetTime(0); |
1529 | + } |
1530 | + externalMutex->lock(); |
1531 | + return 0; |
1532 | +} |
1533 | + |
1534 | +#endif |
1535 | +//////////////////////////////////////////////////////////////////////////////// |
1536 | +// |
1537 | +// Signal a condition and wakeup the waiter. Note: this may be called |
1538 | +// prior to the waiter waiting. |
1539 | +// |
1540 | + |
1541 | +void MprCond::signalCond() |
1542 | +{ |
1543 | + mutex->lock(); |
1544 | + triggered = 1; |
1545 | +#if UNUSED |
1546 | + wakeAll = 0; |
1547 | +#endif |
1548 | + SetEvent(cv); |
1549 | + mutex->unlock(); |
1550 | +} |
1551 | + |
1552 | +/////////////////////////////////////////////////////////////////////////////// |
1553 | +#if UNUSED |
1554 | +// |
1555 | +// Signal all waiters. Note: this may be called prior to anyone waiting. |
1556 | +// |
1557 | + |
1558 | +void MprCond::signalAll() |
1559 | +{ |
1560 | + mutex->lock(); |
1561 | + triggered = 1; |
1562 | +#if UNUSED |
1563 | + wakeAll = 1; |
1564 | +#endif |
1565 | + SetEvent(cv); |
1566 | + mutex->unlock(); |
1567 | +} |
1568 | + |
1569 | +/////////////////////////////////////////////////////////////////////////////// |
1570 | +// |
1571 | +// Use very carefully when you really know what you are doing. More dangerous |
1572 | +// than it looks |
1573 | +// |
1574 | + |
1575 | +void MprCond::reset() |
1576 | +{ |
1577 | + mutex->lock(); |
1578 | + triggered = 0; |
1579 | +#if UNUSED |
1580 | + wakeAll = 0; |
1581 | +#endif |
1582 | + ResetEvent(cv); |
1583 | + mutex->unlock(); |
1584 | +} |
1585 | + |
1586 | +#endif |
1587 | +/////////////////////////////////////////////////////////////////////////////// |
1588 | +////////////////////////////////////// Debug ////////////////////////////////// |
1589 | +/////////////////////////////////////////////////////////////////////////////// |
1590 | +#if BLD_DEBUG |
1591 | +#if UNUSED |
1592 | + |
1593 | +static void lockBuster(void *data, MprThread *tp) |
1594 | +{ |
1595 | + MprMutex *mp; |
1596 | + int duration; |
1597 | + uint tid, whenLocked, ticks; |
1598 | + |
1599 | + tid = (int) GetCurrentThreadId(); |
1600 | + while (! mpr->isExiting()) { |
1601 | + if (numMutex > MPR_MAX_LOCKS) { |
1602 | + mprError(MPR_L, MPR_LOG, "Too many mutexes"); |
1603 | + } |
1604 | + |
1605 | + mp = (MprMutex*) mutexList.getFirst(); |
1606 | + while (mp) { |
1607 | + whenLocked = mp->cs.DebugInfo->Spare[DEBUG_TIME]; |
1608 | + |
1609 | + if (mp->cs.RecursionCount > 0) { |
1610 | + ticks = GetTickCount(); |
1611 | + if (ticks < whenLocked) { |
1612 | + duration = 0xFFFFFFFF - whenLocked + 1 + ticks; |
1613 | + } else { |
1614 | + duration = ticks - whenLocked; |
1615 | + } |
1616 | + if (duration > MPR_MAX_LOCK_TIME) { |
1617 | + mprError(MPR_L, MPR_LOG, "Mutex held too long"); |
1618 | + // FUTURE -- could bust the lock here ... mp->unlock(); |
1619 | + } |
1620 | + } |
1621 | + mp = (MprMutex*) mutexList.getNext(&mp->link); |
1622 | + } |
1623 | + mprSleep(500); |
1624 | + } |
1625 | +} |
1626 | + |
1627 | +#endif // UNUSED |
1628 | +/////////////////////////////////////////////////////////////////////////////// |
1629 | +// |
1630 | +// Add this mutex to the list |
1631 | +// |
1632 | + |
1633 | +static void addMutex(MprMutex *mp) |
1634 | +{ |
1635 | + // |
1636 | + // First time initialization |
1637 | + // |
1638 | + if (numMutex < 0) { |
1639 | + memset(&debugCs, 0, sizeof(debugCs)); |
1640 | + InitializeCriticalSectionAndSpinCount(&debugCs, 4000); |
1641 | + } |
1642 | + EnterCriticalSection(&debugCs); |
1643 | + mutexList.insert(&mp->link); |
1644 | + numMutex++; |
1645 | + LeaveCriticalSection(&debugCs); |
1646 | +} |
1647 | + |
1648 | +/////////////////////////////////////////////////////////////////////////////// |
1649 | +// |
1650 | +// Remove this mutex from the list |
1651 | +// |
1652 | + |
1653 | +static void removeMutex(MprMutex *mp) |
1654 | +{ |
1655 | + EnterCriticalSection(&debugCs); |
1656 | + numMutex--; |
1657 | + mutexList.remove(&mp->link); |
1658 | + LeaveCriticalSection(&debugCs); |
1659 | +} |
1660 | + |
1661 | +/////////////////////////////////////////////////////////////////////////////// |
1662 | +// |
1663 | +// Return the number of mutexes owned by this thread |
1664 | +// |
1665 | + |
1666 | +int MprDebug::getMutexNum() |
1667 | +{ |
1668 | + MprMutex *mp; |
1669 | + int num; |
1670 | + uint tid; |
1671 | + |
1672 | + tid = (uint) GetCurrentThreadId(); |
1673 | + |
1674 | + num = 0; |
1675 | + mp = (MprMutex*) mutexList.getFirst(); |
1676 | + while (mp) { |
1677 | + |
1678 | + if (mp->cs.DebugInfo->Spare[DEBUG_ID] == tid) { |
1679 | + num++; |
1680 | + } |
1681 | + mp = (MprMutex*) mutexList.getNext(&mp->link); |
1682 | + } |
1683 | + return num; |
1684 | +} |
1685 | + |
1686 | +#endif // BLD_DEBUG |
1687 | +#endif // BLD_FEATURE_MULTITHREAD |
1688 | +/////////////////////////////////////////////////////////////////////////////// |
1689 | + |
1690 | +// |
1691 | +// Local variables: |
1692 | +// tab-width: 4 |
1693 | +// c-basic-offset: 4 |
1694 | +// End: |
1695 | +// vim:tw=78 |
1696 | +// vim600: sw=4 ts=4 fdm=marker |
1697 | +// vim<600: sw=4 ts=4 |
1698 | +// |
1699 | |
1700 | === added file 'appweb.cnf' |
1701 | --- appweb.cnf 1970-01-01 00:00:00 +0000 |
1702 | +++ appweb.cnf 2011-11-23 01:01:25 +0000 |
1703 | @@ -0,0 +1,27 @@ |
1704 | +ServerRoot "." |
1705 | +DocumentRoot "." |
1706 | + |
1707 | +LoadModulePath $SERVER_ROOT |
1708 | + |
1709 | +LoadModule psiphonHandler libpsiphonHandler |
1710 | +LoadModule ssl libsslModule |
1711 | +LoadModule openSsl libopenSslModule |
1712 | + |
1713 | +ThreadLimit 100 |
1714 | +KeepAlive on |
1715 | + |
1716 | +<VirtualHost *:*> |
1717 | + AddHandler psiphonHandler |
1718 | + DocumentRoot "." |
1719 | + SSLEngine on |
1720 | + SSLCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNULL |
1721 | + SSLProtocol ALL -SSLV2 |
1722 | + |
1723 | + SSLCertificateFile "$SERVER_ROOT/cert.pem" |
1724 | + SSLCertificateKeyFile "$SERVER_ROOT/key.pem" |
1725 | + |
1726 | + <Location /> |
1727 | + HttpChunking off |
1728 | + SetHandler psiphonHandler |
1729 | + </Location> |
1730 | +</VirtualHost> |
1731 | |
1732 | === added file 'bake-w32.bat' |
1733 | --- bake-w32.bat 1970-01-01 00:00:00 +0000 |
1734 | +++ bake-w32.bat 2011-11-23 01:01:25 +0000 |
1735 | @@ -0,0 +1,1 @@ |
1736 | +bakefile -f msvc6prj psiphon.bkl |
1737 | \ No newline at end of file |
1738 | |
1739 | === added file 'changes.txt' |
1740 | --- changes.txt 1970-01-01 00:00:00 +0000 |
1741 | +++ changes.txt 2011-11-23 01:01:25 +0000 |
1742 | @@ -0,0 +1,99 @@ |
1743 | +------------------------------------------- |
1744 | +Changes in version 1.6 (09 Mar 2007) |
1745 | +- added fingerprint to SSL certificate page |
1746 | +- added update downloading |
1747 | +- minor code revisions |
1748 | + |
1749 | +------------------------------------------- |
1750 | +Changes in version 1.5 (09 Feb 2007) |
1751 | + |
1752 | +- fixed '100% CPU usage' bug |
1753 | +- added psiphon will find available port if 443 is not |
1754 | +- added double click on a link in the log window opens it in default browser |
1755 | +- added column sorting |
1756 | +- added status icons |
1757 | +- added choise for "Get My IP" server |
1758 | +- added SLL country combo sorting |
1759 | +- changed System Tray icon to be always available |
1760 | +- minor GUI revisions |
1761 | +- minor code revisions |
1762 | + |
1763 | +------------------------------------------- |
1764 | +Changes in version 1.4 (26 Jan 2007) |
1765 | + |
1766 | +- added minimize to task bar |
1767 | +- added single bakefile file for both platforms(WIN, LINUX) |
1768 | +- added detailed build instructions for both platforms |
1769 | +- fixed compatibility with Shaw Secure |
1770 | +- improved HTML entities decoding |
1771 | +- minor code revisions |
1772 | + |
1773 | +------------------------------------------- |
1774 | +Changes in version 1.3 (29 Dec 2006) |
1775 | + |
1776 | +Added: |
1777 | +- HTML entities decoding in the HTML filter |
1778 | + |
1779 | +Changed: |
1780 | +- Improved CSS filtering |
1781 | + |
1782 | +- Improved error handling |
1783 | + |
1784 | +- Limited user input |
1785 | + |
1786 | +- Delete user related info when delete user |
1787 | + |
1788 | +- Password overwrite bug fixed |
1789 | + |
1790 | +- Switched to prepared SQL statements throughout the code |
1791 | + |
1792 | +- Minor code revisions |
1793 | + |
1794 | +------------------------------------------- |
1795 | +Changes in version 1.2 (15 Dec 2006) |
1796 | + |
1797 | +Added: |
1798 | +- Custom SSL certificate |
1799 | + |
1800 | +- Log level persistence |
1801 | + |
1802 | +- Log can be disabled |
1803 | + |
1804 | +Changed: |
1805 | +- Image on/off handling through "Javascript:void(0);" in order to avoid extra HTTP requests |
1806 | + |
1807 | +- Updated wxWidgets framework to 2.8 |
1808 | + |
1809 | +- Updated Advanced Installer to 4.6 |
1810 | + |
1811 | +- Fixed several buffer overflow vulnerabilities |
1812 | + |
1813 | +------------------------------------------- |
1814 | +Changes in version 1.1 (8 Dec 2006) |
1815 | + |
1816 | +Added: |
1817 | +- psiphon access is forbidden (HTTP 403) to domains that resolve to localhost or |
1818 | + private network |
1819 | + |
1820 | +- Multiple network interface cards support |
1821 | + |
1822 | +- Our own external IP detection service |
1823 | + |
1824 | +- Version check on startup |
1825 | + |
1826 | +- Users can toggle images on/off in the blue bar |
1827 | + |
1828 | +Changed: |
1829 | +- URLs in HTTP requests to psiphon must be prepended with psiphonode name |
1830 | + set by psiphon admin at setup, i.e. https://<IP>:<port>/<psiphonode>/login/.., |
1831 | + https://<IP>:<port>/<psiphonode>/fetch/.. etc. |
1832 | + |
1833 | +- Replacement tags (<%varname%>) added in HTML templates. |
1834 | + |
1835 | +- wxWidgets HTTP headers are replaced with generic headers |
1836 | + |
1837 | +- New database design in order to minimize SQLite locking |
1838 | + |
1839 | +- GUI changes |
1840 | + |
1841 | +- Minor bug fixes |
1842 | \ No newline at end of file |
1843 | |
1844 | === added directory 'common' |
1845 | === added file 'common/CppSQLite3.cpp' |
1846 | --- common/CppSQLite3.cpp 1970-01-01 00:00:00 +0000 |
1847 | +++ common/CppSQLite3.cpp 2011-11-23 01:01:25 +0000 |
1848 | @@ -0,0 +1,1383 @@ |
1849 | +//////////////////////////////////////////////////////////////////////////////// |
1850 | +// CppSQLite3 - A C++ wrapper around the SQLite3 embedded database library. |
1851 | +// |
1852 | +// Copyright (c) 2004 Rob Groves. All Rights Reserved. rob.groves@btinternet.com |
1853 | +// |
1854 | +// Permission to use, copy, modify, and distribute this software and its |
1855 | +// documentation for any purpose, without fee, and without a written |
1856 | +// agreement, is hereby granted, provided that the above copyright notice, |
1857 | +// this paragraph and the following two paragraphs appear in all copies, |
1858 | +// modifications, and distributions. |
1859 | +// |
1860 | +// IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT, |
1861 | +// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST |
1862 | +// PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, |
1863 | +// EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
1864 | +// |
1865 | +// THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT |
1866 | +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A |
1867 | +// PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF |
1868 | +// ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". THE AUTHOR HAS NO OBLIGATION |
1869 | +// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. |
1870 | +// |
1871 | +// V3.0 03/08/2004 -Initial Version for sqlite3 |
1872 | +// |
1873 | +// V3.1 16/09/2004 -Implemented getXXXXField using sqlite3 functions |
1874 | +// -Added CppSQLiteDB3::tableExists() |
1875 | +//////////////////////////////////////////////////////////////////////////////// |
1876 | +#include "CppSQLite3.h" |
1877 | +#include <cstdlib> |
1878 | + |
1879 | +// Named constant for passing to CppSQLite3Exception when passing it a string |
1880 | +// that cannot be deleted. |
1881 | +static const bool DONT_DELETE_MSG = false; |
1882 | + |
1883 | +//////////////////////////////////////////////////////////////////////////////// |
1884 | +// Prototypes for SQLite functions not included in SQLite DLL, but copied below |
1885 | +// from SQLite encode.c |
1886 | +//////////////////////////////////////////////////////////////////////////////// |
1887 | +int sqlite3_encode_binary(const unsigned char* in, int n, unsigned char* out); |
1888 | +int sqlite3_decode_binary(const unsigned char* in, unsigned char* out); |
1889 | + |
1890 | +//////////////////////////////////////////////////////////////////////////////// |
1891 | + |
1892 | +//////////////////////////////////////////////////////////////////////////////// |
1893 | + |
1894 | +CppSQLite3Exception::CppSQLite3Exception(const int nErrCode, char* szErrMess, bool bDeleteMsg/*=true*/) : mnErrCode(nErrCode) |
1895 | +{ |
1896 | + mpszErrMess = sqlite3_mprintf("%s[%d]: %s", errorCodeAsString(nErrCode), nErrCode, szErrMess ? szErrMess : ""); |
1897 | + |
1898 | + if(bDeleteMsg && szErrMess) |
1899 | + { |
1900 | + sqlite3_free(szErrMess); |
1901 | + } |
1902 | +} |
1903 | + |
1904 | +CppSQLite3Exception::CppSQLite3Exception(const CppSQLite3Exception& e) : mnErrCode(e.mnErrCode) |
1905 | +{ |
1906 | + mpszErrMess = 0; |
1907 | + if(e.mpszErrMess) |
1908 | + { |
1909 | + mpszErrMess = sqlite3_mprintf("%s", e.mpszErrMess); |
1910 | + } |
1911 | +} |
1912 | + |
1913 | +const char* CppSQLite3Exception::errorCodeAsString(int nErrCode) |
1914 | +{ |
1915 | + switch(nErrCode) |
1916 | + { |
1917 | + case SQLITE_OK : |
1918 | + return "SQLITE_OK"; |
1919 | + case SQLITE_ERROR : |
1920 | + return "SQLITE_ERROR"; |
1921 | + case SQLITE_INTERNAL : |
1922 | + return "SQLITE_INTERNAL"; |
1923 | + case SQLITE_PERM : |
1924 | + return "SQLITE_PERM"; |
1925 | + case SQLITE_ABORT : |
1926 | + return "SQLITE_ABORT"; |
1927 | + case SQLITE_BUSY : |
1928 | + return "SQLITE_BUSY"; |
1929 | + case SQLITE_LOCKED : |
1930 | + return "SQLITE_LOCKED"; |
1931 | + case SQLITE_NOMEM : |
1932 | + return "SQLITE_NOMEM"; |
1933 | + case SQLITE_READONLY : |
1934 | + return "SQLITE_READONLY"; |
1935 | + case SQLITE_INTERRUPT : |
1936 | + return "SQLITE_INTERRUPT"; |
1937 | + case SQLITE_IOERR : |
1938 | + return "SQLITE_IOERR"; |
1939 | + case SQLITE_CORRUPT : |
1940 | + return "SQLITE_CORRUPT"; |
1941 | + case SQLITE_NOTFOUND : |
1942 | + return "SQLITE_NOTFOUND"; |
1943 | + case SQLITE_FULL : |
1944 | + return "SQLITE_FULL"; |
1945 | + case SQLITE_CANTOPEN : |
1946 | + return "SQLITE_CANTOPEN"; |
1947 | + case SQLITE_PROTOCOL : |
1948 | + return "SQLITE_PROTOCOL"; |
1949 | + case SQLITE_EMPTY : |
1950 | + return "SQLITE_EMPTY"; |
1951 | + case SQLITE_SCHEMA : |
1952 | + return "SQLITE_SCHEMA"; |
1953 | + case SQLITE_TOOBIG : |
1954 | + return "SQLITE_TOOBIG"; |
1955 | + case SQLITE_CONSTRAINT : |
1956 | + return "SQLITE_CONSTRAINT"; |
1957 | + case SQLITE_MISMATCH : |
1958 | + return "SQLITE_MISMATCH"; |
1959 | + case SQLITE_MISUSE : |
1960 | + return "SQLITE_MISUSE"; |
1961 | + case SQLITE_NOLFS : |
1962 | + return "SQLITE_NOLFS"; |
1963 | + case SQLITE_AUTH : |
1964 | + return "SQLITE_AUTH"; |
1965 | + case SQLITE_FORMAT : |
1966 | + return "SQLITE_FORMAT"; |
1967 | + case SQLITE_RANGE : |
1968 | + return "SQLITE_RANGE"; |
1969 | + case SQLITE_ROW : |
1970 | + return "SQLITE_ROW"; |
1971 | + case SQLITE_DONE : |
1972 | + return "SQLITE_DONE"; |
1973 | + case CPPSQLITE_ERROR : |
1974 | + return "CPPSQLITE_ERROR"; |
1975 | + default: |
1976 | + return "UNKNOWN_ERROR"; |
1977 | + } |
1978 | +} |
1979 | + |
1980 | +CppSQLite3Exception::~CppSQLite3Exception() |
1981 | +{ |
1982 | + if(mpszErrMess) |
1983 | + { |
1984 | + sqlite3_free(mpszErrMess); |
1985 | + mpszErrMess = 0; |
1986 | + } |
1987 | +} |
1988 | + |
1989 | +//////////////////////////////////////////////////////////////////////////////// |
1990 | + |
1991 | +CppSQLite3Buffer::CppSQLite3Buffer() |
1992 | +{ |
1993 | + mpBuf = 0; |
1994 | +} |
1995 | + |
1996 | +CppSQLite3Buffer::~CppSQLite3Buffer() |
1997 | +{ |
1998 | + clear(); |
1999 | +} |
2000 | + |
2001 | +void CppSQLite3Buffer::clear() |
2002 | +{ |
2003 | + if(mpBuf) |
2004 | + { |
2005 | + sqlite3_free(mpBuf); |
2006 | + mpBuf = 0; |
2007 | + } |
2008 | +} |
2009 | + |
2010 | +const char* CppSQLite3Buffer::format(const char* szFormat, ...) |
2011 | +{ |
2012 | + clear(); |
2013 | + va_list va; |
2014 | + va_start(va, szFormat); |
2015 | + mpBuf = sqlite3_vmprintf(szFormat, va); |
2016 | + va_end(va); |
2017 | + return mpBuf; |
2018 | +} |
2019 | + |
2020 | +//////////////////////////////////////////////////////////////////////////////// |
2021 | + |
2022 | +CppSQLite3Binary::CppSQLite3Binary() : mpBuf(0), mnBinaryLen(0), mnBufferLen(0), mnEncodedLen(0), mbEncoded(false) |
2023 | +{ |
2024 | +} |
2025 | + |
2026 | +CppSQLite3Binary::~CppSQLite3Binary() |
2027 | +{ |
2028 | + clear(); |
2029 | +} |
2030 | + |
2031 | +void CppSQLite3Binary::setBinary(const unsigned char* pBuf, int nLen) |
2032 | +{ |
2033 | + mpBuf = allocBuffer(nLen); |
2034 | + memcpy(mpBuf, pBuf, nLen); |
2035 | +} |
2036 | + |
2037 | +void CppSQLite3Binary::setEncoded(const unsigned char* pBuf) |
2038 | +{ |
2039 | + clear(); |
2040 | + |
2041 | + mnEncodedLen = strlen((const char*)pBuf); |
2042 | + mnBufferLen = mnEncodedLen + 1; // Allow for NULL terminator |
2043 | + |
2044 | + mpBuf = (unsigned char*)malloc(mnBufferLen); |
2045 | + |
2046 | + if(!mpBuf) |
2047 | + { |
2048 | + throw CppSQLite3Exception(CPPSQLITE_ERROR, "Cannot allocate memory", DONT_DELETE_MSG); |
2049 | + } |
2050 | + |
2051 | + memcpy(mpBuf, pBuf, mnBufferLen); |
2052 | + mbEncoded = true; |
2053 | +} |
2054 | + |
2055 | +const unsigned char* CppSQLite3Binary::getEncoded() |
2056 | +{ |
2057 | + if(!mbEncoded) |
2058 | + { |
2059 | + unsigned char* ptmp = (unsigned char*)malloc(mnBinaryLen); |
2060 | + memcpy(ptmp, mpBuf, mnBinaryLen); |
2061 | + mnEncodedLen = sqlite3_encode_binary(ptmp, mnBinaryLen, mpBuf); |
2062 | + free(ptmp); |
2063 | + mbEncoded = true; |
2064 | + } |
2065 | + |
2066 | + return mpBuf; |
2067 | +} |
2068 | + |
2069 | +const unsigned char* CppSQLite3Binary::getBinary() |
2070 | +{ |
2071 | + if(mbEncoded) |
2072 | + { |
2073 | + // in/out buffers can be the same |
2074 | + mnBinaryLen = sqlite3_decode_binary(mpBuf, mpBuf); |
2075 | + |
2076 | + if(mnBinaryLen == -1) |
2077 | + { |
2078 | + throw CppSQLite3Exception(CPPSQLITE_ERROR, "Cannot decode binary", DONT_DELETE_MSG); |
2079 | + } |
2080 | + |
2081 | + mbEncoded = false; |
2082 | + } |
2083 | + |
2084 | + return mpBuf; |
2085 | +} |
2086 | + |
2087 | +int CppSQLite3Binary::getBinaryLength() |
2088 | +{ |
2089 | + getBinary(); |
2090 | + return mnBinaryLen; |
2091 | +} |
2092 | + |
2093 | +unsigned char* CppSQLite3Binary::allocBuffer(int nLen) |
2094 | +{ |
2095 | + clear(); |
2096 | + |
2097 | + // Allow extra space for encoded binary as per comments in |
2098 | + // SQLite encode.c See bottom of this file for implementation |
2099 | + // of SQLite functions use 3 instead of 2 just to be sure ;-) |
2100 | + mnBinaryLen = nLen; |
2101 | + mnBufferLen = 3 + (257 * nLen) / 254; |
2102 | + |
2103 | + mpBuf = (unsigned char*)malloc(mnBufferLen); |
2104 | + |
2105 | + if(!mpBuf) |
2106 | + { |
2107 | + throw CppSQLite3Exception(CPPSQLITE_ERROR, "Cannot allocate memory", DONT_DELETE_MSG); |
2108 | + } |
2109 | + |
2110 | + mbEncoded = false; |
2111 | + |
2112 | + return mpBuf; |
2113 | +} |
2114 | + |
2115 | +void CppSQLite3Binary::clear() |
2116 | +{ |
2117 | + if(mpBuf) |
2118 | + { |
2119 | + mnBinaryLen = 0; |
2120 | + mnBufferLen = 0; |
2121 | + free(mpBuf); |
2122 | + mpBuf = 0; |
2123 | + } |
2124 | +} |
2125 | + |
2126 | +//////////////////////////////////////////////////////////////////////////////// |
2127 | + |
2128 | +CppSQLite3Query::CppSQLite3Query() |
2129 | +{ |
2130 | + mpVM = 0; |
2131 | + mbEof = true; |
2132 | + mnCols = 0; |
2133 | + mbOwnVM = false; |
2134 | +} |
2135 | + |
2136 | +CppSQLite3Query::CppSQLite3Query(const CppSQLite3Query& rQuery) |
2137 | +{ |
2138 | + mpVM = rQuery.mpVM; |
2139 | + // Only one object can own the VM |
2140 | + const_cast<CppSQLite3Query&>(rQuery).mpVM = 0; |
2141 | + mbEof = rQuery.mbEof; |
2142 | + mnCols = rQuery.mnCols; |
2143 | + mbOwnVM = rQuery.mbOwnVM; |
2144 | +} |
2145 | + |
2146 | +CppSQLite3Query::CppSQLite3Query(sqlite3* pDB, sqlite3_stmt* pVM, bool bEof, bool bOwnVM/*=true*/) |
2147 | +{ |
2148 | + mpDB = pDB; |
2149 | + mpVM = pVM; |
2150 | + mbEof = bEof; |
2151 | + mnCols = sqlite3_column_count(mpVM); |
2152 | + mbOwnVM = bOwnVM; |
2153 | +} |
2154 | + |
2155 | +CppSQLite3Query::~CppSQLite3Query() |
2156 | +{ |
2157 | + try |
2158 | + { |
2159 | + finalize(); |
2160 | + } |
2161 | + catch(...) |
2162 | + { |
2163 | + } |
2164 | +} |
2165 | + |
2166 | +CppSQLite3Query& CppSQLite3Query::operator=(const CppSQLite3Query& rQuery) |
2167 | +{ |
2168 | + try |
2169 | + { |
2170 | + finalize(); |
2171 | + } |
2172 | + catch(...) |
2173 | + { |
2174 | + } |
2175 | + mpVM = rQuery.mpVM; |
2176 | + // Only one object can own the VM |
2177 | + const_cast<CppSQLite3Query&>(rQuery).mpVM = 0; |
2178 | + mbEof = rQuery.mbEof; |
2179 | + mnCols = rQuery.mnCols; |
2180 | + mbOwnVM = rQuery.mbOwnVM; |
2181 | + return *this; |
2182 | +} |
2183 | + |
2184 | +int CppSQLite3Query::numFields() |
2185 | +{ |
2186 | + checkVM(); |
2187 | + return mnCols; |
2188 | +} |
2189 | + |
2190 | +const char* CppSQLite3Query::fieldValue(int nField) |
2191 | +{ |
2192 | + checkVM(); |
2193 | + |
2194 | + if(nField < 0 || nField > mnCols - 1) |
2195 | + { |
2196 | + throw CppSQLite3Exception(CPPSQLITE_ERROR, "Invalid field index requested", DONT_DELETE_MSG); |
2197 | + } |
2198 | + |
2199 | + return (const char*)sqlite3_column_text(mpVM, nField); |
2200 | +} |
2201 | + |
2202 | +const char* CppSQLite3Query::fieldValue(const char* szField) |
2203 | +{ |
2204 | + int nField = fieldIndex(szField); |
2205 | + return (const char*)sqlite3_column_text(mpVM, nField); |
2206 | +} |
2207 | + |
2208 | +int CppSQLite3Query::getIntField(int nField, int nNullValue/*=0*/) |
2209 | +{ |
2210 | + if(fieldDataType(nField) == SQLITE_NULL) |
2211 | + { |
2212 | + return nNullValue; |
2213 | + } |
2214 | + else |
2215 | + { |
2216 | + return sqlite3_column_int(mpVM, nField); |
2217 | + } |
2218 | +} |
2219 | + |
2220 | +int CppSQLite3Query::getIntField(const char* szField, int nNullValue/*=0*/) |
2221 | +{ |
2222 | + int nField = fieldIndex(szField); |
2223 | + return getIntField(nField, nNullValue); |
2224 | +} |
2225 | + |
2226 | +double CppSQLite3Query::getFloatField(int nField, double fNullValue/*=0.0*/) |
2227 | +{ |
2228 | + if(fieldDataType(nField) == SQLITE_NULL) |
2229 | + { |
2230 | + return fNullValue; |
2231 | + } |
2232 | + else |
2233 | + { |
2234 | + return sqlite3_column_double(mpVM, nField); |
2235 | + } |
2236 | +} |
2237 | + |
2238 | +double CppSQLite3Query::getFloatField(const char* szField, double fNullValue/*=0.0*/) |
2239 | +{ |
2240 | + int nField = fieldIndex(szField); |
2241 | + return getFloatField(nField, fNullValue); |
2242 | +} |
2243 | + |
2244 | +const char* CppSQLite3Query::getStringField(int nField, const char* szNullValue/*=""*/) |
2245 | +{ |
2246 | + if(fieldDataType(nField) == SQLITE_NULL) |
2247 | + { |
2248 | + return szNullValue; |
2249 | + } |
2250 | + else |
2251 | + { |
2252 | + return (const char*)sqlite3_column_text(mpVM, nField); |
2253 | + } |
2254 | +} |
2255 | + |
2256 | +const char* CppSQLite3Query::getStringField(const char* szField, const char* szNullValue/*=""*/) |
2257 | +{ |
2258 | + int nField = fieldIndex(szField); |
2259 | + return getStringField(nField, szNullValue); |
2260 | +} |
2261 | + |
2262 | +const unsigned char* CppSQLite3Query::getBlobField(int nField, int& nLen) |
2263 | +{ |
2264 | + checkVM(); |
2265 | + |
2266 | + if(nField < 0 || nField > mnCols - 1) |
2267 | + { |
2268 | + throw CppSQLite3Exception(CPPSQLITE_ERROR, "Invalid field index requested", DONT_DELETE_MSG); |
2269 | + } |
2270 | + |
2271 | + nLen = sqlite3_column_bytes(mpVM, nField); |
2272 | + return (const unsigned char*)sqlite3_column_blob(mpVM, nField); |
2273 | +} |
2274 | + |
2275 | +const unsigned char* CppSQLite3Query::getBlobField(const char* szField, int& nLen) |
2276 | +{ |
2277 | + int nField = fieldIndex(szField); |
2278 | + return getBlobField(nField, nLen); |
2279 | +} |
2280 | + |
2281 | +bool CppSQLite3Query::fieldIsNull(int nField) |
2282 | +{ |
2283 | + return (fieldDataType(nField) == SQLITE_NULL); |
2284 | +} |
2285 | + |
2286 | +bool CppSQLite3Query::fieldIsNull(const char* szField) |
2287 | +{ |
2288 | + int nField = fieldIndex(szField); |
2289 | + return (fieldDataType(nField) == SQLITE_NULL); |
2290 | +} |
2291 | + |
2292 | +int CppSQLite3Query::fieldIndex(const char* szField) |
2293 | +{ |
2294 | + checkVM(); |
2295 | + |
2296 | + if(szField) |
2297 | + { |
2298 | + for(int nField = 0;nField < mnCols;nField++) |
2299 | + { |
2300 | + const char* szTemp = sqlite3_column_name(mpVM, nField); |
2301 | + |
2302 | + if(strcmp(szField, szTemp) == 0) |
2303 | + { |
2304 | + return nField; |
2305 | + } |
2306 | + } |
2307 | + } |
2308 | + |
2309 | + throw CppSQLite3Exception(CPPSQLITE_ERROR, "Invalid field name requested", DONT_DELETE_MSG); |
2310 | +} |
2311 | + |
2312 | +const char* CppSQLite3Query::fieldName(int nCol) |
2313 | +{ |
2314 | + checkVM(); |
2315 | + |
2316 | + if(nCol < 0 || nCol > mnCols - 1) |
2317 | + { |
2318 | + throw CppSQLite3Exception(CPPSQLITE_ERROR, "Invalid field index requested", DONT_DELETE_MSG); |
2319 | + } |
2320 | + |
2321 | + return sqlite3_column_name(mpVM, nCol); |
2322 | +} |
2323 | + |
2324 | +const char* CppSQLite3Query::fieldDeclType(int nCol) |
2325 | +{ |
2326 | + checkVM(); |
2327 | + |
2328 | + if(nCol < 0 || nCol > mnCols - 1) |
2329 | + { |
2330 | + throw CppSQLite3Exception(CPPSQLITE_ERROR, "Invalid field index requested", DONT_DELETE_MSG); |
2331 | + } |
2332 | + |
2333 | + return sqlite3_column_decltype(mpVM, nCol); |
2334 | +} |
2335 | + |
2336 | +int CppSQLite3Query::fieldDataType(int nCol) |
2337 | +{ |
2338 | + checkVM(); |
2339 | + |
2340 | + if(nCol < 0 || nCol > mnCols - 1) |
2341 | + { |
2342 | + throw CppSQLite3Exception(CPPSQLITE_ERROR, "Invalid field index requested", DONT_DELETE_MSG); |
2343 | + } |
2344 | + |
2345 | + return sqlite3_column_type(mpVM, nCol); |
2346 | +} |
2347 | + |
2348 | +bool CppSQLite3Query::eof() |
2349 | +{ |
2350 | + checkVM(); |
2351 | + return mbEof; |
2352 | +} |
2353 | + |
2354 | +void CppSQLite3Query::nextRow() |
2355 | +{ |
2356 | + checkVM(); |
2357 | + |
2358 | + int nRet = sqlite3_step(mpVM); |
2359 | + |
2360 | + if(nRet == SQLITE_DONE) |
2361 | + { |
2362 | + // no rows |
2363 | + mbEof = true; |
2364 | + } |
2365 | + else if(nRet == SQLITE_ROW) |
2366 | + { |
2367 | + // more rows, nothing to do |
2368 | + } |
2369 | + else |
2370 | + { |
2371 | + nRet = sqlite3_finalize(mpVM); |
2372 | + mpVM = 0; |
2373 | + const char* szError = sqlite3_errmsg(mpDB); |
2374 | + throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG); |
2375 | + } |
2376 | +} |
2377 | + |
2378 | +void CppSQLite3Query::finalize() |
2379 | +{ |
2380 | + if(mpVM && mbOwnVM) |
2381 | + { |
2382 | + int nRet = sqlite3_finalize(mpVM); |
2383 | + mpVM = 0; |
2384 | + if(nRet != SQLITE_OK) |
2385 | + { |
2386 | + const char* szError = sqlite3_errmsg(mpDB); |
2387 | + throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG); |
2388 | + } |
2389 | + } |
2390 | +} |
2391 | + |
2392 | +void CppSQLite3Query::checkVM() |
2393 | +{ |
2394 | + if(mpVM == 0) |
2395 | + { |
2396 | + throw CppSQLite3Exception(CPPSQLITE_ERROR, "Null Virtual Machine pointer", DONT_DELETE_MSG); |
2397 | + } |
2398 | +} |
2399 | + |
2400 | +//////////////////////////////////////////////////////////////////////////////// |
2401 | + |
2402 | +CppSQLite3Table::CppSQLite3Table() |
2403 | +{ |
2404 | + mpaszResults = 0; |
2405 | + mnRows = 0; |
2406 | + mnCols = 0; |
2407 | + mnCurrentRow = 0; |
2408 | +} |
2409 | + |
2410 | +CppSQLite3Table::CppSQLite3Table(const CppSQLite3Table& rTable) |
2411 | +{ |
2412 | + mpaszResults = rTable.mpaszResults; |
2413 | + // Only one object can own the results |
2414 | + const_cast<CppSQLite3Table&>(rTable).mpaszResults = 0; |
2415 | + mnRows = rTable.mnRows; |
2416 | + mnCols = rTable.mnCols; |
2417 | + mnCurrentRow = rTable.mnCurrentRow; |
2418 | +} |
2419 | + |
2420 | +CppSQLite3Table::CppSQLite3Table(char** paszResults, int nRows, int nCols) |
2421 | +{ |
2422 | + mpaszResults = paszResults; |
2423 | + mnRows = nRows; |
2424 | + mnCols = nCols; |
2425 | + mnCurrentRow = 0; |
2426 | +} |
2427 | + |
2428 | +CppSQLite3Table::~CppSQLite3Table() |
2429 | +{ |
2430 | + try |
2431 | + { |
2432 | + finalize(); |
2433 | + } |
2434 | + catch(...) |
2435 | + { |
2436 | + } |
2437 | +} |
2438 | + |
2439 | +CppSQLite3Table& CppSQLite3Table::operator=(const CppSQLite3Table& rTable) |
2440 | +{ |
2441 | + try |
2442 | + { |
2443 | + finalize(); |
2444 | + } |
2445 | + catch(...) |
2446 | + { |
2447 | + } |
2448 | + mpaszResults = rTable.mpaszResults; |
2449 | + // Only one object can own the results |
2450 | + const_cast<CppSQLite3Table&>(rTable).mpaszResults = 0; |
2451 | + mnRows = rTable.mnRows; |
2452 | + mnCols = rTable.mnCols; |
2453 | + mnCurrentRow = rTable.mnCurrentRow; |
2454 | + return *this; |
2455 | +} |
2456 | + |
2457 | +void CppSQLite3Table::finalize() |
2458 | +{ |
2459 | + if(mpaszResults) |
2460 | + { |
2461 | + sqlite3_free_table(mpaszResults); |
2462 | + mpaszResults = 0; |
2463 | + } |
2464 | +} |
2465 | + |
2466 | +int CppSQLite3Table::numFields() |
2467 | +{ |
2468 | + checkResults(); |
2469 | + return mnCols; |
2470 | +} |
2471 | + |
2472 | +int CppSQLite3Table::numRows() |
2473 | +{ |
2474 | + checkResults(); |
2475 | + return mnRows; |
2476 | +} |
2477 | + |
2478 | +const char* CppSQLite3Table::fieldValue(int nField) |
2479 | +{ |
2480 | + checkResults(); |
2481 | + |
2482 | + if(nField < 0 || nField > mnCols - 1) |
2483 | + { |
2484 | + throw CppSQLite3Exception(CPPSQLITE_ERROR, "Invalid field index requested", DONT_DELETE_MSG); |
2485 | + } |
2486 | + |
2487 | + int nIndex = (mnCurrentRow* mnCols) + mnCols + nField; |
2488 | + return mpaszResults[nIndex]; |
2489 | +} |
2490 | + |
2491 | +const char* CppSQLite3Table::fieldValue(const char* szField) |
2492 | +{ |
2493 | + checkResults(); |
2494 | + |
2495 | + if(szField) |
2496 | + { |
2497 | + for(int nField = 0;nField < mnCols;nField++) |
2498 | + { |
2499 | + if(strcmp(szField, mpaszResults[nField]) == 0) |
2500 | + { |
2501 | + int nIndex = (mnCurrentRow* mnCols) + mnCols + nField; |
2502 | + return mpaszResults[nIndex]; |
2503 | + } |
2504 | + } |
2505 | + } |
2506 | + |
2507 | + throw CppSQLite3Exception(CPPSQLITE_ERROR, "Invalid field name requested", DONT_DELETE_MSG); |
2508 | +} |
2509 | + |
2510 | +int CppSQLite3Table::getIntField(int nField, int nNullValue/*=0*/) |
2511 | +{ |
2512 | + if(fieldIsNull(nField)) |
2513 | + { |
2514 | + return nNullValue; |
2515 | + } |
2516 | + else |
2517 | + { |
2518 | + return atoi(fieldValue(nField)); |
2519 | + } |
2520 | +} |
2521 | + |
2522 | +int CppSQLite3Table::getIntField(const char* szField, int nNullValue/*=0*/) |
2523 | +{ |
2524 | + if(fieldIsNull(szField)) |
2525 | + { |
2526 | + return nNullValue; |
2527 | + } |
2528 | + else |
2529 | + { |
2530 | + return atoi(fieldValue(szField)); |
2531 | + } |
2532 | +} |
2533 | + |
2534 | +double CppSQLite3Table::getFloatField(int nField, double fNullValue/*=0.0*/) |
2535 | +{ |
2536 | + if(fieldIsNull(nField)) |
2537 | + { |
2538 | + return fNullValue; |
2539 | + } |
2540 | + else |
2541 | + { |
2542 | + return atof(fieldValue(nField)); |
2543 | + } |
2544 | +} |
2545 | + |
2546 | +double CppSQLite3Table::getFloatField(const char* szField, double fNullValue/*=0.0*/) |
2547 | +{ |
2548 | + if(fieldIsNull(szField)) |
2549 | + { |
2550 | + return fNullValue; |
2551 | + } |
2552 | + else |
2553 | + { |
2554 | + return atof(fieldValue(szField)); |
2555 | + } |
2556 | +} |
2557 | + |
2558 | +const char* CppSQLite3Table::getStringField(int nField, const char* szNullValue/*=""*/) |
2559 | +{ |
2560 | + if(fieldIsNull(nField)) |
2561 | + { |
2562 | + return szNullValue; |
2563 | + } |
2564 | + else |
2565 | + { |
2566 | + return fieldValue(nField); |
2567 | + } |
2568 | +} |
2569 | + |
2570 | +const char* CppSQLite3Table::getStringField(const char* szField, const char* szNullValue/*=""*/) |
2571 | +{ |
2572 | + if(fieldIsNull(szField)) |
2573 | + { |
2574 | + return szNullValue; |
2575 | + } |
2576 | + else |
2577 | + { |
2578 | + return fieldValue(szField); |
2579 | + } |
2580 | +} |
2581 | + |
2582 | +bool CppSQLite3Table::fieldIsNull(int nField) |
2583 | +{ |
2584 | + checkResults(); |
2585 | + return (fieldValue(nField) == 0); |
2586 | +} |
2587 | + |
2588 | +bool CppSQLite3Table::fieldIsNull(const char* szField) |
2589 | +{ |
2590 | + checkResults(); |
2591 | + return (fieldValue(szField) == 0); |
2592 | +} |
2593 | + |
2594 | +const char* CppSQLite3Table::fieldName(int nCol) |
2595 | +{ |
2596 | + checkResults(); |
2597 | + |
2598 | + if(nCol < 0 || nCol > mnCols - 1) |
2599 | + { |
2600 | + throw CppSQLite3Exception(CPPSQLITE_ERROR, "Invalid field index requested", DONT_DELETE_MSG); |
2601 | + } |
2602 | + |
2603 | + return mpaszResults[nCol]; |
2604 | +} |
2605 | + |
2606 | +void CppSQLite3Table::setRow(int nRow) |
2607 | +{ |
2608 | + checkResults(); |
2609 | + |
2610 | + if(nRow < 0 || nRow > mnRows - 1) |
2611 | + { |
2612 | + throw CppSQLite3Exception(CPPSQLITE_ERROR, "Invalid row index requested", DONT_DELETE_MSG); |
2613 | + } |
2614 | + |
2615 | + mnCurrentRow = nRow; |
2616 | +} |
2617 | + |
2618 | +void CppSQLite3Table::checkResults() |
2619 | +{ |
2620 | + if(mpaszResults == 0) |
2621 | + { |
2622 | + throw CppSQLite3Exception(CPPSQLITE_ERROR, "Null Results pointer", DONT_DELETE_MSG); |
2623 | + } |
2624 | +} |
2625 | + |
2626 | +//////////////////////////////////////////////////////////////////////////////// |
2627 | + |
2628 | +CppSQLite3Statement::CppSQLite3Statement() |
2629 | +{ |
2630 | + mpDB = 0; |
2631 | + mpVM = 0; |
2632 | +} |
2633 | + |
2634 | +CppSQLite3Statement::CppSQLite3Statement(const CppSQLite3Statement& rStatement) |
2635 | +{ |
2636 | + mpDB = rStatement.mpDB; |
2637 | + mpVM = rStatement.mpVM; |
2638 | + // Only one object can own VM |
2639 | + const_cast<CppSQLite3Statement&>(rStatement).mpVM = 0; |
2640 | +} |
2641 | + |
2642 | +CppSQLite3Statement::CppSQLite3Statement(sqlite3* pDB, sqlite3_stmt* pVM) |
2643 | +{ |
2644 | + mpDB = pDB; |
2645 | + mpVM = pVM; |
2646 | +} |
2647 | + |
2648 | +CppSQLite3Statement::~CppSQLite3Statement() |
2649 | +{ |
2650 | + try |
2651 | + { |
2652 | + finalize(); |
2653 | + } |
2654 | + catch(...) |
2655 | + { |
2656 | + } |
2657 | +} |
2658 | + |
2659 | +CppSQLite3Statement& CppSQLite3Statement::operator=(const CppSQLite3Statement& rStatement) |
2660 | +{ |
2661 | + mpDB = rStatement.mpDB; |
2662 | + mpVM = rStatement.mpVM; |
2663 | + // Only one object can own VM |
2664 | + const_cast<CppSQLite3Statement&>(rStatement).mpVM = 0; |
2665 | + return *this; |
2666 | +} |
2667 | + |
2668 | +int CppSQLite3Statement::execDML() |
2669 | +{ |
2670 | + checkDB(); |
2671 | + checkVM(); |
2672 | + |
2673 | + const char* szError = 0; |
2674 | + |
2675 | + int nRet = sqlite3_step(mpVM); |
2676 | + |
2677 | + if(nRet == SQLITE_DONE) |
2678 | + { |
2679 | + int nRowsChanged = sqlite3_changes(mpDB); |
2680 | + |
2681 | + nRet = sqlite3_reset(mpVM); |
2682 | + |
2683 | + if(nRet != SQLITE_OK) |
2684 | + { |
2685 | + szError = sqlite3_errmsg(mpDB); |
2686 | + throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG); |
2687 | + } |
2688 | + |
2689 | + return nRowsChanged; |
2690 | + } |
2691 | + else |
2692 | + { |
2693 | + nRet = sqlite3_reset(mpVM); |
2694 | + szError = sqlite3_errmsg(mpDB); |
2695 | + throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG); |
2696 | + } |
2697 | +} |
2698 | + |
2699 | +CppSQLite3Query CppSQLite3Statement::execQuery() |
2700 | +{ |
2701 | + checkDB(); |
2702 | + checkVM(); |
2703 | + |
2704 | + int nRet = sqlite3_step(mpVM); |
2705 | + |
2706 | + if(nRet == SQLITE_DONE) |
2707 | + { |
2708 | + // no rows |
2709 | + return CppSQLite3Query(mpDB, mpVM, true/*eof*/, false); |
2710 | + } |
2711 | + else if(nRet == SQLITE_ROW) |
2712 | + { |
2713 | + // at least 1 row |
2714 | + return CppSQLite3Query(mpDB, mpVM, false/*eof*/, false); |
2715 | + } |
2716 | + else |
2717 | + { |
2718 | + nRet = sqlite3_reset(mpVM); |
2719 | + const char* szError = sqlite3_errmsg(mpDB); |
2720 | + throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG); |
2721 | + } |
2722 | +} |
2723 | + |
2724 | +void CppSQLite3Statement::bind(int nParam, const char* szValue) |
2725 | +{ |
2726 | + checkVM(); |
2727 | + int nRes = sqlite3_bind_text(mpVM, nParam, szValue, -1, SQLITE_TRANSIENT); |
2728 | + |
2729 | + if(nRes != SQLITE_OK) |
2730 | + { |
2731 | + throw CppSQLite3Exception(nRes, "Error binding string param", DONT_DELETE_MSG); |
2732 | + } |
2733 | +} |
2734 | + |
2735 | +void CppSQLite3Statement::bind(int nParam, const int nValue) |
2736 | +{ |
2737 | + checkVM(); |
2738 | + int nRes = sqlite3_bind_int(mpVM, nParam, nValue); |
2739 | + |
2740 | + if(nRes != SQLITE_OK) |
2741 | + { |
2742 | + throw CppSQLite3Exception(nRes, "Error binding int param", DONT_DELETE_MSG); |
2743 | + } |
2744 | +} |
2745 | + |
2746 | +void CppSQLite3Statement::bind(int nParam, const double dValue) |
2747 | +{ |
2748 | + checkVM(); |
2749 | + int nRes = sqlite3_bind_double(mpVM, nParam, dValue); |
2750 | + |
2751 | + if(nRes != SQLITE_OK) |
2752 | + { |
2753 | + throw CppSQLite3Exception(nRes, "Error binding double param", DONT_DELETE_MSG); |
2754 | + } |
2755 | +} |
2756 | + |
2757 | +void CppSQLite3Statement::bind(int nParam, const unsigned char* blobValue, int nLen) |
2758 | +{ |
2759 | + checkVM(); |
2760 | + int nRes = sqlite3_bind_blob(mpVM, nParam, (const void*)blobValue, nLen, SQLITE_TRANSIENT); |
2761 | + |
2762 | + if(nRes != SQLITE_OK) |
2763 | + { |
2764 | + throw CppSQLite3Exception(nRes, "Error binding blob param", DONT_DELETE_MSG); |
2765 | + } |
2766 | +} |
2767 | + |
2768 | +void CppSQLite3Statement::bindNull(int nParam) |
2769 | +{ |
2770 | + checkVM(); |
2771 | + int nRes = sqlite3_bind_null(mpVM, nParam); |
2772 | + |
2773 | + if(nRes != SQLITE_OK) |
2774 | + { |
2775 | + throw CppSQLite3Exception(nRes, "Error binding NULL param", DONT_DELETE_MSG); |
2776 | + } |
2777 | +} |
2778 | + |
2779 | +void CppSQLite3Statement::reset() |
2780 | +{ |
2781 | + if(mpVM) |
2782 | + { |
2783 | + int nRet = sqlite3_reset(mpVM); |
2784 | + |
2785 | + if(nRet != SQLITE_OK) |
2786 | + { |
2787 | + const char* szError = sqlite3_errmsg(mpDB); |
2788 | + throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG); |
2789 | + } |
2790 | + } |
2791 | +} |
2792 | + |
2793 | +void CppSQLite3Statement::finalize() |
2794 | +{ |
2795 | + if(mpVM) |
2796 | + { |
2797 | + int nRet = sqlite3_finalize(mpVM); |
2798 | + mpVM = 0; |
2799 | + |
2800 | + if(nRet != SQLITE_OK) |
2801 | + { |
2802 | + const char* szError = sqlite3_errmsg(mpDB); |
2803 | + throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG); |
2804 | + } |
2805 | + } |
2806 | +} |
2807 | + |
2808 | +void CppSQLite3Statement::checkDB() |
2809 | +{ |
2810 | + if(mpDB == 0) |
2811 | + { |
2812 | + throw CppSQLite3Exception(CPPSQLITE_ERROR, "Database not open", DONT_DELETE_MSG); |
2813 | + } |
2814 | +} |
2815 | + |
2816 | +void CppSQLite3Statement::checkVM() |
2817 | +{ |
2818 | + if(mpVM == 0) |
2819 | + { |
2820 | + throw CppSQLite3Exception(CPPSQLITE_ERROR, "Null Virtual Machine pointer", DONT_DELETE_MSG); |
2821 | + } |
2822 | +} |
2823 | + |
2824 | +//////////////////////////////////////////////////////////////////////////////// |
2825 | + |
2826 | +CppSQLite3DB::CppSQLite3DB() |
2827 | +{ |
2828 | + mpDB = 0; |
2829 | + mnBusyTimeoutMs = 60000; // 60 seconds |
2830 | +} |
2831 | + |
2832 | +CppSQLite3DB::CppSQLite3DB(const CppSQLite3DB& db) |
2833 | +{ |
2834 | + mpDB = db.mpDB; |
2835 | + mnBusyTimeoutMs = 60000; // 60 seconds |
2836 | +} |
2837 | + |
2838 | +CppSQLite3DB::~CppSQLite3DB() |
2839 | +{ |
2840 | + Close(); |
2841 | +} |
2842 | + |
2843 | +CppSQLite3DB& CppSQLite3DB::operator=(const CppSQLite3DB& db) |
2844 | +{ |
2845 | + mpDB = db.mpDB; |
2846 | + mnBusyTimeoutMs = 60000; // 60 seconds |
2847 | + return *this; |
2848 | +} |
2849 | + |
2850 | +void CppSQLite3DB::Open(const char* szFile) |
2851 | +{ |
2852 | + int nRet = sqlite3_open(szFile, &mpDB); |
2853 | + |
2854 | + if(nRet != SQLITE_OK) |
2855 | + { |
2856 | + const char* szError = sqlite3_errmsg(mpDB); |
2857 | + throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG); |
2858 | + } |
2859 | + |
2860 | + setBusyTimeout(mnBusyTimeoutMs); |
2861 | +} |
2862 | + |
2863 | +void CppSQLite3DB::Close() |
2864 | +{ |
2865 | + if(mpDB) |
2866 | + { |
2867 | + sqlite3_close(mpDB); |
2868 | + mpDB = 0; |
2869 | + } |
2870 | +} |
2871 | + |
2872 | +CppSQLite3Statement CppSQLite3DB::compileStatement(const char* szSQL) |
2873 | +{ |
2874 | + checkDB(); |
2875 | + |
2876 | + sqlite3_stmt* pVM = compile(szSQL); |
2877 | + return CppSQLite3Statement(mpDB, pVM); |
2878 | +} |
2879 | + |
2880 | +bool CppSQLite3DB::tableExists(const char* szTable) |
2881 | +{ |
2882 | + char szSQL[128]; |
2883 | + sprintf(szSQL, "select count(*) from sqlite_master where type='table' and name='%s'", szTable); |
2884 | + int nRet = execScalar(szSQL); |
2885 | + return (nRet > 0); |
2886 | +} |
2887 | + |
2888 | +int CppSQLite3DB::execDML(const char* szSQL) |
2889 | +{ |
2890 | + checkDB(); |
2891 | + |
2892 | + char* szError = 0; |
2893 | + |
2894 | + int nRet = sqlite3_exec(mpDB, szSQL, 0, 0, &szError); |
2895 | + |
2896 | + if(nRet == SQLITE_OK) |
2897 | + { |
2898 | + return sqlite3_changes(mpDB); |
2899 | + } |
2900 | + else |
2901 | + { |
2902 | + throw CppSQLite3Exception(nRet, szError); |
2903 | + } |
2904 | +} |
2905 | + |
2906 | +CppSQLite3Query CppSQLite3DB::execQuery(const char* szSQL) |
2907 | +{ |
2908 | + checkDB(); |
2909 | + |
2910 | + sqlite3_stmt* pVM = compile(szSQL); |
2911 | + |
2912 | + int nRet = sqlite3_step(pVM); |
2913 | + |
2914 | + if(nRet == SQLITE_DONE) |
2915 | + { |
2916 | + // no rows |
2917 | + return CppSQLite3Query(mpDB, pVM, true/*eof*/); |
2918 | + } |
2919 | + else if(nRet == SQLITE_ROW) |
2920 | + { |
2921 | + // at least 1 row |
2922 | + return CppSQLite3Query(mpDB, pVM, false/*eof*/); |
2923 | + } |
2924 | + else |
2925 | + { |
2926 | + nRet = sqlite3_finalize(pVM); |
2927 | + const char* szError = sqlite3_errmsg(mpDB); |
2928 | + throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG); |
2929 | + } |
2930 | +} |
2931 | + |
2932 | +int CppSQLite3DB::execScalar(const char* szSQL) |
2933 | +{ |
2934 | + CppSQLite3Query q = execQuery(szSQL); |
2935 | + |
2936 | + if(q.eof() || q.numFields() < 1) |
2937 | + { |
2938 | + throw CppSQLite3Exception(CPPSQLITE_ERROR, "Invalid scalar query", DONT_DELETE_MSG); |
2939 | + } |
2940 | + |
2941 | + return atoi(q.fieldValue(0)); |
2942 | +} |
2943 | + |
2944 | +CppSQLite3Table CppSQLite3DB::getTable(const char* szSQL) |
2945 | +{ |
2946 | + checkDB(); |
2947 | + |
2948 | + char* szError = 0; |
2949 | + char** paszResults = 0; |
2950 | + int nRet; |
2951 | + int nRows(0); |
2952 | + int nCols(0); |
2953 | + |
2954 | + nRet = sqlite3_get_table(mpDB, szSQL, &paszResults, &nRows, &nCols, &szError); |
2955 | + |
2956 | + if(nRet == SQLITE_OK) |
2957 | + { |
2958 | + return CppSQLite3Table(paszResults, nRows, nCols); |
2959 | + } |
2960 | + else |
2961 | + { |
2962 | + throw CppSQLite3Exception(nRet, szError); |
2963 | + } |
2964 | +} |
2965 | + |
2966 | +sqlite_int64 CppSQLite3DB::lastRowId() |
2967 | +{ |
2968 | + return sqlite3_last_insert_rowid(mpDB); |
2969 | +} |
2970 | + |
2971 | +void CppSQLite3DB::setBusyTimeout(int nMillisecs) |
2972 | +{ |
2973 | + mnBusyTimeoutMs = nMillisecs; |
2974 | + sqlite3_busy_timeout(mpDB, mnBusyTimeoutMs); |
2975 | +} |
2976 | + |
2977 | +void CppSQLite3DB::checkDB() |
2978 | +{ |
2979 | + if(!mpDB) |
2980 | + { |
2981 | + throw CppSQLite3Exception(CPPSQLITE_ERROR, "Database not open", DONT_DELETE_MSG); |
2982 | + } |
2983 | +} |
2984 | + |
2985 | +sqlite3_stmt* CppSQLite3DB::compile(const char* szSQL) |
2986 | +{ |
2987 | + checkDB(); |
2988 | + |
2989 | + char* szError = 0; |
2990 | + const char* szTail = 0; |
2991 | + sqlite3_stmt* pVM; |
2992 | + |
2993 | + int nRet = sqlite3_prepare(mpDB, szSQL, -1, &pVM, &szTail); |
2994 | + |
2995 | + if(nRet != SQLITE_OK) |
2996 | + { |
2997 | + throw CppSQLite3Exception(nRet, szError); |
2998 | + } |
2999 | + |
3000 | + return pVM; |
3001 | +} |
3002 | + |
3003 | +//////////////////////////////////////////////////////////////////////////////// |
3004 | +// SQLite encode.c reproduced here, containing implementation notes and source |
3005 | +// for sqlite3_encode_binary() and sqlite3_decode_binary() |
3006 | +//////////////////////////////////////////////////////////////////////////////// |
3007 | + |
3008 | +/* |
3009 | +** 2002 April 25 |
3010 | +** |
3011 | +** The author disclaims copyright to this source code. In place of |
3012 | +** a legal notice, here is a blessing: |
3013 | +** |
3014 | +** May you do good and not evil. |
3015 | +** May you find forgiveness for yourself and forgive others. |
3016 | +** May you share freely, never taking more than you give. |
3017 | +** |
3018 | +************************************************************************* |
3019 | +** This file contains helper routines used to translate binary data into |
3020 | +** a null-terminated string (suitable for use in SQLite) and back again. |
3021 | +** These are convenience routines for use by people who want to store binary |
3022 | +** data in an SQLite database. The code in this file is not used by any other |
3023 | +** part of the SQLite library. |
3024 | +** |
3025 | +** $Id: encode.c,v 1.10 2004/01/14 21:59:23 drh Exp $ |
3026 | +*/ |
3027 | + |
3028 | +/* |
3029 | +** How This Encoder Works |
3030 | +** |
3031 | +** The output is allowed to contain any character except 0x27 (') and |
3032 | +** 0x00. This is accomplished by using an escape character to encode |
3033 | +** 0x27 and 0x00 as a two-byte sequence. The escape character is always |
3034 | +** 0x01. An 0x00 is encoded as the two byte sequence 0x01 0x01. The |
3035 | +** 0x27 character is encoded as the two byte sequence 0x01 0x03. Finally, |
3036 | +** the escape character itself is encoded as the two-character sequence |
3037 | +** 0x01 0x02. |
3038 | +** |
3039 | +** To summarize, the encoder works by using an escape sequences as follows: |
3040 | +** |
3041 | +** 0x00 -> 0x01 0x01 |
3042 | +** 0x01 -> 0x01 0x02 |
3043 | +** 0x27 -> 0x01 0x03 |
3044 | +** |
3045 | +** If that were all the encoder did, it would work, but in certain cases |
3046 | +** it could double the size of the encoded string. For example, to |
3047 | +** encode a string of 100 0x27 characters would require 100 instances of |
3048 | +** the 0x01 0x03 escape sequence resulting in a 200-character output. |
3049 | +** We would prefer to keep the size of the encoded string smaller than |
3050 | +** this. |
3051 | +** |
3052 | +** To minimize the encoding size, we first add a fixed offset value to each |
3053 | +** byte in the sequence. The addition is modulo 256. (That is to say, if |
3054 | +** the sum of the original character value and the offset exceeds 256, then |
3055 | +** the higher order bits are truncated.) The offset is chosen to minimize |
3056 | +** the number of characters in the string that need to be escaped. For |
3057 | +** example, in the case above where the string was composed of 100 0x27 |
3058 | +** characters, the offset might be 0x01. Each of the 0x27 characters would |
3059 | +** then be converted into an 0x28 character which would not need to be |
3060 | +** escaped at all and so the 100 character input string would be converted |
3061 | +** into just 100 characters of output. Actually 101 characters of output - |
3062 | +** we have to record the offset used as the first byte in the sequence so |
3063 | +** that the string can be decoded. Since the offset value is stored as |
3064 | +** part of the output string and the output string is not allowed to contain |
3065 | +** characters 0x00 or 0x27, the offset cannot be 0x00 or 0x27. |
3066 | +** |
3067 | +** Here, then, are the encoding steps: |
3068 | +** |
3069 | +** (1) Choose an offset value and make it the first character of |
3070 | +** output. |
3071 | +** |
3072 | +** (2) Copy each input character into the output buffer, one by |
3073 | +** one, adding the offset value as you copy. |
3074 | +** |
3075 | +** (3) If the value of an input character plus offset is 0x00, replace |
3076 | +** that one character by the two-character sequence 0x01 0x01. |
3077 | +** If the sum is 0x01, replace it with 0x01 0x02. If the sum |
3078 | +** is 0x27, replace it with 0x01 0x03. |
3079 | +** |
3080 | +** (4) Put a 0x00 terminator at the end of the output. |
3081 | +** |
3082 | +** Decoding is obvious: |
3083 | +** |
3084 | +** (5) Copy encoded characters except the first into the decode |
3085 | +** buffer. Set the first encoded character aside for use as |
3086 | +** the offset in step 7 below. |
3087 | +** |
3088 | +** (6) Convert each 0x01 0x01 sequence into a single character 0x00. |
3089 | +** Convert 0x01 0x02 into 0x01. Convert 0x01 0x03 into 0x27. |
3090 | +** |
3091 | +** (7) Subtract the offset value that was the first character of |
3092 | +** the encoded buffer from all characters in the output buffer. |
3093 | +** |
3094 | +** The only tricky part is step (1) - how to compute an offset value to |
3095 | +** minimize the size of the output buffer. This is accomplished by testing |
3096 | +** all offset values and picking the one that results in the fewest number |
3097 | +** of escapes. To do that, we first scan the entire input and count the |
3098 | +** number of occurances of each character value in the input. Suppose |
3099 | +** the number of 0x00 characters is N(0), the number of occurances of 0x01 |
3100 | +** is N(1), and so forth up to the number of occurances of 0xff is N(255). |
3101 | +** An offset of 0 is not allowed so we don't have to test it. The number |
3102 | +** of escapes required for an offset of 1 is N(1)+N(2)+N(40). The number |
3103 | +** of escapes required for an offset of 2 is N(2)+N(3)+N(41). And so forth. |
3104 | +** In this way we find the offset that gives the minimum number of escapes, |
3105 | +** and thus minimizes the length of the output string. |
3106 | +*/ |
3107 | + |
3108 | +/* |
3109 | +** Encode a binary buffer "in" of size n bytes so that it contains |
3110 | +** no instances of characters '\'' or '\000'. The output is |
3111 | +** null-terminated and can be used as a string value in an INSERT |
3112 | +** or UPDATE statement. Use sqlite3_decode_binary() to convert the |
3113 | +** string back into its original binary. |
3114 | +** |
3115 | +** The result is written into a preallocated output buffer "out". |
3116 | +** "out" must be able to hold at least 2 +(257*n)/254 bytes. |
3117 | +** In other words, the output will be expanded by as much as 3 |
3118 | +** bytes for every 254 bytes of input plus 2 bytes of fixed overhead. |
3119 | +** (This is approximately 2 + 1.0118*n or about a 1.2% size increase.) |
3120 | +** |
3121 | +** The return value is the number of characters in the encoded |
3122 | +** string, excluding the "\000" terminator. |
3123 | +*/ |
3124 | +int sqlite3_encode_binary(const unsigned char* in, int n, unsigned char* out) |
3125 | +{ |
3126 | + int i = 0; |
3127 | + int j = 0; |
3128 | + int e = 0; |
3129 | + int m = 0; |
3130 | + |
3131 | + int cnt[256]; |
3132 | + |
3133 | + if(n <= 0) |
3134 | + { |
3135 | + out[0] = 'x'; |
3136 | + out[1] = 0; |
3137 | + return 1; |
3138 | + } |
3139 | + memset(cnt, 0, sizeof(cnt)); |
3140 | + for(i = n - 1;i >= 0;i--) |
3141 | + { |
3142 | + cnt[in[i]]++; |
3143 | + } |
3144 | + m = n; |
3145 | + for(i = 1;i < 256;i++) |
3146 | + { |
3147 | + int sum; |
3148 | + if(i == '\'') |
3149 | + continue; |
3150 | + sum = cnt[i] + cnt[(i + 1) & 0xff] + cnt[(i + '\'') & 0xff]; |
3151 | + if(sum < m) |
3152 | + { |
3153 | + m = sum; |
3154 | + e = i; |
3155 | + if(m == 0) |
3156 | + break; |
3157 | + } |
3158 | + } |
3159 | + out[0] = e; |
3160 | + j = 1; |
3161 | + for(i = 0;i < n;i++) |
3162 | + { |
3163 | + int c = (in[i] - e) & 0xff; |
3164 | + if(c == 0) |
3165 | + { |
3166 | + out[j++] = 1; |
3167 | + out[j++] = 1; |
3168 | + } |
3169 | + else if(c == 1) |
3170 | + { |
3171 | + out[j++] = 1; |
3172 | + out[j++] = 2; |
3173 | + } |
3174 | + else if(c == '\'') |
3175 | + { |
3176 | + out[j++] = 1; |
3177 | + out[j++] = 3; |
3178 | + } |
3179 | + else |
3180 | + { |
3181 | + out[j++] = c; |
3182 | + } |
3183 | + } |
3184 | + out[j] = 0; |
3185 | + return j; |
3186 | +} |
3187 | + |
3188 | +/* |
3189 | +** Decode the string "in" into binary data and write it into "out". |
3190 | +** This routine reverses the encoding created by sqlite3_encode_binary(). |
3191 | +** The output will always be a few bytes less than the input. The number |
3192 | +** of bytes of output is returned. If the input is not a well-formed |
3193 | +** encoding, -1 is returned. |
3194 | +** |
3195 | +** The "in" and "out" parameters may point to the same buffer in order |
3196 | +** to decode a string in place. |
3197 | +*/ |
3198 | +int sqlite3_decode_binary(const unsigned char* in, unsigned char* out) |
3199 | +{ |
3200 | + int i = 0; |
3201 | + int c = 0; |
3202 | + int e = 0; |
3203 | + |
3204 | + e = *(in++); |
3205 | + i = 0; |
3206 | + while((c = *(in++)) != 0) |
3207 | + { |
3208 | + if(c == 1) |
3209 | + { |
3210 | + c = *(in++); |
3211 | + if(c == 1) |
3212 | + { |
3213 | + c = 0; |
3214 | + } |
3215 | + else if(c == 2) |
3216 | + { |
3217 | + c = 1; |
3218 | + } |
3219 | + else if(c == 3) |
3220 | + { |
3221 | + c = '\''; |
3222 | + } |
3223 | + else |
3224 | + { |
3225 | + return -1; |
3226 | + } |
3227 | + } |
3228 | + out[i++] = (c + e) & 0xff; |
3229 | + } |
3230 | + return i; |
3231 | +} |
3232 | |
3233 | === added file 'common/CppSQLite3.h' |
3234 | --- common/CppSQLite3.h 1970-01-01 00:00:00 +0000 |
3235 | +++ common/CppSQLite3.h 2011-11-23 01:01:25 +0000 |
3236 | @@ -0,0 +1,270 @@ |
3237 | +#pragma once |
3238 | + |
3239 | +#include "sqlite3.h" |
3240 | +#include <cstdio> |
3241 | +#include <cstring> |
3242 | + |
3243 | +#define CPPSQLITE_ERROR 1000 |
3244 | + |
3245 | +class CppSQLite3Exception |
3246 | +{ |
3247 | +public: |
3248 | + |
3249 | + CppSQLite3Exception(const int nErrCode, |
3250 | + char* szErrMess, |
3251 | + bool bDeleteMsg=true); |
3252 | + |
3253 | + CppSQLite3Exception(const CppSQLite3Exception& e); |
3254 | + |
3255 | + virtual ~CppSQLite3Exception(); |
3256 | + |
3257 | + const int errorCode() { return mnErrCode; } |
3258 | + |
3259 | + const char* errorMessage() { return mpszErrMess; } |
3260 | + |
3261 | + static const char* errorCodeAsString(int nErrCode); |
3262 | + |
3263 | +private: |
3264 | + |
3265 | + int mnErrCode; |
3266 | + char* mpszErrMess; |
3267 | +}; |
3268 | + |
3269 | +class CppSQLite3Buffer |
3270 | +{ |
3271 | +public: |
3272 | + |
3273 | + CppSQLite3Buffer(); |
3274 | + |
3275 | + ~CppSQLite3Buffer(); |
3276 | + |
3277 | + const char* format(const char* szFormat, ...); |
3278 | + |
3279 | + operator const char*() { return mpBuf; } |
3280 | + |
3281 | + void clear(); |
3282 | + |
3283 | +private: |
3284 | + |
3285 | + char* mpBuf; |
3286 | +}; |
3287 | + |
3288 | +class CppSQLite3Binary |
3289 | +{ |
3290 | +public: |
3291 | + |
3292 | + CppSQLite3Binary(); |
3293 | + |
3294 | + ~CppSQLite3Binary(); |
3295 | + |
3296 | + void setBinary(const unsigned char* pBuf, int nLen); |
3297 | + void setEncoded(const unsigned char* pBuf); |
3298 | + |
3299 | + const unsigned char* getEncoded(); |
3300 | + const unsigned char* getBinary(); |
3301 | + |
3302 | + int getBinaryLength(); |
3303 | + |
3304 | + unsigned char* allocBuffer(int nLen); |
3305 | + |
3306 | + void clear(); |
3307 | + |
3308 | +private: |
3309 | + |
3310 | + unsigned char* mpBuf; |
3311 | + int mnBinaryLen; |
3312 | + int mnBufferLen; |
3313 | + int mnEncodedLen; |
3314 | + bool mbEncoded; |
3315 | +}; |
3316 | + |
3317 | +class CppSQLite3Query |
3318 | +{ |
3319 | +public: |
3320 | + |
3321 | + CppSQLite3Query(); |
3322 | + |
3323 | + CppSQLite3Query(const CppSQLite3Query& rQuery); |
3324 | + |
3325 | + CppSQLite3Query(sqlite3* pDB, |
3326 | + sqlite3_stmt* pVM, |
3327 | + bool bEof, |
3328 | + bool bOwnVM=true); |
3329 | + |
3330 | + CppSQLite3Query& operator=(const CppSQLite3Query& rQuery); |
3331 | + |
3332 | + virtual ~CppSQLite3Query(); |
3333 | + |
3334 | + int numFields(); |
3335 | + |
3336 | + int fieldIndex(const char* szField); |
3337 | + const char* fieldName(int nCol); |
3338 | + |
3339 | + const char* fieldDeclType(int nCol); |
3340 | + int fieldDataType(int nCol); |
3341 | + |
3342 | + const char* fieldValue(int nField); |
3343 | + const char* fieldValue(const char* szField); |
3344 | + |
3345 | + int getIntField(int nField, int nNullValue=0); |
3346 | + int getIntField(const char* szField, int nNullValue=0); |
3347 | + |
3348 | + double getFloatField(int nField, double fNullValue=0.0); |
3349 | + double getFloatField(const char* szField, double fNullValue=0.0); |
3350 | + |
3351 | + const char* getStringField(int nField, const char* szNullValue=""); |
3352 | + const char* getStringField(const char* szField, const char* szNullValue=""); |
3353 | + |
3354 | + const unsigned char* getBlobField(int nField, int& nLen); |
3355 | + const unsigned char* getBlobField(const char* szField, int& nLen); |
3356 | + |
3357 | + bool fieldIsNull(int nField); |
3358 | + bool fieldIsNull(const char* szField); |
3359 | + |
3360 | + bool eof(); |
3361 | + |
3362 | + void nextRow(); |
3363 | + |
3364 | + void finalize(); |
3365 | + |
3366 | +private: |
3367 | + |
3368 | + void checkVM(); |
3369 | + |
3370 | + sqlite3* mpDB; |
3371 | + sqlite3_stmt* mpVM; |
3372 | + bool mbEof; |
3373 | + int mnCols; |
3374 | + bool mbOwnVM; |
3375 | +}; |
3376 | + |
3377 | +class CppSQLite3Table |
3378 | +{ |
3379 | +public: |
3380 | + |
3381 | + CppSQLite3Table(); |
3382 | + |
3383 | + CppSQLite3Table(const CppSQLite3Table& rTable); |
3384 | + |
3385 | + CppSQLite3Table(char** paszResults, int nRows, int nCols); |
3386 | + |
3387 | + virtual ~CppSQLite3Table(); |
3388 | + |
3389 | + CppSQLite3Table& operator=(const CppSQLite3Table& rTable); |
3390 | + |
3391 | + int numFields(); |
3392 | + |
3393 | + int numRows(); |
3394 | + |
3395 | + const char* fieldName(int nCol); |
3396 | + |
3397 | + const char* fieldValue(int nField); |
3398 | + const char* fieldValue(const char* szField); |
3399 | + |
3400 | + int getIntField(int nField, int nNullValue=0); |
3401 | + int getIntField(const char* szField, int nNullValue=0); |
3402 | + |
3403 | + double getFloatField(int nField, double fNullValue=0.0); |
3404 | + double getFloatField(const char* szField, double fNullValue=0.0); |
3405 | + |
3406 | + const char* getStringField(int nField, const char* szNullValue=""); |
3407 | + const char* getStringField(const char* szField, const char* szNullValue=""); |
3408 | + |
3409 | + bool fieldIsNull(int nField); |
3410 | + bool fieldIsNull(const char* szField); |
3411 | + |
3412 | + void setRow(int nRow); |
3413 | + |
3414 | + void finalize(); |
3415 | + |
3416 | +private: |
3417 | + |
3418 | + void checkResults(); |
3419 | + |
3420 | + int mnCols; |
3421 | + int mnRows; |
3422 | + int mnCurrentRow; |
3423 | + char** mpaszResults; |
3424 | +}; |
3425 | + |
3426 | +class CppSQLite3Statement |
3427 | +{ |
3428 | +public: |
3429 | + |
3430 | + CppSQLite3Statement(); |
3431 | + |
3432 | + CppSQLite3Statement(const CppSQLite3Statement& rStatement); |
3433 | + |
3434 | + CppSQLite3Statement(sqlite3* pDB, sqlite3_stmt* pVM); |
3435 | + |
3436 | + virtual ~CppSQLite3Statement(); |
3437 | + |
3438 | + CppSQLite3Statement& operator=(const CppSQLite3Statement& rStatement); |
3439 | + |
3440 | + int execDML(); |
3441 | + |
3442 | + CppSQLite3Query execQuery(); |
3443 | + |
3444 | + void bind(int nParam, const char* szValue); |
3445 | + void bind(int nParam, const int nValue); |
3446 | + void bind(int nParam, const double dwValue); |
3447 | + void bind(int nParam, const unsigned char* blobValue, int nLen); |
3448 | + void bindNull(int nParam); |
3449 | + |
3450 | + void reset(); |
3451 | + |
3452 | + void finalize(); |
3453 | + |
3454 | +private: |
3455 | + |
3456 | + void checkDB(); |
3457 | + void checkVM(); |
3458 | + |
3459 | + sqlite3* mpDB; |
3460 | + sqlite3_stmt* mpVM; |
3461 | +}; |
3462 | + |
3463 | +class CppSQLite3DB |
3464 | +{ |
3465 | +public: |
3466 | + |
3467 | + CppSQLite3DB(); |
3468 | + |
3469 | + virtual ~CppSQLite3DB(); |
3470 | + |
3471 | + void Open(const char* szFile); |
3472 | + |
3473 | + void Close(); |
3474 | + |
3475 | + bool tableExists(const char* szTable); |
3476 | + |
3477 | + int execDML(const char* szSQL); |
3478 | + |
3479 | + CppSQLite3Query execQuery(const char* szSQL); |
3480 | + |
3481 | + int execScalar(const char* szSQL); |
3482 | + |
3483 | + CppSQLite3Table getTable(const char* szSQL); |
3484 | + |
3485 | + CppSQLite3Statement compileStatement(const char* szSQL); |
3486 | + |
3487 | + sqlite_int64 lastRowId(); |
3488 | + |
3489 | + void interrupt() { sqlite3_interrupt(mpDB); } |
3490 | + |
3491 | + void setBusyTimeout(int nMillisecs); |
3492 | + |
3493 | + static const char* SQLiteVersion() { return SQLITE_VERSION; } |
3494 | + |
3495 | +private: |
3496 | + |
3497 | + CppSQLite3DB(const CppSQLite3DB& db); |
3498 | + CppSQLite3DB& operator=(const CppSQLite3DB& db); |
3499 | + |
3500 | + sqlite3_stmt* compile(const char* szSQL); |
3501 | + |
3502 | + void checkDB(); |
3503 | + |
3504 | + sqlite3* mpDB; |
3505 | + int mnBusyTimeoutMs; |
3506 | +}; |
3507 | |
3508 | === added file 'common/SHA1.cpp' |
3509 | --- common/SHA1.cpp 1970-01-01 00:00:00 +0000 |
3510 | +++ common/SHA1.cpp 2011-11-23 01:01:25 +0000 |
3511 | @@ -0,0 +1,282 @@ |
3512 | +/* |
3513 | + 100% free public domain implementation of the SHA-1 algorithm |
3514 | + by Dominik Reichl <dominik.reichl@t-online.de> |
3515 | + Web: http://www.dominik-reichl.de/ |
3516 | + |
3517 | + Version 1.6 - 2005-02-07 (thanks to Howard Kapustein for patches) |
3518 | + - You can set the endianness in your files, no need to modify the |
3519 | + header file of the CSHA1 class any more |
3520 | + - Aligned data support |
3521 | + - Made support/compilation of the utility functions (ReportHash |
3522 | + and HashFile) optional (useful, if bytes count, for example in |
3523 | + embedded environments) |
3524 | + |
3525 | + Version 1.5 - 2005-01-01 |
3526 | + - 64-bit compiler compatibility added |
3527 | + - Made variable wiping optional (define SHA1_WIPE_VARIABLES) |
3528 | + - Removed unnecessary variable initializations |
3529 | + - ROL32 improvement for the Microsoft compiler (using _rotl) |
3530 | + |
3531 | + ======== Test Vectors (from FIPS PUB 180-1) ======== |
3532 | + |
3533 | + SHA1("abc") = |
3534 | + A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D |
3535 | + |
3536 | + SHA1("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") = |
3537 | + 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 |
3538 | + |
3539 | + SHA1(A million repetitions of "a") = |
3540 | + 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F |
3541 | +*/ |
3542 | + |
3543 | +#include "SHA1.h" |
3544 | + |
3545 | +#ifdef SHA1_UTILITY_FUNCTIONS |
3546 | +#define SHA1_MAX_FILE_BUFFER 8000 |
3547 | +#endif |
3548 | + |
3549 | +// Rotate x bits to the left |
3550 | +#ifndef ROL32 |
3551 | +#ifdef _MSC_VER |
3552 | +#define ROL32(_val32, _nBits) _rotl(_val32, _nBits) |
3553 | +#else |
3554 | +#define ROL32(_val32, _nBits) (((_val32)<<(_nBits))|((_val32)>>(32-(_nBits)))) |
3555 | +#endif |
3556 | +#endif |
3557 | + |
3558 | +#ifdef SHA1_LITTLE_ENDIAN |
3559 | +#define SHABLK0(i) (m_block->l[i] = \ |
3560 | + (ROL32(m_block->l[i],24) & 0xFF00FF00) | (ROL32(m_block->l[i],8) & 0x00FF00FF)) |
3561 | +#else |
3562 | +#define SHABLK0(i) (m_block->l[i]) |
3563 | +#endif |
3564 | + |
3565 | +#define SHABLK(i) (m_block->l[i&15] = ROL32(m_block->l[(i+13)&15] ^ m_block->l[(i+8)&15] \ |
3566 | + ^ m_block->l[(i+2)&15] ^ m_block->l[i&15],1)) |
3567 | + |
3568 | +// SHA-1 rounds |
3569 | +#define _R0(v,w,x,y,z,i) { z+=((w&(x^y))^y)+SHABLK0(i)+0x5A827999+ROL32(v,5); w=ROL32(w,30); } |
3570 | +#define _R1(v,w,x,y,z,i) { z+=((w&(x^y))^y)+SHABLK(i)+0x5A827999+ROL32(v,5); w=ROL32(w,30); } |
3571 | +#define _R2(v,w,x,y,z,i) { z+=(w^x^y)+SHABLK(i)+0x6ED9EBA1+ROL32(v,5); w=ROL32(w,30); } |
3572 | +#define _R3(v,w,x,y,z,i) { z+=(((w|x)&y)|(w&x))+SHABLK(i)+0x8F1BBCDC+ROL32(v,5); w=ROL32(w,30); } |
3573 | +#define _R4(v,w,x,y,z,i) { z+=(w^x^y)+SHABLK(i)+0xCA62C1D6+ROL32(v,5); w=ROL32(w,30); } |
3574 | + |
3575 | +CSHA1::CSHA1() |
3576 | +{ |
3577 | + m_block = (SHA1_WORKSPACE_BLOCK *)m_workspace; |
3578 | + |
3579 | + Reset(); |
3580 | +} |
3581 | + |
3582 | +CSHA1::~CSHA1() |
3583 | +{ |
3584 | + Reset(); |
3585 | +} |
3586 | + |
3587 | +void CSHA1::Reset() |
3588 | +{ |
3589 | + // SHA1 initialization constants |
3590 | + m_state[0] = 0x67452301; |
3591 | + m_state[1] = 0xEFCDAB89; |
3592 | + m_state[2] = 0x98BADCFE; |
3593 | + m_state[3] = 0x10325476; |
3594 | + m_state[4] = 0xC3D2E1F0; |
3595 | + |
3596 | + m_count[0] = 0; |
3597 | + m_count[1] = 0; |
3598 | +} |
3599 | + |
3600 | +void CSHA1::Transform(UINT_32* state, UINT_8* buffer) |
3601 | +{ |
3602 | + // Copy state[] to working vars |
3603 | + UINT_32 a = state[0], b = state[1], c = state[2], d = state[3], e = state[4]; |
3604 | + |
3605 | + memcpy(m_block, buffer, 64); |
3606 | + |
3607 | + // 4 rounds of 20 operations each. Loop unrolled. |
3608 | + _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); |
3609 | + _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); |
3610 | + _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); |
3611 | + _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); |
3612 | + _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); |
3613 | + _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); |
3614 | + _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); |
3615 | + _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); |
3616 | + _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); |
3617 | + _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); |
3618 | + _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); |
3619 | + _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); |
3620 | + _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); |
3621 | + _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); |
3622 | + _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); |
3623 | + _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); |
3624 | + _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); |
3625 | + _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); |
3626 | + _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); |
3627 | + _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); |
3628 | + |
3629 | + // Add the working vars back into state |
3630 | + state[0] += a; |
3631 | + state[1] += b; |
3632 | + state[2] += c; |
3633 | + state[3] += d; |
3634 | + state[4] += e; |
3635 | + |
3636 | + // Wipe variables |
3637 | +#ifdef SHA1_WIPE_VARIABLES |
3638 | + a = b = c = d = e = 0; |
3639 | +#endif |
3640 | +} |
3641 | + |
3642 | +// Use this function to hash in binary data and strings |
3643 | +void CSHA1::Update(UINT_8* data, UINT_32 len) |
3644 | +{ |
3645 | + UINT_32 i, j; |
3646 | + |
3647 | + j = (m_count[0] >> 3) & 63; |
3648 | + |
3649 | + if((m_count[0] += len << 3) < (len << 3)) |
3650 | + m_count[1]++; |
3651 | + |
3652 | + m_count[1] += (len >> 29); |
3653 | + |
3654 | + if((j + len) > 63) |
3655 | + { |
3656 | + i = 64 - j; |
3657 | + memcpy(&m_buffer[j], data, i); |
3658 | + Transform(m_state, m_buffer); |
3659 | + |
3660 | + for(;i + 63 < len;i += 64) |
3661 | + Transform(m_state, &data[i]); |
3662 | + |
3663 | + j = 0; |
3664 | + } |
3665 | + else |
3666 | + i = 0; |
3667 | + |
3668 | + memcpy(&m_buffer[j], &data[i], len - i); |
3669 | +} |
3670 | + |
3671 | +#ifdef SHA1_UTILITY_FUNCTIONS |
3672 | +// Hash in file contents |
3673 | +bool CSHA1::HashFile(char* szFileName) |
3674 | +{ |
3675 | + unsigned long ulFileSize, ulRest, ulBlocks; |
3676 | + unsigned long i; |
3677 | + UINT_8 uData[SHA1_MAX_FILE_BUFFER]; |
3678 | + FILE* fIn; |
3679 | + |
3680 | + if(szFileName == NULL) |
3681 | + return false; |
3682 | + |
3683 | + fIn = fopen(szFileName, "rb"); |
3684 | + if(fIn == NULL) |
3685 | + return false; |
3686 | + |
3687 | + fseek(fIn, 0, SEEK_END); |
3688 | + ulFileSize = (unsigned long)ftell(fIn); |
3689 | + fseek(fIn, 0, SEEK_SET); |
3690 | + |
3691 | + if(ulFileSize != 0) |
3692 | + { |
3693 | + ulBlocks = ulFileSize / SHA1_MAX_FILE_BUFFER; |
3694 | + ulRest = ulFileSize % SHA1_MAX_FILE_BUFFER; |
3695 | + } |
3696 | + else |
3697 | + { |
3698 | + ulBlocks = 0; |
3699 | + ulRest = 0; |
3700 | + } |
3701 | + |
3702 | + for(i = 0;i < ulBlocks;i++) |
3703 | + { |
3704 | + fread(uData, 1, SHA1_MAX_FILE_BUFFER, fIn); |
3705 | + Update((UINT_8 *)uData, SHA1_MAX_FILE_BUFFER); |
3706 | + } |
3707 | + |
3708 | + if(ulRest != 0) |
3709 | + { |
3710 | + fread(uData, 1, ulRest, fIn); |
3711 | + Update((UINT_8 *)uData, ulRest); |
3712 | + } |
3713 | + |
3714 | + fclose(fIn); fIn = NULL; |
3715 | + return true; |
3716 | +} |
3717 | + |
3718 | +#endif |
3719 | + |
3720 | +void CSHA1::Final() |
3721 | +{ |
3722 | + UINT_32 i; |
3723 | + UINT_8 finalcount[8]; |
3724 | + |
3725 | + for(i = 0;i < 8;i++) |
3726 | + finalcount[i] = (UINT_8)((m_count[((i >= 4) ? 0 : 1)] >> ((3 - (i & 3)) * 8)) & 255); // Endian independent |
3727 | + |
3728 | + Update((UINT_8 *)"\200", 1); |
3729 | + |
3730 | + while((m_count[0] & 504) != 448) |
3731 | + Update((UINT_8 *)"\0", 1); |
3732 | + |
3733 | + Update(finalcount, 8); // Cause a SHA1Transform() |
3734 | + |
3735 | + for(i = 0;i < 20;i++) |
3736 | + { |
3737 | + m_digest[i] = (UINT_8)((m_state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255); |
3738 | + } |
3739 | + |
3740 | + // Wipe variables for security reasons |
3741 | +#ifdef SHA1_WIPE_VARIABLES |
3742 | + i = 0; |
3743 | + memset(m_buffer, 0, 64); |
3744 | + memset(m_state, 0, 20); |
3745 | + memset(m_count, 0, 8); |
3746 | + memset(finalcount, 0, 8); |
3747 | + Transform(m_state, m_buffer); |
3748 | +#endif |
3749 | +} |
3750 | + |
3751 | +#ifdef SHA1_UTILITY_FUNCTIONS |
3752 | +// Get the final hash as a pre-formatted string |
3753 | +void CSHA1::ReportHash(char* szReport, unsigned char uReportType) |
3754 | +{ |
3755 | + unsigned char i; |
3756 | + char szTemp[16]; |
3757 | + |
3758 | + if(szReport == NULL) |
3759 | + return; |
3760 | + |
3761 | + if(uReportType == REPORT_HEX) |
3762 | + { |
3763 | + sprintf(szTemp, "%02X", m_digest[0]); |
3764 | + strcat(szReport, szTemp); |
3765 | + |
3766 | + for(i = 1;i < 20;i++) |
3767 | + { |
3768 | + sprintf(szTemp, " %02X", m_digest[i]); |
3769 | + strcat(szReport, szTemp); |
3770 | + } |
3771 | + } |
3772 | + else if(uReportType == REPORT_DIGIT) |
3773 | + { |
3774 | + sprintf(szTemp, "%u", m_digest[0]); |
3775 | + strcat(szReport, szTemp); |
3776 | + |
3777 | + for(i = 1;i < 20;i++) |
3778 | + { |
3779 | + sprintf(szTemp, " %u", m_digest[i]); |
3780 | + strcat(szReport, szTemp); |
3781 | + } |
3782 | + } |
3783 | + else |
3784 | + strcpy(szReport, "Error: Unknown report type!"); |
3785 | +} |
3786 | + |
3787 | +#endif |
3788 | + |
3789 | +// Get the raw message digest |
3790 | +void CSHA1::GetHash(UINT_8* puDest) |
3791 | +{ |
3792 | + memcpy(puDest, m_digest, 20); |
3793 | +} |
3794 | |
3795 | === added file 'common/SHA1.h' |
3796 | --- common/SHA1.h 1970-01-01 00:00:00 +0000 |
3797 | +++ common/SHA1.h 2011-11-23 01:01:25 +0000 |
3798 | @@ -0,0 +1,150 @@ |
3799 | +/* |
3800 | + 100% free public domain implementation of the SHA-1 algorithm |
3801 | + by Dominik Reichl <dominik.reichl@t-online.de> |
3802 | + Web: http://www.dominik-reichl.de/ |
3803 | + |
3804 | + Version 1.6 - 2005-02-07 (thanks to Howard Kapustein for patches) |
3805 | + - You can set the endianness in your files, no need to modify the |
3806 | + header file of the CSHA1 class any more |
3807 | + - Aligned data support |
3808 | + - Made support/compilation of the utility functions (ReportHash |
3809 | + and HashFile) optional (useful, if bytes count, for example in |
3810 | + embedded environments) |
3811 | + |
3812 | + Version 1.5 - 2005-01-01 |
3813 | + - 64-bit compiler compatibility added |
3814 | + - Made variable wiping optional (define SHA1_WIPE_VARIABLES) |
3815 | + - Removed unnecessary variable initializations |
3816 | + - ROL32 improvement for the Microsoft compiler (using _rotl) |
3817 | + |
3818 | + ======== Test Vectors (from FIPS PUB 180-1) ======== |
3819 | + |
3820 | + SHA1("abc") = |
3821 | + A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D |
3822 | + |
3823 | + SHA1("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") = |
3824 | + 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 |
3825 | + |
3826 | + SHA1(A million repetitions of "a") = |
3827 | + 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F |
3828 | +*/ |
3829 | + |
3830 | +#ifndef ___SHA1_HDR___ |
3831 | +#define ___SHA1_HDR___ |
3832 | + |
3833 | +#if !defined(SHA1_UTILITY_FUNCTIONS) && !defined(SHA1_NO_UTILITY_FUNCTIONS) |
3834 | +#define SHA1_UTILITY_FUNCTIONS |
3835 | +#endif |
3836 | + |
3837 | +#include <memory.h> // Needed for memset and memcpy |
3838 | + |
3839 | +#ifdef SHA1_UTILITY_FUNCTIONS |
3840 | +#include <stdio.h> // Needed for file access and sprintf |
3841 | +#include <string.h> // Needed for strcat and strcpy |
3842 | +#endif |
3843 | + |
3844 | +#ifdef _MSC_VER |
3845 | +#include <stdlib.h> |
3846 | +#endif |
3847 | + |
3848 | +// You can define the endian mode in your files, without modifying the SHA1 |
3849 | +// source files. Just #define SHA1_LITTLE_ENDIAN or #define SHA1_BIG_ENDIAN |
3850 | +// in your files, before including the SHA1.h header file. If you don't |
3851 | +// define anything, the class defaults to little endian. |
3852 | + |
3853 | +#if !defined(SHA1_LITTLE_ENDIAN) && !defined(SHA1_BIG_ENDIAN) |
3854 | +#define SHA1_LITTLE_ENDIAN |
3855 | +#endif |
3856 | + |
3857 | +// Same here. If you want variable wiping, #define SHA1_WIPE_VARIABLES, if |
3858 | +// not, #define SHA1_NO_WIPE_VARIABLES. If you don't define anything, it |
3859 | +// defaults to wiping. |
3860 | + |
3861 | +#if !defined(SHA1_WIPE_VARIABLES) && !defined(SHA1_NO_WIPE_VARIABLES) |
3862 | +#define SHA1_WIPE_VARIABLES |
3863 | +#endif |
3864 | + |
3865 | +///////////////////////////////////////////////////////////////////////////// |
3866 | +// Define 8- and 32-bit variables |
3867 | + |
3868 | +#ifndef UINT_32 |
3869 | + |
3870 | +#ifdef _MSC_VER |
3871 | + |
3872 | +#define UINT_8 unsigned __int8 |
3873 | +#define UINT_32 unsigned __int32 |
3874 | + |
3875 | +#else |
3876 | + |
3877 | +#define UINT_8 unsigned char |
3878 | +/*AFF |
3879 | +#if (ULONG_MAX == 0xFFFFFFFF) |
3880 | +#define UINT_32 unsigned long |
3881 | +#else |
3882 | +#define UINT_32 unsigned int |
3883 | +#endif |
3884 | +*/ |
3885 | +#define UINT_32 unsigned int |
3886 | + |
3887 | +#endif |
3888 | +#endif |
3889 | + |
3890 | +///////////////////////////////////////////////////////////////////////////// |
3891 | +// Declare SHA1 workspace |
3892 | + |
3893 | +typedef union |
3894 | +{ |
3895 | + UINT_8 c[64]; |
3896 | + UINT_32 l[16]; |
3897 | +} SHA1_WORKSPACE_BLOCK; |
3898 | + |
3899 | +class CSHA1 |
3900 | +{ |
3901 | +public: |
3902 | +#ifdef SHA1_UTILITY_FUNCTIONS |
3903 | + // Two different formats for ReportHash(...) |
3904 | + enum |
3905 | + { |
3906 | + REPORT_HEX = 0, |
3907 | + REPORT_DIGIT = 1 |
3908 | + }; |
3909 | +#endif |
3910 | + |
3911 | + // Constructor and Destructor |
3912 | + CSHA1(); |
3913 | + ~CSHA1(); |
3914 | + |
3915 | + UINT_32 m_state[5]; |
3916 | + UINT_32 m_count[2]; |
3917 | + UINT_32 __reserved1[1]; |
3918 | + UINT_8 m_buffer[64]; |
3919 | + UINT_8 m_digest[20]; |
3920 | + UINT_32 __reserved2[3]; |
3921 | + |
3922 | + void Reset(); |
3923 | + |
3924 | + // Update the hash value |
3925 | + void Update(UINT_8* data, UINT_32 len); |
3926 | +#ifdef SHA1_UTILITY_FUNCTIONS |
3927 | + bool HashFile(char* szFileName); |
3928 | +#endif |
3929 | + |
3930 | + // Finalize hash and report |
3931 | + void Final(); |
3932 | + |
3933 | + // Report functions: as pre-formatted and raw data |
3934 | +#ifdef SHA1_UTILITY_FUNCTIONS |
3935 | + void ReportHash(char* szReport, unsigned char uReportType = REPORT_HEX); |
3936 | +#endif |
3937 | + void GetHash(UINT_8* puDest); |
3938 | + |
3939 | +private: |
3940 | + // Private SHA-1 transformation |
3941 | + void Transform(UINT_32* state, UINT_8* buffer); |
3942 | + |
3943 | + // Member variables |
3944 | + UINT_8 m_workspace[64]; |
3945 | + SHA1_WORKSPACE_BLOCK* m_block; // SHA1 pointer to the byte array above |
3946 | +}; |
3947 | + |
3948 | +#endif |
3949 | |
3950 | === added file 'common/SetupInfo.cpp' |
3951 | --- common/SetupInfo.cpp 1970-01-01 00:00:00 +0000 |
3952 | +++ common/SetupInfo.cpp 2011-11-23 01:01:25 +0000 |
3953 | @@ -0,0 +1,512 @@ |
3954 | +//////////////////////////////////////////////////////////////////////////////// |
3955 | +// Copyright (c) CitizenLab, 2006. All Rights Reserved. |
3956 | +// The latest version of this code is available at http://psiphon.civisec.org/ |
3957 | +// |
3958 | +// This software is open source; you can redistribute it and/or modify it |
3959 | +// under the terms of the GNU General Public License as published by the |
3960 | +// Free Software Foundation; either version 2 of the License, or (at your |
3961 | +// option) any later version. |
3962 | +// |
3963 | +// This program is distributed WITHOUT ANY WARRANTY; without even the |
3964 | +// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
3965 | +// See the GNU General Public License for more details at: |
3966 | +// http://psiphon.civisec.org/ |
3967 | +// |
3968 | +// This General Public License does NOT permit incorporating this software |
3969 | +// into proprietary programs. |
3970 | +//////////////////////////////////////////////////////////////////////////////// |
3971 | + |
3972 | +#include "SetupInfo.h" |
3973 | +#include <stdio.h> |
3974 | +#include <string.h> |
3975 | +#include <stdlib.h> |
3976 | +#include "strfunc.h" |
3977 | +#include <sys/stat.h> |
3978 | + |
3979 | +#define SETUP_FUNC "psiphon.cnf" |
3980 | + |
3981 | +#define _T(X) X |
3982 | + |
3983 | +CSetupInfo g_info; |
3984 | + |
3985 | +CSetupInfo::CSetupInfo() |
3986 | +{ |
3987 | + Init(); |
3988 | +} |
3989 | + |
3990 | +CSetupInfo::CSetupInfo(const char* sIn) |
3991 | +{ |
3992 | + Init(); |
3993 | + Parse(sIn); |
3994 | +} |
3995 | + |
3996 | +CSetupInfo::~CSetupInfo() |
3997 | +{ |
3998 | + delete m_sIP; |
3999 | + delete m_sName; |
4000 | + delete m_Common; |
4001 | + delete m_Country; |
4002 | + delete m_State; |
4003 | + delete m_Email; |
4004 | + delete m_Unit; |
4005 | + delete m_Organization; |
4006 | + delete m_sIPServer; |
4007 | + delete m_sFinger; |
4008 | +} |
4009 | + |
4010 | +void CSetupInfo::Init() |
4011 | +{ |
4012 | + m_sIP = strdup(_T("127.0.0.1")); |
4013 | + m_nPort = 443; |
4014 | + m_nShowImages = 1; |
4015 | + m_nAutoUpdateIP = 1; |
4016 | + m_nTestPort = 1; |
4017 | + m_nStartOnStartUp = 0; |
4018 | + m_sName = NULL; |
4019 | + m_nCheckForUpdatesOnStartUp = 1; |
4020 | + m_Common = strdup(_T("somename.somewhere.com")); |
4021 | + m_Country = strdup(_T("US")); |
4022 | + m_State = strdup(_T("Some State")); |
4023 | + m_Email = strdup(_T("root@somename.somewhere.com")); |
4024 | + m_Unit = strdup(_T("My Subunit of Large Organization")); |
4025 | + m_Organization = strdup(_T("My Large Organization Name")); |
4026 | + m_nRegenrateOnStartUp = 0; |
4027 | + m_nLogLevel = 0; |
4028 | + m_sIPServer = strdup(_T("http://psiphon.civisec.org/ip.php")); |
4029 | + m_sFinger = NULL; |
4030 | +} |
4031 | + |
4032 | +void CSetupInfo::Out(char*& sOut) |
4033 | +{ |
4034 | + char FORMAT[] = _T("%s\t%d\t%d\t%d\t%d\t%d\t%s\t%d\t%s\t%s\t%s\t%s\t%s\t%s\t%d\t%d\t%s"); |
4035 | + |
4036 | + int nSize = GetStrLength(FORMAT) |
4037 | + + GetStrLength(m_sIP) |
4038 | + + GetStrLength(m_nPort) |
4039 | + + GetStrLength(m_nShowImages) |
4040 | + + GetStrLength(m_nAutoUpdateIP) |
4041 | + + GetStrLength(m_nTestPort) |
4042 | + + GetStrLength(m_nStartOnStartUp) |
4043 | + + GetStrLength(m_sName) |
4044 | + + GetStrLength(m_nCheckForUpdatesOnStartUp) |
4045 | + + GetStrLength(m_Common) |
4046 | + + GetStrLength(m_Country) |
4047 | + + GetStrLength(m_State) |
4048 | + + GetStrLength(m_Email) |
4049 | + + GetStrLength(m_Organization) |
4050 | + + GetStrLength(m_Unit) |
4051 | + + GetStrLength(m_nRegenrateOnStartUp) |
4052 | + + GetStrLength(m_nLogLevel) |
4053 | + + GetStrLength(m_sIPServer); |
4054 | + |
4055 | + sOut = new char[nSize]; |
4056 | + |
4057 | + int nLen = _snprintf(sOut, nSize, FORMAT |
4058 | + , m_sIP |
4059 | + , m_nPort |
4060 | + , m_nShowImages |
4061 | + , m_nAutoUpdateIP |
4062 | + , m_nTestPort |
4063 | + , m_nStartOnStartUp |
4064 | + , m_sName |
4065 | + , m_nCheckForUpdatesOnStartUp |
4066 | + , m_Common |
4067 | + , m_Country |
4068 | + , m_State |
4069 | + , m_Email |
4070 | + , m_Organization |
4071 | + , m_Unit |
4072 | + , m_nRegenrateOnStartUp |
4073 | + , m_nLogLevel |
4074 | + , m_sIPServer); |
4075 | + |
4076 | + if(nLen <= 0 || nLen >= nSize) |
4077 | + { |
4078 | + delete sOut; |
4079 | + sOut = NULL; |
4080 | + } |
4081 | +} |
4082 | + |
4083 | +void CSetupInfo::Parse(const char* sIn) |
4084 | +{ |
4085 | + if(!sIn || !*sIn) |
4086 | + return; |
4087 | + |
4088 | + char* _sIn = strdup(sIn); |
4089 | + |
4090 | + char seps[] = _T("\t"); |
4091 | + char* token = strtok(_sIn, seps); |
4092 | + |
4093 | + if(!token) |
4094 | + return; |
4095 | + |
4096 | + if(strcmp(token, _T("NULL")) != 0) |
4097 | + SetIP(token); |
4098 | + |
4099 | + token = strtok(NULL, seps); |
4100 | + if(!token) |
4101 | + { |
4102 | + delete _sIn; |
4103 | + return; |
4104 | + } |
4105 | + SetPort(atoi(token)); |
4106 | + |
4107 | + token = strtok(NULL, seps); |
4108 | + if(!token) |
4109 | + { |
4110 | + delete _sIn; |
4111 | + return; |
4112 | + } |
4113 | + SetShowImages(atoi(token)); |
4114 | + |
4115 | + token = strtok(NULL, seps); |
4116 | + if(!token) |
4117 | + { |
4118 | + delete _sIn; |
4119 | + return; |
4120 | + } |
4121 | + SetAutoUpdateIP(atoi(token)); |
4122 | + |
4123 | + token = strtok(NULL, seps); |
4124 | + if(!token) |
4125 | + { |
4126 | + delete _sIn; |
4127 | + return; |
4128 | + } |
4129 | + SetTestPort(atoi(token)); |
4130 | + |
4131 | + token = strtok(NULL, seps); |
4132 | + if(!token) |
4133 | + { |
4134 | + delete _sIn; |
4135 | + return; |
4136 | + } |
4137 | + SetStartOnStartUp(atoi(token)); |
4138 | + |
4139 | + token = strtok(NULL, seps); |
4140 | + if(!token) |
4141 | + { |
4142 | + delete _sIn; |
4143 | + return; |
4144 | + } |
4145 | + SetName(token); |
4146 | + |
4147 | + token = strtok(NULL, seps); |
4148 | + if(!token) |
4149 | + { |
4150 | + delete _sIn; |
4151 | + return; |
4152 | + } |
4153 | + SetCheckForUpdatesOnStartUp(atoi(token)); |
4154 | + |
4155 | + token = strtok(NULL, seps); |
4156 | + if(!token) |
4157 | + { |
4158 | + delete _sIn; |
4159 | + return; |
4160 | + } |
4161 | + SetCommon(token); |
4162 | + |
4163 | + token = strtok(NULL, seps); |
4164 | + if(!token) |
4165 | + { |
4166 | + delete _sIn; |
4167 | + return; |
4168 | + } |
4169 | + SetCountry(token); |
4170 | + |
4171 | + token = strtok(NULL, seps); |
4172 | + if(!token) |
4173 | + { |
4174 | + delete _sIn; |
4175 | + return; |
4176 | + } |
4177 | + SetState(token); |
4178 | + |
4179 | + token = strtok(NULL, seps); |
4180 | + if(!token) |
4181 | + { |
4182 | + delete _sIn; |
4183 | + return; |
4184 | + } |
4185 | + SetEmail(token); |
4186 | + |
4187 | + token = strtok(NULL, seps); |
4188 | + if(!token) |
4189 | + { |
4190 | + delete _sIn; |
4191 | + return; |
4192 | + } |
4193 | + SetOrganization(token); |
4194 | + |
4195 | + token = strtok(NULL, seps); |
4196 | + if(!token) |
4197 | + { |
4198 | + delete _sIn; |
4199 | + return; |
4200 | + } |
4201 | + SetUnit(token); |
4202 | + |
4203 | + token = strtok(NULL, seps); |
4204 | + if(!token) |
4205 | + { |
4206 | + delete _sIn; |
4207 | + return; |
4208 | + } |
4209 | + SetRegenrateOnStartUp(atoi(token)); |
4210 | + |
4211 | + token = strtok(NULL, seps); |
4212 | + if(!token) |
4213 | + { |
4214 | + delete _sIn; |
4215 | + return; |
4216 | + } |
4217 | + SetLogLevel(atoi(token)); |
4218 | + |
4219 | + token = strtok(NULL, seps); |
4220 | + if(!token) |
4221 | + { |
4222 | + delete _sIn; |
4223 | + return; |
4224 | + } |
4225 | + SetIPServer(token); |
4226 | + |
4227 | + delete _sIn; |
4228 | +} |
4229 | + |
4230 | +bool CSetupInfo::Store() |
4231 | +{ |
4232 | + FILE* pFile = fopen(SETUP_FUNC, _T("w")); |
4233 | + if(pFile == NULL) |
4234 | + return false; |
4235 | + |
4236 | + char* pOut = NULL; |
4237 | + Out(pOut); |
4238 | + if(pOut == NULL) |
4239 | + return false; |
4240 | + |
4241 | + fwrite(pOut, sizeof(char), strlen(pOut), pFile); |
4242 | + |
4243 | + delete pOut; |
4244 | + |
4245 | + fclose(pFile); |
4246 | + |
4247 | + return true; |
4248 | +} |
4249 | + |
4250 | +void CSetupInfo::Load() |
4251 | +{ |
4252 | + struct stat results; |
4253 | + if(stat(SETUP_FUNC, &results) != 0) |
4254 | + return; |
4255 | + |
4256 | + FILE* pFile = fopen(SETUP_FUNC, _T("r")); |
4257 | + if(pFile == NULL) |
4258 | + return; |
4259 | + |
4260 | + int nSize = results.st_size/sizeof(char) + 1; |
4261 | + |
4262 | + char* pIn = new char[nSize]; |
4263 | + memset(pIn, 0, nSize * sizeof(char)); |
4264 | + |
4265 | + fread(pIn, sizeof(char), nSize, pFile); |
4266 | + |
4267 | + pIn[nSize - 1] = 0; |
4268 | + |
4269 | + Parse(pIn); |
4270 | + |
4271 | + delete pIn; |
4272 | + |
4273 | + fclose(pFile); |
4274 | +} |
4275 | + |
4276 | +char* CSetupInfo::GetIP() |
4277 | +{ |
4278 | + return m_sIP; |
4279 | +} |
4280 | + |
4281 | +void CSetupInfo::SetIP(const char* _sIP) |
4282 | +{ |
4283 | + delete m_sIP; |
4284 | + m_sIP = strdup(_sIP); |
4285 | +} |
4286 | + |
4287 | +int CSetupInfo::GetPort() |
4288 | +{ |
4289 | + return m_nPort; |
4290 | +} |
4291 | + |
4292 | +void CSetupInfo::SetPort(int _nPort) |
4293 | +{ |
4294 | + m_nPort = _nPort; |
4295 | +} |
4296 | + |
4297 | +int CSetupInfo::GetShowImages() |
4298 | +{ |
4299 | + return m_nShowImages; |
4300 | +} |
4301 | + |
4302 | +void CSetupInfo::SetShowImages(int _nShowImages) |
4303 | +{ |
4304 | + m_nShowImages = _nShowImages; |
4305 | +} |
4306 | + |
4307 | +int CSetupInfo::GetAutoUpdateIP() |
4308 | +{ |
4309 | + return m_nAutoUpdateIP; |
4310 | +} |
4311 | + |
4312 | +void CSetupInfo::SetAutoUpdateIP(int _nAutoUpdateIP) |
4313 | +{ |
4314 | + m_nAutoUpdateIP = _nAutoUpdateIP; |
4315 | +} |
4316 | + |
4317 | +int CSetupInfo::GetTestPort() |
4318 | +{ |
4319 | + return m_nTestPort; |
4320 | +} |
4321 | + |
4322 | +void CSetupInfo::SetTestPort(int _nTestPort) |
4323 | +{ |
4324 | + m_nTestPort = _nTestPort; |
4325 | +} |
4326 | + |
4327 | +int CSetupInfo::GetStartOnStartUp() |
4328 | +{ |
4329 | + return m_nStartOnStartUp; |
4330 | +} |
4331 | + |
4332 | +void CSetupInfo::SetStartOnStartUp(int _nStartOnStartUp) |
4333 | +{ |
4334 | + m_nStartOnStartUp = _nStartOnStartUp; |
4335 | +} |
4336 | + |
4337 | +char* CSetupInfo::GetName() |
4338 | +{ |
4339 | + return m_sName; |
4340 | +} |
4341 | + |
4342 | +void CSetupInfo::SetName(const char* _sName) |
4343 | +{ |
4344 | + delete m_sName; |
4345 | + m_sName = strdup(_sName); |
4346 | +} |
4347 | + |
4348 | +int CSetupInfo::GetCheckForUpdatesOnStartUp() |
4349 | +{ |
4350 | + return m_nCheckForUpdatesOnStartUp; |
4351 | +} |
4352 | + |
4353 | +void CSetupInfo::SetCheckForUpdatesOnStartUp(int _nCheckForUpdatesOnStartUp) |
4354 | +{ |
4355 | + m_nCheckForUpdatesOnStartUp = _nCheckForUpdatesOnStartUp; |
4356 | +} |
4357 | + |
4358 | +void CSetupInfo::SetCommon(const char* _Common) |
4359 | +{ |
4360 | + delete m_Common; |
4361 | + m_Common = strdup(_Common); |
4362 | +} |
4363 | + |
4364 | +void CSetupInfo::SetUnit(const char* _Unit) |
4365 | +{ |
4366 | + delete m_Unit; |
4367 | + m_Unit = strdup(_Unit); |
4368 | +} |
4369 | + |
4370 | +void CSetupInfo::SetOrganization(const char* _Organization) |
4371 | +{ |
4372 | + delete m_Organization; |
4373 | + m_Organization = strdup(_Organization); |
4374 | +} |
4375 | + |
4376 | +void CSetupInfo::SetEmail(const char* _Email) |
4377 | +{ |
4378 | + delete m_Email; |
4379 | + m_Email = strdup(_Email); |
4380 | +} |
4381 | + |
4382 | +void CSetupInfo::SetCountry(const char* _Country) |
4383 | +{ |
4384 | + delete m_Country; |
4385 | + m_Country = strdup(_Country); |
4386 | +} |
4387 | + |
4388 | +void CSetupInfo::SetState(const char* _State) |
4389 | +{ |
4390 | + delete m_State; |
4391 | + m_State = strdup(_State); |
4392 | +} |
4393 | + |
4394 | +void CSetupInfo::SetRegenrateOnStartUp(int _nRegenrateOnStartUp) |
4395 | +{ |
4396 | + m_nRegenrateOnStartUp = _nRegenrateOnStartUp; |
4397 | +} |
4398 | + |
4399 | +char* CSetupInfo::GetCommon() |
4400 | +{ |
4401 | + return m_Common; |
4402 | +} |
4403 | + |
4404 | +char* CSetupInfo::GetUnit() |
4405 | +{ |
4406 | + return m_Unit; |
4407 | +} |
4408 | + |
4409 | +char* CSetupInfo::GetOrganization() |
4410 | +{ |
4411 | + return m_Organization; |
4412 | +} |
4413 | + |
4414 | +char* CSetupInfo::GetEmail() |
4415 | +{ |
4416 | + return m_Email; |
4417 | +} |
4418 | + |
4419 | +char* CSetupInfo::GetCountry() |
4420 | +{ |
4421 | + return m_Country; |
4422 | +} |
4423 | + |
4424 | +char* CSetupInfo::GetState() |
4425 | +{ |
4426 | + return m_State; |
4427 | +} |
4428 | + |
4429 | +int CSetupInfo::GetRegenrateOnStartUp() |
4430 | +{ |
4431 | + return m_nRegenrateOnStartUp; |
4432 | +} |
4433 | + |
4434 | +int CSetupInfo::GetLogLevel() |
4435 | +{ |
4436 | + return m_nLogLevel; |
4437 | +} |
4438 | + |
4439 | +void CSetupInfo::SetLogLevel(int _nLogLevel) |
4440 | +{ |
4441 | + m_nLogLevel = _nLogLevel; |
4442 | +} |
4443 | + |
4444 | +char* CSetupInfo::GetIPServer() |
4445 | +{ |
4446 | + return m_sIPServer; |
4447 | +} |
4448 | + |
4449 | +void CSetupInfo::SetIPServer(const char* _sIPServer) |
4450 | +{ |
4451 | + delete m_sIPServer; |
4452 | + m_sIPServer = strdup(_sIPServer); |
4453 | +} |
4454 | + |
4455 | +char* CSetupInfo::GetFinger() |
4456 | +{ |
4457 | + return m_sFinger; |
4458 | +} |
4459 | + |
4460 | +void CSetupInfo::SetFinger(const char* _sFinger) |
4461 | +{ |
4462 | + delete m_sFinger; |
4463 | + m_sFinger = strdup(_sFinger); |
4464 | +} |
4465 | + |
4466 | |
4467 | === added file 'common/SetupInfo.h' |
4468 | --- common/SetupInfo.h 1970-01-01 00:00:00 +0000 |
4469 | +++ common/SetupInfo.h 2011-11-23 01:01:25 +0000 |
4470 | @@ -0,0 +1,110 @@ |
4471 | +//////////////////////////////////////////////////////////////////////////////// |
4472 | +// Copyright (c) CitizenLab, 2006. All Rights Reserved. |
4473 | +// The latest version of this code is available at http://psiphon.civisec.org/ |
4474 | +// |
4475 | +// This software is open source; you can redistribute it and/or modify it |
4476 | +// under the terms of the GNU General Public License as published by the |
4477 | +// Free Software Foundation; either version 2 of the License, or (at your |
4478 | +// option) any later version. |
4479 | +// |
4480 | +// This program is distributed WITHOUT ANY WARRANTY; without even the |
4481 | +// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
4482 | +// See the GNU General Public License for more details at: |
4483 | +// http://psiphon.civisec.org/ |
4484 | +// |
4485 | +// This General Public License does NOT permit incorporating this software |
4486 | +// into proprietary programs. |
4487 | +//////////////////////////////////////////////////////////////////////////////// |
4488 | + |
4489 | +#pragma once |
4490 | + |
4491 | +class CSetupInfo |
4492 | +{ |
4493 | + char* m_sIP; |
4494 | + int m_nPort; |
4495 | + int m_nShowImages; |
4496 | + int m_nAutoUpdateIP; |
4497 | + int m_nTestPort; |
4498 | + int m_nStartOnStartUp; |
4499 | + char* m_sName; |
4500 | + int m_nCheckForUpdatesOnStartUp; |
4501 | + |
4502 | + char* m_Common; |
4503 | + char* m_Unit; |
4504 | + char* m_Organization; |
4505 | + char* m_Email; |
4506 | + char* m_Country; |
4507 | + char* m_State; |
4508 | + int m_nRegenrateOnStartUp; |
4509 | + int m_nLogLevel; |
4510 | + char* m_sIPServer; |
4511 | + char* m_sFinger; |
4512 | + |
4513 | +public: |
4514 | + CSetupInfo(); |
4515 | + |
4516 | + CSetupInfo(const char* sIn); |
4517 | + ~CSetupInfo(); |
4518 | + |
4519 | +public: |
4520 | + char* GetIP(); |
4521 | + void SetIP(const char* _sIP); |
4522 | + |
4523 | + int GetShowImages(); |
4524 | + void SetShowImages(int _nShowImages); |
4525 | + |
4526 | + int GetPort(); |
4527 | + void SetPort(int _nPort); |
4528 | + |
4529 | + int GetAutoUpdateIP(); |
4530 | + void SetAutoUpdateIP(int _nAutoUpdateIP); |
4531 | + |
4532 | + int GetTestPort(); |
4533 | + void SetTestPort(int _nTestPort); |
4534 | + |
4535 | + int GetStartOnStartUp(); |
4536 | + void SetStartOnStartUp(int _nStartOnStartUp); |
4537 | + |
4538 | + char* GetName(); |
4539 | + void SetName(const char* _sName); |
4540 | + |
4541 | + int GetCheckForUpdatesOnStartUp(); |
4542 | + void SetCheckForUpdatesOnStartUp(int _nCheckForUpdatesOnStartUp); |
4543 | + |
4544 | + bool Store(); |
4545 | + void Load(); |
4546 | + |
4547 | + void SetCommon(const char* _Common); |
4548 | + void SetUnit(const char* _Unit); |
4549 | + void SetOrganization(const char* _Organization); |
4550 | + void SetEmail(const char* _Email); |
4551 | + void SetCountry(const char* _Country); |
4552 | + void SetState(const char* _State); |
4553 | + void SetRegenrateOnStartUp(int _nRegenrateOnStartUp); |
4554 | + |
4555 | + char* GetCommon(); |
4556 | + char* GetUnit(); |
4557 | + char* GetOrganization(); |
4558 | + char* GetEmail(); |
4559 | + char* GetCountry(); |
4560 | + char* GetState(); |
4561 | + int GetRegenrateOnStartUp(); |
4562 | + |
4563 | + int GetLogLevel(); |
4564 | + void SetLogLevel(int _nLogLevel); |
4565 | + |
4566 | + char* GetIPServer(); |
4567 | + void SetIPServer(const char* pIPServer); |
4568 | + |
4569 | + char* GetFinger(); |
4570 | + void SetFinger(const char* pFinger); |
4571 | + |
4572 | +protected: |
4573 | + void Init(); |
4574 | + void Out(char*& sOut); |
4575 | + |
4576 | + void Parse(const char* sIn); |
4577 | +}; |
4578 | + |
4579 | +extern CSetupInfo g_info; |
4580 | + |
4581 | |
4582 | === added file 'common/User.cpp' |
4583 | --- common/User.cpp 1970-01-01 00:00:00 +0000 |
4584 | +++ common/User.cpp 2011-11-23 01:01:25 +0000 |
4585 | @@ -0,0 +1,598 @@ |
4586 | +//////////////////////////////////////////////////////////////////////////////// |
4587 | +// Copyright (c) CitizenLab, 2006. All Rights Reserved. |
4588 | +// The latest version of this code is available at http://psiphon.civisec.org/ |
4589 | +// |
4590 | +// This software is open source; you can redistribute it and/or modify it |
4591 | +// under the terms of the GNU General Public License as published by the |
4592 | +// Free Software Foundation; either version 2 of the License, or (at your |
4593 | +// option) any later version. |
4594 | +// |
4595 | +// This program is distributed WITHOUT ANY WARRANTY; without even the |
4596 | +// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
4597 | +// See the GNU General Public License for more details at: |
4598 | +// http://psiphon.civisec.org/ |
4599 | +// |
4600 | +// This General Public License does NOT permit incorporating this software |
4601 | +// into proprietary programs. |
4602 | +//////////////////////////////////////////////////////////////////////////////// |
4603 | + |
4604 | +#include "convert.h" |
4605 | +#include "CppSQLite3.h" |
4606 | +#include "User.h" |
4607 | +#include "SHA1.h" |
4608 | +#include "strfunc.h" |
4609 | + |
4610 | +#define _T(X) X |
4611 | + |
4612 | +void escape(char* pDest, int nSize, const char* pSrc); |
4613 | + |
4614 | +char* CDBUser::m_sDB = _T("users.db"); |
4615 | + |
4616 | +LOG_ROUTINE CDBUser::m_pLogFunc = NULL; |
4617 | + |
4618 | +CDBUser::CDBUser() |
4619 | +{ |
4620 | + Init(); |
4621 | +} |
4622 | + |
4623 | +CDBUser::~CDBUser() |
4624 | +{ |
4625 | + Cleanup(); |
4626 | +} |
4627 | + |
4628 | +void CDBUser::Init() |
4629 | +{ |
4630 | + m_sUserName = NULL; |
4631 | + m_sPassword = NULL; |
4632 | + m_sEmail = NULL; |
4633 | + m_sFullName = NULL; |
4634 | + |
4635 | + m_nID = 0; |
4636 | + m_nDeleted = false; |
4637 | + |
4638 | + m_nLastAccess = 0; |
4639 | + m_nWritten = 0; |
4640 | + m_nRead = 0; |
4641 | + m_nWriteTime = 0; |
4642 | + m_nReadTime = 0; |
4643 | +} |
4644 | + |
4645 | +void CDBUser::Cleanup() |
4646 | +{ |
4647 | + delete m_sUserName; |
4648 | + delete m_sPassword; |
4649 | + delete m_sEmail; |
4650 | + delete m_sFullName; |
4651 | + |
4652 | + Init(); |
4653 | +} |
4654 | + |
4655 | +int CDBUser::Get(int nUserID) |
4656 | +{ |
4657 | + if(nUserID <= 0) |
4658 | + return -1; |
4659 | + |
4660 | + try |
4661 | + { |
4662 | + CppSQLite3DB db; |
4663 | + db.Open(m_sDB); |
4664 | + |
4665 | + if(!db.tableExists(_T("users"))) |
4666 | + return false; |
4667 | + |
4668 | + CppSQLite3Statement stmt = db.compileStatement(_T("select nIndex, sUsername, sPassword, sEmail, sFullname from users where nIndex = ?;")); |
4669 | + |
4670 | + stmt.bind(1, nUserID); |
4671 | + |
4672 | + CppSQLite3Query q = stmt.execQuery(); |
4673 | + |
4674 | + if(!q.eof()) |
4675 | + { |
4676 | + SetID(q.getIntField(0)); |
4677 | + |
4678 | + CConverter wUsername(q.fieldValue(1)); |
4679 | + SetUsername(wUsername); |
4680 | + |
4681 | + CConverter wPassword(q.fieldValue(2)); |
4682 | + SetPassword(wPassword); |
4683 | + |
4684 | + CConverter wEmail(q.fieldValue(3)); |
4685 | + SetEmail(wEmail); |
4686 | + |
4687 | + CConverter wFullName(q.fieldValue(4)); |
4688 | + SetFullName(wFullName); |
4689 | + |
4690 | + q.nextRow(); |
4691 | + |
4692 | + return 0; |
4693 | + } |
4694 | + } |
4695 | + catch(CppSQLite3Exception& e) |
4696 | + { |
4697 | + CConverter wMsg(e.errorMessage()); |
4698 | + CDBUser::Log(wMsg); |
4699 | + } |
4700 | + |
4701 | + return -1; |
4702 | +} |
4703 | + |
4704 | +int CDBUser::FindUser(const char* pUserName, const char* pPassword) |
4705 | +{ |
4706 | + if(!pUserName || strlen(pUserName) > 100) |
4707 | + return -1; |
4708 | + |
4709 | + if(!pPassword || strlen(pPassword) > 64) |
4710 | + return -1; |
4711 | + |
4712 | + try |
4713 | + { |
4714 | + CppSQLite3DB db; |
4715 | + db.Open(m_sDB); |
4716 | + |
4717 | + if(!db.tableExists(_T("users"))) |
4718 | + return -1; |
4719 | + |
4720 | + CppSQLite3Statement stmt = db.compileStatement(_T("select nIndex from users where sUsername=? and sPassword=? and nDeleted != 1;")); |
4721 | + |
4722 | + stmt.bind(1, pUserName); |
4723 | + stmt.bind(2, pPassword); |
4724 | + |
4725 | + CppSQLite3Query q = stmt.execQuery(); |
4726 | + |
4727 | + if(!q.eof()) |
4728 | + { |
4729 | + return (q.getIntField(0)); |
4730 | + } |
4731 | + } |
4732 | + catch(CppSQLite3Exception& e) |
4733 | + { |
4734 | + CConverter wMsg(e.errorMessage()); |
4735 | + CDBUser::Log(wMsg); |
4736 | + } |
4737 | + |
4738 | + return -1; |
4739 | +} |
4740 | + |
4741 | +int CDBUser::FindUsername(const char* pUserName) |
4742 | +{ |
4743 | + if(!pUserName || strlen(pUserName) > 100) |
4744 | + return -1; |
4745 | + |
4746 | + try |
4747 | + { |
4748 | + CppSQLite3DB db; |
4749 | + db.Open(m_sDB); |
4750 | + |
4751 | + if(!db.tableExists(_T("users"))) |
4752 | + return -1; |
4753 | + |
4754 | + |
4755 | + CppSQLite3Statement stmt = db.compileStatement(_T("select nIndex from users where sUsername=?;")); |
4756 | + |
4757 | + stmt.bind(1, pUserName); |
4758 | + |
4759 | + CppSQLite3Query q = stmt.execQuery(); |
4760 | + |
4761 | + if(!q.eof()) |
4762 | + { |
4763 | + return (q.getIntField(0)); |
4764 | + } |
4765 | + } |
4766 | + catch(CppSQLite3Exception& e) |
4767 | + { |
4768 | + CConverter wMsg(e.errorMessage()); |
4769 | + CDBUser::Log(wMsg); |
4770 | + } |
4771 | + |
4772 | + return -1; |
4773 | +} |
4774 | + |
4775 | +int CDBUser::Insert() |
4776 | +{ |
4777 | + if(!m_sUserName || strlen(m_sUserName) > 100) |
4778 | + return -1; |
4779 | + |
4780 | + if(!m_sPassword || strlen(m_sPassword) > 64) |
4781 | + return -1; |
4782 | + |
4783 | + if(!m_sEmail || strlen(m_sEmail) > 100) |
4784 | + return -1; |
4785 | + |
4786 | + if(!m_sFullName || strlen(m_sFullName) > 100) |
4787 | + return -1; |
4788 | + try |
4789 | + { |
4790 | + CppSQLite3DB db; |
4791 | + db.Open(m_sDB); |
4792 | + |
4793 | + if(!db.tableExists(_T("users"))) |
4794 | + { |
4795 | + db.execDML(_T("create table users(nIndex integer primary key, sUsername char(100), sPassword char(64), sEmail char(100), sFullname char(100), nDeleted int);")); |
4796 | + } |
4797 | + |
4798 | + CppSQLite3Statement stmt = db.compileStatement(_T("insert into users (sUsername, sPassword, sEmail, sFullname, nDeleted)" |
4799 | + " values (?, ?, ?, ?, ?);")); |
4800 | + |
4801 | + stmt.bind(1, m_sUserName); |
4802 | + stmt.bind(2, m_sPassword); |
4803 | + stmt.bind(3, m_sEmail); |
4804 | + stmt.bind(4, m_sFullName); |
4805 | + stmt.bind(5, m_nDeleted); |
4806 | + |
4807 | + |
4808 | + int nRows = stmt.execDML(); |
4809 | + |
4810 | + m_nID = (int)db.lastRowId(); |
4811 | + |
4812 | + return nRows; |
4813 | + } |
4814 | + catch(CppSQLite3Exception& e) |
4815 | + { |
4816 | + CConverter wMsg(e.errorMessage()); |
4817 | + CDBUser::Log(wMsg); |
4818 | + } |
4819 | + |
4820 | + return -1; |
4821 | +} |
4822 | + |
4823 | +int CDBUser::Update() |
4824 | +{ |
4825 | + if(m_nID <= 0) |
4826 | + return -1; |
4827 | + |
4828 | + if(!m_sPassword || strlen(m_sPassword) > 64) |
4829 | + return -1; |
4830 | + |
4831 | + if(!m_sEmail || strlen(m_sEmail) > 100) |
4832 | + return -1; |
4833 | + |
4834 | + if(!m_sFullName || strlen(m_sFullName) > 100) |
4835 | + return -1; |
4836 | + |
4837 | + try |
4838 | + { |
4839 | + CppSQLite3DB db; |
4840 | + db.Open(m_sDB); |
4841 | + |
4842 | + if(!db.tableExists("users")) |
4843 | + return -1; |
4844 | + |
4845 | + CppSQLite3Statement stmt; |
4846 | + |
4847 | + if(strlen(m_sPassword) > 0) |
4848 | + { |
4849 | + stmt = db.compileStatement(_T("update users set sPassword=?, sEmail=?, sFullname=? where nIndex=?;")); |
4850 | + stmt.bind(1, m_sPassword); |
4851 | + stmt.bind(2, m_sEmail); |
4852 | + stmt.bind(3, m_sFullName); |
4853 | + stmt.bind(4, m_nID); |
4854 | + } |
4855 | + else |
4856 | + { |
4857 | + stmt = db.compileStatement(_T("update users set sEmail=?, sFullname=? where nIndex=?;")); |
4858 | + stmt.bind(1, m_sEmail); |
4859 | + stmt.bind(2, m_sFullName); |
4860 | + stmt.bind(3, m_nID); |
4861 | + } |
4862 | + |
4863 | + int nRows = stmt.execDML(); |
4864 | + return nRows; |
4865 | + } |
4866 | + catch(CppSQLite3Exception& e) |
4867 | + { |
4868 | + CConverter wMsg(e.errorMessage()); |
4869 | + CDBUser::Log(wMsg); |
4870 | + } |
4871 | + |
4872 | + return -1; |
4873 | +} |
4874 | + |
4875 | +void CDBUser::EncryptPassword(char* pKey, int nKeySize, const char* _pUsername, const char* _pPassword) |
4876 | +{ |
4877 | + if(!pKey) |
4878 | + return; |
4879 | + |
4880 | + if(nKeySize == 0) |
4881 | + return; |
4882 | + |
4883 | + if(!_pUsername || strlen(_pUsername) > 100) |
4884 | + return; |
4885 | + if(!_pPassword || strlen(_pPassword) > 64) |
4886 | + return; |
4887 | + |
4888 | + CSHA1 sha1; |
4889 | + |
4890 | + CConverter aUsername(_pUsername); |
4891 | + CConverter aPassword(_pPassword); |
4892 | + |
4893 | + sha1.Update((UINT_8*)(char*)(const char*)aUsername, strlen(aUsername)); |
4894 | + sha1.Update((UINT_8*)(char*)(const char*)aPassword, strlen(aPassword)); |
4895 | + sha1.Final(); |
4896 | + |
4897 | + char* aKey = new char[nKeySize]; |
4898 | + memset(aKey, 0, nKeySize * sizeof(char)); |
4899 | + sha1.ReportHash(aKey, CSHA1::REPORT_HEX); |
4900 | + |
4901 | + CConverter _pKey(aKey); |
4902 | + strncpy(pKey, _pKey, nKeySize); |
4903 | + |
4904 | + delete aKey; |
4905 | +} |
4906 | + |
4907 | +int CDBUser::Delete(int nUserID) |
4908 | +{ |
4909 | + if(nUserID <= 0) |
4910 | + return -1; |
4911 | + |
4912 | + try |
4913 | + { |
4914 | + CppSQLite3DB db; |
4915 | + db.Open(m_sDB); |
4916 | + |
4917 | + if(!db.tableExists(_T("users"))) |
4918 | + return false; |
4919 | + |
4920 | + CppSQLite3Statement stmt = db.compileStatement(_T("update users set nDeleted=1 where nIndex=?;")); |
4921 | + stmt.bind(1, nUserID); |
4922 | + stmt.execDML(); |
4923 | + |
4924 | + return 0; |
4925 | + } |
4926 | + catch(CppSQLite3Exception& e) |
4927 | + { |
4928 | + CConverter wMsg(e.errorMessage()); |
4929 | + CDBUser::Log(wMsg); |
4930 | + } |
4931 | + |
4932 | + return -1; |
4933 | +} |
4934 | + |
4935 | +int CDBUser::GetUserCount() |
4936 | +{ |
4937 | + try |
4938 | + { |
4939 | + CppSQLite3DB db; |
4940 | + db.Open(m_sDB); |
4941 | + |
4942 | + if(!db.tableExists(_T("users"))) |
4943 | + return 0; |
4944 | + |
4945 | + int nRet = db.execScalar(_T("select count(*) from users where nDeleted = 0")); |
4946 | + |
4947 | + return nRet; |
4948 | + } |
4949 | + catch(CppSQLite3Exception& e) |
4950 | + { |
4951 | + CConverter wMsg(e.errorMessage()); |
4952 | + CDBUser::Log(wMsg); |
4953 | + } |
4954 | + |
4955 | + return -1; |
4956 | +} |
4957 | + |
4958 | +int CDBUser::LoadUsers(CDBUser**& pUsers) |
4959 | +{ |
4960 | + int nUserCount = GetUserCount(); |
4961 | + if(nUserCount <= 0) |
4962 | + return 0; |
4963 | + |
4964 | + pUsers = new CDBUser * [nUserCount]; |
4965 | + |
4966 | + try |
4967 | + { |
4968 | + CppSQLite3DB db; |
4969 | + db.Open(m_sDB); |
4970 | + |
4971 | + if(!db.tableExists(_T("users"))) |
4972 | + return 0; |
4973 | + |
4974 | + CppSQLite3Query q = db.execQuery(_T("select * from users where nDeleted = 0;")); |
4975 | + |
4976 | + int i = 0; |
4977 | + |
4978 | + while(!q.eof()) |
4979 | + { |
4980 | + CDBUser* pUser = new CDBUser; |
4981 | + |
4982 | + pUser->SetID(q.getIntField(0)); |
4983 | + |
4984 | + CConverter wUsername(q.fieldValue(1)); |
4985 | + pUser->SetUsername(wUsername); |
4986 | + |
4987 | + CConverter wPassword(q.fieldValue(2)); |
4988 | + pUser->SetPassword(wPassword); |
4989 | + |
4990 | + CConverter wEmail(q.fieldValue(3)); |
4991 | + pUser->SetEmail(wEmail); |
4992 | + |
4993 | + CConverter wFullName(q.fieldValue(4)); |
4994 | + pUser->SetFullName(wFullName); |
4995 | + |
4996 | + pUsers[i++] = pUser; |
4997 | + |
4998 | + q.nextRow(); |
4999 | + } |
5000 | + |
The diff has been truncated for viewing.