Exemple #1
0
bool ContactList::remove( size_t index, const RedirectPlugin& plugin )
{
   bool success = false;
   if( index < mContactList.size() )
   {
      success = true;
      mbListWasModified = true;

      OsSysLog::add(FAC_SIP, PRI_NOTICE, "ContactList::remove(): %s removed contact index %d  for '%s':\n"
                                        "   was:    '%s'",
                                plugin.name().data(),
                                index,
                                mRequestString.data(),
                                mContactList[ index ].data() );

      mContactList.erase( mContactList.begin() + index );
   }
   else
   {
      OsSysLog::add(FAC_SIP, PRI_ERR, "ContactList::remove(): %s failed to remove contact index %d - list only has %d elements",
                                plugin.name().data(),
                                index,
                                mContactList.size() );
   }
   return success;
}
Exemple #2
0
bool ContactList::set( size_t index, const UtlString& contact, const RedirectPlugin& plugin )
{
   bool success = false;
   if( index < mContactList.size() )
   {
      mbListWasModified = true;
      success = true;

      OsSysLog::add(FAC_SIP, PRI_NOTICE, "ContactList::set(): %s modified contact index %d for '%s':\n"
                                "   was:    '%s'\n"
                                "   now is: '%s'",
                                plugin.name().data(),
                                index,
                                mRequestString.data(),
                                mContactList[ index ].data(),
                                contact.data() );
      mContactList[ index ] = contact;
   }
   else
   {
      OsSysLog::add(FAC_SIP, PRI_ERR, "ContactList::set(): %s failed to set contact index %d - list only has %d elements",
                                plugin.name().data(),
                                index,
                                mContactList.size() );
   }
   return success;
}
Exemple #3
0
bool ContactList::removeAll( const RedirectPlugin& plugin )
{
   OsSysLog::add(FAC_SIP, PRI_NOTICE, "ContactList::removeAll(): %s removed %d contacts for '%s'",
                             plugin.name().data(),
                             mContactList.size(),
                             mRequestString.data() );

   mbListWasModified = true;
   mContactList.clear();
   return true;
}
Exemple #4
0
bool ContactList::add( const UtlString& contact, const RedirectPlugin& plugin )
{
   mbListWasModified = true;
   mContactList.push_back( contact );
   OsSysLog::add(FAC_SIP, PRI_NOTICE, "ContactList::add(): %s added contact for '%s':\n"
                             "   '%s' (contact index %d)",
                             plugin.name().data(),
                             mRequestString.data(),
                             contact.data(),
                             mContactList.size() - 1 );
   return true;
}
/**
 * Process a redirection.  The caller sets up our processing, but we
 * carry it through to the generation of the response, queuing of the
 * suspend object, etc.  We send the response if we finish processing.
 *
 * message is the message to be processed.  Its memory is owned by our
 * caller, or is attached to the suspend object.
 *
 * method is the request's SIP method.  Its memory is owned by our caller.
 *
 * seqNo is the sequence number to be used for this request.  (If this
 * request is to be suspended and seqNo == mNextSeqNo, we must increment
 * mNextSeqNo.)
 *
 * suspendObject is the suspend object for this request (if it already
 * exists) or NULL.  It is passed as an argument to avoid attempting to
 * look it up if the caller knows that it does not exist (because this
 * is a first processing attempt).
 */
void SipRedirectServer::processRedirect(const SipMessage* pMessage,
                                        UtlString& method,
                                        RedirectPlugin::RequestSeqNo seqNo,
                                        RedirectSuspend* suspendObject)
{
   ErrorDescriptor errorDescriptor;

   // Extract the request URI.

   // This code is not strictly correct, as the request could have:
   //    Route: <registrar [added by proxy]>,
   //           sip:[user]@[domain],
   //           [more]
   // due to an element Record-Routing with its AOR, but no element seems
   // to do that.
   // If we desire to handle that case, we have to correct the code here
   // to remove/skip any top routes that refer to the Registrar, then examine
   // the topmost remaining route (if any).
   // It would also require changing the code for routing ACKs that we forward
   // to modify the topmost route if present, instead of the request-URI.
   // There may be further complications due to strict routing.
   // All of this would be much like the Proxy forwarding requests.
   // Currently, we trust that all Route values refer to the registrar
   // and blindly remove them from any ACK that we must forward directly.

   UtlString stringUri;
   pMessage->getRequestUri(&stringUri);
   // The requestUri is an addr-spec, not a name-addr.
   Url requestUri(stringUri, TRUE);
   Os::Logger::instance().log(FAC_SIP, PRI_DEBUG,
                 "SipRedirectServer::processRedirect "
                 "Starting to process request URI '%s'",
                 stringUri.data());

   /*
    * Normalize the port in the Request URI
    *   This is not strictly kosher, but it solves interoperability problems.
    *   Technically, user@foo:5060 != user@foo , but many implementations
    *   insist on including the explicit port even when they should not, and
    *   it causes registration mismatches, so we normalize the URI when inserting
    *   and looking up in the database so that if explicit port is the same as
    *   the proxy listening port, then we remove it.
    *   (Since our proxy has mProxyNormalPort open, no other SIP entity
    *   can use sip:user@domain:mProxyNormalPort, so this normalization
    *   cannot interfere with valid addresses.)
    *
    * For the strict rules, set the configuration parameter
    *   SIP_REGISTRAR_PROXY_PORT : PORT_NONE
    */
   if (   mProxyNormalPort != PORT_NONE
       && requestUri.getHostPort() == mProxyNormalPort
       )
   {
      requestUri.setHostPort(PORT_NONE);
   }

   // Seize the lock that protects the list of suspend objects.
   OsLock lock(mRedirectorMutex);

   // Process with the redirectors.
   // Set to TRUE if any of the redirectors requests suspension.
   UtlBoolean willSuspend = FALSE;
   // Set to TRUE if any of the redirectors requests an error response.
   UtlBoolean willError = FALSE;
   PluginIterator iterator(mRedirectPlugins);
   RedirectPlugin* redirector;
   // Authority level of the last redirector to have modified the contact list.
   ssize_t contactListAuthorityLevel = LOWEST_AUTHORITY_LEVEL;
   ContactList contactList( stringUri );

   int i;                       // Iterator sequence number.
   for (i = 0; (redirector = static_cast <RedirectPlugin*> (iterator.next())) && !willError;
        i++)
   {
      if (mpConfiguredRedirectors[i].bActive)
      {
         // verify if the redirector has a suitable authority level to perform a look-up
         if( mpConfiguredRedirectors[i].authorityLevel >= contactListAuthorityLevel )
         {
            // Place to store the private storage pointer.
            SipRedirectorPrivateStorage* privateStorageP;
            // Initialize it.
            privateStorageP = (suspendObject ?
                               suspendObject->mRedirectors[i].privateStorage :
                               NULL);

            // Call the redirector to process the request.
            contactList.resetWasModifiedFlag();
            RedirectPlugin::LookUpStatus status =
               redirector->lookUp(*pMessage, stringUri, requestUri, method,
                                  contactList, seqNo, i, privateStorageP, errorDescriptor);

            // Create the suspend object if it does not already exist and we need it.
            if (!suspendObject &&
                (status == RedirectPlugin::SEARCH_PENDING || privateStorageP))
            {
               suspendObject = new RedirectSuspend(mRedirectorCount);
               // Insert it into mSuspendList, keyed by seqNo.
               UtlInt* containableSeqNo = new UtlInt(seqNo);
               mSuspendList.insertKeyAndValue(containableSeqNo, suspendObject);
               // Save in it a copy of the message.  (*pMessage is
               // dependent on the OsMsg bringing the message to us, and
               // will be freed when we are done with that OsMsg.)
               suspendObject->mMessage = *pMessage;
               // Use the next sequence number for the next request.
               if (seqNo == mNextSeqNo)
               {
                  // Increment to the next value (and roll over if necessary).
                  mNextSeqNo++;
               }
            }
            // Store the private storage pointer.
            if (suspendObject)
            {
               suspendObject->mRedirectors[i].privateStorage = privateStorageP;
            }

            int statusCode;
            UtlString reasonPhrase;

            // Dispatch on status.
            switch (status)
            {
            case RedirectPlugin::SUCCESS:
               // Processing was successful. If the plug-in modified the Contact list then
               // raise the authority level required to modify the contact list to the
               // authority level of this plug-in.
               if( contactList.wasListModified() )
               {
                  contactListAuthorityLevel = mpConfiguredRedirectors[i].authorityLevel;
               }
               break;

            case RedirectPlugin::ERROR:
               // Processing detected an error.  Log it and set the 'error' flag.
               errorDescriptor.getStatusLineData( statusCode, reasonPhrase );

               Os::Logger::instance().log(FAC_SIP, PRI_ERR,
                             "SipRedirectServer::processRedirect "
                             "ERROR returned by redirector "
                             "'%s' while processing method '%s' URI '%s': "
                             "Status code = %d (%s)",
                             redirector->name().data(), method.data(), stringUri.data(), statusCode, reasonPhrase.data() );
               willError = TRUE;
               break;

            case RedirectPlugin::SEARCH_PENDING:
               Os::Logger::instance().log(FAC_SIP, PRI_DEBUG,
                             "SipRedirectServer::processRedirect "
                             "SEARCH_PENDING returned by redirector "
                             "'%s' while processing method '%s' URI '%s'",
                             redirector->name().data(), method.data(), stringUri.data());
               willSuspend = TRUE;
               // Mark that this redirector has requested suspension.
               suspendObject->mRedirectors[i].suspended = TRUE;
               suspendObject->mRedirectors[i].needsCancel = TRUE;
               suspendObject->mSuspendCount++;
               break;

            default:
               Os::Logger::instance().log(FAC_SIP, PRI_ERR,
                             "SipRedirectServer::processRedirect "
                             "Invalid status value %d returned by redirector "
                             "'%s' while processing method '%s' URI '%s'",
                             status, redirector->name().data(), method.data(), stringUri.data());
               break;
            }  // end status switch
         } // end authorityLevel >= contactListAuthorityLevel
         else
         {
            // redirector plug-in does not have a suitable authority level to look up the
            // request - it is only allowed to observe it.
            redirector->observe(*pMessage, stringUri, requestUri, method,
                               contactList, seqNo, i);
         }
      }  // end mpConfiguredRedirectors[i]
   }  // end Redirector plug-in iterator

   if (willError || !willSuspend)   // redirector has done all it can
   {
       int numContacts = 0;
       if (method.compareTo(SIP_ACK_METHOD, UtlString::ignoreCase) == 0)
       {
          // See if location server has returned an address to use
          // to forward or just drop the ACK here.
           if (!willError && ((numContacts = contactList.entries()) == 1))
           {
               Os::Logger::instance().log(FAC_SIP, PRI_DEBUG,
                             "SipRedirectServer::processRedirect "
                             "Forwarding ACK for URI '%s': ",
                             stringUri.data());

               UtlString contactNameAddr;
               UtlString routeEntries;
               int maxForwards;

               // Get the (single) contact.
               contactList.get(0, contactNameAddr);
               // Convert from name-addr format (which is what is in
               // contactList) to addr-spec (which is what is needed
               // for a request-URI.
               Url contactUri(contactNameAddr, Url::NameAddr);
               UtlString contactAddrSpec;
               contactUri.getUri(contactAddrSpec);

               // create the message to forward -
               // change reqUri to located value, add route for debugging info, decrement max-forwards
               // leave last via since we are circling back, not responding
               SipMessage ackCopy(*pMessage);    // copy original ACK
               ackCopy.setRequestFirstHeaderLine(SIP_ACK_METHOD,
                                                 contactAddrSpec,
                                                 SIP_PROTOCOL_VERSION);

               // Remove any existing Route headers.
               // See the comment at the top of this method ("Extract
               // the request URI") for discussion.
               while (ackCopy.removeHeader(SIP_ROUTE_FIELD, 0))
               {
                  // empty
               }

               // Process header parameters in the request URI,
               // especially moving any Route parameters to Route headers.
               ackCopy.applyTargetUriHeaderParams();

               // Put Route to proxy in the first position, so the proxy
               // can see the ACK.
               ackCopy.addRouteUri(mAckRouteToProxy.data());

               // Update or create the Max-Forwards header.
               if (!ackCopy.getMaxForwards(maxForwards))
               {
                   maxForwards = SIP_DEFAULT_MAX_FORWARDS;
               }
               maxForwards--;
               ackCopy.setMaxForwards(maxForwards);

               // get send-to address/port/protocol from top via
               UtlString lastViaAddress;
               int lastViaPort;
               UtlString lastViaProtocol;
               OsSocket::IpProtocolSocketType viaProtocol = OsSocket::UNKNOWN;

               ackCopy.getTopVia(&lastViaAddress, &lastViaPort, &lastViaProtocol);
               SipMessage::convertProtocolStringToEnum(lastViaProtocol.data(), viaProtocol);


               Os::Logger::instance().log(FAC_SIP, PRI_DEBUG,
                             "SipRedirectServer::processRedirect "
                             "sending ACK to '%s':%d using '%s' "
                             "location service returned '%s', "
                             "converted into '%s'",
                             lastViaAddress.data(),
                             lastViaPort,
                             lastViaProtocol.data(),
                             contactNameAddr.data(),
                             contactAddrSpec.data());

               // This ACK has no matching INVITE, special case
               mpSipUserAgent->sendStatelessAck(ackCopy,            // this will add via
                                                lastViaAddress,
                                                lastViaPort,
                                                viaProtocol);
           }
           else  // locater must return EXACTLY one value to forward
           {
               Os::Logger::instance().log(FAC_SIP, PRI_ERR,
                             "SipRedirectServer::processRedirect "
                             "Cannot redirect ACK for URI '%s', dropping: "
                             "number of contacts=%d  ",
                             stringUri.data(), numContacts);
           }
       }   // end handle ACK redirection
       else     // build and send the proper (error) response
       {
          // The response we will compose and, hopefully, send.
          SipMessage response;

          // Send a response and terminate processing now if an error has
          // been found or if no redirector has requested suspension.
          if (willError)
          {
             buildResponseFromRequestAndErrorDescriptor( response, *pMessage, errorDescriptor );
          }
          else
          {
             // If request processing is finished, construct a response,
             // either 302 or 404.
             if (contactList.entries() > 0)
             {
                // There are contacts, so send a 302 Moved Temporarily.
                Os::Logger::instance().log(FAC_SIP, PRI_DEBUG,
                              "SipRedirectServer::processRedirect "
                              "Contacts added, sending 302 response");
                response.setResponseData(pMessage,
                                         SIP_TEMPORARY_MOVE_CODE,
                                         SIP_TEMPORARY_MOVE_TEXT);

                // add contacts collected in the contactList to the response
                size_t index;
                size_t numEntries = contactList.entries();

                for( index = 0; index < numEntries; index++ )
                {
                   UtlString contactString;
                   if( contactList.get( index, contactString ) )
                   {
                      response.setContactField(contactString, index );
                   }
                   else
                   {
                      Os::Logger::instance().log(FAC_SIP, PRI_CRIT,
                                    "SipRedirectServer::processRedirect "
                                    "Failed to retrieve contact index %zu", index );
                   }
                }
             }
             else
             {
                // There are no contacts, send back a 404 Not Found.
                Os::Logger::instance().log(FAC_SIP, PRI_DEBUG,
                              "SipRedirectServer::processRedirect "
                              "No contacts added, sending 404 response");
                response.setResponseData(pMessage,
                                         SIP_NOT_FOUND_CODE,
                                         SIP_NOT_FOUND_TEXT);
             }
          }

          // Identify ourselves in the response
          mpSipUserAgent->setUserAgentHeader(response);

          // Now that we've set the right code into the response, send the
          // response.
          mpSipUserAgent->send(response);
       }    // end sending response to Invite

       // If the suspend object exists, remove it from mSuspendList
       // and delete it.
       if (suspendObject)
       {
          Os::Logger::instance().log(FAC_SIP, PRI_DEBUG,
                        "SipRedirectServer::processRedirect "
                        "Cleaning up suspense of request %d", seqNo);
          UtlInt containableSeqNo(seqNo);
          cancelRedirect(containableSeqNo, suspendObject);
       }
   }    // end redirector did all it could
   else
   {
      // Request is suspended.
      Os::Logger::instance().log(FAC_SIP, PRI_DEBUG,
                    "SipRedirectServer::processRedirect "
                    "Suspending request %d", seqNo);
   }
}
Exemple #6
0
void ContactList::touch( const RedirectPlugin& plugin )
{
   OsSysLog::add(FAC_SIP, PRI_NOTICE, "ContactList::touch(): list touched by %s",
                             plugin.name().data() );
   mbListWasModified = true;
}