sipfsm 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
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: []