opensips-mi 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,122 @@
1
+ module Opensips
2
+ module MI
3
+ class Response
4
+ attr_reader :code, :success, :message
5
+ attr_reader :rawdata # raw data array
6
+ attr_reader :result # formatted data
7
+
8
+ def initialize(data)
9
+ raise InvalidResponseData,
10
+ 'Invalid parameter' unless data.is_a? Array
11
+ raise EmptyResponseData,
12
+ 'Empty parameter array' if data.empty?
13
+
14
+ if /^(?<code>\d+) (?<message>.+)$/ =~ data.shift.to_s
15
+ @code = code.to_i
16
+ @message = message
17
+ else
18
+ raise InvalidResponseData,
19
+ 'Invalid response parameter. Can not parse'
20
+ end
21
+
22
+ @success = (200..299).include?(@code)
23
+
24
+ # successfull responses have additional new line
25
+ data.pop if @success
26
+ @rawdata = data
27
+ @result = nil
28
+ end
29
+
30
+ # Parse user locations records to Hash
31
+ def ul_dump
32
+ return nil unless /^Domain:: location table=\d+ records=(\d+)$/ =~ @rawdata.shift
33
+ records = Hash.new
34
+ aor = ''
35
+ @rawdata.each do |r|
36
+ if /\tAOR:: (?<peer>.+)$/ =~ r
37
+ aor = peer
38
+ records[aor] = Hash.new
39
+ end
40
+ if /^\t{2,3}(?<key>[^:]+):: (?<val>.*)$/ =~ r
41
+ records[aor][key] = val if aor
42
+ end
43
+ end
44
+ @result = records
45
+ self
46
+ end
47
+
48
+ # returns struct
49
+ def uptime
50
+ res = Hash.new
51
+ @rawdata.each do |r|
52
+ next if /^Now::/ =~ r
53
+ if /^Up since:: [^\s]+ (?'mon'[^\s]+)\s+(?'d'\d+) (?'h'\d+):(?'m'\d+):(?'s'\d+) (?'y'\d+)/ =~ r
54
+ res[:since] = Time.local(y,mon,d,h,m,s)
55
+ end
56
+ if /^Up time:: (?'sec'\d+) / =~ r
57
+ res[:uptime] = sec.to_i
58
+ end
59
+ end
60
+ @result = OpenStruct.new res
61
+ self
62
+ end
63
+
64
+ # returns struct
65
+ def cache_fetch
66
+ res = Hash.new
67
+ @rawdata.each do |r|
68
+ if /^(?'label'[^=]+)=\s+\[(?'value'[^\]]+)\]/ =~ r
69
+ label.strip!
70
+ res[label.to_sym] = value
71
+ end
72
+ end
73
+ @result = OpenStruct.new res
74
+ self
75
+ end
76
+
77
+ # returns Array of registered contacts
78
+ def ul_show_contact
79
+ res = Array.new
80
+ @rawdata.each do |r|
81
+ cont = Hash.new
82
+ r.split(?;).each do |rec|
83
+ if /^Contact:: (.*)$/ =~ rec
84
+ cont[:contact] = $1
85
+ else
86
+ key,val = rec.split ?=
87
+ cont[key.to_sym] = val
88
+ end
89
+ end
90
+ res << cont
91
+ end
92
+ @result = res
93
+ self
94
+ end
95
+
96
+ # returns hash of dialogs
97
+ def dlg_list
98
+ # parse dialogs information into array
99
+ # assuming new block always starts with "dialog:: hash=..."
100
+ calls, key = Hash.new, nil
101
+ @rawdata.each do |l|
102
+ l.strip!
103
+ if l.match(/^dialog::\s+hash=(.*)$/)
104
+ key = $1
105
+ calls[key] = Hash.new
106
+ next
107
+ end
108
+ # building dialog array
109
+ if l.match(/^([^:]+)::\s+(.*)$/)
110
+ calls[key][$1.to_sym] = $2
111
+ end
112
+ end
113
+ @result = calls
114
+ self
115
+ end
116
+
117
+ end
118
+
119
+ class InvalidResponseData < Exception;end
120
+ class EmptyResponseData < Exception;end
121
+ end
122
+ end
@@ -0,0 +1,10 @@
1
+ require_relative "transport/fifo"
2
+ require_relative "transport/datagram"
3
+ require_relative "transport/xmlrpc"
4
+
5
+ module Opensips
6
+ module MI
7
+ module Transport
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,40 @@
1
+ module Opensips
2
+ module MI
3
+ module Transport
4
+ class Datagram < Opensips::MI::Command
5
+ RECVMAXLEN = 2**16 - 1
6
+
7
+ class << self
8
+ def init(params)
9
+ Datagram.new params
10
+ end
11
+ end
12
+
13
+ def initialize(params)
14
+ raise ArgumentError,
15
+ 'Missing socket host' if params[:host].nil?
16
+ raise ArgumentError,
17
+ 'Missing socket port' if params[:port].nil?
18
+ Socket.getaddrinfo(params[:host], nil) rescue
19
+ raise SocketError, "Invalid host #{params[:host]}"
20
+ raise SocketError,
21
+ "Invalid port #{params[:port]}" unless (1..(2**16-1)).include?(params[:port])
22
+ @sock = UDPSocket.new
23
+ @sock.connect params[:host], params[:port]
24
+ end
25
+
26
+ def command(cmd, params = [])
27
+ request = ":#{cmd}:\n"
28
+ params.each do |c|
29
+ request << "#{c}\n"
30
+ end
31
+ @sock.send request, 0
32
+ # will raise Errno::ECONNREFUSED if failed to connect
33
+ response, = @sock.recvfrom RECVMAXLEN
34
+ Opensips::MI::Response.new response.split(?\n)
35
+ end
36
+
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,90 @@
1
+ module Opensips
2
+ module MI
3
+ module Transport
4
+ class Fifo < Opensips::MI::Command
5
+ PERMISIONS = '0666'
6
+ attr_accessor :reply_fifo # name of the reply fifo file
7
+ attr_accessor :fifo_name # OpenSIPs fifo file. See mi_fifo module
8
+ attr_accessor :reply_dir # path to directory with where the reply fif is located
9
+
10
+ class << self
11
+ def init(params)
12
+ fifo = Fifo.new params
13
+ fifo.open
14
+ end
15
+ end
16
+
17
+ def initialize(params)
18
+ # set default values
19
+ @reply_fifo = if params[:reply_fifo].nil?
20
+ "opensips_reply_" << Digest::MD5.hexdigest(rand.to_s)[0,8]
21
+ else
22
+ @reply_fifo = params[:reply_fifo]
23
+ end
24
+
25
+ @reply_dir = if params[:reply_dir].nil?
26
+ '/tmp/'
27
+ else
28
+ params[:reply_dir]
29
+ end
30
+ raise ArgumentError,
31
+ "Fifo reply directory does not exists #{@reply_dir}" unless Dir.exists? @reply_dir
32
+
33
+ # fifo_name is required parameter
34
+ raise ArgumentError,
35
+ 'Missing required parameter fifo_name' if params[:fifo_name].nil?
36
+
37
+ @fifo_name = params[:fifo_name]
38
+ raise ArgumentError,
39
+ "OpenSIPs fifo_name file does not exist: #{@fifo_name}" unless File.exists? @fifo_name
40
+ raise ArgumentError,
41
+ "File #{@fifo_name} is not pipe" unless File.pipe? @fifo_name
42
+
43
+ # set finalizing method
44
+ reply_file = File.expand_path(@reply_fifo, @reply_dir)
45
+ ObjectSpace.define_finalizer(self, proc{self.class.finalize(reply_file)})
46
+ end
47
+
48
+ def open
49
+ # create fifo file
50
+ fifo_file = File.expand_path(@reply_fifo, @reply_dir)
51
+ Kernel.system "mkfifo -m #{PERMISIONS} #{fifo_file}"
52
+ raise SystemCallError,
53
+ "Can not create reply pipe: #{fifo_file}" unless File.pipe?(fifo_file)
54
+ self
55
+ end
56
+
57
+ def command(cmd, params = [])
58
+ fd_w = IO::sysopen(@fifo_name, Fcntl::O_WRONLY)
59
+ fifo_w = IO.open(fd_w)
60
+
61
+ request = ":#{cmd}:#{@reply_fifo}\n"
62
+ params.each do |c|
63
+ request << "#{c}\n"
64
+ end
65
+ # additional new line to terminate command
66
+ request << ?\n
67
+ fifo_w.syswrite request
68
+
69
+ # read response
70
+ file = File.expand_path(File.expand_path(@reply_fifo,@reply_dir))
71
+ fd_r = IO::sysopen(file, Fcntl::O_RDONLY )
72
+ fifo_r = IO.open(fd_r)
73
+
74
+ response = Array[]
75
+ response << $_.chomp while fifo_r.gets
76
+ Opensips::MI::Response.new response
77
+ ensure
78
+ # make sure we always close files' descriptors
79
+ fifo_r.close if fifo_r
80
+ fifo_w.close if fifo_w
81
+ end
82
+
83
+ def self.finalize(reply_file)
84
+ File.unlink(reply_file) if File.exists?(reply_file)
85
+ end
86
+
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,43 @@
1
+ module Opensips
2
+ module MI
3
+ module Transport
4
+ class Xmlrpc < Opensips::MI::Command
5
+ RPCSEG = 'RPC2'
6
+ class << self
7
+ def init(params)
8
+ Xmlrpc.new params
9
+ end
10
+ end
11
+
12
+ def initialize(params)
13
+ raise ArgumentError,
14
+ 'Missing socket host' if params[:host].nil?
15
+ raise ArgumentError,
16
+ 'Missing socket port' if params[:port].nil?
17
+ Socket.getaddrinfo(params[:host], nil) rescue
18
+ raise SocketError, "Invalid host #{params[:host]}"
19
+ raise SocketError,
20
+ "Invalid port #{params[:port]}" unless (1..(2**16-1)).include?(params[:port])
21
+ uri = "http://#{params[:host]}:#{params[:port]}/#{RPCSEG}"
22
+ @client = XMLRPC::Client.new_from_uri(uri, nil, 3)
23
+ rescue => e
24
+ raise e.class,
25
+ "Can not connect OpenSIPs server.\n#{e.message}"
26
+ end
27
+
28
+ def command(cmd, params = [])
29
+ response = ["200 OK"]
30
+ response += @client.call(cmd, *params).split(?\n)
31
+ response << ""
32
+ Opensips::MI::Response.new response
33
+ rescue => e
34
+ response = ["600 " << e.message]
35
+ Opensips::MI::Response.new response
36
+ end
37
+
38
+ def set_header(header);header;end
39
+
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,5 @@
1
+ module Opensips
2
+ module MI
3
+ VERSION = "0.0.1"
4
+ end
5
+ end
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'opensips/mi/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "opensips-mi"
8
+ gem.version = Opensips::MI::VERSION
9
+ gem.authors = ["Stas Kobzar"]
10
+ gem.email = ["stas@modulis.ca"]
11
+ gem.description = %q{Ruby module for interacting with OpenSIPs management interface}
12
+ gem.summary = %q{OpenSIPs management interface}
13
+ gem.homepage = "http://github.com/staskobzar/opensips-mi"
14
+
15
+ gem.files = `git ls-files`.split($/).reject{|f| %r|^examples/.*|.match f}
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+
20
+ gem.add_development_dependency('bundler', '~> 1.3')
21
+ gem.add_development_dependency('rdoc')
22
+ gem.add_development_dependency('rake')
23
+ gem.add_development_dependency('mocha')
24
+ end
@@ -0,0 +1,20 @@
1
+ 200 OK
2
+ dialog:: hash=3212:2099935485
3
+ state:: 4
4
+ user_flags:: 0
5
+ timestart:: 1365817158
6
+ timeout:: 1365824358
7
+ callid:: 1854719653
8
+ from_uri:: sip:7747@voip.etsmtl.ca
9
+ to_uri:: sip:95142842020@voip.etsmtl.ca
10
+ caller_tag:: 1614235294
11
+ caller_contact:: sip:7747@10.130.8.100
12
+ callee_cseq:: 0
13
+ caller_route_set::
14
+ caller_bind_addr:: udp:10.130.8.21:5060
15
+ callee_tag:: as2e60b080
16
+ callee_contact:: sip:95142842020@10.130.8.240:5060
17
+ caller_cseq:: 20
18
+ callee_route_set::
19
+ callee_bind_addr:: udp:10.130.8.21:5060
20
+
@@ -0,0 +1,168 @@
1
+ 200 OK
2
+ Domain:: location table=512 records=15
3
+ AOR:: 7962
4
+ Contact:: sip:7962@10.164.112.13 Q=
5
+ Expires:: 143
6
+ Callid:: 5e7a1e47da91c41c
7
+ Cseq:: 31401
8
+ User-agent:: Avaya IP Phone 1120E (SIP1120e.04.03.12.00)
9
+ State:: CS_SYNC
10
+ Flags:: 0
11
+ Cflag:: 0
12
+ Socket:: udp:10.130.8.21:5060
13
+ Methods:: 7551
14
+ AOR:: 7329
15
+ Contact:: sip:7329@10.132.113.171 Q=
16
+ Expires:: 95
17
+ Callid:: 504e5ee5baf3e7d8
18
+ Cseq:: 10412
19
+ User-agent:: Avaya IP Phone 1120E (SIP1120e.04.03.12.00)
20
+ State:: CS_SYNC
21
+ Flags:: 0
22
+ Cflag:: 0
23
+ Socket:: udp:10.130.8.21:5060
24
+ Methods:: 7551
25
+ AOR:: 7863
26
+ Contact:: sip:7863@10.132.113.172 Q=
27
+ Expires:: 142
28
+ Callid:: d808729f9d47ec2d
29
+ Cseq:: 28091
30
+ User-agent:: Avaya IP Phone 1120E (SIP1120e.04.03.12.00)
31
+ State:: CS_SYNC
32
+ Flags:: 0
33
+ Cflag:: 0
34
+ Socket:: udp:10.130.8.21:5060
35
+ Methods:: 7551
36
+ AOR:: 3812
37
+ Contact:: sip:3812@10.132.113.163 Q=
38
+ Expires:: 58
39
+ Callid:: a59c4a46f79d7317
40
+ Cseq:: 19050
41
+ User-agent:: Avaya IP Phone 1120E (SIP1120e.04.03.12.00)
42
+ State:: CS_SYNC
43
+ Flags:: 0
44
+ Cflag:: 0
45
+ Socket:: udp:10.130.8.21:5060
46
+ Methods:: 7551
47
+ AOR:: 3810
48
+ Contact:: sip:3810@10.132.113.166 Q=
49
+ Expires:: 87
50
+ Callid:: dd38e788e386a79d
51
+ Cseq:: 18259
52
+ User-agent:: Avaya IP Phone 1140E (SIP1140e.04.03.12.00)
53
+ State:: CS_SYNC
54
+ Flags:: 0
55
+ Cflag:: 0
56
+ Socket:: udp:10.130.8.21:5060
57
+ Methods:: 7551
58
+ AOR:: 7519
59
+ Contact:: sip:7519@10.132.113.174 Q=
60
+ Expires:: 63
61
+ Callid:: f0a2566a33a42295
62
+ Cseq:: 28149
63
+ User-agent:: Avaya IP Phone 1120E (SIP1120e.04.03.12.00)
64
+ State:: CS_SYNC
65
+ Flags:: 0
66
+ Cflag:: 0
67
+ Socket:: udp:10.130.8.21:5060
68
+ Methods:: 7551
69
+ AOR:: 7259
70
+ Contact:: sip:7259@10.164.112.18 Q=
71
+ Expires:: 32
72
+ Callid:: 7f0d07e8c1415bbc
73
+ Cseq:: 32493
74
+ User-agent:: Avaya IP Phone 1120E (SIP1120e.04.03.12.00)
75
+ State:: CS_SYNC
76
+ Flags:: 0
77
+ Cflag:: 0
78
+ Socket:: udp:10.130.8.21:5060
79
+ Methods:: 7551
80
+ AOR:: 7577
81
+ Contact:: sip:7577@10.132.113.178 Q=
82
+ Expires:: 159
83
+ Callid:: 5eca2b3d1062416b
84
+ Cseq:: 12767
85
+ User-agent:: Avaya IP Phone 1140E (SIP1140e.04.03.12.00)
86
+ State:: CS_SYNC
87
+ Flags:: 0
88
+ Cflag:: 0
89
+ Socket:: udp:10.130.8.21:5060
90
+ Methods:: 7551
91
+ AOR:: 3901
92
+ Contact:: sip:3901@10.132.113.160 Q=
93
+ Expires:: 132
94
+ Callid:: a57d709ba8c7d6d7
95
+ Cseq:: 27476
96
+ User-agent:: Avaya IP Phone 1120E (SIP1120e.04.03.12.00)
97
+ State:: CS_SYNC
98
+ Flags:: 0
99
+ Cflag:: 0
100
+ Socket:: udp:10.130.8.21:5060
101
+ Methods:: 7551
102
+ AOR:: 7806
103
+ Contact:: sip:7806@10.132.113.175 Q=
104
+ Expires:: 132
105
+ Callid:: 0fb4baf2782a89b3
106
+ Cseq:: 23944
107
+ User-agent:: Avaya IP Phone 1120E (SIP1120e.04.03.12.00)
108
+ State:: CS_SYNC
109
+ Flags:: 0
110
+ Cflag:: 0
111
+ Socket:: udp:10.130.8.21:5060
112
+ Methods:: 7551
113
+ AOR:: 7402
114
+ Contact:: sip:7402@10.132.113.168 Q=
115
+ Expires:: 47981
116
+ Callid:: ef8fa87d63302751
117
+ Cseq:: 13537
118
+ User-agent:: Avaya IP Phone 1120E (SIP1120e.04.03.12.00)
119
+ State:: CS_SYNC
120
+ Flags:: 0
121
+ Cflag:: 0
122
+ Socket:: udp:10.130.8.21:5060
123
+ Methods:: 7551
124
+ AOR:: 3822
125
+ Contact:: sip:3822@10.132.113.162 Q=
126
+ Expires:: 97
127
+ Callid:: f534f0b8d8a070e7
128
+ Cseq:: 50129
129
+ User-agent:: Avaya IP Phone 1220 (SIP12x0.04.03.12.00)
130
+ State:: CS_SYNC
131
+ Flags:: 0
132
+ Cflag:: 0
133
+ Socket:: udp:10.130.8.21:5060
134
+ Methods:: 7551
135
+ AOR:: 7641
136
+ Contact:: sip:7641@10.164.112.28 Q=
137
+ Expires:: 98
138
+ Callid:: df0f22a80302737a
139
+ Cseq:: 33571
140
+ User-agent:: Avaya IP Phone 1140E (SIP1140e.04.03.12.00)
141
+ State:: CS_SYNC
142
+ Flags:: 0
143
+ Cflag:: 0
144
+ Socket:: udp:10.130.8.21:5060
145
+ Methods:: 7551
146
+ AOR:: 7423
147
+ Contact:: sip:7423@10.164.113.25 Q=
148
+ Expires:: 109
149
+ Callid:: ab10dabda2f0f257
150
+ Cseq:: 39074
151
+ User-agent:: Avaya IP Phone 1120E (SIP1120e.04.03.12.00)
152
+ State:: CS_SYNC
153
+ Flags:: 0
154
+ Cflag:: 0
155
+ Socket:: udp:10.130.8.21:5060
156
+ Methods:: 7551
157
+ AOR:: 7747
158
+ Contact:: sip:7747@10.132.113.198 Q=
159
+ Expires:: 69
160
+ Callid:: 8c026d6f-9afd173e-c4d03305@10.132.113.198
161
+ Cseq:: 41286
162
+ User-agent:: PolycomSoundStationIP-SSIP_6000-UA/3.3.5.0247_0004f2f18103
163
+ State:: CS_SYNC
164
+ Flags:: 0
165
+ Cflag:: 0
166
+ Socket:: udp:10.130.8.21:5060
167
+ Methods:: 8063
168
+