Project

General

Profile

SipMSRPApi » History » Version 39

Luci Stanescu, 04/15/2010 01:32 PM

1 1 Adrian Georgescu
= MSRP API =
2
3 34 Adrian Georgescu
[[TOC(SipMSRPApi, SipDeveloperGuide, depth=3)]]
4 1 Adrian Georgescu
5 31 Adrian Georgescu
Message Session Relay Protocol (MSRP) is a protocol for transmitting a series of related Instant Messages in the context of a session. Message sessions are treated like any other media stream when set up via a rendezvous or session creation protocol such as the Session Initiation Protocol (SIP). 
6 1 Adrian Georgescu
7 25 Adrian Georgescu
 * MSRP sessions are defined in [http://tools.ietf.org/html/rfc4975 RFC 4975]
8
 * MSRP relay extension used for NAT traversal of instant messaging and file transfer sessions is defined in [http://tools.ietf.org/html/rfc4976 RFC 4976]
9 1 Adrian Georgescu
10 32 Adrian Georgescu
The MSRP protocol stack is implemented by [http://devel.ag-projects.com/cgi-bin/darcsweb.cgi?r=python-msrplib;a=summary msrplib] Python package. 
11 4 Oliver Bril
12 33 Adrian Georgescu
{{{msrplib}}} is based upon [http://twistedmatrix.com twisted] and [http://download.ag-projects.com/SipClient/ eventlet] and provides a set of classes for establishing and managing MSRP connections.
13 1 Adrian Georgescu
14 28 Adrian Georgescu
The library consists of the following modules:
15 1 Adrian Georgescu
16
 '''msrplib.transport'''::
17 27 Adrian Georgescu
 Defines {{{MSRPTransport}}} class, which provides low level control over MSRP connections.
18 2 Redmine Admin
19 1 Adrian Georgescu
 '''msrplib.connect'''::
20
 Defines means to establish a connection, bind it, and provide an initialized {{{MSRPTransport}}} instance.
21
22
 '''msrplib.session'''::
23
 Defines {{{MSRPSession}}} class, which provides high level control over a MSRP connection.
24
25
 '''msrplib.protocol'''::
26 27 Adrian Georgescu
 Provides representation and parsing of MSRP entities - chunks and MSRP URIs.
27 1 Adrian Georgescu
28
 '''msrplib.trafficlog'''::
29
 Defines {{{Logger}}} class that is used through out the library to log the connection state.
30
  
31
32 39 Luci Stanescu
== Classes ==
33 3 Oliver Bril
34 39 Luci Stanescu
=== URI ===
35 1 Adrian Georgescu
36 39 Luci Stanescu
 This class is implemented in the {{{msrplib.protocol}}} module and is used to represent an MSRP URI.
37 1 Adrian Georgescu
38 39 Luci Stanescu
==== Methods ====
39 1 Adrian Georgescu
40 39 Luci Stanescu
 '''!__init!__'''(''self'', '''host'''={{{None}}}, '''use_tls'''={{{False}}}, '''user'''={{{None}}}, '''port'''={{{None}}}, '''session_id'''={{{None}}}, '''parameters'''={{{None}}}, '''credentials'''={{{None}}})::
41
  Constructs a new {{{URI}}}. All the arguments specified here are also attributes on the object. For more information on these attributes, see RFC4975.
42
  [[BR]]''host'':[[BR]]
43
  The hostname or IP address which forms the URI.
44
  [[BR]]''use_tls'':[[BR]]
45
  Whether this identifies an msrps or msrp URI.
46
  [[BR]]''user'':[[BR]]
47
  The user part of the URI.
48
  [[BR]]''port'':[[BR]]
49
  The port in the URI.
50
  [[BR]]''session_id'':[[BR]]
51
  The session identifier part of the URI.
52
  [[BR]]''parameters'':[[BR]]
53
  A {{{dict}}} containing the parameters which will be appended to the URI.
54
  [[BR]]''credentials'':[[BR]]
55
  A {{{gnutls.interfaces.twisted.X509Credentials}}} object which will be used if this identifies a TLS URI to authenticate to the other endpoint.
56 1 Adrian Georgescu
57 39 Luci Stanescu
=== MSRPRelaySettings ===
58 1 Adrian Georgescu
59 39 Luci Stanescu
 This class is used to specify the MSRP relay which will be used when connecting via a relay (using the {{{ConnectorRelay}}} or {{{AcceptorRelay}}} classes).
60
61
==== Methods ====
62
63
 '''!__init!__'''(''self'', '''domain''', '''username''', '''password''', '''host'''={{{None}}}, '''use_tls'''={{{False}}}, '''port'''={{{None}}}, '''credentials'''={{{None}}})::
64
  Constructs a new {{{URI}}}. All the arguments specified here are also attributes on the object. For more information on these attributes, see RFC4975.
65
  [[BR]]''domain'':[[BR]]
66
  The DNS domain in which to search for a MSRP relay using SRV queries.
67
  [[BR]]''username'':[[BR]]
68
  The username which will be used to authenticate to the relay.
69
  [[BR]]''password'':[[BR]]
70
  The password which will be used to authenticate to the relay.
71
  [[BR]]''host'':[[BR]]
72
  The hostname or IP address of the MSRP relay.
73
  [[BR]]''use_tls'':[[BR]]
74
  Whether this identifies an msrps or msrp URI.
75
  [[BR]]''port'':[[BR]]
76
  The port in the URI.
77
  [[BR]]''credentials'':[[BR]]
78
  A {{{gnutls.interfaces.twisted.X509Credentials}}} object which will be used to authenticate to the relay if TLS is used.
79
80
=== ConnectorDirect ===
81
82
 This class is implemented in the {{{msrplib.connect}}} module and is used for outbound MSRP connections without a relay.
83
84
==== Methods ====
85
86
 '''!__init!__'''(''self'', '''loger'''={{{None}}})::
87
  Constructs a new ConnectorDirect.
88
 [[BR]]''logger'':[[BR]]
89
 The logger which will be used for this MSRP connection. See the [wiki:SipMSRPApi#Logging Logging] section for more information.
90
91
 '''prepare'''(''self'', '''local_uri'''={{{None}}})::
92
 This method returns a full local path - list of {{{protocol.URI}}} instances, suitable to be put in SDP {{{'a:path'}}} attribute.
93
 [[BR]]''local_uri'':[[BR]]
94
 This attribute will be used to construct the local path, but other than that it is not used anywhere else in case of the ConnectorDirect. If not provided, one
95
 will be automatically generated
96 1 Adrian Georgescu
 
97 39 Luci Stanescu
 '''complete'''(''self'', '''full_remote_path''')::
98
 This method establishes the connection and binds it (sends an empty chunk to verify each other's From-Path and To-Path). It returns {{{transport.MSRPTransport}}} instance, ready to read and send chunks.
99
 [[BR]]''full_remote_path'':[[BR]]
100
 A list of {{{protocol.URI}}} instances, obtained by parsing {{{'a:path'}}} put in SDP by the remote party.
101 1 Adrian Georgescu
102 39 Luci Stanescu
 '''cleanup'''(''self'')::
103
 This method cleans up after {{{prepare()}}}; it should be called if {{{complete()}}} will not be called for whatever reason.
104 1 Adrian Georgescu
105 39 Luci Stanescu
=== ConnectorRelay ===
106 1 Adrian Georgescu
107 39 Luci Stanescu
 This class is implemented in the {{{msrplib.connect}}} module and is used for outbound MSRP connections using a relay.
108 1 Adrian Georgescu
109 39 Luci Stanescu
==== Methods ====
110
111
 '''!__init!__'''(''self'', '''relay''', '''loger'''={{{None}}})::
112
 Constructs a new ConnectorRelay.
113
 [[BR]]''relay'':[[BR]]
114
 An instance of {{{MSRPRelaySettings}}} which identifies the relay which is to be used.
115
 [[BR]]''logger'':[[BR]]
116
 The logger which will be used for this MSRP connection. See the [wiki:SipMSRPApi#Logging Logging] section for more information.
117
118
 '''prepare'''(''self'', '''local_uri'''={{{None}}})::
119
 This method returns a full local path - list of {{{protocol.URI}}} instances, suitable to be put in SDP {{{'a:path'}}} attribute.
120
 [[BR]]''local_uri'':[[BR]]
121
 This attribute will be used to construct the local path, but other than that it is not used anywhere else in case of the ConnectorRelay. If not provided, one
122
 will be automatically generated
123
 
124
 '''complete'''(''self'', '''full_remote_path''')::
125
 This method establishes the connection to the relay and binds it (sends an empty chunk to verify each other's From-Path and To-Path). It returns {{{transport.MSRPTransport}}} instance, ready to read and send chunks.
126
 [[BR]]''full_remote_path'':[[BR]]
127
 A list of {{{protocol.URI}}} instances, obtained by parsing {{{'a:path'}}} put in SDP by the remote party.
128
129 1 Adrian Georgescu
 '''cleanup'''(''self'')::
130 39 Luci Stanescu
 This method cleans up after {{{prepare()}}}; it should be called if {{{complete()}}} will not be called for whatever reason.
131 1 Adrian Georgescu
132 39 Luci Stanescu
=== AcceptorDirect ===
133 1 Adrian Georgescu
134 39 Luci Stanescu
 This class is implemented in the {{{msrplib.connect}}} module and is used for inbound MSRP connections without using a relay.
135 1 Adrian Georgescu
136 39 Luci Stanescu
==== Methods =====
137
138
 '''!__init!__'''(''self'', '''loger'''={{{None}}})::
139
  Constructs a new AcceptorDirect.
140
 [[BR]]''logger'':[[BR]]
141
 The logger which will be used for this MSRP connection. See the [wiki:SipMSRPApi#Logging Logging] section for more information.
142
143
 '''prepare'''(''self'', '''local_uri'''={{{None}}})::
144
 This method starts listening on a socket identified by the parameters in the {{{local_uri}}} argument. It returns a full local path - list of {{{protocol.URI}}} instances, suitable to be put in SDP {{{'a:path'}}} attribute.
145
 [[BR]]''local_uri'':[[BR]]
146
 This attribute will be used to construct the local path and to listen for incomming connections. If not provided, one
147
 will be automatically generated
148
 
149
 '''complete'''(''self'', '''full_remote_path''')::
150
 This method waits for an incoming connection and a chunk sent by the other party. It returns {{{transport.MSRPTransport}}} instance, ready to read and send chunks.
151
 [[BR]]''full_remote_path'':[[BR]]
152
 A list of {{{protocol.URI}}} instances, obtained by parsing {{{'a:path'}}} put in SDP by the remote party. This is checked agains the From-Path header in the binding chunk.
153
154
 '''cleanup'''(''self'')::
155
 This method cleans up after {{{prepare()}}}; it should be called if {{{complete()}}} will not be called for whatever reason.
156
157
=== AcceptorRelay ===
158
159
 This class is implemented in the {{{msrplib.connect}}} module and is used for inbound MSRP connections using a relay.
160
161
==== Methods ====
162
163
 '''!__init!__'''(''self'', '''relay''', '''loger'''={{{None}}})::
164
 Constructs a new AcceptorRelay.
165
 [[BR]]''relay'':[[BR]]
166
 An instance of {{{MSRPRelaySettings}}} which identifies the relay which is to be used.
167
 [[BR]]''logger'':[[BR]]
168
 The logger which will be used for this MSRP connection. See the [wiki:SipMSRPApi#Logging Logging] section for more information.
169
170
 '''prepare'''(''self'', '''local_uri'''={{{None}}})::
171
 This method connects to the relay specified in {{{__init__}}}. It returns a full local path - list of {{{protocol.URI}}} instances, suitable to be put in SDP {{{'a:path'}}} attribute.
172
 [[BR]]''local_uri'':[[BR]]
173
 This attribute will be used to construct the local path. If not provided, one will be automatically generated
174
 
175
 '''complete'''(''self'', '''full_remote_path''')::
176
 This method waits for an incoming chunk sent by the other party. It returns {{{transport.MSRPTransport}}} instance, ready to read and send chunks.
177
 [[BR]]''full_remote_path'':[[BR]]
178
 A list of {{{protocol.URI}}} instances, obtained by parsing {{{'a:path'}}} put in SDP by the remote party. This is checked agains the From-Path header in the binding chunk.
179
180
 '''cleanup'''(''self'')::
181
 This method cleans up after {{{prepare()}}}; it should be called if {{{complete()}}} will not be called for whatever reason.
182
183
=== MSRPTransport ===
184
185
This class is implemented in the {{{msrplib.transport}}} module and provies low level access to the MSRP connection.
186
187
==== Methods ====
188
189
 '''make_chunk'''(''self'', '''transaction_id'''={{{None}}}, '''method'''={{{'SEND'}}}, '''code'''={{{None}}}, '''comment'''={{{None}}}, '''data'''={{{''}}}, '''contflag'''={{{None}}}, '''start'''={{{1}}}, '''end'''={{{None}}}, '''length'''={{{None}}}, '''message_id'''={{{None}}})::
190 1 Adrian Georgescu
 Makes a new chunk ({{{protocol.MSRPData}}} instance) with proper {{{From-Path}}}, {{{To-Path}}}, {{{Byte-Range}}} and {{{Message-ID}}} headers set up based on MSRPTransport's state and the parameters provided. Use ''data'' for payload, and ''start''/''end''/''length'' to generate {{{Byte-Range}}} header. Generate new random strings for default values of ''transaction_id'' and ''message_id''. 
191
 [[BR]]''contflag'':[[BR]]
192
 MSRP chunk's continuation flag ({{{'$'}}}, {{{'+'}}} or {{{'#'}}}). Default is {{{'$'}}}, unless you have a partial {{{SEND}}} chunk, in which case it is {{{'+'}}}
193 14 Oliver Bril
194 39 Luci Stanescu
 '''write'''(''self'', '''bytes''', '''sync'''={{{True}}})::
195 1 Adrian Georgescu
 Writes ''bytes'' to the socket. If ''sync'' is true, waits for an operation to complete.
196
197 39 Luci Stanescu
 '''read_chunk'''(''self'', '''size'''={{{None}}})::
198 1 Adrian Georgescu
 Waits for a new chunk and returns it.
199
 If there was an error, closes the connection and raises {{{ChunkParseError}}}.
200
201 15 Oliver Bril
 In case of unintelligible input, loses the connection and returns {{{None}}}.
202 1 Adrian Georgescu
 When the connection is closed, raises the reason of the closure (e.g. {{{ConnectionDone}}}).
203 27 Adrian Georgescu
204
 If the data already read exceeds ''size'', stops reading the data and returns
205 38 Adrian Georgescu
 a "virtual" chunk, i.e. the one that does not actually correspond the the real
206 1 Adrian Georgescu
 MSRP chunk. Such chunks have Byte-Range header changed to match the number of
207 4 Oliver Bril
 bytes read and continuation that is {{{'+'}}}; they also possess {{{segment}}} attribute,
208 1 Adrian Georgescu
 an integer, starting with 1 and increasing with every new segment of the chunk.
209 15 Oliver Bril
210 27 Adrian Georgescu
 Note, that ''size'' only hints when to interrupt the segment but does not affect
211 1 Adrian Georgescu
 how the data is read from socket. You may have segments bigger than ''size'' and it's
212 15 Oliver Bril
 legal to set ''size'' to zero (which would mean return a chunk as long as you get
213 27 Adrian Georgescu
 some data, regardless how small).
214 15 Oliver Bril
215 39 Luci Stanescu
 '''check_incoming_SEND_chunk'''(''self'', '''chunk''')::
216 15 Oliver Bril
 Checks the 'To-Path' and 'From-Path' of the incoming SEND chunk.
217 1 Adrian Georgescu
 Returns None is the paths are valid for this connection.
218 15 Oliver Bril
 If an error is detected an MSRPError is created and returned.
219 1 Adrian Georgescu
220 39 Luci Stanescu
=== MSRPSession ===
221 15 Oliver Bril
222 39 Luci Stanescu
 This class is implemented in the {{{msrplib.session}}} module and provides a high level API for MSRP sessions.
223
224
==== Methods ====
225
226
 '''!__init!__'''(''self'', '''msrptransport''', '''accept_types'''={{{['*']}}}, '''on_incoming_cb'''={{{None}}})::
227 1 Adrian Georgescu
 Initializes MSRPSession instance. Reports the incoming chunks through ''on_incoming_cb'' callback.
228
229 39 Luci Stanescu
 '''send_chunk'''(''self'', '''chunk''', '''response_cb'''={{{None}}})::
230 1 Adrian Georgescu
 Sends ''chunk''. Report the result via ''response_cb''.
231
232
 When ''response_cb'' argument is present, it will be used to report
233
 the transaction response to the caller. When a response is received or generated
234
 locally, ''response_cb'' is called with one argument. The function must do something
235
 quickly and must not block, because otherwise it would block the reader greenlet.
236
237
 If no response was received after {{{RESPONSE_TIMEOUT}}} seconds,
238
 * 408 response is generated if Failure-Report was {{{'yes'}}} or absent
239
 * 200 response is generated if Failure-Report was {{{'partial'}}} or {{{'no'}}}
240
241
 Note that it's rather wasteful to provide ''response_cb'' argument other than {{{None}}}
242
 for chunks with Failure-Report='no' since it will always fire 30 seconds later
243
 with 200 result (unless the other party is broken and ignores Failure-Report header)
244
245
 If sending is impossible raise {{{MSRPSessionError}}}.
246 38 Adrian Georgescu
247 39 Luci Stanescu
 '''deliver_chunk'''(''self'', '''chunk''', '''event'''={{{None}}})::
248 1 Adrian Georgescu
 Sends the chunk, waits for the transaction response (if Failure-Report header is not {{{'no'}}}).
249
 Returns the transaction response if it's a success, raise {{{MSRPTransactionError}}} if it's not.
250
251
 If chunk's Failure-Report is {{{'no'}}}, returns {{{None}}} immediately.
252
253 39 Luci Stanescu
 '''shutdown'''(''self'', '''sync'''={{{True}}})::
254 1 Adrian Georgescu
 Sends the messages already in queue then close the connection.
255
256 39 Luci Stanescu
=== MSRPServer ===
257 38 Adrian Georgescu
258 39 Luci Stanescu
 This class is implemented in the {{{msrplib.connect}}} module.
259 1 Adrian Georgescu
    
260
 MSRPServer solves the problem with AcceptorDirect: concurrent using of 2
261
 or more AcceptorDirect instances on the same non-zero port is not possible.
262
 If you initialize() those instances, one after another, one will listen on
263
 the socket and another will get BindError.
264
265
 MSRPServer avoids the problem by sharing the listening socket between multiple connections.
266
 It has a slightly different interface from AcceptorDirect, so it cannot be considered a drop-in
267
 replacement.
268
269 39 Luci Stanescu
 It manages the listening sockets and binds incoming requests.
270
271
272
==== Methods ====
273
274 1 Adrian Georgescu
 '''prepare'''(''self'', ''local_uri''={{{None}}}, ''logger''={{{None}}})::
275
 Starts a listening port specified by ''local_uri'' if there isn't one on that port/interface already.
276
 Adds ''local_uri'' to the list of expected URIs, so that incoming connections featuring this URI won't be rejected.
277
 If ''logger'' is provided, it uses it for this connection instead of the default one.
278
279 15 Oliver Bril
 '''complete'''(''self'', ''full_remote_path'')::
280 1 Adrian Georgescu
 Waits until one of the incoming connections binds using provided ''full_remote_path''.
281 15 Oliver Bril
 Returns connected and bounds the {{{MSRPTransport}}} instance.
282
        
283
 If no such binding was made within {{{MSRPBindSessionTimeout.seconds}}}, raise {{{MSRPBindSessionTimeout}}}.
284 38 Adrian Georgescu
 ''full_remote_path'' should be a list of {{{protocol.URI}}} instances, obtained by parsing {{{'a:path'}}} put in SDP by the remote party.
285
286
 '''cleanup'''(''self'', ''local_uri'')::
287
 Removes ''local_uri'' from the list of expected URIs.
288
289 39 Luci Stanescu
== Example ==
290 38 Adrian Georgescu
291
=== Establish a connection ===
292
293
{{{msrplib.connect}}} provides a number of classes to establish a connection, so the first
294
thing to do is to select which one applies to your situation:
295
296
    1. Calling endpoint, not using a relay ({{{ConnectorDirect}}})
297
    2. Answering endpoint, not using a relay ({{{AcceptorDirect}}})
298
    3. Calling endpoint, using a relay ({{{ConnectorRelay}}})
299
    4. Answering endpoint, using a relay ({{{AcceptorRelay}}})
300
301
The answering endpoint may skip using the relay if sure that it's accessible directly, e.g is not behind a NAT. To be sure it works in any network topology a called end-point should always use a relay.
302
303
The calling endpoint does not need a relay as the protocol mandates that it is establishing an outbound connection which always work from behind a NAT.
304
305
Once you have an instance of the right class (use the convenience functions
306
{{{get_connector()}}} and {{{get_acceptor()}}} to get one), the procedure to establish the
307
connection is the same:
308
309
{{{
310
full_local_path = connector.prepare()
311
try:
312
    ... put full_local_path in SDP 'a:path' attribute
313
    ... get full_remote_path from remote's 'a:path: attribute
314
    ... (the order of the above steps is reversed if you're the
315
    ... answering party, but that does not affect connector's usage)
316
    msrptransport = connector.complete(full_remote_path)
317
finally:
318
    connector.cleanup()
319
}}}
320
321
To customize connection's parameters, creates a new {{{protocol.URI}}} object and passes
322
it to prepare() function, e.g.
323
{{{
324
local_uri = protocol.URI(use_tls=False, port=5000)
325
connector.prepare(local_uri)
326
}}}
327
328
{{{prepare()}}} may update {{{local_uri}}} in place with the actual connection parameters
329
used (e.g. if you specified port=0). 'port' attribute of {{{local_uri}}} is currently
330
only respected by {{{AcceptorDirect}}}.
331
332 1 Adrian Georgescu
Note that, acceptors and connectors are one-use only. Which means, that {{{AcceptorDirect}}}
333
will open a port just to handle one incoming connection and close it right after.
334
If your application behaves more like a server, i.e. opens a port and listens on it
335
constantly, use {{{MSRPServer}}} class.