oversip_p 1.0.0

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