예제 #1
0
RedirectPlugin::LookUpStatus
SipRedirectorRegDB::lookUp(
   const SipMessage& message,
   const UtlString& requestString,
   const Url& requestUri,
   const UtlString& method,
   ContactList& contactList,
   RequestSeqNo requestSeqNo,
   int redirectorNo,
   SipRedirectorPrivateStorage*& privateStorage,
   ErrorDescriptor& errorDescriptor)
{
   unsigned long timeNow = OsDateTime::getSecsSinceEpoch();
   
   // Local copy of requestUri
   Url requestUriCopy = requestUri;

   // Look for any grid parameter and remove it.
   UtlString gridParameter;
   UtlBoolean gridPresent =
      requestUriCopy.getUrlParameter("grid", gridParameter, 0);
   if (gridPresent)
   {
      requestUriCopy.removeUrlParameter("grid");
   }
   if (Os::Logger::instance().willLog(FAC_SIP, PRI_DEBUG))
   {
      UtlString temp;
      requestUriCopy.getUri(temp);
      Os::Logger::instance().log(FAC_SIP, PRI_DEBUG,
                    "%s::lookUp gridPresent = %d, gridParameter = '%s', "
                    "requestUriCopy after removing grid = '%s'",
                    mLogName.data(), gridPresent, gridParameter.data(),
                    temp.data());
   }

   RegDB::Bindings registrations;

   // Give the ~~in~ URIs separate processing.
   UtlString user;
   requestUriCopy.getUserId(user);
   if (user.index(URI_IN_PREFIX) == 0)
   {
      // This is a ~~in~ URI.
      // Check for an '&' separator.
      ssize_t s = user.last('&');
      if (s != UTL_NOT_FOUND)
      {
         // This is a ~~in~[user]&[instrument] URI.
         const char* instrumentp = user.data() + s + 1;
         UtlString u;
         u.append(user,
                  sizeof (URI_IN_PREFIX) - 1,
                  s - (sizeof (URI_IN_PREFIX) - 1));
         requestUriCopy.setUserId(u);

         //regDB->
         //   getUnexpiredContactsUserInstrument(requestUriCopy, instrumentp, timeNow, registrations);
         UtlString identity;
         requestUriCopy.getIdentity(identity);
         _dataStore.regDB().getUnexpiredContactsUserInstrument(identity.str(), instrumentp, timeNow, registrations);
      }
      else
      {
         // This is a ~~in~[instrument] URI.
         const char* instrumentp = user.data() + sizeof (URI_IN_PREFIX) - 1;

          _dataStore.regDB().getUnexpiredContactsInstrument(instrumentp, timeNow, registrations);
      }         
   }
   else
   {
      // Note that getUnexpiredContactsUser will reduce the requestUri to its
      // identity (user/host/port) part before searching in the
      // database.  The requestUri identity is matched against the
      // "identity" column of the database, which is the identity part of
      // the "uri" column which is stored in registration.xml.

      UtlString identity;
     requestUriCopy.getIdentity(identity);
     _dataStore.regDB().getUnexpiredContactsUser(identity.str(), timeNow, registrations);

   }

   int numUnexpiredContacts = registrations.size();

   Os::Logger::instance().log(FAC_SIP, PRI_DEBUG,
                 "%s::lookUp got %d unexpired contacts",
                 mLogName.data(), numUnexpiredContacts);

   // Check for a per-user call forward timer.
   // Don't set timer if we're not going to forward to voicemail.
   std::ostringstream userCfwdTimer;
   bool foundUserCfwdTimer = false;

   if (method.compareTo(SIP_INVITE_METHOD) == 0)
   {
      UtlString noRoute;
      requestUriCopy.getUrlParameter("sipx-noroute", noRoute);

      if ((!noRoute.isNull()) && (noRoute.compareTo("Voicemail") == 0))
      {
          // This is not a call scenerio controlled by this users "forward to voicemail" timer
      }
      else
      {
          UtlString identity;
          requestUriCopy.getIdentity(identity);
          EntityRecord entity;

          foundUserCfwdTimer = _dataStore.entityDB().findByIdentity(identity.str(), entity);
          if (foundUserCfwdTimer)
            userCfwdTimer << entity.callForwardTime();
      }
   }

   for (RegDB::Bindings::const_iterator iter = registrations.begin(); iter != registrations.end(); iter++)
   {
      // Query the Registration DB for the contact, expires and qvalue columns.

      Os::Logger::instance().log(FAC_SIP, PRI_DEBUG,
                    "%s::lookUp contact = '%s', qvalue = '%s', path = '%s'",
                    mLogName.data(), iter->getContact().c_str(), iter->getQvalue().c_str(), iter->getPath().c_str() );
      Url contactUri(iter->getContact().c_str());

      // If available set the per-user call forward timer.
      if (foundUserCfwdTimer)
      {
          contactUri.setHeaderParameter("expires", userCfwdTimer.str().c_str());
      }

      // If the contact URI is the same as the request URI, ignore it.
      if (!contactUri.isUserHostPortEqual(requestUriCopy))
      {
         // Check if the q-value from the database is valid, and if so,
         // add it into contactUri.
         if (!iter->getQvalue().empty())
         {
            // :TODO: (XPL-3) need a RegEx copy constructor here
            // Check if q value is numeric and between the range 0.0 and 1.0.
            static RegEx qValueValid("^(0(\\.\\d{0,3})?|1(\\.0{0,3})?)$");
            if (qValueValid.Search(iter->getQvalue().c_str()))
            {
               contactUri.setFieldParameter(SIP_Q_FIELD, iter->getQvalue().c_str());
            }
         }

         // Re-apply any grid parameter.
         if (gridPresent)
         {
            contactUri.setUrlParameter("grid", gridParameter);
         }

         contactUri.setUrlParameter(SIP_SIPX_CALL_DEST_FIELD, "INT");
         // Check if database contained a Path value.  If so, add a Route
         // header parameter to the contact with the Path vector taken from
         // the registration data.
         if (!iter->getPath().empty())
         {
            UtlString existingRouteValue;
            std::string pathVector = iter->getPath();
            if ( contactUri.getHeaderParameter(SIP_ROUTE_FIELD, existingRouteValue))
            {
               // there is already a Route header parameter in the contact; append it to the
               // Route derived from the Path vector.
                pathVector += SIP_MULTIFIELD_SEPARATOR;
                pathVector += existingRouteValue.str();
            }
            contactUri.setHeaderParameter(SIP_ROUTE_FIELD, pathVector.c_str());
         }

         // Add the contact.
         contactList.add( contactUri, *this );
      }
   }

   return RedirectPlugin::SUCCESS;
}
예제 #2
0
void HttpFileAccess::sendFile(const UtlString& path,
                              const UtlString& peerName,
                              const HttpRequestContext& requestContext,
                              const HttpMessage& request,
                              HttpMessage*& response
                              )
{
   UtlString message;
   
   int file = open(path.data(), O_RDONLY);
   if (0 <= file)
   {
      UtlString fileBuffer;
      if (fileBuffer.capacity(MAX_FILE_CHUNK_SIZE + 1) >= MAX_FILE_CHUNK_SIZE + 1)
      {
         response->setResponseFirstHeaderLine(HTTP_PROTOCOL_VERSION_1_1,
                                              HTTP_OK_CODE, HTTP_OK_TEXT);
         response->useChunkedBody(true);

         // @TODO Annotate file resources with a mime type?

         // add a Content-Disposition header to suggest saving as the basename of the file
         response->setContentType("application/octet-stream");
         UtlString dispositionValue;
         UtlString basename;
         ssize_t finalSlash = path.last('/');
         if (UTL_NOT_FOUND != finalSlash)
         {
            basename.append(path, finalSlash+1, path.length()-finalSlash);
         }
         else
         {
            basename.append(path); // don't think this should ever be true....
         }
         dispositionValue.append("attachment; filename=\"");
         dispositionValue.append(basename);
         dispositionValue.append("\"");
         response->setHeaderValue(HTTP_CONTENT_DISPOSITION_FIELD,dispositionValue.data());

         bool    writtenOk = response->writeHeaders(requestContext.socket());
         ssize_t bytes;
         Int64   totalBytes = 0;
         Int64   chunks = 0;
         while (   writtenOk
                && (bytes = read(file, (void*)fileBuffer.data(),
                                 MAX_FILE_CHUNK_SIZE)))
         {
            fileBuffer.setLength(bytes);
            writtenOk = response->writeChunk(requestContext.socket(), fileBuffer);
            if (writtenOk)
            {
               totalBytes += bytes;
               chunks++;
            }
            OsSysLog::add(FAC_SUPERVISOR, PRI_DEBUG,
                          "file block %"FORMAT_INTLL"d %zd %s", chunks, bytes,
                          writtenOk ? "ok" : "failed");
         }
         if (writtenOk)
         {
            response->writeEndOfChunks(requestContext.socket());

            message.append(" sent file '");
            message.append(path);
            message.append("' (");
            message.appendNumber(totalBytes,"%"FORMAT_INTLL"d");
            message.append(" bytes in ");
            message.appendNumber(chunks,"%"FORMAT_INTLL"d");
            message.append(" chunks) to peer ");
            message.append(peerName);
            OsSysLog::add(FAC_SUPERVISOR, PRI_INFO, "HttpFileAccess::processRequest %s",
                          message.data());
         }
         else
         {
            message.append("error writing response after ");
            message.appendNumber(totalBytes,"%"FORMAT_INTLL"d");
            message.append(" body bytes in ");
            message.appendNumber(chunks,"%"FORMAT_INTLL"d");
            message.append(" chunks) to peer ");
            message.append(peerName);
            OsSysLog::add(FAC_SUPERVISOR, PRI_ERR, "HttpFileAccess::processRequest %s",
                          message.data());
         }

         /*
          * We've already written the response, so prevent HttpServer from sending it by
          * not passing it back.
          */
         delete response;
         response = NULL;
      }
      else
      {
         // Send out-of-resources message
         message.append("Supervisor Buffer Exhausted");
         response->setResponseFirstHeaderLine(HTTP_PROTOCOL_VERSION,
                                              HTTP_OUT_OF_RESOURCES_CODE,
                                              message.data());
         response->setContentType(CONTENT_TYPE_TEXT_PLAIN);
         response->setBody(new HttpBody(message.data(),message.length()));
         response->setContentLength(message.length());

         OsSysLog::add(FAC_SUPERVISOR, PRI_ERR,
                       "HttpFileAccess::processRequest from %s %s",
                       peerName.data(), message.data());
      }
   }
   else
   {
      int       httpStatusCode;
      UtlString httpStatusText;

      switch (errno)
      {
      case EACCES:
         httpStatusCode = HTTP_FORBIDDEN_CODE;
         httpStatusText = "File Access Denied";
         break;

      case ENOENT:
         httpStatusCode = HTTP_FILE_NOT_FOUND_CODE;
         httpStatusText = HTTP_FILE_NOT_FOUND_TEXT;
         break;

      default:
         httpStatusCode = HTTP_SERVER_ERROR_CODE;
         httpStatusText = HTTP_SERVER_ERROR_TEXT;
         break;
      }

      message.append("File '");
      message.append(path);
      message.append("' errno ");
      message.appendNumber(errno);
      message.append(" ");

      char errnoMsg[1024];
      strerror_r(errno, errnoMsg, sizeof(errnoMsg));
      message.append(errnoMsg);

      OsSysLog::add(FAC_SUPERVISOR, PRI_ERR, "HttpFileAccess::processRequest from %s %s",
                    peerName.data(), message.data());

      response->setResponseFirstHeaderLine(HTTP_PROTOCOL_VERSION,
                                           httpStatusCode,
                                           httpStatusText);
      response->setBody(new HttpBody(message.data(),message.length()));
      response->setContentType(CONTENT_TYPE_TEXT_PLAIN);
      response->setContentLength(message.length());
   }
}