📄 tuim.cxx
字号:
#if defined(HAVE_CONFIG_H)
#include "resip/stack/config.hxx"
#endif
/* TODO list for this file ....
handle 302 in message
handle 302 in subscribe
sort out how contact is formed
keep track of ourstanding message dialogs
add a publish sending dialogs
send options to register, see if do publish, if so use
suppport loading destination certificates from server
*/
#include <cassert>
#include <memory>
#include "resip/stack/SipStack.hxx"
#include "resip/stack/DeprecatedDialog.hxx"
#include "resip/stack/SipMessage.hxx"
#include "resip/stack/TuIM.hxx"
#include "resip/stack/Contents.hxx"
#include "resip/stack/ParserCategories.hxx"
#include "resip/stack/PlainContents.hxx"
#include "resip/stack/CpimContents.hxx"
#include "resip/stack/Pkcs7Contents.hxx"
#include "resip/stack/MultipartSignedContents.hxx"
#include "resip/stack/MultipartMixedContents.hxx"
#include "resip/stack/OctetContents.hxx"
#include "resip/stack/Security.hxx"
#include "resip/stack/Helper.hxx"
#include "resip/stack/Pidf.hxx"
#include "resip/stack/SipFrag.hxx"
#include "rutil/Data.hxx"
#include "rutil/Logger.hxx"
#include "rutil/Random.hxx"
#include "rutil/Socket.hxx"
#include "rutil/WinLeakCheck.hxx"
#define RESIPROCATE_SUBSYSTEM Subsystem::SIP
using namespace resip;
using namespace std;
static int IMMethodList[] = { (int) REGISTER,
(int) MESSAGE,
(int) SUBSCRIBE,
(int) NOTIFY };
const int IMMethodListSize = sizeof(IMMethodList) / sizeof(*IMMethodList);
TuIM::Callback::~Callback()
{
}
TuIM::TuIM(SipStack* stack,
const Uri& aor,
const Uri& contact,
Callback* callback,
const int registrationTimeSeconds,
const int subscriptionTimeSeconds)
: mCallback(callback),
mStack(stack),
mAor(aor),
mContact(contact),
mPidf( new Pidf ),
mRegistrationDialog(NameAddr(contact)),
mNextTimeToRegister(0),
mRegistrationPassword( Data::Empty ),
mLastAuthCSeq(0),
mRegistrationTimeSeconds(registrationTimeSeconds),
mSubscriptionTimeSeconds(subscriptionTimeSeconds),
mDefaultProtocol( UNKNOWN_TRANSPORT )
{
assert( mStack );
assert(mCallback);
assert(mPidf);
mPidf->setSimpleId( Random::getRandomHex(4) );
mPidf->setEntity(mAor);
mPidf->setSimpleStatus( true, Data::Empty, mContact.getAor() );
}
bool
TuIM::haveCerts( bool sign, const Data& encryptFor )
{
/* assert(0); */
#if defined( USE_SSL )
Security* sec = mStack->getSecurity();
assert(sec);
if ( sign )
{
if ( !sec->hasUserPrivateKey(mAor.getAor()) )
{
return false;
}
}
if ( !encryptFor.empty() )
{
if ( !sec->hasUserCert( encryptFor ) )
{
return false;
}
}
#else
if ( (!encryptFor.empty()) || (sign) )
{
return false;
}
#endif
return true;
}
void
TuIM::sendPage(const Data& text, const Uri& dest,
const bool sign, const Data& encryptFor)
{
if ( text.empty() )
{
DebugLog( << "tried to send blank message - dropped " );
return;
}
DebugLog( << "send to <" << dest << ">" << "\n" << text );
NameAddr target;
target.uri() = dest;
NameAddr from;
from.uri() = mAor;
NameAddr contact;
contact.uri() = mContact;
DeprecatedDialog* dialog = new DeprecatedDialog( NameAddr(mContact) );
auto_ptr<SipMessage> msg( dialog->makeInitialMessage(NameAddr(target),NameAddr(from)) );
Page page;
page.text = text;
page.uri = dest;
page.sign = sign;
page.encryptFor = encryptFor;
page.dialog = dialog;
mPages.push_back(page);
Contents* body = ( new PlainContents(text) );
#if 1
msg->header(h_ContentTransferEncoding) = StringCategory(Data("binary"));
#endif
#if defined( USE_SSL )
if ( !encryptFor.empty() )
{
Security* sec = mStack->getSecurity();
assert(sec);
Contents* old = body;
old->header(h_ContentTransferEncoding) = msg->header(h_ContentTransferEncoding);
body = sec->encrypt( old, encryptFor );
delete old;
if ( !body )
{
mCallback->sendPageFailed( dest, -2 );
return;
}
#if 0
msg->header(h_ContentTransferEncoding) = StringCategory(Data("binary"));
#endif
}
if ( sign )
{
Security* sec = mStack->getSecurity();
assert(sec);
Contents* old = body;
old->header(h_ContentTransferEncoding) = msg->header(h_ContentTransferEncoding);
body = sec->sign( mAor.getAor(), old );
delete old;
if ( !body )
{
mCallback->sendPageFailed( dest, -1 );
return;
}
#if 0
msg->header(h_ContentTransferEncoding) = StringCategory(Data("binary"));
#endif
}
#endif
msg->setContents(body);
if (1) // Compute the identity header.
{
//Security* sec = mStack->getSecurity();
//assert(sec);
DateCategory now;
msg->header(h_Date) = now;
//Data token = msg->getCanonicalIdentityString();
//Data res = sec->computeIdentity( token );
msg->header(h_Identity).value() = Data::Empty;
}
setOutbound( *msg );
//ErrLog( "About to send " << *msg );
mStack->send( *msg );
delete body;
}
void
TuIM::processRequest(SipMessage* msg)
{
if ( msg->header(h_RequestLine).getMethod() == MESSAGE )
{
processMessageRequest(msg);
return;
}
if ( msg->header(h_RequestLine).getMethod() == SUBSCRIBE )
{
processSubscribeRequest(msg);
return;
}
if ( msg->header(h_RequestLine).getMethod() == REGISTER )
{
processRegisterRequest(msg);
return;
}
if ( msg->header(h_RequestLine).getMethod() == NOTIFY )
{
processNotifyRequest(msg);
return;
}
InfoLog(<< "Don't support this METHOD, send 405" );
SipMessage * resp = Helper::make405( *msg, IMMethodList, IMMethodListSize );
mStack->send(*resp);
delete resp;
}
void
TuIM::processSipFrag(SipMessage* msg)
{
Contents* contents = msg->getContents();
if ( !contents )
{
InfoLog(<< "Received message with no contents" );
return;
}
InfoLog(<< "Received message with body contents" );
assert( contents );
Mime mime = contents->getType();
DebugLog ( << "got body of type " << mime.type() << "/" << mime.subType() );
Data signedBy;
#if defined( USE_SSL )
SignatureStatus sigStat = SignatureNone;
MultipartSignedContents* mBody = dynamic_cast<MultipartSignedContents*>(contents);
if ( mBody )
{
Security* sec = mStack->getSecurity();
assert(sec);
contents = sec->checkSignature( mBody, &signedBy, &sigStat );
if ( !contents )
{
InfoLog( << "Some problem decoding multipart/signed message");
return;
}
InfoLog( << "Signed by " << signedBy << " stat = " << sigStat );
}
#endif
if ( contents )
{
MultipartMixedContents* mixed = dynamic_cast<MultipartMixedContents*>(contents);
if ( mixed )
{
InfoLog( << "Got a multipart mixed" );
contents = NULL;
MultipartMixedContents::Parts& parts = mixed->parts();
for( MultipartMixedContents::Parts::const_iterator i = parts.begin();
i != parts.end();
++i)
{
Contents* c = *i;
assert( c );
InfoLog ( << "mixed has a " << c->getType() );
if ( c->getType() == Mime("application","sipfrag") )
{
InfoLog ( << "mixed has sipfrag " << c->getType() );
SipFrag* frag = dynamic_cast<SipFrag*>(c);
if ( frag )
{
InfoLog( << "Got a sipFrag inside mixed" );
SipMessage& m = frag->message();
InfoLog( <<"Frag is " << m );
}
}
}
}
}
if ( contents )
{
SipFrag* frag = dynamic_cast<SipFrag*>(contents);
if ( frag )
{
InfoLog( << "Got a sipFrag" );
SipMessage& m = frag->message();
InfoLog( <<"Frag is " << m );
}
else
{
InfoLog ( << "Can not handle type " << contents->getType() );
return;
}
}
}
void
TuIM::processSubscribeRequest(SipMessage* msg)
{
assert( msg->header(h_RequestLine).getMethod() == SUBSCRIBE );
CallId id = msg->header(h_CallId);
processSipFrag( msg );
int expires=mSubscriptionTimeSeconds;
if ( msg->exists(h_Expires) )
{
expires = msg->header(h_Expires).value();
}
if (expires > mSubscriptionTimeSeconds )
{
expires = mSubscriptionTimeSeconds;
}
DeprecatedDialog* dialog = NULL;
// see if we already have this subscription
for ( SubscriberIterator i=mSubscribers.begin(); i != mSubscribers.end(); i++)
{
DeprecatedDialog* d = i->dialog;
assert( d );
if ( d->getCallId() == id )
{
// found the subscrition in list of current subscrbtions
dialog = d;
break;
}
}
if ( !dialog )
{
// create a new subscriber
DebugLog ( << "Creating new subscrition dialog ");
Subscriber s;
s.dialog = new DeprecatedDialog( NameAddr(mContact) );
dialog = s.dialog;
Uri from = msg->header(h_From).uri();
s.aor = from.getAorNoPort();
assert( mCallback );
s.authorized = mCallback->authorizeSubscription( from );
mSubscribers.push_back( s );
}
assert( dialog );
dialog->setExpirySeconds( expires );
auto_ptr<SipMessage> response( dialog->makeResponse( *msg, 200 ));
response->header(h_Expires).value() = expires;
response->header(h_Event).value() = Data("presence");
mStack->send( *response );
sendNotify( dialog );
#if 1
// do symetric subscriptions
// See if this person is our buddy list and if we are not subscribed to them
UInt64 now = Timer::getTimeMs();
Uri from = msg->header(h_From).uri();
for ( BuddyIterator i=mBuddies.begin(); i != mBuddies.end(); i++)
{
Data buddyAor = i->uri.getAor();
if ( ! (i->presDialog->isCreated()) )
{
if ( from.getAor() == i->uri.getAor() )
{
if ( from.getAor() != mAor.getAor() )
{
i->mNextTimeToSubscribe = now;
}
}
}
}
#endif
}
void
TuIM::processRegisterRequest(SipMessage* msg)
{
assert( msg->header(h_RequestLine).getMethod() == REGISTER );
CallId id = msg->header(h_CallId);
int expires = msg->header(h_Expires).value();
if ( expires == 0 )
{
expires = 3600;
}
SipMessage* response = Helper::makeResponse( *msg, 200 );
// the Contacts from the default Helper are wrong for a Registration
response->remove(h_Contacts);
if ( msg->exists(h_Contacts) )
{
ParserContainer<NameAddr> &providedContacts(msg->header(h_Contacts));
int multipleContacts = providedContacts.size();
DebugLog ( << multipleContacts << " contacts were in received message." );
ParserContainer<NameAddr>::iterator i(providedContacts.begin());
for ( ; i != providedContacts.end() ; ++ i) {
if ( i->isAllContacts() && multipleContacts ) // oops, multiple Contacts and one is "*"
{
delete response; // do I need to do this?
response = Helper::makeResponse( *msg, 400 );
mStack->send( *response );
delete response;
return;
}
if ( !i->exists(p_expires) ) // add expires params where they don't exist
{
i->param(p_expires) = expires;
}
response->header(h_Contacts).push_back(*i); // copy each Contact into response
}
}
// else the REGISTER is a query, just send the message with no Contacts
mStack->send( *response );
delete response;
}
void
TuIM::processNotifyRequest(SipMessage* msg)
{
assert( mCallback );
assert( msg->header(h_RequestLine).getMethod() == NOTIFY );
processSipFrag( msg );
auto_ptr<SipMessage> response( Helper::makeResponse( *msg, 200 ));
mStack->send( *response );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -