Drizzled Public API Documentation

CSException.cc
00001 /* Copyright (C) 2008 PrimeBase Technologies GmbH, Germany
00002  *
00003  * PrimeBase Media Stream for MySQL
00004  *
00005  * This program is free software; you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License as published by
00007  * the Free Software Foundation; either version 2 of the License, or
00008  * (at your option) any later version.
00009  *
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program; if not, write to the Free Software
00017  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
00018  *
00019  * Original author: Paul McCullagh (H&G2JCtL)
00020  * Continued development: Barry Leslie
00021  *
00022  * 2007-05-20
00023  *
00024  * The main exception classes
00025  *
00026  */
00027 
00028 #include "CSConfig.h"
00029 
00030 #ifdef OS_WINDOWS
00031 #define strsignal(s) NULL
00032 #else
00033 #include <sys/signal.h>
00034 #endif
00035 
00036 #include <limits.h>
00037 #include <string.h>
00038 
00039 #include "CSGlobal.h"
00040 #include "CSException.h"
00041 #include "CSStrUtil.h"
00042 #include "CSLog.h"
00043 
00044 void CSException::setStackTrace(CSThread *self, const char *stack)
00045 {
00046   char buffer[CS_EXC_CONTEXT_SIZE];
00047 
00048   self->myException.iStackTrace.setLength(0);
00049   if (stack)
00050     self->myException.iStackTrace.append(stack);
00051   for (int i=self->callTop-1; i>=0; i--) {
00052     cs_format_context(CS_EXC_CONTEXT_SIZE, buffer,
00053       self->callStack[i].cs_func, self->callStack[i].cs_file, self->callStack[i].cs_line);
00054     self->myException.iStackTrace.append(buffer);
00055     self->myException.iStackTrace.append('\n');
00056   }
00057 }
00058 
00059 void CSException::setStackTrace(CSThread *self)
00060 {
00061   setStackTrace(self, NULL);
00062 }
00063 
00064 const char *CSException::getStackTrace()
00065 {
00066   return iStackTrace.getCString();
00067 }
00068 
00069 void CSException::log(CSThread *self)
00070 {
00071   CSL.lock();
00072   CSL.log(self, CSLog::Error, getContext());
00073   CSL.log(self, CSLog::Error, " ");
00074   CSL.log(self, CSLog::Error, getMessage());
00075   CSL.eol(self, CSLog::Error);
00076 #ifdef DUMP_STACK_TRACE
00077   CSL.log(self, CSLog::Error, getStackTrace());
00078 #endif
00079   CSL.unlock();
00080 }
00081 
00082 void CSException::log(CSThread *self, const char *message)
00083 {
00084   CSL.lock();
00085   CSL.log(self, CSLog::Error, message);
00086   CSL.eol(self, CSLog::Error);
00087   CSL.log(self, CSLog::Error, getContext());
00088   CSL.log(self, CSLog::Error, " ");
00089   CSL.log(self, CSLog::Error, getMessage());
00090   CSL.eol(self, CSLog::Error);
00091 #ifdef DUMP_STACK_TRACE
00092   CSL.log(self, CSLog::Error, getStackTrace());
00093 #endif
00094   CSL.unlock();
00095 }
00096 
00097 void CSException::initException_va(const char *func, const char *file, int line, int err, const char *fmt, va_list ap)
00098 {
00099 
00100   cs_format_context(CS_EXC_CONTEXT_SIZE, iContext, func, file, line);
00101   iErrorCode = err;
00102 #ifdef OS_WINDOWS
00103   vsprintf(iMessage, fmt, ap);
00104 #else
00105   size_t len;
00106   len = vsnprintf(iMessage, CS_EXC_MESSAGE_SIZE-1, fmt, ap);
00107   if (len > CS_EXC_MESSAGE_SIZE-1)
00108     len = CS_EXC_MESSAGE_SIZE-1;
00109   iMessage[len] = 0;
00110 #endif
00111 }
00112 
00113 void CSException::initExceptionf(const char *func, const char *file, int line, int err, const char *fmt, ...)
00114 {
00115   va_list ap;
00116 
00117   va_start(ap, fmt);
00118   initException_va(func, file, line, err, fmt, ap);
00119   va_end(ap);
00120 }
00121 
00122 void CSException::initException(const char *func, const char *file, int line, int err, const char *message)
00123 {
00124   cs_format_context(CS_EXC_CONTEXT_SIZE, iContext, func, file, line);
00125   iErrorCode = err;
00126   cs_strcpy(CS_EXC_MESSAGE_SIZE, iMessage, message);
00127 }
00128 
00129 void CSException::initException(CSException &exception)
00130 {
00131   iErrorCode = exception.iErrorCode;
00132   strcpy(iContext, exception.iContext);
00133   strcpy(iMessage, exception.iMessage);
00134   
00135   iStackTrace.setLength(0);
00136   iStackTrace.append(exception.iStackTrace.getCString());
00137 
00138 }
00139 
00140 void CSException::initAssertion(const char *func, const char *file, int line, const char *message)
00141 {
00142   cs_format_context(CS_EXC_CONTEXT_SIZE, iContext, func, file, line);
00143   iErrorCode = CS_ERR_ASSERTION;
00144   cs_strcpy(CS_EXC_MESSAGE_SIZE, iMessage, "Assertion failed: ");
00145   cs_strcat(CS_EXC_MESSAGE_SIZE, iMessage, message);
00146 }
00147 
00148 void CSException::getCoreError(uint32_t size, char *buffer, int err)
00149 {
00150   const char *message = NULL;
00151 
00152   switch (err) {
00153     case CS_ERR_JUMP_OVERFLOW: message = "Jump stack overflow"; break;
00154     case CS_ERR_BAD_ADDRESS: message = "Incorrect network address: %"; break;
00155     case CS_ERR_UNKNOWN_SERVICE: message = "Unknown network service: %"; break;
00156     case CS_ERR_UNKNOWN_HOST:  message = "Unknown host: %"; break;
00157     case CS_ERR_UNKNOWN_METHOD: message = "Unknown HTTP method: %"; break;
00158     case CS_ERR_NO_LISTENER: message = "Listening port has been closed"; break;
00159     case CS_ERR_RELEASE_OVERFLOW: message = "Release stack overflow"; break;
00160     case CS_ERR_IMPL_MISSING: message = "Function %s not implemented"; break;
00161     case CS_ERR_BAD_HEADER_MAGIC: message = "Incorrect file type"; break;
00162     case CS_ERR_VERSION_TOO_NEW: message = "Incompatible file version"; break;
00163   }
00164   if (message)
00165     cs_strcpy(size, buffer, message);
00166   else {
00167     cs_strcpy(size, buffer, "Unknown system error ");
00168     cs_strcat(size, buffer, err);
00169   }
00170 }
00171 
00172 void CSException::initCoreError(const char *func, const char *file, int line, int err)
00173 {
00174   cs_format_context(CS_EXC_CONTEXT_SIZE, iContext, func, file, line);
00175   iErrorCode = err;
00176   getCoreError(CS_EXC_MESSAGE_SIZE, iMessage, err);
00177 }
00178 
00179 void CSException::initCoreError(const char *func, const char *file, int line, int err, const char *item)
00180 {
00181   cs_format_context(CS_EXC_CONTEXT_SIZE, iContext, func, file, line);
00182   iErrorCode = err;
00183   getCoreError(CS_EXC_MESSAGE_SIZE, iMessage, err);
00184   cs_replace_string(CS_EXC_MESSAGE_SIZE, iMessage, "%s", item);
00185 }
00186 
00187 void CSException::initOSError(const char *func, const char *file, int line, int err)
00188 {
00189   char *msg;
00190 
00191   cs_format_context(CS_EXC_CONTEXT_SIZE, iContext, func, file, line);
00192   iErrorCode = err;
00193 
00194 #ifdef XT_WIN
00195   if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, 0, iMessage, CS_EXC_MESSAGE_SIZE, NULL)) {
00196     char *ptr;
00197 
00198     ptr = &iMessage[strlen(iMessage)];
00199     while (ptr-1 > err_msg) {
00200       if (*(ptr-1) != '\n' && *(ptr-1) != '\r' && *(ptr-1) != '.')
00201         break;
00202       ptr--;
00203     }
00204     *ptr = 0;
00205 
00206     cs_strcat(CS_EXC_MESSAGE_SIZE, iMessage, " (");
00207     cs_strcat(CS_EXC_MESSAGE_SIZE, iMessage, err);
00208     cs_strcat(CS_EXC_MESSAGE_SIZE, iMessage, ")");
00209     return;
00210   }
00211 #endif
00212 
00213   msg = strerror(err);
00214   if (msg) {
00215     cs_strcpy(CS_EXC_MESSAGE_SIZE, iMessage, msg);
00216     cs_strcat(CS_EXC_MESSAGE_SIZE, iMessage, " (");
00217     cs_strcat(CS_EXC_MESSAGE_SIZE, iMessage, err);
00218     cs_strcat(CS_EXC_MESSAGE_SIZE, iMessage, ")");
00219   }
00220   else {
00221     cs_strcpy(CS_EXC_MESSAGE_SIZE, iMessage, "Unknown OS error code ");
00222     cs_strcat(CS_EXC_MESSAGE_SIZE, iMessage, err);
00223   }
00224 }
00225 
00226 void CSException::initFileError(const char *func, const char *file, int line, const char *path, int err)
00227 {
00228   initOSError(func, file, line, err);
00229   cs_strcat(CS_EXC_MESSAGE_SIZE, iMessage, ": '");
00230   cs_strcat(CS_EXC_MESSAGE_SIZE, iMessage, path);
00231   cs_strcat(CS_EXC_MESSAGE_SIZE, iMessage, "'");
00232 }
00233 
00234 void CSException::initSignal(const char *func, const char *file, int line, int sig)
00235 {
00236   char *str;
00237 
00238   cs_format_context(CS_EXC_CONTEXT_SIZE, iContext, func, file, line);
00239   iErrorCode = sig;
00240   if (!(str = strsignal(sig))) {
00241     cs_strcpy(CS_EXC_MESSAGE_SIZE, iMessage, "Unknown signal ");
00242     cs_strcat(CS_EXC_MESSAGE_SIZE, iMessage, sig);
00243   }
00244   else {
00245     cs_strcpy(CS_EXC_MESSAGE_SIZE, iMessage, str);
00246     cs_strcat(CS_EXC_MESSAGE_SIZE, iMessage, " (");
00247     cs_strcat(CS_EXC_MESSAGE_SIZE, iMessage, sig);
00248     cs_strcat(CS_EXC_MESSAGE_SIZE, iMessage, ")");
00249   }
00250 }
00251 
00252 void CSException::initEOFError(const char *func, const char *file, int line, const char *path)
00253 {
00254   cs_format_context(CS_EXC_CONTEXT_SIZE, iContext, func, file, line);
00255   iErrorCode = CS_ERR_EOF;
00256   cs_strcpy(CS_EXC_MESSAGE_SIZE, iMessage, "EOF encountered: '");
00257   cs_strcat(CS_EXC_MESSAGE_SIZE, iMessage, path);
00258   cs_strcat(CS_EXC_MESSAGE_SIZE, iMessage, "'");
00259 }
00260 
00261 void CSException::RecordException(const char *func, const char *file, int line, int err, const char *message)
00262 {
00263   CSThread *self;
00264 
00265   if ((self = CSThread::getSelf())) {
00266     if (!self->myException.getErrorCode())
00267       self->myException.initException(func, file, line, err, message);
00268   }
00269 }
00270 
00271 void CSException::ClearException()
00272 {
00273   CSThread *self;
00274 
00275   if ((self = CSThread::getSelf())) {
00276     self->myException.setErrorCode(0);
00277   }
00278 }
00279 
00280 void CSException::throwException(const char *func, const char *file, int line, int err, const char *message, const char *stack)
00281 {
00282   CSThread *self;
00283 
00284   if ((self = CSThread::getSelf())) {
00285     self->myException.initException(func, file, line, err, message);
00286     self->myException.setStackTrace(self, stack);
00287     self->throwException();
00288   }
00289   else {
00290     CSException e;
00291     
00292     e.initException(func, file, line, err, message);
00293     e.log(NULL, "*** Uncaught error");
00294   }
00295 }
00296 
00297 void CSException::throwException(const char *func, const char *file, int line, int err, const char *message)
00298 {
00299   throwException(func, file, line, err, message, NULL);
00300 }
00301 
00302 void CSException::throwExceptionf(const char *func, const char *file, int line, int err, const char *fmt, ...)
00303 {
00304   CSThread  *self;
00305   va_list   ap;
00306 
00307   va_start(ap, fmt);
00308   if ((self = CSThread::getSelf())) {
00309     self->myException.initException_va(func, file, line, err, fmt, ap);
00310     va_end(ap);
00311     self->myException.setStackTrace(self, NULL);
00312     self->throwException();
00313   }
00314   else {
00315     CSException e;
00316     
00317     e.initException_va(func, file, line, err, fmt, ap);
00318     va_end(ap);
00319     e.log(NULL, "*** Uncaught error");
00320   }
00321 }
00322 
00323 void CSException::throwAssertion(const char *func, const char *file, int line, const char *message)
00324 {
00325   CSThread *self;
00326 
00327   if ((self = CSThread::getSelf())) {
00328     self->myException.initAssertion(func, file, line, message);
00329     self->myException.setStackTrace(self);
00330     /* Not sure why we log the excpetion down here?!
00331     self->logException();
00332     */
00333     self->throwException();
00334   }
00335   else {
00336     CSException e;
00337     
00338     e.initAssertion(func, file, line, message);
00339     e.log(NULL, "*** Uncaught error");
00340   }
00341 }
00342 
00343 void CSException::throwCoreError(const char *func, const char *file, int line, int err)
00344 {
00345   CSThread *self;
00346 
00347   if ((self = CSThread::getSelf())) {
00348     self->myException.initCoreError(func, file, line, err);
00349     self->myException.setStackTrace(self);
00350     self->throwException();
00351   }
00352   else {
00353     CSException e;
00354     
00355     e.initCoreError(func, file, line, err);
00356     e.log(NULL, "*** Uncaught error");
00357   }
00358 }
00359 
00360 void CSException::throwCoreError(const char *func, const char *file, int line, int err, const char *item)
00361 {
00362   CSThread *self;
00363 
00364   if ((self = CSThread::getSelf())) {
00365     self->myException.initCoreError(func, file, line, err, item);
00366     self->myException.setStackTrace(self);
00367     self->throwException();
00368   }
00369   else {
00370     CSException e;
00371     
00372     e.initCoreError(func, file, line, err, item);
00373     e.log(NULL, "*** Uncaught error");
00374   }
00375 }
00376 
00377 void CSException::throwOSError(const char *func, const char *file, int line, int err)
00378 {
00379   CSThread *self;
00380 
00381   if ((self = CSThread::getSelf())) {
00382     /* A pending signal has priority over a system error,
00383      * In fact, the pending signal may be the reason for
00384      * system error:
00385      */
00386     self->interrupted();
00387     self->myException.initOSError(func, file, line, err);
00388     self->myException.setStackTrace(self);
00389     self->throwException();
00390   }
00391   else {
00392     CSException e;
00393     
00394     e.initOSError(func, file, line, err);
00395     e.log(NULL, "*** Uncaught error");
00396   }
00397 }
00398 
00399 void CSException::throwFileError(const char *func, const char *file, int line, const char *path, int err)
00400 {
00401   CSThread *self;
00402 
00403   if ((self = CSThread::getSelf())) {
00404     self->interrupted();
00405     self->myException.initFileError(func, file, line, path, err);
00406     self->myException.setStackTrace(self);
00407     self->throwException();
00408   }
00409   else {
00410     CSException e;
00411     
00412     e.initFileError(func, file, line, path, err);
00413     e.log(NULL, "*** Uncaught error");
00414   }
00415 }
00416 
00417 void CSException::throwFileError(const char *func, const char *file, int line, CSString *path, int err)
00418 {
00419   CSThread *self;
00420 
00421   if ((self = CSThread::getSelf())) {
00422     self->interrupted();
00423     self->myException.initFileError(func, file, line, path->getCString(), err);
00424     self->myException.setStackTrace(self);
00425     self->throwException();
00426   }
00427   else {
00428     CSException e;
00429     
00430     e.initFileError(func, file, line, path->getCString(), err);
00431     e.log(NULL, "*** Uncaught error");
00432   }
00433 }
00434 
00435 void CSException::throwSignal(const char *func, const char *file, int line, int sig)
00436 {
00437   CSThread *self;
00438 
00439   if ((self = CSThread::getSelf())) {
00440     self->myException.initSignal(func, file, line, sig);
00441     self->myException.setStackTrace(self);
00442     self->throwException();
00443   }
00444   else {
00445     CSException e;
00446     
00447     e.initSignal(func, file, line, sig);
00448     e.log(NULL, "*** Uncaught error");
00449   }
00450 }
00451 
00452 void CSException::throwEOFError(const char *func, const char *file, int line, const char *path)
00453 {
00454   CSThread *self;
00455 
00456   if ((self = CSThread::getSelf())) {
00457     self->interrupted();
00458     self->myException.initEOFError(func, file, line, path);
00459     self->myException.setStackTrace(self);
00460     self->throwException();
00461   }
00462   else {
00463     CSException e;
00464     
00465     e.initEOFError(func, file, line, path);
00466     e.log(NULL, "*** Uncaught error");
00467   }
00468 }
00469 
00470 void CSException::throwLastError(const char *func, const char *file, int line)
00471 {
00472 #ifdef OS_WINDOWS
00473   throwOSError(func, file, line, (int) GetLastError());
00474 #else
00475   throwOSError(func, file, line, (int) errno);
00476 #endif
00477 }
00478 
00479 void CSException::logOSError(const char *func, const char *file, int line, int err)
00480 {
00481   CSThread *self;
00482 
00483   if ((self = CSThread::getSelf())) {
00484     self->myException.initOSError(func, file, line, err);
00485     self->myException.setStackTrace(self);
00486     self->logException();
00487   }
00488   else {
00489     CSException e;
00490     
00491     e.initOSError(func, file, line, err);
00492     e.log(NULL);
00493   }
00494 }
00495 
00496 void CSException::logOSError(CSThread *self, const char *func, const char *file, int line, int err)
00497 {
00498   self->myException.initOSError(func, file, line, err);
00499   self->myException.setStackTrace(self);
00500   self->logException();
00501 }
00502 
00503 void CSException::logException(const char *func, const char *file, int line, int err, const char *message)
00504 {
00505   CSThread *self;
00506 
00507   if ((self = CSThread::getSelf())) {
00508     self->myException.initException(func, file, line, err, message);
00509     self->logException();
00510   }
00511   else {
00512     CSException e;
00513     
00514     e.initException(func, file, line, err,message);
00515     e.log(NULL);
00516   }
00517 }
00518 
00519