00001 /* 00002 !concept {:name => "Multipart HTTP posting (Qt)", 00003 :desc => "Multipart HTTP(S) POSTing using the QtNetwork API."} 00004 */ 00005 00006 #include "up_uploader_qt_private.hpp" 00007 00008 #include "cf_query.h" 00009 #include "er_errors.h" 00010 #include "ld_log_db.h" 00011 #include "up_private.h" 00012 #include "ut_exceptions.hpp" 00013 #include "utils_cl2.h" 00014 00015 #include "moment_parser.h" 00016 00017 #include "common/assertions.h" 00018 #include "common/error_list.h" 00019 #include "common/gx_exception.hpp" 00020 #include "common/logging_qt.hpp" 00021 #include "common/logging-time.h" 00022 #include "common/platform_error.h" 00023 00024 #include <errno.h> 00025 #include <stdlib.h> 00026 #include <stdio.h> 00027 00028 #include <QNetworkConfiguration> 00029 #include <QNetworkConfigurationManager> 00030 00031 #include <QtDebug> 00032 00033 #if defined(__SYMBIAN32__) 00034 #include "epoc-iap.h" 00035 #include "common/epoc-time.h" 00036 #endif /* __SYMBIAN32__ */ 00037 00038 // -------------------------------------------------- 00039 // CUploader 00040 // -------------------------------------------------- 00041 00042 static time_t TimeNow() 00043 { 00044 time_t now = time(NULL); 00045 if (now == -1) 00046 er_log_errno(er_FATAL, "time(NULL) failed"); 00047 return now; 00048 } 00049 00050 static void DataChanged(bb_Blackboard* bb, enum bb_DataType dt, 00051 gpointer data, int len, gpointer arg) 00052 { 00053 (void)dt; 00054 (void)len; 00055 CUploader* self = (CUploader*)arg; 00056 bb_Board* bd = bb_Blackboard_board(bb); 00057 bool val = bd->uploads_allowed; 00058 self->Set_uploads_allowed(val); 00059 } 00060 00061 void CUploader::Set_uploads_allowed(bool val) 00062 { 00063 i_uploads_allowed = val; 00064 StateChanged(); 00065 } 00066 00067 void CUploader::BbRegisterL() 00068 { 00069 // Initial value (internal). 00070 bb_Blackboard* bb = ac_global_Blackboard; 00071 bb_Board* bd = bb_Blackboard_board(bb); 00072 i_uploads_allowed = bd->uploads_allowed; 00073 00074 // Closure init. 00075 iClosure.changed = DataChanged; 00076 iClosure.arg = this; 00077 00078 // Registration proper. 00079 if (!bb_Blackboard_register(bb, 00080 bb_dt_uploads_allowed, 00081 iClosure, NULL)) 00082 throw std::bad_alloc(); 00083 } 00084 00085 void CUploader::BbUnregister() 00086 { 00087 bb_Blackboard_unregister(ac_global_Blackboard, iClosure); 00088 } 00089 00090 // The effect is not immediate. Will only take effect when the next 00091 // poster is created. 00092 // 00093 // We do logging here to make it possible to find out if the setting 00094 // change succeeded. 00095 void CUploader::RefreshIap(bool aNotInitial) 00096 { 00097 #if defined(__SYMBIAN32__) 00098 // TUint32 coercion hopefully okay. 00099 iIapId = (TUint32)get_config_iap_id(); 00100 if (aNotInitial) 00101 log_db_log_status(GetLogDb(), NULL, "Uploader IAP changed to %d", iIapId); 00102 #endif /* __SYMBIAN32__ */ 00103 } 00104 00105 void CUploader::RefreshSnapshotTimeExpr(bool aNotInitial) 00106 { 00107 GError* localError = NULL; 00108 gchar* newOne = NULL; 00109 if (!get_ConfigDb_str("uploader.time_expr", 00110 &newOne, __UPLOAD_TIME_EXPR__, 00111 &localError)) { 00112 if (aNotInitial) 00113 gx_dblog_error_free_check(GetLogDb(), localError, NULL); 00114 else 00115 gx_error_free(localError); 00116 } else { 00117 assert(newOne != NULL); 00118 g_free(iSnapshotTimeExpr); 00119 iSnapshotTimeExpr = newOne; 00120 logt("got time expression"); 00121 logt(iSnapshotTimeExpr); 00122 if (aNotInitial) { 00123 log_db_log_status(GetLogDb(), NULL, "Upload time expression set to '%s'", 00124 newOne); 00125 00126 // We may need to recompute the next snapshot time based on the 00127 // new expression. But if a previosly set time has already 00128 // passed, then that is not affected by the expression change. 00129 // What is past is past. 00130 { 00131 if (iSnapshotTimerAo.isActive()) 00132 iSnapshotTimerAo.stop(); 00133 iNoNextSnapshotTime = false; 00134 StateChanged(); 00135 } 00136 } 00137 } 00138 } 00139 00140 static const char* KBoundary = "-----AaB03xeql7dsxeql7ds"; 00141 00142 CUploader::CUploader(ac_AppContext* aAppContext) : 00143 iAppContext(aAppContext), iNoConfig(false), 00144 iNoOldFiles(false), 00145 iNumPostFailures(0), 00146 iPostSession(NULL), iFileToPost(NULL), 00147 iSnapshotTimePassed(false), iSnapshotTimeExpr(NULL), 00148 iNoNextSnapshotTime(false) 00149 { 00150 // Ensure that uploads directory exists. 00151 GError* mdError = NULL; 00152 if (!mkdir_p(LOG_UPLOADS_DIR, &mdError)) { 00153 er_log_gerror(er_FATAL|er_FREE, mdError, 00154 "failure creating uploads directory"); 00155 } 00156 00157 const gchar* upload_url = ac_STATIC_GET(upload_url); 00158 if (!upload_url) { 00159 iNoConfig = true; 00160 logt("uploads disabled: no upload URL"); 00161 } else { 00162 logg("upload URL: %s", upload_url); 00163 iNetworkRequest.setUrl(QUrl(upload_url)); 00164 QByteArray ct("multipart/form-data, boundary="); 00165 ct.append(KBoundary); 00166 iNetworkRequest.setHeader(QNetworkRequest::ContentTypeHeader, ct); 00167 iNetworkRequest.setRawHeader("Connection", "close"); 00168 00169 // On Symbian we currently assume that CA public certs are 00170 // installed system wide. 00171 #if !defined(__SYMBIAN32__) 00172 iSslConfiguration = QSslConfiguration::defaultConfiguration(); 00173 QList<QSslCertificate> caList = iSslConfiguration.caCertificates(); 00174 QList<QSslCertificate> myList = QSslCertificate::fromPath("etc/ca-certs/*.crt", QSsl::Pem, QRegExp::Wildcard); 00175 caList.append(myList); 00176 #if 1 00177 foreach (const QSslCertificate& cert, myList) { 00178 qxDebug() << cert.issuerInfo(QSslCertificate::Organization); 00179 } 00180 #endif 00181 #if 1 00182 // This should make server authentication succeed, but it does not, due to Qt bug http://bugreports.qt.nokia.com/browse/QTBUG-13684. See ./src/network/ssl/qsslerror.cpp. It is wrong to say that our "root CA certificate is not trusted for this purpose" as it is a CA certificate that we have specified as such. 00183 iSslConfiguration.setCaCertificates(caList); 00184 iNetworkRequest.setSslConfiguration(iSslConfiguration); 00185 #else 00186 // So let us try this global setting instead. Of course we do not want to do this more than once as it is a global setting. But no, this does not work either. 00187 QList<QSslCertificate> curList = QSslSocket::defaultCaCertificates(); 00188 foreach (const QSslCertificate& cert, myList) { 00189 if (!curList.contains(cert)) { 00190 qxDebug() << "globally adding CA" << cert.issuerInfo(QSslCertificate::Organization); 00191 QSslSocket::addDefaultCaCertificates(myList); 00192 } 00193 } 00194 #endif 00195 #endif /* not __SYMBIAN32__ */ 00196 } 00197 00198 RefreshIap(false); 00199 #if defined(__SYMBIAN32__) 00200 logg("uploader using IAP %d", iIapId); 00201 #endif /* __SYMBIAN32__ */ 00202 00203 //qxDebug() << "testing qxDebug"; 00204 #if defined(__SYMBIAN32__) 00205 // Beware of naming clashes, as both Mobility and Qt Network have these classes. 00206 // Requires Qt 4.7, unless using the Mobility version. 00207 // http://doc.qt.nokia.com/qtmobility-1.1.0-beta/bearer-management.html 00208 QNetworkConfigurationManager mgr; 00209 QList<QNetworkConfiguration> cfgList = mgr.allConfigurations(); 00210 // We want to print out the list of configurations. Perhaps we can 00211 // select one by platform specific ID, which we already have. It 00212 // seems that currently on Symbian^3 we get no configurations even if 00213 // IAP entries do exist. 00214 logt("network config list begin"); 00215 foreach (const QNetworkConfiguration& cfg, cfgList) { 00216 logt("config entry:"); 00217 qxDebug() << cfg.identifier() << cfg.name() << cfg.bearerTypeName(); 00218 } 00219 logt("network config list end"); 00220 //iNetworkAccessManager.setConfiguration(cfg); 00221 #endif /* __SYMBIAN32__ */ 00222 00223 iPostTimerAo.setSingleShot(true); 00224 connect(&iPostTimerAo, SIGNAL(timeout()), 00225 this, SLOT(handlePosterTimerEvent())); 00226 connect(&iSnapshotTimerAo, SIGNAL(timeout()), 00227 this, SLOT(handleSnapshotTimerEvent())); 00228 00229 RefreshSnapshotTimeExpr(false); 00230 iSnapshotTimeCtx = TimeNow(); 00231 //logg("using snapshot time '%s'", iSnapshotTimeExpr); 00232 00233 // Note that if this ConstructL() leaves, the dtor of this will 00234 // unregister us. xxx 00235 BbRegisterL(); 00236 00237 StateChangedL(); 00238 } 00239 00240 CUploader::~CUploader() 00241 { 00242 BbUnregister(); 00243 DestroyPosterAo(); 00244 g_free(iSnapshotTimeExpr); // safe when NULL 00245 } 00246 00247 void CUploader::Inactivate() 00248 { 00249 DestroyPosterAo(); 00250 if (iSnapshotTimerAo.isActive()) 00251 iSnapshotTimerAo.stop(); 00252 if (iPostTimerAo.isActive()) 00253 iPostTimerAo.stop(); 00254 } 00255 00256 void CUploader::FatalError(const std::exception &ex) 00257 { 00258 Inactivate(); 00259 er_log_none(er_FATAL, "error in uploader: %s", ex.what()); 00260 } 00261 00262 #define CATCH_FATAL(_act) \ 00263 try { \ 00264 _act ; \ 00265 } catch (const std::exception &_ex) { \ 00266 FatalError(_ex); \ 00267 } 00268 00269 void CUploader::StateChanged() 00270 { 00271 CATCH_FATAL(StateChangedL()); 00272 } 00273 00274 struct ScopedPointerGfree 00275 { 00276 static inline void cleanup(gchar* pointer) 00277 { 00278 g_free(pointer); 00279 } 00280 }; 00281 00282 void CUploader::NextOldFileL() 00283 { 00284 if (iNoOldFiles) return; 00285 00286 DELETE_Z(iFileToPost); 00287 00288 GError* error = NULL; 00289 gchar* pathname = NULL; 00290 if (getNextOldLogFile(&pathname, &error)) { 00291 if (pathname) { 00292 dblogg("found old log file '%s'", pathname); 00293 QScopedPointer<gchar, ScopedPointerGfree> pn(pathname); 00294 QString qs = QString::fromUtf8(pathname); 00295 //qDebug() << qs; 00296 iFileToPost = q_check_ptr(new QFile(qs)); 00297 //qDebug() << (iFileToPost->fileName().toLocal8Bit()); 00298 return; 00299 } else { 00300 iNoOldFiles = true; 00301 dblogt("no more old files to upload"); 00302 } 00303 } else { 00304 er_log_gerror(er_FATAL|er_FREE, error, "getting next log file"); 00305 } 00306 } 00307 00308 // External API. 00309 void CUploader::RequestSnapshot() 00310 { 00311 iSnapshotTimePassed = true; 00312 if (iSnapshotTimerAo.isActive()) 00313 iSnapshotTimerAo.stop(); 00314 StateChanged(); 00315 } 00316 00317 // Computes next snapshot time (if any), and sets a timer for it as 00318 // appropriate. 00319 void CUploader::SetSnapshotTimerL() 00320 { 00321 assert(!iSnapshotTimePassed); 00322 if (iSnapshotTimerAo.isActive()) 00323 iSnapshotTimerAo.stop(); 00324 if (iNoNextSnapshotTime) 00325 return; // flag to avoid needless computation 00326 time_t now = TimeNow(); 00327 time_t ctx = iSnapshotTimeCtx; 00328 time_t snaptime; 00329 GError* parseError = NULL; 00330 if (!parse_moment(iSnapshotTimeExpr, ctx, now, &snaptime, &parseError)) { 00331 gx_dblog_error_free(GetLogDb(), parseError); 00332 iNoNextSnapshotTime = true; 00333 return; 00334 } 00335 if (!snaptime) { 00336 dblogt("no snapshot time upcoming"); 00337 iNoNextSnapshotTime = true; 00338 return; 00339 } 00340 logt("next snapshot time computed"); 00341 log_time(snaptime); 00342 00343 QDateTime atTime; 00344 atTime.setTime_t(snaptime); 00345 atTime = atTime.toUTC(); 00346 #if __DO_LOGGING__ 00347 int diffTime = snaptime - now; 00348 logg("snapshot %d secs from now", diffTime); 00349 qxDebug() << "snapshot time at" << atTime << " UTC"; 00350 #endif 00351 iSnapshotTimerAo.start(atTime); 00352 } 00353 00354 static int SecsToMsecs(int secs) 00355 { 00356 long long ms64 = (long long)(secs) * 1000LL; 00357 if (ms64 > 0x7fffffffLL) ms64 = 0x7fffffffLL; 00358 return (int)ms64; 00359 } 00360 00361 void CUploader::SetPostTimer() 00362 { 00363 assert(iNumPostFailures > 0); 00364 00365 if (iPostTimerAo.isActive()) 00366 iPostTimerAo.stop(); 00367 00368 // Roughly num_failures * 5 mins. 00369 int secs = 5 * 60 * iNumPostFailures + (rand() % 60); 00370 int interval = SecsToMsecs(secs); 00371 dblogg("retrying upload in %d secs / %d msecs", secs, interval); 00372 00373 iPostTimerAo.start(interval); 00374 } 00375 00376 // Make sure this method does not leave. 00377 void CUploader::handlePosterTimerEvent() 00378 { 00379 logt("posting timer event"); 00380 StateChanged(); 00381 } 00382 00383 // Make sure this method does not leave. 00384 void CUploader::handleSnapshotTimerEvent() 00385 { 00386 logt("snapshot timer event"); 00387 iSnapshotTimePassed = true; 00388 StateChanged(); 00389 } 00390 00391 bool CUploader::PosterAoIsActive() 00392 { 00393 return iPostSession && 00394 iPostSession->iNetworkReply && 00395 iPostSession->iNetworkReply->isRunning(); 00396 } 00397 00398 void CUploader::postingSslErrors(const QList<QSslError> & errors) 00399 { 00400 #if 1 00401 foreach (const QSslError& err, errors) { 00402 const QSslCertificate& cert = err.certificate(); 00403 qxDebug() << err.errorString() << (int)err.error() << cert.issuerInfo(QSslCertificate::Organization); 00404 } 00405 #endif 00406 // We do want security, and hence do not make any exceptions here. A 00407 // self-signed CA is only okay if we have a locally registered copy. 00408 // For now we only do a bug workaround here. Essentially, we want 00409 // all CA certificates to be accepted as such, and accept no errors 00410 // regarding any of them. Even this workaround only works if the 00411 // server can give us the CA cert, as only then will the comparison 00412 // succeed. 00413 #if !defined(__SYMBIAN32__) && (QT_VERSION <= 0x040701) 00414 { 00415 QList<QSslCertificate> caList = iSslConfiguration.caCertificates(); 00416 int trueErrors = 0; 00417 //qxDebug() << "ca" << caList.last(); 00418 foreach (const QSslError& err, errors) { 00419 const QSslCertificate& cert = err.certificate(); 00420 //qxDebug() << "cert" << cert; 00421 //qxDebug() << "equal" << (caList.last() == cert); 00422 if (!caList.contains(cert)) { 00423 trueErrors++; 00424 } else { 00425 qxDebug() << "cert is a CA cert, ignoring errors regarding it:" << 00426 cert; 00427 } 00428 } 00429 if (!trueErrors) { 00430 logt("ignoring all SSL errors"); 00431 iPostSession->iNetworkReply->ignoreSslErrors(); 00432 } 00433 } 00434 #endif /* __SYMBIAN32__ */ 00435 } 00436 00437 void CUploader::postingFinished() 00438 { 00439 QNetworkReply::NetworkError errCode = iPostSession->iNetworkReply->error(); 00440 dblogg("poster finished with %d", errCode); 00441 00442 // Cannot delete while still open. 00443 iFileToPost->close(); 00444 00445 iPostSession->iFileToPost = NULL; 00446 iPostSession->deleteLater(); 00447 iPostSession = NULL; 00448 00449 switch (errCode) 00450 { 00451 //// success 00452 case QNetworkReply::NoError: 00453 { 00454 GError* localError = NULL; 00455 QByteArray ba = (iFileToPost->fileName().toLocal8Bit()); 00456 const char* pathname = ba.data(); 00457 if (!rm_file(pathname, &localError)) { 00458 FatalError(GException(localError)); 00459 } else { 00460 log_db_log_status(GetLogDb(), NULL, "posted log file '%s'", pathname); 00461 iNumPostFailures = 0; 00462 DELETE_Z(iFileToPost); 00463 00464 { 00465 time_t t = TimeNow(); 00466 ac_global_Registry->last_upload_time = t; 00467 } 00468 00469 StateChanged(); 00470 } 00471 break; 00472 } 00473 //// aborted (do we ever get these signals) 00474 case QNetworkReply::OperationCanceledError: 00475 { 00476 logt("upload operation cancelled event"); 00477 break; 00478 } 00479 //// transient failure 00480 case QNetworkReply::ConnectionRefusedError: 00481 case QNetworkReply::RemoteHostClosedError: 00482 case QNetworkReply::HostNotFoundError: 00483 case QNetworkReply::TimeoutError: 00484 case QNetworkReply::SslHandshakeFailedError: 00485 case QNetworkReply::TemporaryNetworkFailureError: 00486 case QNetworkReply::ProxyConnectionRefusedError: 00487 case QNetworkReply::ProxyConnectionClosedError: 00488 case QNetworkReply::ProxyNotFoundError: 00489 case QNetworkReply::ProxyTimeoutError: 00490 case QNetworkReply::ProxyAuthenticationRequiredError: 00491 case QNetworkReply::ContentAccessDenied: 00492 case QNetworkReply::ContentOperationNotPermittedError: 00493 case QNetworkReply::ContentNotFoundError: 00494 case QNetworkReply::ContentReSendError: 00495 case QNetworkReply::ProtocolUnknownError: 00496 case QNetworkReply::ProtocolInvalidOperationError: 00497 case QNetworkReply::UnknownNetworkError: 00498 case QNetworkReply::UnknownProxyError: 00499 case QNetworkReply::UnknownContentError: 00500 case QNetworkReply::ProtocolFailure: 00501 { 00502 // Retry later. 00503 logg("upload failure %d, retrying later", errCode); 00504 iNumPostFailures++; 00505 SetPostTimer(); 00506 break; 00507 } 00508 //// permanent failure 00509 case QNetworkReply::AuthenticationRequiredError: 00510 { 00511 // We must be doing something wrong. Better stop altogether, 00512 // barring external intervention. 00513 er_log_none(0, "inactivating uploader due to a permanent posting failure (%d)", errCode); 00514 Inactivate(); 00515 break; 00516 } 00517 //// unknown failure 00518 default: 00519 { 00520 logg("unknown upload failure %d, retrying later", errCode); 00521 iNumPostFailures++; 00522 SetPostTimer(); 00523 break; 00524 } 00525 } 00526 } 00527 00528 PostSession::PostSession() : 00529 iNetworkReply(NULL), iFileToPost(NULL), 00530 iPrologue(NULL), iEpilogue(NULL), 00531 iPostData(NULL) 00532 { 00533 } 00534 00535 PostSession::~PostSession() 00536 { 00537 //logh(); 00538 if (iNetworkReply) { 00539 iNetworkReply->abort(); 00540 DELETE_Z(iNetworkReply); 00541 } 00542 DELETE_Z(iPostData); 00543 iPostElems.clear(); 00544 if (iFileToPost) { 00545 iFileToPost->close(); 00546 } 00547 DELETE_Z(iPrologue); 00548 DELETE_Z(iEpilogue); 00549 } 00550 00551 void CUploader::DestroyPosterAo() 00552 { 00553 DELETE_Z(iPostSession); 00554 } 00555 00556 void CUploader::CreatePosterAoL() 00557 { 00558 assert(!iPostSession); 00559 assert(iFileToPost); 00560 00561 QByteArray ba = (iFileToPost->fileName().toLocal8Bit()); 00562 const char* pathname = ba.data(); 00563 dblogg("asking poster to post '%s'", pathname); 00564 00565 iPostSession = q_check_ptr(new PostSession()); 00566 00567 iPostSession->iFileToPost = iFileToPost; 00568 00569 iPostSession->iPrologue = q_check_ptr(new QBuffer()); 00570 iPostSession->iEpilogue = q_check_ptr(new QBuffer()); 00571 00572 const gchar* username = get_config_username(); 00573 logg("uploader using username '%s'", username); 00574 00575 static const char* KSep = "--"; 00576 static const char* KCrLf = "\r\n"; 00577 00578 QByteArray& prologue = iPostSession->iPrologue->buffer(); 00579 prologue.append(KSep); 00580 prologue.append(KBoundary); 00581 prologue.append(KCrLf); 00582 prologue.append("Content-Disposition: form-data; name=\"logdata\"; filename=\""); 00583 prologue.append(username); 00584 prologue.append(".db\"\r\nContent-Type: application/octet-stream\r\nContent-Transfer-Encoding: binary\r\n\r\n"); 00585 00586 QByteArray& epilogue = iPostSession->iEpilogue->buffer(); 00587 epilogue.append(KCrLf); 00588 epilogue.append(KSep); 00589 epilogue.append(KBoundary); 00590 epilogue.append(KCrLf); 00591 epilogue.append("Content-Disposition: form-data; name=\"logdata_submit\"\r\n\r\nUpload\r\n"); 00592 epilogue.append(KSep); 00593 epilogue.append(KBoundary); 00594 epilogue.append(KSep); 00595 epilogue.append(KCrLf); 00596 00597 if (!iFileToPost->open(QIODevice::ReadOnly)) { 00598 int errCode = (iFileToPost->error()); 00599 gx_throw(gx_error_new(domain_qt, errCode, 00600 "failed to open file '%s': QFile::FileError %d", 00601 pathname, errCode)); 00602 } 00603 00604 #define CHECKBUFOPEN(x) throw_cstr_unless(x, "QBuffer open failed") 00605 CHECKBUFOPEN(iPostSession->iPrologue->open(QIODevice::ReadOnly)); 00606 CHECKBUFOPEN(iPostSession->iEpilogue->open(QIODevice::ReadOnly)); 00607 00608 iPostSession->iPostElems.append(iPostSession->iPrologue); 00609 iPostSession->iPostElems.append(iPostSession->iFileToPost); 00610 iPostSession->iPostElems.append(iPostSession->iEpilogue); 00611 00612 iPostSession->iPostData = q_check_ptr(new QIODeviceSeq(iPostSession->iPostElems)); 00613 00614 // Note that the file object (or the file) may not be deleted until 00615 // we get the finished() signal for this reply. 00616 iPostSession->iNetworkReply = 00617 iNetworkAccessManager.post(iNetworkRequest, iPostSession->iPostData); 00618 00619 connect(iPostSession->iNetworkReply, SIGNAL(sslErrors(const QList<QSslError> &)), 00620 this, SLOT(postingSslErrors(const QList<QSslError> &))); 00621 connect(iPostSession->iNetworkReply, SIGNAL(finished()), 00622 this, SLOT(postingFinished())); 00623 } 00624 00625 void CUploader::PostNowL() 00626 { 00627 CreatePosterAoL(); 00628 } 00629 00630 void CUploader::TakeSnapshotNowL() 00631 { 00632 dblogt("taking snapshot now"); 00633 00634 // LOG_UPLOADS_DIR and LOGDB_DIR must be on the same device to allow 00635 // for renaming rather than copying. 00636 char* pathname = tempnam(LOG_UPLOADS_DIR, "log_"); // caller must free 'pathname' 00637 if (!pathname) { 00638 er_log_errno(er_FATAL, "failure in tempnam"); 00639 } 00640 00641 gboolean wasRenamed = FALSE; 00642 GError* snapError = NULL; 00643 if (!log_db_take_snapshot(GetLogDb(), pathname, &wasRenamed, &snapError)) { 00644 logg("failure taking snapshot to file '%s'", pathname); 00645 free(pathname); 00646 logg("snapshot file was%s created", wasRenamed ? "" : " not"); 00647 er_log_gerror(er_FATAL|er_FREE, snapError, "taking snapshot"); 00648 } 00649 00650 log_db_log_status(GetLogDb(), NULL, "snapshot taken as '%s'", pathname); 00651 00652 assert(!iFileToPost); 00653 iFileToPost = q_check_ptr(new QFile(QString::fromUtf8(pathname))); 00654 iSnapshotTimePassed = false; 00655 StateChangedL(); 00656 } 00657 00658 // Better by careful not to run out of stack calling this recursively. 00659 // Can always use an "ImmediateAo" if necessary to avoid such a risk. 00660 void CUploader::StateChangedL() 00661 { 00662 if (iNoConfig) 00663 return; 00664 00665 if (!iSnapshotTimePassed && 00666 !iNoNextSnapshotTime && 00667 !iSnapshotTimerAo.isActive()) { 00668 SetSnapshotTimerL(); 00669 } 00670 00671 if (!PosterAoIsActive()) 00672 DestroyPosterAo(); // make sure no connection remains 00673 00674 again: 00675 if (iFileToPost) { 00676 if (PosterAoIsActive() || iPostTimerAo.isActive()) 00677 return; 00678 if (i_uploads_allowed) { 00679 PostNowL(); // not called elsewhere 00680 } 00681 } else if (!iNoOldFiles) { 00682 NextOldFileL(); 00683 goto again; 00684 } else if (iSnapshotTimePassed) { 00685 TakeSnapshotNowL(); // not called elsewhere 00686 } 00687 } 00688 00689 // -------------------------------------------------- 00690 // global system state 00691 // -------------------------------------------------- 00692 00693 EXTERN_C gboolean up_global_init(GError** error) 00694 { 00695 // Nothing to do. 00696 return TRUE; 00697 } 00698 00699 EXTERN_C void up_global_cleanup() 00700 { 00701 // Nothing to do. 00702 } 00703 00704 // -------------------------------------------------- 00705 // API 00706 // -------------------------------------------------- 00707 00708 EXTERN_C gboolean up_Uploader_upload_now(up_Uploader* object, GError** error) 00709 { 00710 ((CUploader*)object)->RequestSnapshot(); 00711 return TRUE; 00712 } 00713 00714 EXTERN_C gboolean up_Uploader_reconfigure(up_Uploader* object, 00715 const gchar* key, 00716 const gchar* value, 00717 GError** error) 00718 { 00719 if (strcmp(key, "iap") == 0) { 00720 ((CUploader*)object)->RefreshIap(true); 00721 } else if (strcmp(key, "uploader.time_expr") == 0) { 00722 ((CUploader*)object)->RefreshSnapshotTimeExpr(true); 00723 } 00724 return TRUE; 00725 } 00726 00727 EXTERN_C up_Uploader* up_Uploader_new(ac_AppContext* aAppContext, GError** error) 00728 { 00729 CUploader* object = NULL; 00730 try { 00731 object = q_check_ptr(new CUploader(aAppContext)); 00732 } catch (const std::exception &ex) { 00733 if (error) 00734 *error = gx_error_new(domain_qt, -1, "Uploader init failure: %s", ex.what()); 00735 return NULL; 00736 } 00737 return (up_Uploader*)object; 00738 } 00739 00740 EXTERN_C void up_Uploader_destroy(up_Uploader* object) 00741 { 00742 delete ((CUploader*)object); 00743 } 00744 00745 /** 00746 00747 Copyright 2009 Helsinki Institute for Information Technology (HIIT) 00748 and the authors. All rights reserved. 00749 00750 Authors: Tero Hasu <tero.hasu@hut.fi> 00751 00752 Permission is hereby granted, free of charge, to any person 00753 obtaining a copy of this software and associated documentation files 00754 (the "Software"), to deal in the Software without restriction, 00755 including without limitation the rights to use, copy, modify, merge, 00756 publish, distribute, sublicense, and/or sell copies of the Software, 00757 and to permit persons to whom the Software is furnished to do so, 00758 subject to the following conditions: 00759 00760 The above copyright notice and this permission notice shall be 00761 included in all copies or substantial portions of the Software. 00762 00763 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 00764 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 00765 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 00766 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 00767 BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 00768 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 00769 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 00770 SOFTWARE. 00771 00772 **/
ContextLogger2—ContextLogger2 Logger Daemon Internals—Generated on Mon May 2 13:49:57 2011 by Doxygen 1.6.1