bool NodeConfigManager::getBitmunkHomePath(string& path)
{
   bool rval;

   Config c = getConfigManager()->getConfig(MAIN_ID);
   // get initial value
   const char* bitmunkHomePath = c["monarch.app.Core"]["home"]->getString();
   // make sure bitmunkHomePath is user-expanded
   rval = File::expandUser(bitmunkHomePath, path);
   // make sure path is absolute
   if(!rval || !File::isPathAbsolute(path.c_str()))
   {
      ExceptionRef e = new Exception(
         "Could not get absolute bitmunk home path.",
         "bitmunk.node.NodeConfigManager.ConfigError");
      e->getDetails()["bitmunkHomePath"] = bitmunkHomePath;
      Exception::push(e);
      rval = false;
   }

#ifdef WIN32
   if(rval)
   {
      // swap backslashes to standard if on windows
      StringTools::replaceAll(path, "\\", "/");
   }
#endif

   return rval;
}
示例#2
0
int FileInputStream::read(char* b, int length)
{
   int rval = -1;

   if(ensureOpen())
   {
      rval = 0;

      // do read
      int count = fread(b, 1, length, mHandle);
      if(count != length)
      {
         // check for an error
         if(ferror(mHandle) != 0)
         {
            ExceptionRef e = new Exception(
               "Could not read file.",
               "monarch.io.File.ReadError");
            e->getDetails()["path"] = mFile->getAbsolutePath();
            e->getDetails()["error"] = strerror(errno);
            Exception::set(e);
            rval = -1;
         }
      }

      if(rval != -1)
      {
         // return number of bytes read
         rval = count;
      }
   }

   return rval;
}
示例#3
0
int64_t MySqlRow::getColumnIndex(const char* name)
{
   // use 64-bit signed int to cover all values + error (negative 1)
   int64_t rval = -1;

   for(unsigned int i = 0; i < mFieldCount; ++i)
   {
      if(strcmp(name, mFields[i].name) == 0)
      {
         rval = i;
         break;
      }
   }

   if(rval == -1)
   {
      // set exception
      ExceptionRef e = new Exception(
         "Could not get column value. Invalid column name.",
         "monarch.sql.mysql.MySql");
      e->getDetails()["name"] = name;
      Exception::set(e);
   }

   return rval;
}
示例#4
0
bool PortService::start()
{
   if(!mOperation.isNull())
   {
      // stop service
      stop();
   }

   // initialize service
   mOperation = initialize();
   if(!mOperation.isNull())
   {
      // run service
      mServer->getOperationRunner()->runOperation(mOperation);
   }
   else
   {
      // set exception
      ExceptionRef e = new Exception(
         "Port service failed to start.",
         "monarch.net.PortService.StartFailed");
      e->getDetails()["name"] = mName;
      Exception::push(e);

      // clean up service
      cleanup();
   }

   return !mOperation.isNull();
}
Config NodeConfigManager::getModuleConfig(const char* moduleName, bool raw)
{
   Config rval(NULL);
   if(raw)
   {
      rval = getConfigManager()->getConfig(moduleName, raw);
   }
   else
   {
      Config tmp = getConfigManager()->getConfig(MAIN_ID, raw);
      if(!tmp.isNull() && tmp->hasMember(moduleName))
      {
         rval = tmp[moduleName];
      }
      else
      {
         ExceptionRef e = new Exception(
            "Could not get module config. Invalid module name.",
            "bitmunk.node.NodeConfigManager.InvalidModuleName");
         e->getDetails()["moduleName"] = moduleName;
         Exception::push(e);
      }
   }

   return rval;
}
DynamicObject ValidatorContext::addError(
   const char* type, DynamicObject* object)
{
   DynamicObject errorDetail;

   // setup error detail
   errorDetail["type"] = type;
   // FIXME: localize message -- lehn
   // FIXME: really? do we need to mention this, because we'd have to
   //        do this for every string in the system.. -- manu
   errorDetail["message"] = "The given value does not meet all of the data "
      "validation requirements. Please examine the error details for more "
      "information about the specific requirements.";
   if(object != NULL && (mMaskType & ValidatorContext::MaskInvalidValues) == 0)
   {
      errorDetail["invalidValue"] = *object;
   }

   // add error detail to results errors
   std::string fullpath = getPath();
   mResults["errors"][fullpath.c_str()] = errorDetail;

   // Skip setting exceptions if requested. Return errorDetail regardless.
   if(mSetExceptions)
   {
      ExceptionRef e;

      if(!Exception::isSet())
      {
         e = new Exception(
            "The given object does not meet all of the data validation "
            "requirements. Please examine the error details for more "
            "information about the specific requirements.",
            "monarch.validation.ValidationError");
         Exception::set(e);
      }
      else
      {
         e = Exception::get();
         // Check if we are adding to a ValidationError
         if(!e->isType("monarch.validation.ValidationError"))
         {
            // FIXME: this is a bit bogus. If validation checking keeps causing
            // other exceptions then a long cause chain could be generated
            // switching between ValidationError and other types.
            e = new Exception(
               "The given object does not meet all of the data validation "
               "requirements. Please examine the error details for more "
               "information about the specific requirements.",
               "monarch.validation.ValidationError");
            Exception::push(e);
         }
      }

      // add detail to "errors" section of exception details
      e->getDetails()["errors"][fullpath.c_str()] = errorDetail;
   }

   return errorDetail;
}
示例#7
0
bool AbstractSocket::listen(int backlog)
{
   if(!isBound())
   {
      ExceptionRef e = new Exception(
         "Cannot listen on unbound socket.",
         SOCKET_EXCEPTION_TYPE ".NotBound");
      Exception::set(e);
   }
   else
   {
      // set backlog
      mBacklog = backlog;

      // listen
      int error = SOCKET_MACRO_listen(mFileDescriptor, backlog);
      if(error < 0)
      {
         ExceptionRef e = new Exception(
            "Could not listen on socket.", SOCKET_EXCEPTION_TYPE);
         e->getDetails()["error"] = strerror(errno);
         Exception::set(e);
      }
      else
      {
         // now listening
         mListening = true;

         // set socket to non-blocking so accept() calls can be interrupted
         SOCKET_MACRO_fcntl(mFileDescriptor, F_SETFL, O_NONBLOCK);
      }
   }

   return mListening;
}
示例#8
0
bool SessionManager::getSessionFromAction(
   BtpAction* action, string& session, InternetAddress* ip)
{
   bool rval = true;

   // get client cookies
   CookieJar jar;
   jar.readCookies(action->getRequest()->getHeader(), CookieJar::Client);

   // check for bitmunk-session cookie
   Cookie cookie = jar.getCookie("bitmunk-session");
   if(cookie.isNull())
   {
      ExceptionRef e = new Exception(
         "No 'bitmunk-session' cookie.",
         "bitmunk.webui.SessionManager.MissingCookie");
      e->getDetails()["missingCookie"] = "bitmunk-session";
      Exception::set(e);
      rval = false;
   }
   else
   {
      // get session ID
      session = cookie["value"]->getString();
   }

   if(rval)
   {
      // get IP
      rval = action->getClientInternetAddress(ip);
   }

   return rval;
}
示例#9
0
bool SessionManager::checkAccessControl(
   const char* username, InternetAddress* ip)
{
   bool rval;

   // check the address against 127.x.x.x for localhost status, any user
   // has access control from localhost
   rval = (strncmp(ip->getAddress(), "127.", 4) == 0);
   if(!rval)
   {
      // not localhost, will have to check session database:

      // get bitmunk user ID
      Url url;
      url.format("/api/3.0/users?username=%s", username);
      DynamicObject user;
      if(mNode->getMessenger()->getFromBitmunk(&url, user))
      {
         rval = mSessionDatabase.checkAccessControl(
            BM_USER_ID(user["id"]), ip->getAddress());
      }
   }

   if(!rval)
   {
      ExceptionRef e = new Exception(
         "Access denied for user.",
         "bitmunk.webui.SessionManager.AccessDenied");
      e->getDetails()["username"] = username;
      e->getDetails()["ip"] = ip->getAddress();
      Exception::push(e);
   }

   return rval;
}
static PatternRef _compileDomainRegex(const char* domain)
{
   PatternRef rval(NULL);

   string regex = "^";
   regex.append(domain);
   regex.append("$");

   // escape all periods
   StringTools::replaceAll(regex, ".", "\\.");

   // replace all wildcards with (.*)
   StringTools::replaceAll(regex, "*", ".*");

   // try to compile the pattern (match case, no-sub matches allowed)
   rval = Pattern::compile(regex.c_str(), true, false);
   if(rval.isNull())
   {
      ExceptionRef e = new Exception(
         "Could not add proxy domain. Invalid domain format.",
         "bitmunk.node.ProxyResourceHandler.InvalidDomainFormat");
      e->getDetails()["domain"] = domain;
      e->getDetails()["regex"] = regex.c_str();
      Exception::push(e);
   }

   return rval;
}
示例#11
0
void Thread::setException(ExceptionRef& e, bool caused)
{
   // initialize threads
   pthread_once(&sThreadsInit, &initializeThreads);

   // get the exception reference for the current thread
   ExceptionRef* ref =
      static_cast<ExceptionRef*>(pthread_getspecific(sExceptionKey));
   if(ref == NULL)
   {
      // create the exception reference
      ref = new ExceptionRef(NULL);
      *ref = e;
      pthread_setspecific(sExceptionKey, ref);
   }
   else
   {
      if(caused && !e.isNull())
      {
         // set cause of passed exception to previous exception
         e->setCause(*ref);
      }

      // update the reference
      *ref = e;
   }
}
示例#12
0
bool ControlPoint::performAction(
   const char* actionName, DynamicObject& params,
   Service& service, ActionResult& result)
{
   bool rval = false;

   // ensure action exists in the service
   if(!service->hasMember("actions") ||
      !service["actions"]->hasMember(actionName))
   {
      ExceptionRef e = new Exception(
         "Service has no such action.",
         "monarch.upnp.NoSuchAction");
      e->getDetails()["actionName"] = actionName;
      e->getDetails()["serviceType"] = service["serviceType"]->getString();
      e->getDetails()["serviceId"] = service["serviceId"]->getString();
      Exception::set(e);
   }
   else
   {
      // create a soap message
      SoapMessage msg;
      msg["name"] = actionName;
      msg["namespace"] = service["serviceType"]->getString();
      msg["params"] = params;

      // do soap transfer
      rval = doSoap(service, msg, result);
   }

   return rval;
}
bool AbstractConnection::connect(const char* url)
{
    bool rval = false;

    // clean up old url
    mUrl.setNull();

    // ensure URL isn't malformed
    Exception::clear();
    mUrl = new Url(url);
    if(Exception::isSet())
    {
        ExceptionRef e = new Exception(
            "Invalid database url.",
            "monarch.sql.Connection.InvalidUrl");
        e->getDetails()["url"] = url;
        Exception::push(e);
    }
    else
    {
        // call implementation-specific code
        rval = connect(&(*mUrl));
    }

    return rval;
}
bool AbstractConnection::rollback()
{
    bool rval = false;

    // save the reason for the rollback
    ExceptionRef reason = Exception::get();

    // attempt to do the rollback
    Statement* s = prepare("ROLLBACK");
    rval = (s != NULL) && s->execute() && s->reset();
    if(!rval)
    {
        ExceptionRef e = new Exception(
            "Could not rollback transaction.",
            "monarch.sql.Connection.TransactionRollbackError");
        if(!reason.isNull())
        {
            e->getDetails()["rollbackReason"] =
                Exception::convertToDynamicObject(reason);
        }
        Exception::push(e);
    }

    return rval;
}
示例#15
0
bool NodeConfigManager::getUserDataPath(UserId userId, string& path)
{
   bool rval;
   Config c = getConfigManager()->getConfig(MAIN_ID);
   // get initial value
   const char* usersPath = c["node"]["usersPath"]->getString();
   rval = expandBitmunkHomePath(usersPath, path);
   if(rval)
   {
      // append user id path
      char userIdStr[ID_MAX];
      snprintf(userIdStr, ID_MAX, ID_FMT, userId);
      path.assign(File::join(path.c_str(), userIdStr));

#ifdef WIN32
      // swap backslashes to standard if on windows
      StringTools::replaceAll(path, "\\", "/");
#endif
   }

   if(!rval)
   {
      ExceptionRef e = new Exception(
         "Could not get absolute user data path.",
         "bitmunk.node.NodeConfigManager.ConfigError");
      e->getDetails()["usersPath"] = usersPath;
      Exception::push(e);
   }

   return rval;
}
示例#16
0
bool DirectiveService::createDirective(
   BtpAction* action, DynamicObject& in, DynamicObject& out)
{
   bool rval = false;

   UserId userId;
   if(mNode->checkLogin(action, &userId))
   {
      // turn user ID into a key
      char key[22];
      snprintf(key, 22, "%" PRIu64, userId);

      // lock to insert directive
      mCacheLock.lock();
      {
         // initialize user's directive cache as needed
         if(!mDirectives->hasMember(key))
         {
            mDirectives[key]->setType(Map);
         }

         DynamicObject& cache = mDirectives[key];
         if(cache->length() < MAX_DIRECTIVES)
         {
            // insert directive into cache
            insertDirective(cache, in);

            // return directive ID
            out["directiveId"] = in["id"]->getString();
            rval = true;

            // fire created event
            Event e;
            e["type"] = "bitmunk.system.Directive.created";
            e["details"]["userId"] = userId;
            e["details"]["directiveId"] = in["id"];
            e["details"]["directive"] = in;
            mNode->getEventController()->schedule(e);
         }
         else
         {
            // too many directives
            ExceptionRef e = new Exception(
               "Could not add directive. Maximum number of "
               "directives reached.",
               "bitmunk.system.DirectiveService.TooManyDirectives");
            e->getDetails()["userId"] = userId;
            e->getDetails()["max"] = MAX_DIRECTIVES;
            Exception::set(e);
         }
      }
      mCacheLock.unlock();
   }

   return rval;
}
示例#17
0
bool UdpSocket::joinGroup(SocketAddress* group, SocketAddress* localAddress)
{
   int error = 0;

   if(group->getCommunicationDomain() == SocketAddress::IPv6)
   {
      // create IPv6 multicast request
      struct ipv6_mreq request;

      // set multicast address
      inet_pton(AF_INET6, group->getAddress(), &request.ipv6mr_multiaddr);

      // use any address for local interface
      request.ipv6mr_interface = 0;

      // join group
      error = setsockopt(
         mFileDescriptor, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP,
         (char*)&request, sizeof(request));
   }
   else
   {
      // create IPv4 multicast request
      struct ip_mreq request;

      // set multicast address
      inet_pton(AF_INET, group->getAddress(), &request.imr_multiaddr);

      // set local interface
      if(localAddress == NULL)
      {
         // use any address for local interface
         request.imr_interface.s_addr = INADDR_ANY;
      }
      else
      {
         inet_pton(AF_INET, localAddress->getAddress(), &request.imr_interface);
      }

      // join group
      error = setsockopt(
         mFileDescriptor, IPPROTO_IP, IP_ADD_MEMBERSHIP,
         (char*)&request, sizeof(request));
   }

   if(error < 0)
   {
      ExceptionRef e = new Exception(
         "Could not join multicast group.", SOCKET_EXCEPTION_TYPE);
      e->getDetails()["error"] = strerror(errno);
      Exception::set(e);
   }

   return error == 0;
}
示例#18
0
void Thread::clearException()
{
   // get the exception reference for the current thread
   ExceptionRef* ref =
      static_cast<ExceptionRef*>(pthread_getspecific(sExceptionKey));
   if(ref != NULL)
   {
      // clear the reference
      ref->setNull();
   }
}
示例#19
0
int FileInputStream::readLine(string& line, char delimiter)
{
   int rval = -1;

   if(ensureOpen())
   {
      rval = 0;

      // feof returns non-zero when EOF
      if(feof(mHandle) == 0)
      {
         // get line
         char* data = NULL;
         size_t size = 0;
         ssize_t length = getdelim(&data, &size, delimiter, mHandle);
         if(length == -1)
         {
            if(feof(mHandle) != 0)
            {
               // end of file
            }
            else
            {
               ExceptionRef e = new Exception(
                  "Could not read file.",
                  "monarch.io.File.ReadError");
               e->getDetails()["path"] = mFile->getAbsolutePath();
               e->getDetails()["error"] = strerror(errno);
               Exception::set(e);
               rval = -1;
            }
         }
         else
         {
            // line was read
            rval = 1;
            if(data[length - 1] == delimiter)
            {
               // do not include delimiter
               line.assign(data, length - 1);
            }
            else
            {
               line.assign(data, length);
            }
            free(data);
         }
      }
   }

   return rval;
}
示例#20
0
bool DirectiveService::processDirective(
   BtpAction* action, DynamicObject& in, DynamicObject& out)
{
   bool rval = false;

   UserId userId;
   if(mNode->checkLogin(action, &userId))
   {
      // get directive by its ID
      DynamicObject params;
      action->getResourceParams(params);
      const char* id = params[0]->getString();
      DynamicObject directive(NULL);

      // remove directive from cache
      removeDirective(userId, id, &directive);

      // ensure directive is not invalid
      if(directive.isNull())
      {
         // directive not found
         ExceptionRef e = new Exception(
            "Could not process directive. Directive does not exist.",
            "bitmunk.system.DirectiveService.InvalidDirectiveId", 404);
         e->getDetails()["userId"] = userId;
         e->getDetails()["directiveId"] = id;
         Exception::set(e);
      }
      // process directive
      else
      {
         // include user ID in directive
         directive["userId"] = userId;

         // include directive in output
         out["userId"] = userId;
         out["directive"] = directive;

         // run directive processor fiber
         DirectiveProcessor* dp = new DirectiveProcessor(mNode);
         dp->setDirective(directive);
         mNode->getFiberScheduler()->addFiber(dp);
         rval = true;
      }
   }

   return rval;
}
示例#21
0
bool Messenger::exchange(
   UserId peerId,
   Url* url, BtpMessage* out, BtpMessage* in, UserId userId, UserId agentId,
   uint32_t timeout)
{
   bool rval = true;

   if(userId != 0)
   {
      // get user profile
      ProfileRef p;
      if(!mNode->getLoginData(agentId == 0 ? userId : agentId, NULL, &p))
      {
         ExceptionRef e = new Exception(
            "Could not do BTP exchange. Not logged in.",
            "bitmunk.node.Messenger.NotLoggedIn");
         BM_ID_SET(e->getDetails()["userId"], userId);
         BM_ID_SET(e->getDetails()["agentId"], agentId);
         Exception::set(e);
         rval = false;
      }
      else if(!p.isNull())
      {
         // set user ID and profile for outgoing secure message
         out->setUserId(userId);
         out->setAgentProfile(p);

         // set public key source for incoming secure message
         in->setPublicKeySource(mNode->getPublicKeyCache());
      }
   }

   // do btp exchange
   if(rval)
   {
      // if nodeuser is set, override peer ID with it
      DynamicObject vars;
      url->getQueryVariables(vars);
      if(vars->hasMember("nodeuser"))
      {
         peerId = BM_USER_ID(vars["nodeuser"]);
      }

      rval = mClient.exchange(peerId, url, out, in, timeout);
   }

   return rval;
}
示例#22
0
ExceptionRef Exception::getExceptionOfType(
   ExceptionRef& e, const char* type, bool startsWith)
{
   ExceptionRef rval(NULL);

   if(e->isType(type, startsWith))
   {
      rval = e;
   }
   else
   {
      rval = e->getCauseOfType(type, startsWith);
   }

   return rval;
}
示例#23
0
// method to optimize deep searches for exception type base names
static ExceptionRef _getCauseOfType(ExceptionRef& e, const char* type, int n)
{
   ExceptionRef rval(NULL);

   // check this exception's type
   if(strncmp(e->getType(), type, n) == 0)
   {
      rval = e;
   }
   // check this exception's cause
   else if(!e->getCause().isNull())
   {
      rval = _getCauseOfType(e->getCause(), type, n);
   }

   return rval;
}
示例#24
0
bool DatabaseClient::checkForSchema(const char* table)
{
   bool rval = true;

   // ensure the schema exists
   if(!mSchemas->hasMember(table))
   {
      ExceptionRef e = new Exception(
         "No schema defined for table.",
         DBC_EXCEPTION ".MissingSchema");
      e->getDetails()["table"] = table;
      Exception::set(e);
      rval = false;
   }

   return rval;
}
示例#25
0
bool UdpSocket::setBroadcastEnabled(bool enable)
{
   // set broadcast flag
   int broadcast = (enable) ? 1 : 0;
   int error = setsockopt(
      mFileDescriptor, SOL_SOCKET, SO_BROADCAST,
      (char *)&broadcast, sizeof(broadcast));
   if(error < 0)
   {
      ExceptionRef e = new Exception(
         "Could not set broadcast flag.", SOCKET_EXCEPTION_TYPE);
      e->getDetails()["error"] = strerror(errno);
      Exception::set(e);
   }

   return error == 0;
}
示例#26
0
bool UdpSocket::setMulticastTimeToLive(unsigned char ttl)
{
   int error = 0;

   // set multicast ttl flag
   error = setsockopt(
      mFileDescriptor, IPPROTO_IP, IP_MULTICAST_TTL, (char*)&ttl, sizeof(ttl));

   if(error < 0)
   {
      ExceptionRef e = new Exception(
         "Could not set multicast TTL.", SOCKET_EXCEPTION_TYPE);
      e->getDetails()["error"] = strerror(errno);
      Exception::set(e);
   }

   return error == 0;
}
示例#27
0
bool Thread::hasException()
{
   bool rval = false;

   // initialize threads
   pthread_once(&sThreadsInit, &initializeThreads);

   // get the exception reference for the current thread
   ExceptionRef* ref =
      static_cast<ExceptionRef*>(pthread_getspecific(sExceptionKey));
   if(ref != NULL)
   {
      // return true if the reference isn't to NULL
      rval = !ref->isNull();
   }

   return rval;
}
示例#28
0
bool AbstractSocket::getRemoteAddress(SocketAddress* address)
{
   bool rval = false;

   if(!mConnected)
   {
      ExceptionRef e = new Exception(
         "Cannot get local address for an unconnected socket.",
         SOCKET_EXCEPTION_TYPE ".Closed");
      Exception::set(e);
   }
   else
   {
      // get address structure
      socklen_t size = 130;
      char addr[size];

      // get remote information
      int error = SOCKET_MACRO_getpeername(
         mFileDescriptor, (sockaddr*)&addr, &size);
      if(error < 0)
      {
         // invalidate file descriptor if bad
         if(errno == EBADF)
         {
            mFileDescriptor = -1;
            close();
         }
         ExceptionRef e = new Exception(
            "Could not get socket remote address.",
            SOCKET_EXCEPTION_TYPE);
         e->getDetails()["error"] = strerror(errno);
         Exception::set(e);
      }
      else
      {
         // convert socket address
         address->fromSockAddr((sockaddr*)&addr, size);
         rval = true;
      }
   }

   return rval;
}
示例#29
0
DynamicObject Exception::convertToDynamicObject(ExceptionRef& e)
{
   DynamicObject dyno;

   dyno["message"] = e->getMessage();
   dyno["type"] = e->getType();

   if(!e->getCause().isNull())
   {
      dyno["cause"] = convertToDynamicObject(e->getCause());
   }

   if(!(*e).mDetails->isNull())
   {
      dyno["details"] = e->getDetails();
   }

   return dyno;
}
示例#30
0
ExceptionRef Exception::convertToException(DynamicObject& dyno)
{
   ExceptionRef rval = new Exception(
      dyno["message"]->getString(),
      dyno["type"]->getString());

   if(dyno->hasMember("cause"))
   {
      ExceptionRef cause = convertToException(dyno["cause"]);
      rval->setCause(cause);
   }

   if(dyno->hasMember("details"))
   {
      *(*rval).mDetails = dyno["details"].clone();
   }

   return rval;
}