oversip_p 1.0.0

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 (132) hide show
  1. checksums.yaml +7 -0
  2. data/AUTHORS +22 -0
  3. data/LICENSE +25 -0
  4. data/README.md +43 -0
  5. data/Rakefile +54 -0
  6. data/bin/oversip +184 -0
  7. data/etc/oversip.conf +274 -0
  8. data/etc/proxies.conf +145 -0
  9. data/etc/server.rb +315 -0
  10. data/etc/tls/ca/cacert.pem +3894 -0
  11. data/etc/tls/demo-tls.oversip.net.crt +17 -0
  12. data/etc/tls/demo-tls.oversip.net.key +15 -0
  13. data/etc/tls/upgrade-cacert.sh +12 -0
  14. data/etc/tls/utils/create-cert.rb +162 -0
  15. data/etc/tls/utils/get-sip-identities.rb +95 -0
  16. data/ext/common/c_util.h +74 -0
  17. data/ext/common/ruby_c_util.h +88 -0
  18. data/ext/sip_parser/common_headers.h +210 -0
  19. data/ext/sip_parser/ext_help.h +18 -0
  20. data/ext/sip_parser/extconf.rb +3 -0
  21. data/ext/sip_parser/sip_message_parser.c +29741 -0
  22. data/ext/sip_parser/sip_parser.h +250 -0
  23. data/ext/sip_parser/sip_parser_ruby.c +1370 -0
  24. data/ext/sip_parser/sip_uri_parser.c +39699 -0
  25. data/ext/stud/extconf.rb +43 -0
  26. data/ext/stun/ext_help.h +16 -0
  27. data/ext/stun/extconf.rb +3 -0
  28. data/ext/stun/stun_ruby.c +394 -0
  29. data/ext/utils/ext_help.h +14 -0
  30. data/ext/utils/extconf.rb +3 -0
  31. data/ext/utils/haproxy_protocol.c +6163 -0
  32. data/ext/utils/haproxy_protocol.h +27 -0
  33. data/ext/utils/ip_utils.c +5952 -0
  34. data/ext/utils/ip_utils.h +64 -0
  35. data/ext/utils/outbound_utils.c +3227 -0
  36. data/ext/utils/outbound_utils.h +27 -0
  37. data/ext/utils/utils_ruby.c +392 -0
  38. data/ext/utils/utils_ruby.h +76 -0
  39. data/ext/websocket_framing_utils/ext_help.h +18 -0
  40. data/ext/websocket_framing_utils/extconf.rb +3 -0
  41. data/ext/websocket_framing_utils/ws_framing_utils.h +47 -0
  42. data/ext/websocket_framing_utils/ws_framing_utils_ruby.c +135 -0
  43. data/ext/websocket_http_parser/ext_help.h +18 -0
  44. data/ext/websocket_http_parser/extconf.rb +3 -0
  45. data/ext/websocket_http_parser/ws_http_parser.c +1635 -0
  46. data/ext/websocket_http_parser/ws_http_parser.h +87 -0
  47. data/ext/websocket_http_parser/ws_http_parser_ruby.c +630 -0
  48. data/lib/oversip/config.rb +597 -0
  49. data/lib/oversip/config_validators.rb +126 -0
  50. data/lib/oversip/default_server.rb +52 -0
  51. data/lib/oversip/errors.rb +10 -0
  52. data/lib/oversip/fiber_pool.rb +56 -0
  53. data/lib/oversip/launcher.rb +635 -0
  54. data/lib/oversip/logger.rb +84 -0
  55. data/lib/oversip/modules/outbound_mangling.rb +56 -0
  56. data/lib/oversip/modules/user_assertion.rb +73 -0
  57. data/lib/oversip/proxies_config.rb +189 -0
  58. data/lib/oversip/ruby_ext/eventmachine.rb +38 -0
  59. data/lib/oversip/sip/client.rb +428 -0
  60. data/lib/oversip/sip/client_transaction.rb +586 -0
  61. data/lib/oversip/sip/constants.rb +88 -0
  62. data/lib/oversip/sip/core.rb +217 -0
  63. data/lib/oversip/sip/launcher.rb +221 -0
  64. data/lib/oversip/sip/listeners/connection.rb +54 -0
  65. data/lib/oversip/sip/listeners/ipv4_tcp_client.rb +21 -0
  66. data/lib/oversip/sip/listeners/ipv4_tcp_server.rb +22 -0
  67. data/lib/oversip/sip/listeners/ipv4_tls_client.rb +21 -0
  68. data/lib/oversip/sip/listeners/ipv4_tls_server.rb +22 -0
  69. data/lib/oversip/sip/listeners/ipv4_tls_tunnel_server.rb +22 -0
  70. data/lib/oversip/sip/listeners/ipv4_udp_server.rb +21 -0
  71. data/lib/oversip/sip/listeners/ipv6_tcp_client.rb +21 -0
  72. data/lib/oversip/sip/listeners/ipv6_tcp_server.rb +22 -0
  73. data/lib/oversip/sip/listeners/ipv6_tls_client.rb +21 -0
  74. data/lib/oversip/sip/listeners/ipv6_tls_server.rb +22 -0
  75. data/lib/oversip/sip/listeners/ipv6_tls_tunnel_server.rb +22 -0
  76. data/lib/oversip/sip/listeners/ipv6_udp_server.rb +21 -0
  77. data/lib/oversip/sip/listeners/tcp_client.rb +97 -0
  78. data/lib/oversip/sip/listeners/tcp_connection.rb +202 -0
  79. data/lib/oversip/sip/listeners/tcp_server.rb +71 -0
  80. data/lib/oversip/sip/listeners/tls_client.rb +125 -0
  81. data/lib/oversip/sip/listeners/tls_server.rb +88 -0
  82. data/lib/oversip/sip/listeners/tls_tunnel_connection.rb +89 -0
  83. data/lib/oversip/sip/listeners/tls_tunnel_server.rb +61 -0
  84. data/lib/oversip/sip/listeners/udp_connection.rb +214 -0
  85. data/lib/oversip/sip/listeners.rb +24 -0
  86. data/lib/oversip/sip/message.rb +177 -0
  87. data/lib/oversip/sip/message_processor.rb +213 -0
  88. data/lib/oversip/sip/name_addr.rb +51 -0
  89. data/lib/oversip/sip/proxy.rb +324 -0
  90. data/lib/oversip/sip/request.rb +179 -0
  91. data/lib/oversip/sip/response.rb +37 -0
  92. data/lib/oversip/sip/rfc3263.rb +643 -0
  93. data/lib/oversip/sip/server_transaction.rb +295 -0
  94. data/lib/oversip/sip/sip.rb +76 -0
  95. data/lib/oversip/sip/tags.rb +39 -0
  96. data/lib/oversip/sip/timers.rb +55 -0
  97. data/lib/oversip/sip/transport_manager.rb +130 -0
  98. data/lib/oversip/sip/uac.rb +89 -0
  99. data/lib/oversip/sip/uac_request.rb +84 -0
  100. data/lib/oversip/sip/uri.rb +208 -0
  101. data/lib/oversip/syslog.rb +68 -0
  102. data/lib/oversip/system_callbacks.rb +45 -0
  103. data/lib/oversip/tls.rb +172 -0
  104. data/lib/oversip/utils.rb +30 -0
  105. data/lib/oversip/version.rb +21 -0
  106. data/lib/oversip/websocket/constants.rb +55 -0
  107. data/lib/oversip/websocket/http_request.rb +59 -0
  108. data/lib/oversip/websocket/launcher.rb +183 -0
  109. data/lib/oversip/websocket/listeners/connection.rb +51 -0
  110. data/lib/oversip/websocket/listeners/ipv4_ws_server.rb +22 -0
  111. data/lib/oversip/websocket/listeners/ipv4_wss_server.rb +22 -0
  112. data/lib/oversip/websocket/listeners/ipv4_wss_tunnel_server.rb +22 -0
  113. data/lib/oversip/websocket/listeners/ipv6_ws_server.rb +22 -0
  114. data/lib/oversip/websocket/listeners/ipv6_wss_server.rb +22 -0
  115. data/lib/oversip/websocket/listeners/ipv6_wss_tunnel_server.rb +22 -0
  116. data/lib/oversip/websocket/listeners/ws_server.rb +331 -0
  117. data/lib/oversip/websocket/listeners/wss_server.rb +88 -0
  118. data/lib/oversip/websocket/listeners/wss_tunnel_server.rb +133 -0
  119. data/lib/oversip/websocket/listeners.rb +13 -0
  120. data/lib/oversip/websocket/websocket.rb +13 -0
  121. data/lib/oversip/websocket/ws_framing.rb +545 -0
  122. data/lib/oversip/websocket/ws_sip_app.rb +120 -0
  123. data/lib/oversip.rb +127 -0
  124. data/test/oversip_test_helper.rb +19 -0
  125. data/test/test_http_parser.rb +73 -0
  126. data/test/test_name_addr.rb +27 -0
  127. data/test/test_name_addr_parser.rb +24 -0
  128. data/test/test_sip_message_parser.rb +168 -0
  129. data/test/test_sip_uri_parser.rb +56 -0
  130. data/test/test_uri.rb +68 -0
  131. data/thirdparty/stud/stud.tar.gz +0 -0
  132. metadata +334 -0
@@ -0,0 +1,89 @@
1
+ module OverSIP::SIP
2
+
3
+ class TlsTunnelConnection < TcpConnection
4
+
5
+ # Max size (bytes) of the buffered data when receiving message headers
6
+ # (avoid DoS attacks).
7
+ HEADERS_MAX_SIZE = 16384
8
+
9
+ def process_received_data
10
+ @state == :ignore and return
11
+
12
+ while (case @state
13
+ when :init
14
+ @parser.reset
15
+ @parser_nbytes = 0
16
+ # If it's a TCP connection from the TLS tunnel then parse the HAProxy Protocol line
17
+ # if it's not yet done.
18
+ unless @haproxy_protocol_parsed
19
+ @state = :haproxy_protocol
20
+ else
21
+ @state = :headers
22
+ end
23
+
24
+ when :haproxy_protocol
25
+ parse_haproxy_protocol
26
+
27
+ when :headers
28
+ parse_headers
29
+
30
+ when :body
31
+ get_body
32
+
33
+ when :finished
34
+ if @msg.request?
35
+ process_request
36
+ else
37
+ process_response
38
+ end
39
+
40
+ # Set state to :init.
41
+ @state = :init
42
+ # Return true to continue processing possible remaining data.
43
+ true
44
+
45
+ when :ignore
46
+ false
47
+ end)
48
+ end # while
49
+
50
+ end
51
+
52
+ def parse_haproxy_protocol
53
+ if (haproxy_protocol_data = ::OverSIP::Utils.parse_haproxy_protocol(@buffer.to_str))
54
+ @haproxy_protocol_parsed = true
55
+
56
+ # Update connection information.
57
+ @remote_ip_type = haproxy_protocol_data[1]
58
+ @remote_ip = haproxy_protocol_data[2]
59
+ @remote_port = haproxy_protocol_data[3]
60
+
61
+ # Add the connection with the client's source data. Note that we pass a TlsServer as class, but
62
+ # the server instance is a TcpServer.
63
+ @connection_id = case @remote_ip_type
64
+ when :ipv4
65
+ ::OverSIP::SIP::TransportManager.add_connection self, ::OverSIP::SIP::IPv4TlsServer, :ipv4, @remote_ip, @remote_port
66
+ when :ipv6
67
+ ::OverSIP::SIP::TransportManager.add_connection self, ::OverSIP::SIP::IPv6TlsServer, :ipv6, @remote_ip, @remote_port
68
+ end
69
+
70
+ # Update log information.
71
+ remote_desc true
72
+
73
+ # Remove the HAProxy Protocol line from the received data.
74
+ @buffer.read haproxy_protocol_data[0]
75
+
76
+ @state = :headers
77
+
78
+ else
79
+ log_system_error "HAProxy Protocol parsing error, closing connection"
80
+ close_connection_after_writing
81
+ @state = :ignore
82
+ return false
83
+ end
84
+ end
85
+
86
+ end
87
+
88
+ end
89
+
@@ -0,0 +1,61 @@
1
+ module OverSIP::SIP
2
+
3
+ class TlsTunnelServer < TlsTunnelConnection
4
+
5
+ attr_reader :outbound_flow_token
6
+
7
+ def post_connection
8
+ begin
9
+ # Temporal @remote_ip and @remote_port until the HAProxy protocol line is parsed.
10
+ @remote_port, @remote_ip = ::Socket.unpack_sockaddr_in(get_peername)
11
+ rescue => e
12
+ log_system_error "error obtaining remote IP/port (#{e.class}: #{e.message}), closing connection"
13
+ close_connection
14
+ @state = :ignore
15
+ return
16
+ end
17
+
18
+ # Create an Outbound (RFC 5626) flow token for this connection.
19
+ @outbound_flow_token = ::OverSIP::SIP::TransportManager.add_outbound_connection self
20
+
21
+ log_system_debug ("connection from the TLS tunnel " << remote_desc) if $oversip_debug
22
+ end
23
+
24
+ def remote_desc force=nil
25
+ if force
26
+ @remote_desc = case @remote_ip_type
27
+ when :ipv4 ; "#{@remote_ip}:#{@remote_port.to_s}"
28
+ when :ipv6 ; "[#{@remote_ip}]:#{@remote_port.to_s}"
29
+ end
30
+ else
31
+ @remote_desc ||= case self.class.ip_type
32
+ when :ipv4 ; "#{@remote_ip}:#{@remote_port.to_s}"
33
+ when :ipv6 ; "[#{@remote_ip}]:#{@remote_port.to_s}"
34
+ end
35
+ end
36
+ end
37
+
38
+
39
+ def unbind cause=nil
40
+ @state = :ignore
41
+
42
+ # Remove the connection.
43
+ self.class.connections.delete @connection_id if @connection_id
44
+
45
+ # Remove the Outbound token flow.
46
+ ::OverSIP::SIP::TransportManager.delete_outbound_connection @outbound_flow_token
47
+
48
+ @local_closed = true if cause == ::Errno::ETIMEDOUT
49
+
50
+ if $oversip_debug
51
+ log_msg = "connection from the TLS tunnel #{remote_desc} "
52
+ log_msg << ( @local_closed ? "locally closed" : "remotely closed" )
53
+ log_msg << " (cause: #{cause.inspect})" if cause
54
+ log_system_debug log_msg
55
+ end unless $!
56
+ end
57
+
58
+ end
59
+
60
+ end
61
+
@@ -0,0 +1,214 @@
1
+ module OverSIP::SIP
2
+
3
+ class UdpConnection < Connection
4
+
5
+ def receive_data data
6
+ @buffer << data
7
+
8
+ while (case @state
9
+ when :init
10
+ @parser.reset
11
+ @parser_nbytes = 0
12
+ @state = :message
13
+
14
+ when :message
15
+ parse_message
16
+
17
+ when :finished
18
+ if @msg.request?
19
+ process_request
20
+ else
21
+ process_response
22
+ end
23
+ @state = :init
24
+ false
25
+ end)
26
+ end # while
27
+ end
28
+
29
+ def parse_message
30
+ return false if @buffer.empty?
31
+
32
+ buffer_str = @buffer.to_str
33
+
34
+ # Quikly ignore single CRLF (widely used by SIP UDP clients as keep-alive).
35
+ if buffer_str == CRLF
36
+ @buffer.clear
37
+ @state = :init
38
+ return false
39
+ end
40
+
41
+ begin
42
+ source_port, source_ip = ::Socket.unpack_sockaddr_in(get_peername)
43
+ rescue => e
44
+ log_system_crit "error obtaining remote IP/port (#{e.class}: #{e.message})"
45
+ @buffer.clear
46
+ @state = :init
47
+ return false
48
+ end
49
+
50
+ case stun_res = ::OverSIP::Stun.parse_request(buffer_str, source_ip, source_port)
51
+ # Not a STUN request so continue with SIP parsing.
52
+ when nil
53
+ # An invalid STUN request, log it and drop it.
54
+ when false
55
+ log_system_debug "invalid STUN message received (not a valid STUN Binding Request)" if $oversip_debug
56
+ @buffer.clear
57
+ @state = :init
58
+ return false
59
+ # A valid STUN Binding Request so we get a response to be sent.
60
+ when ::String
61
+ log_system_debug "STUN Binding Request received, replying to it" if $oversip_debug
62
+ send_data stun_res
63
+ @buffer.clear
64
+ @state = :init
65
+ return false
66
+ end
67
+
68
+ # Parse the currently buffered data. If parsing fails @parser_nbytes gets nil value.
69
+ unless @parser_nbytes = @parser.execute(buffer_str, @parser_nbytes)
70
+ # The parsed data is invalid, however some data could be parsed so @parsed.parsed
71
+ # can be:
72
+ # - SIP::Request
73
+ # - SIP::Response
74
+ # - nil (the message is so wrong that cannot be neither a request or response).
75
+ if wrong_message = @parser.parsed
76
+ log_system_warn "parsing error for #{MSG_TYPE[wrong_message.class]}: \"#{@parser.error}\""
77
+ else
78
+ log_system_warn "parsing error: \"#{@parser.error}\""
79
+ end
80
+
81
+ @buffer.clear
82
+ @state = :init
83
+ return false
84
+ end
85
+
86
+ unless @parser.finished?
87
+ # The parsing has not finished.
88
+ # If UDP it's invalid as per RFC 3261 a UDP datagram MUST contain an entire
89
+ # SIP request or response. Note we also allow double CRLF in UDP. If just a
90
+ # single CRLF arrives ignore it and clear the buffer.
91
+ # Maybe the parser has gone enought data to determine if the unfinished
92
+ # message is a SIP request or response, log it if so.
93
+ # If not, then @parser.parsed returns nil and nothing is logged.
94
+ unfinished_msg = @parser.parsed
95
+ log_system_warn "ignoring not finished #{MSG_TYPE[unfinished_msg.class]} via UDP" if
96
+ unfinished_msg.is_a? ::OverSIP::SIP::Request or unfinished_msg.is_a? ::OverSIP::SIP::Response
97
+ # Clear the buffer, set :init state and wait for new messages.
98
+ @buffer.clear
99
+ @state = :init
100
+ return false
101
+ end
102
+
103
+ # At this point we've got a SIP::Request, SIP::Response or :outbound_keepalive symbol.
104
+ @msg = @parser.parsed
105
+
106
+ # Clear parsed data from the buffer.
107
+ @buffer.read(@parser_nbytes)
108
+
109
+ # Received data is a Outbound keealive (also allowed in UDP however). Reply single CRLF.
110
+ if @msg == :outbound_keepalive
111
+ log_system_debug "Outbound keepalive received, replying single CRLF" if $oversip_debug
112
+ # Reply a single CRLF over the same connection.
113
+ send_data CRLF
114
+ # If UDP there could be invalid data after double CRLF CRLF, just ignore it
115
+ # and clear the buffer. Set :init state and return false so we leave receive_data()
116
+ # method.
117
+ @buffer.clear
118
+ @state = :init
119
+ return false
120
+ end
121
+
122
+ @parser.post_parsing
123
+
124
+ # Here we have received the entire headers of a SIP request or response. Fill some
125
+ # attributes.
126
+ @msg.connection = self
127
+ @msg.transport = :udp
128
+ @msg.source_ip = source_ip
129
+ @msg.source_port = source_port
130
+ @msg.source_ip_type = self.class.ip_type
131
+
132
+ unless valid_message? @parser
133
+ @buffer.clear
134
+ @state = :init
135
+ return false
136
+ end
137
+
138
+ add_via_received_rport if @msg.request?
139
+
140
+ unless check_via_branch
141
+ @buffer.clear
142
+ @state = :init
143
+ return false
144
+ end
145
+
146
+ # Examine Content-Length header.
147
+ # There is Content-Length header.
148
+ if cl = @msg.content_length and cl > 0
149
+ # Body size is correct. Read it and clear the buffer.
150
+ # Set :finished state and return true so message will be processed.
151
+ if cl == @buffer.size
152
+ @msg.body = @buffer.read.force_encoding(::Encoding::UTF_8)
153
+ @buffer.clear
154
+ @state = :finished
155
+ return true
156
+ # In UDP the remaining data after headers must be the entire body
157
+ # and fill exactly Content-Length bytes. If not it's invalid. Reply
158
+ # 400 and clear the buffer.
159
+ else
160
+ if @msg.request?
161
+ unless @msg.sip_method == :ACK
162
+ log_system_warn "request body size doesn't match Content-Length => 400"
163
+ @msg.reply 400, "Body size doesn't match Content-Length"
164
+ else
165
+ log_system_warn "ACK body size doesn't match Content-Length, ignoring it"
166
+ end
167
+ else
168
+ log_system_warn "response body size doesn't match Content-Length, ignoring it"
169
+ end
170
+ @buffer.clear
171
+ @state = :init
172
+ return false
173
+ end
174
+ # No Content-Length header or 0 value. However it could occur that the datagram
175
+ # contains remaining unuseful data, in this case reply 400. If not
176
+ # set :finished state and return true so message will be processed.
177
+ else
178
+ # Ensure there is no more data in the buffer. If it's ok set :finished
179
+ # state and return true so message will be processed.
180
+ if @buffer.size.zero?
181
+ @state = :finished
182
+ return true
183
+ # Non valid remaining data in the UDP datagram. Reply 400.
184
+ else
185
+ if @msg.request?
186
+ log_system_warn "request contains body but Content-Length is zero or not present => 400"
187
+ @msg.reply 400, "request contains body but Content-Length is zero or not present"
188
+ else
189
+ log_system_warn "response contains body but Content-Length is zero or not present, ignoring it"
190
+ end
191
+ @buffer.clear
192
+ @state = :init
193
+ return false
194
+ end
195
+ end
196
+
197
+ end # parse_headers
198
+
199
+ def send_sip_msg msg, ip, port
200
+ send_datagram msg, ip, port
201
+ true
202
+ end
203
+
204
+
205
+ def unbind cause=nil
206
+ unless $!
207
+ log_system_crit "UDP socket closed!!! cause: #{cause.inspect}"
208
+ end
209
+ end
210
+
211
+ end
212
+
213
+ end
214
+
@@ -0,0 +1,24 @@
1
+ # OverSIP files
2
+
3
+ require "oversip/sip/listeners/connection"
4
+ require "oversip/sip/listeners/udp_connection"
5
+ require "oversip/sip/listeners/tcp_connection"
6
+ require "oversip/sip/listeners/tls_tunnel_connection"
7
+ require "oversip/sip/listeners/tcp_server"
8
+ require "oversip/sip/listeners/tls_server"
9
+ require "oversip/sip/listeners/tls_tunnel_server"
10
+ require "oversip/sip/listeners/tcp_client"
11
+ require "oversip/sip/listeners/tls_client"
12
+
13
+ require "oversip/sip/listeners/ipv4_udp_server"
14
+ require "oversip/sip/listeners/ipv6_udp_server"
15
+ require "oversip/sip/listeners/ipv4_tcp_server"
16
+ require "oversip/sip/listeners/ipv6_tcp_server"
17
+ require "oversip/sip/listeners/ipv4_tls_server"
18
+ require "oversip/sip/listeners/ipv6_tls_server"
19
+ require "oversip/sip/listeners/ipv4_tls_tunnel_server"
20
+ require "oversip/sip/listeners/ipv6_tls_tunnel_server"
21
+ require "oversip/sip/listeners/ipv4_tcp_client"
22
+ require "oversip/sip/listeners/ipv6_tcp_client"
23
+ require "oversip/sip/listeners/ipv4_tls_client"
24
+ require "oversip/sip/listeners/ipv6_tls_client"
@@ -0,0 +1,177 @@
1
+ module OverSIP::SIP
2
+
3
+ class Message
4
+
5
+ include ::OverSIP::Logger
6
+
7
+ DIALOG_FORMING_METHODS = { :INVITE=>true, :SUBSCRIBE=>true, :REFER=>true }
8
+ RECORD_ROUTING_AWARE_METHODS = { :INVITE=>true, :REGISTER=>true, :SUBSCRIBE=>true, :REFER=>true }
9
+ OUTBOUND_AWARE_METHODS = { :INVITE=>true, :REGISTER=>true, :SUBSCRIBE=>true, :REFER=>true }
10
+ EMPTY_ARRAY = [].freeze
11
+
12
+ # SIP related attributes.
13
+ attr_accessor :transport
14
+ attr_accessor :source_ip
15
+ attr_accessor :source_ip_type
16
+ attr_accessor :source_port
17
+ attr_accessor :connection
18
+
19
+ # SIP message attributes.
20
+ attr_reader :sip_method
21
+ attr_reader :sip_version
22
+ attr_reader :headers
23
+
24
+ attr_reader :via_sent_by_host
25
+ attr_reader :via_sent_by_port
26
+ attr_reader :via_branch
27
+ attr_accessor :via_branch_id # It's the branch value without "z9hG4bK".
28
+ attr_reader :via_branch_rfc3261
29
+ attr_reader :via_received
30
+ attr_reader :via_has_rport
31
+ attr_accessor :via_rport # Value not parsed.
32
+ attr_reader :via_has_alias
33
+ attr_reader :via_core_value
34
+ attr_reader :via_params
35
+ attr_reader :num_vias
36
+
37
+ attr_reader :call_id
38
+ attr_reader :cseq
39
+ attr_reader :max_forwards
40
+ attr_reader :content_length
41
+ attr_reader :routes
42
+ attr_reader :require
43
+ attr_reader :supported
44
+ attr_reader :proxy_require
45
+
46
+ attr_accessor :body
47
+
48
+ attr_accessor :from # NameAddr instance.
49
+ attr_reader :from_tag
50
+ attr_accessor :to # NameAddr instance.
51
+ attr_reader :to_tag
52
+ attr_reader :contact # NameAddr instance (when it has a single value).
53
+ attr_reader :contact_params
54
+
55
+ attr_reader :hdr_via # Array
56
+ attr_reader :hdr_from # String
57
+ attr_reader :hdr_to # String
58
+ attr_reader :hdr_route # Array
59
+
60
+ # Other attributes.
61
+ attr_accessor :tvars # Transaction variables (a hash).
62
+
63
+ def udp? ; @transport == :udp end
64
+ def tcp? ; @transport == :tcp end
65
+ def tls? ; @transport == :tls end
66
+ def ws? ; @transport == :ws end
67
+ def wss? ; @transport == :wss end
68
+
69
+ def websocket? ; @transport == :ws || @transport == :wss end
70
+
71
+ def unknown_method? ; @is_unknown_method end
72
+
73
+ def via_rport? ; @via_has_rport end
74
+
75
+ def via_alias? ; @via_has_alias end
76
+
77
+ def contact_reg_id? ; @contact_has_reg_id end
78
+
79
+ def dialog_forming?
80
+ DIALOG_FORMING_METHODS[@sip_method]
81
+ end
82
+
83
+ def record_routing_aware?
84
+ RECORD_ROUTING_AWARE_METHODS[@sip_method]
85
+ end
86
+
87
+ def outbound_aware?
88
+ OUTBOUND_AWARE_METHODS[@sip_method]
89
+ end
90
+
91
+ # Returns true if a header with the given header _name_ exists, false otherwise.
92
+ def has_header? name
93
+ @headers[MessageParser.headerize(name)] && true
94
+ end
95
+
96
+ # Returns the first value of the given header _name_, nil if it doesn't exist.
97
+ def header_top name
98
+ ( hdr = @headers[MessageParser.headerize(name)] ) ? hdr[0] : nil
99
+ end
100
+ alias :header :header_top
101
+
102
+ # Returns an array with all the values of the given header _name_, an empty array
103
+ # if it doesn't exist.
104
+ def header_all name
105
+ ( hdr = @headers[MessageParser.headerize(name)] ) ? hdr : EMPTY_ARRAY
106
+ end
107
+
108
+ # Replaces the header of given _name_ with a the given _value_.
109
+ # _value_ can be a single value or an array.
110
+ def set_header name, value
111
+ @headers[MessageParser.headerize(name)] =
112
+ case value
113
+ when ::Array
114
+ value
115
+ else
116
+ [ value.to_s ]
117
+ end
118
+ end
119
+
120
+ # Completely deletes the header with given _name_.
121
+ # Returns an array containing all the header values, nil otherwise.
122
+ def delete_header name
123
+ @headers.delete MessageParser.headerize(name)
124
+ end
125
+
126
+ # Removes the first value of a given header _name_.
127
+ # Returns the extracted value, nil otherwise.
128
+ def delete_header_top name
129
+ if hdr = @headers[k=MessageParser.headerize(name)]
130
+ hdr.size > 1 ? hdr.shift : @headers.delete(k)[0]
131
+ end
132
+ end
133
+
134
+ # Inserts the given _value_ in the first position of header _name_.
135
+ # _value_ must be a string.
136
+ def insert_header name, value
137
+ if hdr = @headers[k=MessageParser.headerize(name)]
138
+ hdr.unshift value.to_s
139
+ else
140
+ #@headers[k] = [ value.to_s ]
141
+ # NOTE: If the header name doesn't already exist in the mesage, insert
142
+ # the new header in the first position of the Hash.
143
+ @headers = { k => [ value.to_s ] }.merge! @headers
144
+ end
145
+ end
146
+
147
+ # Append the given _value_ in the last position of header _name_.
148
+ # _value_ must be a string.
149
+ def append_header name, value
150
+ if hdr = @headers[k=MessageParser.headerize(name)]
151
+ hdr.push value.to_s
152
+ else
153
+ @headers[k] = [ value.to_s ]
154
+ end
155
+ end
156
+
157
+ # Replaces the top value of the given header _name_ with the
158
+ # string given as argument _value_.
159
+ def replace_header_top name, value
160
+ if hdr = @headers[k=MessageParser.headerize(name)]
161
+ hdr[0] = value.to_s
162
+ else
163
+ @headers[k] = [ value.to_s ]
164
+ end
165
+ end
166
+
167
+ # Close the connection from which the SIP request/response has been
168
+ # received.
169
+ def close_connection
170
+ return false if @transport == :udp
171
+ @connection.close
172
+ true
173
+ end
174
+
175
+ end # class Message
176
+
177
+ end