عملکرد پروتکل XMPP
در این بخش می خواهیم عملکرد پروتکل XMPP را در یک پیام رسان، با ایجاد یک مثالی از یک ارتباط فرضی، برای شما بیان کنیم.
جزییات بیشتری از شروع یک ارتباط کلاینت با سرور یا (سرور به سرور) در زیر می آید که در آن از قابلیت namespace
زبان XML استفاده می شود. ابتدا یک طرف برای شروع ارتباط اقدام می نماید و در جواب، سرور یک تگ stream
می فرستد که حاوی یک id
می باشد و به نوعی session id
محسوب می شود.
سپس، سرور می تواند شرایطی را برای ادامه ارتباط تعیین کند، مانند احراز هویت، Authentication و امنیت کانال ارتباطی یا Confidentiality. این شرایط در قالب یک تگ <stream:features>
به طرف شروع کننده ارسال می شود.
اولین مورد Handshake TLS است که امنیت و نبود شنود ارتباط را تامین می کند و به صورت زیر انجام می شود. البته استفاده از TLS در ارتباط کلاینت با سرور به معنی encryption end to end نیست و به این منظور از یک XMPP Extension به نام OMEMO استفاده می شود.
R: <stream:features>
<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'>
<required/>
</starttls>
</stream:features>
I: <starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>
If Success:
R: <proceed xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>If Failure:
R: <failure xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>
Closing Stream:
R: </stream:stream>
در صورت موفقیت در برقراری TLS دوباره کلاینت یک تگ stream
جدید ارسال می کند و سرور با تگ stream
با id
جدید پاسخ می دهد و برای Authentication ، SASL Handshake را شروع می کند.
I: <?xml version='1.0'?>
<stream:stream
from='juliet@im.example.com'
to='im.example.com'
version='1.0'
xml:lang='en'
xmlns='jabber:client'
xmlns:stream='http://etherx.jabber.org/streams'>
R: <?xml version='1.0'?>
<stream:stream
from='im.example.com'
id='++TR84Sm6A3hnt3Q065SnAbbk3Y='
to='juliet@im.example.com'
version='1.0'
xml:lang='en'
xmlns='jabber:client'
xmlns:stream='http://etherx.jabber.org/streams'>
طرف شروع کننده ارتباط متناسب با یکی از مکانیسم های مطرح شده می تواند تگ <auth/>
را بفرستد و پاسخ موفقیت یا شکست را دریافت نماید.
R: <stream:features>
<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>
<mechanism>EXTERNAL</mechanism>
<mechanism>SCRAM-SHA-1-PLUS</mechanism>
<mechanism>SCRAM-SHA-1</mechanism>
<mechanism>PLAIN</mechanism>
</mechanisms>
</stream:features>
I: <auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl'
mechanism='PLAIN'>AGp1bGlldAByMG0zMG15cjBtMzA=</auth>
If Success:
R: <success xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/>
If Failure:
R: <failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>
<not-authorized/>
</failure>
در صورت موفقیت، دوباره تگ <stream>
ارسال شده و با id
جدید دریافت می شود و سرور عملیات resource binding
را شروع می کند. resource binding
اجازه می دهد کاربر با یک JID
بتواند به وسیله دستگاه های مختلف به سرور متصل شود. در مثال زیر کاربر با فرستادن تگ <iq>
از سرور می خواهد که یک resource
به صورت تصادفی به او اختصاص دهد و سرور با ارسال JID
شامل resource
به کاربر پاسخ می دهد.
S: <stream:features>
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/>
</stream:features>
C: <iq id='tn281v37' type='set'>
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/>
</iq>
S: <iq id='tn281v37' type='result'>
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'>
<jid>
juliet@im.example.com/4db06f06-1ea4-11dc-aca3-000bcd821bfb
</jid>
</bind>
</iq>
پس از این مرحله کلاینت می تواند در قالب تگ <message>
پیام خود را ارسال کند.( attribute های to و from حتما باید معین باشد). و از طرف مقابل پاسخ دریافت کند.
C: <message from='juliet@im.example.com/balcony'
id='ju2ba41c'
to='romeo@example.net'
type='chat'
xml:lang='en'>
<body>Hello Romeo!</body>
</message>
E: <message from='romeo@example.net/orchard'
id='ju2ba41c'
to='juliet@im.example.com/balcony'
type='chat'
xml:lang='en'>
<body>Hi Juliet! </body>
</message>
همچنین کلاینت می تواند وضعیت آنلاین بودن خود را به وسیله تگ <presence>
ارسال کند. در این مثال از قابلیت چند زبانه بودن XML استفاده شده است. وقتی یک کلاینت presence خود را اعلام می کند، سرور باید این اعلام را به تمام کلاینت هایی که برای این کلاینت subscribe کرده اند، بفرستد.
<presence from='romeo@example.net/orchard' xml:lang='en'>
<show>dnd</show>
<status>Wooing Juliet</status>
<status xml:lang='cs'>Dvořím se Julii</status>
</presence>
سومین نوع XML stanza که برای درخواست اطلاعات کلاینت از سرور استفاده می شود، Info/Query
است که با تگ <iq>
ارسال می شود و attribute های type
و id
حتما باید معین باشد. مثلا برای مدیریت لیست contact
ها که roster
نامیده می شود از این تگ استفاده می شود. مثال زیر برای دریافت لیست کاربران از سرور است و سرور با تگ item
افراد موجود در لیست را ارسال می کند.
همچنین برای اضافه کردن یا حذف افراد از لیست کاربران query های مشابهی با تگ <iq>
تعریف می شود.
C: <iq from='juliet@example.com/balcony'
id='bv1bs71f'
type='get'>
<query xmlns='jabber:iq:roster'/>
</iq>S: <iq id='bv1bs71f'
to='juliet@example.com/chamber'
type='result'>
<query xmlns='jabber:iq:roster' ver='ver7'>
<item jid='nurse@example.com'/>
<item jid='romeo@example.net'/>
</query>
</iq>
همچنین هر تگ <item>
می تواند برای دسته بندی کاربران، تعدادی تگ <group>
داشته باشد که کاربر می تواند آن را با ارسال درخواست <iq>
تنظیم کند.
C: <iq from='juliet@example.com/balcony'
id='lf72v157'
type='set'>
<query xmlns='jabber:iq:roster'>
<item jid='romeo@example.net'
name='Romeo'>
<group>Lovers</group>
</item>
</query>
</iq>
برای حذف یک کاربر از لیست roster می توان به طریق زیر درخواست داد و attribute subscription را برابر remove قرار داد.
C: <iq from='juliet@example.com/balcony'
id='hm4hs97y'
type='set'>
<query xmlns='jabber:iq:roster'>
<item jid='nurse@example.com'
subscription='remove'/>
این بود خلاصه ای از عملکرد پروتکل XMPP که بسیاری از نیازمندی های لازم برای یک سیستم پیام رسانی را تعریف کرده است. همچنین جزییاتی مانند Error-Handling در شرایط مختلف و همین طور جلوگیری از مشکلات امنیتی را معین کرده که برای مطالعه بیشتر بهRFC 6120 و RFC 6121 می توان مراجعه کرد. در ضمن، Extension های مختلفی برای افزودن قابلیت های پیشرفته تر مثل Group Chat، ارسال فایل، تماس صوتی و تصویری، پیاده سازی روی Web به کمک WebSocket اضافه شده که لیست آن ها را در اینجا می توانید ببینید.