sipfsm 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. checksums.yaml +15 -0
  2. data/lib/sipfsm.rb +306 -0
  3. metadata +60 -0
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: !binary |-
4
+ ZmNhMzE5N2M0NTc1YWE1NzMwY2YzYTcwOGIyMTU4YjViOTg2ZWQ1ZA==
5
+ data.tar.gz: !binary |-
6
+ ZTkxYzE1NmJkN2JjNTJlZTNiMjRkZmMxZTk3NGQ2MWJiNDhjZmJiMQ==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ MWZjNmQ3MzA3ZDVmNjE5MjM1ODU2MjU3OTM0M2UxMmM4NmMxYmNmMjJlNzZh
10
+ NGExYjQ3YzlhNTg3MDFiNWQ4MmVkNzE5ZWY4MTZjMzcxYWM5ZGMzYTBhNjNh
11
+ MzU5MDljYWQ2NGViMzg4ZGExYTBmNTBkYzliNmVjZTMxOTQ1NjU=
12
+ data.tar.gz: !binary |-
13
+ YjNiMDhkMTU0NTVhZTRjZjdiZDAxZjdmODgxOGM0ZTg0ZTcyMDI0Yjk2NDE3
14
+ Y2YzMDgwNTliMzk1NmVhOWZlZDA1NDU4YmM3ZjI2ZDY5Y2IzZjRkOTgzOGM4
15
+ ZGE2NTQzMGQyZTdiZGU3MWJhMGRhYTk3NTg5MDYzMTc1ZDUzZGI=
data/lib/sipfsm.rb ADDED
@@ -0,0 +1,306 @@
1
+ require 'java'
2
+ require 'simplefsm'
3
+
4
+ # SipFSM
5
+ # SIP application development using SimpleFSM DSL
6
+
7
+ module SipFSM
8
+ class SipFSM < Java::javax.servlet.sip.SipServlet
9
+ include javax.servlet.sip.TimerListener
10
+ include javax.servlet.sip.SipSessionListener
11
+
12
+ include SimpleFSM
13
+ FSM_STATE_ATTR = 'sipFSM_STATE'
14
+
15
+ # Method service is overriden in order to get servlet context.
16
+ # Then the service method of the Java base class is called.
17
+ def service(req, res)
18
+ msg = req || res
19
+ $servlet_context = msg.session.servlet_context if !$servlet_context
20
+ super
21
+ end
22
+
23
+ # Standard SIP servlet request dispatching
24
+ # is overriden and modified to call the DSL event methods.
25
+ def doRequest(request)
26
+ m = request.get_method
27
+ fsmm = "sip#{m}".to_sym
28
+ run if !fsm_prepare_state([request, nil])
29
+
30
+ if fsm_state_responds_to? @state, fsmm
31
+ send(fsmm, request, nil)
32
+ elsif fsm_state_responds_to? @state, :sipREQUEST_ANY
33
+ send(:sipREQUEST_ANY, request, nil)
34
+ else
35
+ super
36
+ end
37
+ end
38
+
39
+ # Standard SIP servlet response dispatching
40
+ # is overriden and modified to call the DSL event methods.
41
+ def doResponse(response)
42
+ m = response.get_status.to_s
43
+ run if ! fsm_prepare_state([nil, response])
44
+
45
+ resp_exact = "sipRESPONSE_#{m}".to_sym
46
+ resp_group = "sipRESPONSE_#{m[/./].to_s}xx".to_sym
47
+
48
+ if fsm_state_responds_to? @state, resp_exact
49
+ send(resp_exact, nil, response)
50
+
51
+ elsif fsm_state_responds_to? @state, resp_group
52
+ send(resp_group, nil, response)
53
+
54
+ elsif fsm_state_responds_to? @state, :sipRESPONSE_ANY
55
+ send(:sipRESPONSE_ANY, nil, response)
56
+
57
+ else
58
+ super
59
+ end
60
+ end
61
+
62
+ # creates and returns INVITE request
63
+ def self.create_request(app_session, method, from, to)
64
+ sip_factory = $servlet_context.get_attribute('javax.servlet.sip.SipFactory')
65
+ addr_from = sip_factory.create_address(sip_factory.create_uri(from[:uri]), from[:display_name])
66
+ addr_to = sip_factory.create_address(sip_factory.create_uri(to[:uri]), to[:display_name])
67
+
68
+ req = sip_factory.create_request(app_session, method, addr_from, addr_to);
69
+ req
70
+ end
71
+
72
+ # returns application session
73
+ def self.get_application_session_by_id(app_session_id)
74
+ return nil if !app_session_id
75
+ util = $servlet_context.get_attribute('javax.servlet.sip.SipSessionsUtil')
76
+ util.get_application_session_by_id(app_session_id)
77
+ end
78
+
79
+ # returns sip application session or creates one if flag is true
80
+ def self.http_get_application_session(http_request, create_flag, key_sufix="")
81
+ # HttpSession <=> ConvergedHttpSession
82
+ sid = http_request.env['java.servlet_request'].get_session().get_id
83
+
84
+ util = $servlet_context.get_attribute('javax.servlet.sip.SipSessionsUtil')
85
+ app_key = "sipfsmApp_#{key_sufix}#{sid}"
86
+ app = util.get_application_session_by_key(app_key, create_flag)
87
+ app
88
+ end
89
+
90
+ # returns sip-fsm state saved in application session attribute
91
+ def self.get_fsm_state_by_app_id(app_session_id)
92
+ return nil if !app_session_id
93
+ app_session = get_application_session_by_id(app_session_id)
94
+ if app_session
95
+ app_session.get_attribute(FSM_STATE_ATTR)
96
+ else
97
+ nil
98
+ end
99
+ end
100
+
101
+ # returns all SIP sessions bound to the given application session
102
+ def self.get_sip_sessions_by_app_id(app_session_id)
103
+ return nil if !app_session_id
104
+ app_session = get_application_session_by_id(app_session_id)
105
+ app_session.get_sessions("SIP")
106
+ end
107
+
108
+ def self.get_attr_const
109
+ FSM_STATE_ATTR
110
+ end
111
+
112
+ def prepare_state_by_req msg
113
+ fsm_prepare_state [msg, nil]
114
+ end
115
+
116
+ private
117
+ ##### Overriden methods (for FSM) ###########################
118
+
119
+ # Loading and saving application FSM state from application attribute
120
+ def fsm_prepare_state msgs
121
+ m = msgs[0] || msgs[1]
122
+
123
+ @sip_session = m.get_session
124
+ @app_session = m.get_application_session
125
+ s = @app_session.get_attribute(FSM_STATE_ATTR)
126
+ @state = s if s
127
+ s
128
+ end
129
+
130
+
131
+ def fsm_save_state request
132
+ @app_session.set_attribute(FSM_STATE_ATTR, @state)
133
+ @state
134
+ end
135
+
136
+ ####### Helper methods ###############
137
+
138
+ # Dynamic methods:
139
+ # send_response_YYY - for sending response with
140
+ # the code specified in the method name (send_response_200 etc.)
141
+ # is_XXX? - check if the SIP request is of type (method) specified
142
+ # in the method name (is_INVITE? etc.)
143
+ #
144
+ def method_missing(name, args)
145
+ if name.to_s =~ /send_response_(.*)/
146
+ args[0].create_response($1.to_i).send
147
+ elsif name.to_s =~ /is_(.*)_request?/
148
+ args[0].get_method == $1
149
+ end
150
+ end
151
+
152
+ # proxy request to given URI
153
+ def proxy_to_helper(request, touri, recroute=false)
154
+ l_proxy = request.get_proxy
155
+ l_proxy.set_record_route(recroute)
156
+
157
+ to_URI = create_uri touri
158
+ l_proxy.proxy_to(to_URI)
159
+
160
+ end
161
+
162
+ # creates URI java object using SipFactory
163
+ def create_uri(str_uri)
164
+ if @sip_session
165
+ sipURI = @sip_session.get_servlet_context.get_attribute('javax.servlet.sip.SipFactory').create_uri('sip:' + str_uri)
166
+ sipURI
167
+ else
168
+ nil
169
+ end
170
+ end
171
+
172
+
173
+ # copies content (SDP) from message m1 to message m2
174
+ def copy_msg_content(m1, m2)
175
+ if m1.get_content_length > 0
176
+ m2.set_content(m1.get_raw_content, m1.get_content_type)
177
+
178
+ enc = m1.get_character_encoding
179
+ m2.set_character_encoding(enc) if enc and enc.length > 0
180
+ end
181
+ end
182
+
183
+ # Sends SIP request and sets custom session attributes
184
+ # given in a hash as a second element in attributes
185
+ def send_req args
186
+ req = args[0]
187
+ if args.size > 2
188
+ attrib = args[2]
189
+ end
190
+ s = req.get_session
191
+ s.set_handler(self.class.to_s)
192
+ if attrib and attrib.size > 0 and attrib.class = Hash
193
+ attrib.each do |k, v|
194
+ s.set_attribute(k.to_s, v)
195
+ end
196
+ end
197
+ req.send
198
+ end
199
+
200
+ ###########################################################
201
+ # Methods that can be called directly from FSM definition.
202
+ # All methods have atributes according to the SipFSM standard
203
+ # meaning the first in the argument array is request and
204
+ # the second is response.
205
+
206
+ def invalidate_session msgs
207
+ msg = msgs[0] || msgs[1]
208
+ msg.get_session.invalidate
209
+ # ACK is sent by the SIP servlets container
210
+ end
211
+
212
+ def send_OK msgs
213
+ req = msgs[0]
214
+ req.create_response(200).send
215
+ end
216
+
217
+ def send_ACK msgs
218
+ res = msgs[1]
219
+ res.create_ack.send
220
+ end
221
+
222
+ def send_BYE msgs
223
+ req, res = msgs
224
+ m = req || res
225
+ m.get_session.create_request("BYE").send
226
+ end
227
+
228
+ def cancel_req args
229
+ req = args[0]
230
+ req.create_cancel.send
231
+ req.session.invalidate
232
+ end
233
+
234
+ # B2B Helper methods ##################################
235
+
236
+ # forwards request to the linked session (B2BUA Helper)
237
+ def b2b_forward_message msgs
238
+ req, res = msgs
239
+ r = req || res.get_request
240
+ begin
241
+ b2b = r.get_b2bua_helper
242
+ linked = b2b.get_linked_session(r.get_session)
243
+ if linked
244
+ other_leg = nil
245
+ resp_session = res.get_session
246
+ resp_request = res.get_request
247
+ if resp_request.is_initial
248
+ other_leg = b2b.create_response_to_original_request(linked, res.get_status, res.get_reason_phrase)
249
+ else
250
+ other_req = b2b.get_linked_sip_servlet_request(resp_request)
251
+ other_leg = other_req.create_response(res.get_status, res.get_reason_phrase)
252
+ end
253
+ copy_msg_content(res, other_leg)
254
+ other_leg.send
255
+ else
256
+ raise "No linked session."
257
+ end
258
+ rescue Exception => e
259
+ puts "Error: #{e.message}"
260
+ end
261
+ end
262
+
263
+ # send BYE to the linked session
264
+ def b2bua_BYE_other msgs
265
+ req, res = msgs
266
+ req ||= res.get_request
267
+ current_sess = req.get_session
268
+ b2b = req.get_b2bua_helper
269
+ session2 =
270
+ b2b.get_linked_session(current_sess)
271
+ session2.create_request("BYE").send
272
+ end
273
+
274
+ # send BYE to both linked session
275
+ def b2bua_BYE_both msgs
276
+ req, res = msgs
277
+ req ||= res.request
278
+ session1 = req.session
279
+ session2 = req.b2bua_helper.get_linked_session(session1)
280
+ session1.create_request("BYE").send
281
+ session2.create_request("BYE").send
282
+ session1.invalidate
283
+ session2.invalidate
284
+ end
285
+
286
+ # Send initial request using B2BUA helper.
287
+ # The third and other argument array elements
288
+ # can be attributes to save into the SIP session.
289
+ def b2b_send_initial_req args
290
+ req = args[0]
291
+ if args.size > 2
292
+ attrib = args[2]
293
+ end
294
+ new_req = req.b2bua_helper.create_request(req)
295
+ s = new_req.session
296
+ s.set_attribute('initialINVITE', new_req)
297
+ if attrib and attrib.size > 0 and attrib.is_a?(Hash)
298
+ attrib.each do |k, v|
299
+ s.set_attribute(k.to_s, v)
300
+ end
301
+ end
302
+ new_req.send
303
+ end
304
+
305
+ end
306
+ end
metadata ADDED
@@ -0,0 +1,60 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sipfsm
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.2
5
+ platform: ruby
6
+ authors:
7
+ - Edin Pjanic
8
+ - Amer Hasanovic
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-02-15 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: simplefsm
16
+ version_requirements: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: '0.1'
21
+ requirement: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '0.1'
26
+ prerelease: false
27
+ type: :runtime
28
+ description: SIP application development in Ruby using SimpleFSM, a simple and lightweight domain specific language (DSL).
29
+ email:
30
+ - edin@ictlab.com.ba
31
+ - amer@ictlab.com.ba
32
+ executables: []
33
+ extensions: []
34
+ extra_rdoc_files: []
35
+ files:
36
+ - lib/sipfsm.rb
37
+ homepage: http://github.com/edictlab/SipFSM
38
+ licenses: []
39
+ metadata: {}
40
+ post_install_message:
41
+ rdoc_options: []
42
+ require_paths:
43
+ - lib
44
+ required_ruby_version: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ required_rubygems_version: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ requirements: []
55
+ rubyforge_project:
56
+ rubygems_version: 2.0.3
57
+ signing_key:
58
+ specification_version: 4
59
+ summary: SipFSM - SIP application development in Ruby
60
+ test_files: []