Browse code

* Module: mediaproxy

Moved modules_k/mediaproxy to modules and removed modules_s/mediaproxy.

Juha Heinanen authored on 20/04/2009 05:42:45
Showing 13 changed files
1 1
similarity index 100%
2 2
rename from modules_k/mediaproxy/Makefile
3 3
rename to modules/mediaproxy/Makefile
4 4
similarity index 100%
5 5
rename from modules_k/mediaproxy/README
6 6
rename to modules/mediaproxy/README
7 7
similarity index 100%
8 8
rename from modules_k/mediaproxy/doc/mediaproxy.xml
9 9
rename to modules/mediaproxy/doc/mediaproxy.xml
10 10
similarity index 100%
11 11
rename from modules_k/mediaproxy/doc/mediaproxy_admin.xml
12 12
rename to modules/mediaproxy/doc/mediaproxy_admin.xml
13 13
similarity index 100%
14 14
rename from modules_k/mediaproxy/mediaproxy.c
15 15
rename to modules/mediaproxy/mediaproxy.c
16 16
deleted file mode 100644
... ...
@@ -1,16 +0,0 @@
1
-# $Id$
2
-#
3
-# mediaproxy module makefile
4
-#
5
-# 
6
-# WARNING: do not run this directly, it should be run by the master Makefile
7
-
8
-include ../../Makefile.defs
9
-auto_gen=
10
-NAME=mediaproxy.so
11
-LIBS=
12
-
13
-DEFS+=-DSER_MOD_INTERFACE
14
-
15
-include ../../Makefile.modules
16
-
17 0
deleted file mode 100644
... ...
@@ -1,259 +0,0 @@
1
-
2
-                       Mediaproxy SER module
3
-
4
-                        Copyright Dan Pascu
5
-    		       2002-2004 AG Projects
6
-
7
-
8
-  Mediaproxy is a SER module that is designed to allow automatic NAT
9
-traversal for the majority of existing SIP clients. This means that there
10
-will be no need to configure anything in particular on the NAT box to allow
11
-these clients to work behind NAT when using the mediaproxy module.
12
-
13
-Section 1 for a description of the modus operandi.
14
-Section 2 describes the types of SIP phones that work with mediaproxy and a
15
-          short description about how the NAT traversal is working.
16
-Section 3 is about mediaproxy features.
17
-Section 4 describes the exported module parameters and functions.
18
-Section 5 is a comparison with nathelper.
19
-
20
-1. Principle of operation
21
-   ----------------------
22
-
23
-  This NAT traversal solution operates by placing a mediaproxy server in the
24
-middle between 2 SIP user-agents. It mangles the SDP messages for both of
25
-them in a way that will make the parties talk with mediaproxy while they
26
-think they talk directly with each other.
27
-
28
-To achieve this, mediaproxy is actually composed by 2 components:
29
-  - the SER mediaproxy module itself
30
-  - an external proxy server called SER MediaProxy (available from
31
-    http://mediaproxy.ag-projects.com/ )
32
-
33
-To avoid confusion in this document the mediaproxy module will be called
34
-'module' or 'mediaproxy module', while the mediaproxy server will be called
35
-'proxy server' from here on.
36
-
37
-  The proxy server can be run on the same machine as the module or on a
38
-remote host. Moreover it is possible for a single module to control multiple
39
-proxy servers running on multiple geographically distributed hosts. To find
40
-out more about the architecture of SER MediaProxy please read the
41
-documentation that comes with it.
42
-
43
-  To be able to act as a proxy between the 2 talking parties, the machine(s)
44
-running the module/proxy server must have a public IP address.
45
-
46
-  The module will ask the proxy server to allocate as many sockets as there
47
-are media streams in the SDP body of the SIP INVITE/Ok messages. The proxy
48
-server will send back to the module the address and port(s) for them. Then
49
-the module will replace the original contact IP and RTP ports from the SDP
50
-messages with the ones provided by the proxy server. By doing this both
51
-clients will try to contact the proxy server instead of talking directly
52
-with each other. Once the clients contact the proxy server, it will record
53
-the addresses they came from and will know where to forward packets received
54
-from the other party This is needed because the address/port the NAT box
55
-will allocate for the leaving streams is not known before they actually
56
-leave the NAT box. However the address of the proxy server is always known
57
-(being a public one) so the 2 parties know where to connect and then after
58
-they did so, the proxy learns the addresses they came from and can forward
59
-packets between them.
60
-
61
-
62
-2. Types of SIP clients
63
-   --------------------
64
-
65
-  The SIP clients that will work transparently behind NAT when using the
66
-mediaproxy module are the so-called symmetric clients. The symmetric clients
67
-have the particularity that use the same port to send the data as the one
68
-they use to receive it. In other words, if they are for example configured
69
-to use port 5060 for SIP signaling, they will use the same port when sending
70
-data as well as when receiving it. This must be true for both the SIP
71
-signaling as well as the RTP streams for a client to work transparently with
72
-the mediaproxy module without any additional configuration on the NAT box.
73
-
74
-  This ability is important because the only way to get back to a client
75
-behind NAT is to send to the IP address and port the packet was received
76
-from. Once a packet is sent from the client behind NAT to the outside world,
77
-it opens a communication channel in the NAT box that is open in both
78
-directions for a while (it will timeout after a while after no more data is
79
-sent through it, but it can be kept active by sending data through it at
80
-certain regular time intervals). While this channel is open, any data sent
81
-to the public address and port that the NAT box assigned for the address and
82
-port the client behind NAT is sending from (and this mapping is guaranteed
83
-to be unique), will go back straight to the address and port the client has
84
-sent from. This is why is necessary for the clients to be symmetric. If they
85
-listen on the same port they sent from, the data sent back to the public
86
-address that the NAT box assigned to the leaving packets will actually reach
87
-the listening port of the client behind NAT.
88
-
89
-  Some SIP clients implement particular algorithms to detect if they are
90
-actually behind a NAT box and try to act smart by detecting the IP address
91
-of the NAT box (or simply allowing one to manually configure it), and then
92
-use this IP address in the SIP and SDP messages instead of their own private
93
-IP address. This situation can be confusing for a module that tries to
94
-perform transparent NAT traversal as it can wrongly mistake such a client
95
-that is behind NAT with a client that is actually in the public address
96
-space. However for the mediaproxy module it is not important if the clients
97
-apply or not this kind of behavior, as it is able to cope with both
98
-situations gracefully.
99
-
100
-  This doesn't mean that mediaproxy is not able to work with asymmetric
101
-clients behind NAT, but in their case special static forwarding routes need
102
-to be configured on the NAT box.
103
-
104
-  Mediaproxy has special support for asymmetric clients, can detect them and
105
-send the data to the ports they expect it to, however they can work behind
106
-NAT only if static routes are configured on the NAT box since there is no
107
-way of getting back to an address/port that has not previously opened a data
108
-channel in the NAT box by sending something out first. Nevertheless the
109
-support for asymmetric clients is important, because without it they won't
110
-be able to work even when they have public Internet addresses. Also this
111
-support allows one to use an asymmetric client behind NAT if he can
112
-configure the NAT box to forward the packets meant to that client.
113
-
114
-  The only requirement a symmetric SIP client must met to be able to work
115
-transparently behind NAT when using the mediaproxy module is to accept to be
116
-configured to use a so called outbound proxy and this proxy must be the one
117
-running with the mediaproxy module loaded.
118
-
119
-
120
-3. Features
121
-   --------
122
-
123
-- make symmetric clients work behind NAT transparently if they use the SIP
124
-  server as the outbound SIP server.
125
-- handle all media streams specified in the SDP body. There is a limit of 64
126
-  RTP streams per session in the code now, but we hardly find this to be a
127
-  limitation for the time being.
128
-- able to distribute RTP traffic load on multiple proxy servers running on
129
-  multiple hosts.
130
-- able to specify which proxy server to use based on the SIP domain of the
131
-  caller/destination (done by the proxy server's dispatcher module)
132
-- handle asymmetric clients properly. They can even work behind NAT if a
133
-  proper port forwarding is done for them on the NAT box.
134
-
135
-
136
-4. Module parameters and exported functions
137
-   ----------------------------------------
138
-
139
-  The module exports the following parameters:
140
-
141
-  - mediaproxy_socket
142
-
143
-    it is the path to the filesystem socket where the proxy server
144
-    listens for commands from the module.
145
-
146
-  - sip_asymmetrics
147
-
148
-    it is the path to a file that lists regular expressions that match
149
-    'User-Agent' or 'Server' fields from clients that are asymmetric
150
-    regarding SIP signaling. Needed to detect when a client is asymmetric
151
-    regarding SIP signaling. An example file is in the config/ subdirectory.
152
-
153
-  - rtp_asymmetrics
154
-
155
-    it is the path to a file that lists regular expressions that match
156
-    'User-Agent' or 'Server' fields from clients that are asymmetric
157
-    regarding the RTP media. Needed to detect when a client is asymmetric
158
-    regarding the RTP media. An example file is in the config/ subdirectory.
159
-
160
-  - natping_interval
161
-
162
-    it holds an integer value representing how often the module will
163
-    send packets to all registered clients that are behind NAT to keep
164
-    their opened channels alive. Represents an interval in seconds.
165
-
166
-Parameters are set in the SER configuration file by using the modparam
167
-command. Below are examples, which contain the actual default values of the
168
-parameters. If you are Ok with them it is not necessary to specify them in the
169
-configuration file at all.
170
-
171
-modparam("mediaproxy", "mediaproxy_socket", "/var/run/proxydispatcher.sock")
172
-modparam("mediaproxy", "sip_asymmetrics", "/etc/ser/sip-asymmetrics-clients")
173
-modparam("mediaproxy", "rtp_asymmetrics", "/etc/ser/rtp-asymmetrics-clients")
174
-modparam("mediaproxy", "natping_interval", 20)
175
-
176
-  The module exports the following functions:
177
-
178
-  - client_nat_test(type)
179
-
180
-    tests if the client is behind NAT or not. The types of tests are
181
-    specified by the type parameter which represents a sum of the 
182
-    following numbers (add the values of the ones you wish to perform
183
-    tests for):
184
-
185
-      1 - tests if client has a private IP address (as defined by RFC1918)
186
-          in the Contact field of the SIP message.
187
-
188
-      2 - tests if client has contacted SER from an address that is different
189
-          from the one in the 1st Via field. Both IP and port are checked,
190
-          except for asymmetric clients for which the port is ignored.
191
-
192
-      4 - tests if client has a private IP address (as defined by RFC1918)
193
-          in the top Via field of the SIP message.
194
-
195
-    for example calling client_nat_test("3") in ser.cfg will perform
196
-    first 2 tests listen above and return true as soon as one succeeds
197
-    if both fail will return false.
198
-
199
-  - fix_contact()
200
-
201
-    will replace the IP:Port in the Contact field of the SIP message
202
-    with the ones the SIP message was received from. For clients that
203
-    are asymmetric regarding SIP signaling (as determined from the
204
-    sip_asymmetrics file) will preserve the port.
205
-    usually called after an if (client_nat_test(type)) has succeded
206
-
207
-  - use_media_proxy()
208
-
209
-    will make a call to the proxy server and replace the IPs and ports
210
-    in the SDP body with the ones returned by the proxy server for
211
-    each media stream that the SDP message describes. This will force
212
-    the media streams to be routed through the proxy server.
213
-    called when you want to make the session go through a proxy server
214
-
215
-  - end_media_session()
216
-
217
-    will call on the proxy server to end the media session for that call
218
-    this is done at the end of the call to instruct the proxy server to
219
-    free the resources allocated to that call as well as to save log
220
-    information about the call.
221
-    called when a session should end (BYE or CANCEL received)
222
-
223
-
224
-5. Comparison with the nathelper module
225
-   ------------------------------------
226
-
227
-  After reading all this you may wonder what this module can offer you that
228
-the nathelper module (a similar nat traversal solution) can't and why was
229
-necessary to develop this module.
230
-
231
-While at surface they seem to offer about the same functionality, there are
232
-a few core differences that make them quite different.
233
-
234
-  The main and most notable difference is that mediaproxy offers a
235
-distributed environment, where the mediaproxy module can control multiple
236
-mediaproxy servers. The mediaproxy servers can be local or remote and they
237
-can be specified per domain or as defaults for domains that don't have their
238
-own mediaproxy servers defined. These mediaproxy servers can be arranged in
239
-load balancing and fallback schemes allowing the platform to scale up easily
240
-and also offer redundancy to keep the service running even if some of the
241
-mediaproxies go offline. Mediaproxy is able to detect the dead proxies and
242
-redistribute the calls among the other mediaproxies that are available.
243
-(More details about this can be found in the SER MediaProxy documentation)
244
-
245
-  Another important difference is that mediaproxy tries to move the complex
246
-logic of decision from the ser configuration file to the module and the
247
-proxy servers themselves. This is why there are very few functions in this
248
-module that take any parameters. Instead, control is achieved by modifying
249
-resources outside of ser.cfg. This includes for example specifying the
250
-mediaproxy servers using DNS SRV records, or declaring asymmetric clients
251
-in external files that are automatically re-read as soon as they change.
252
-This allows SER to run without interruption or restarts. If one wants to
253
-change SER's behavior, instead of changing ser.cfg and restarting SER, one
254
-will change these external resources and SER will adapt it's behavior on the
255
-fly without any need for restart.
256
-Another advantage of this is that ser.cfg becomes simpler and easier to
257
-maintain.
258
-
259
-
260 0
deleted file mode 100644
... ...
@@ -1,8 +0,0 @@
1
-
2
-sip-asymmetric-clients and rtp-asymmetric-clients list clients that are
3
-asymmetric regarding the SIP signaling respective the RTP media streams.
4
-
5
-By default these files should go in /etc/ser/ (unless specifically
6
-configured to be somewhere else using the sip_asymmetrics and/or
7
-rtp_asymmetrics options available with the mediaproxy module.
8
-
9 0
deleted file mode 100644
... ...
@@ -1,12 +0,0 @@
1
-#
2
-# Lines starting with a '#' character or empty lines are ignored.
3
-# Put a User-Agent name or regular expression per line.
4
-# Check is case insensitive.
5
-#
6
-# This file should only list SIP clients that are asymmetric regarding
7
-# the RTP media streams. For clients that are asymmetric regarding the SIP
8
-# signaling, use the equivalent SIP version of this file.
9
-# Clients that are asymmetric for both SIP signaling as well as RTP media
10
-# streams should go in both files.
11
-#
12
-
13 0
deleted file mode 100644
... ...
@@ -1,118 +0,0 @@
1
-# Example ser.cfg for mediaproxy functionality
2
-
3
-loadmodule "/usr/lib/ser/modules/registrar.so"
4
-loadmodule "/usr/lib/ser/modules/domain.so"
5
-loadmodule "/usr/lib/ser/modules/mediaproxy.so"
6
-
7
-modparam("mediaproxy", "natping_interval", 60)
8
-modparam("registrar",  "nat_flag",         2)
9
-
10
-route{
11
-    if (!mf_process_maxfwd_header("10")) {
12
-        if (method!="ACK") {
13
-            sl_send_reply("483", "Too many hops");
14
-        };
15
-        break;
16
-    };
17
-
18
-    if (msg:len >= max_len) {
19
-        if (method!="ACK") {
20
-            sl_send_reply("513", "Message too big");
21
-        };
22
-        break;
23
-    };
24
-
25
-    if (method=="REGISTER") {
26
-        if (is_from_local()) {
27
-            # Mark as NAT'ed
28
-            if (client_nat_test("3")) {
29
-                setflag(2);
30
-                force_rport();
31
-                fix_contact();
32
-            };
33
-
34
-            if (!www_authorize("", "subscriber")) {
35
-                www_challenge("", "0");
36
-                break;
37
-            } else if (!check_to()) {
38
-                sl_send_reply("403", "Username!=To not allowed");
39
-                break;
40
-            };
41
-
42
-            if (!save("location")) {
43
-                sl_reply_error();  
44
-            };
45
-        } else {
46
-            sl_send_reply("403", "This domain is not served here");
47
-        };
48
-
49
-        break;
50
-    };
51
-
52
-    if (method=="INVITE") {
53
-        if (!(is_from_local() || is_uri_host_local())) {
54
-            sl_send_reply("403", "Relaying is forbidden");
55
-            break;
56
-        };
57
-        t_on_failure("1");
58
-    } else if (method == "BYE" || method == "CANCEL") {
59
-        end_media_session();
60
-    };
61
-
62
-    if (loose_route()) { 
63
-        if (method=="INVITE" || method=="ACK") {
64
-            use_media_proxy();
65
-        };
66
-        # end media session for BYE and CANCEL is done above
67
-        # before entering the loose route. no need to call it here
68
-        t_relay();
69
-        break;
70
-    };
71
-
72
-    # Force subsequent messages to pass trough this proxy
73
-    if (method == "INVITE") {
74
-        record_route();
75
-    };
76
-
77
-    if (client_nat_test("3") && !search("^Record-Route:")) {
78
-        # Mark as NAT'ed
79
-        force_rport();
80
-        fix_contact();
81
-    };
82
-
83
-    if (method=="INVITE") {
84
-        t_on_reply("1");
85
-    };
86
-
87
-    if (is_uri_host_local()) { # join with next if?
88
-        if (!lookup("location")) {
89
-            sl_send_reply("404", "User not found");
90
-            break;
91
-        };
92
-    };
93
-
94
-    if (method=="INVITE" || method=="ACK") {
95
-        use_media_proxy();
96
-    };
97
-
98
-    if (!t_relay()) {
99
-        if (method=="INVITE" || method=="ACK") {
100
-            end_media_session();
101
-        };
102
-        sl_reply_error();
103
-    };
104
-}
105
-
106
-failure_route[1] {
107
-    end_media_session();
108
-}
109
-
110
-onreply_route[1] {
111
-    if (status=~"(183)|(2[0-9][0-9])") {
112
-        if (client_nat_test("1")) {
113
-            fix_contact();
114
-        };
115
-        use_media_proxy();
116
-    };
117
-}
118
-
119 0
deleted file mode 100644
... ...
@@ -1,14 +0,0 @@
1
-#
2
-# Lines starting with a '#' character or empty lines are ignored.
3
-# Put a User-Agent name or regular expression per line.
4
-# Check is case insensitive.
5
-#
6
-# This file should only list SIP clients that are asymmetric regarding
7
-# the SIP signaling. For clients that are asymmetric regarding the RTP
8
-# media streams, use the equivalent RTP version of this file.
9
-# Clients that are asymmetric for both SIP signaling as well as RTP media
10
-# streams should go in both files.
11
-#
12
-
13
-ipDialog SipTone.*
14
-
15 0
deleted file mode 100644
... ...
@@ -1,194 +0,0 @@
1
-/* $Id$
2
- *
3
- * Copyright (C) 2004 Dan Pascu
4
- * Copyright (C) 2003 Porta Software Ltd
5
- *
6
- * This file is part of ser, a free SIP server.
7
- *
8
- * ser is free software; you can redistribute it and/or modify
9
- * it under the terms of the GNU General Public License as published by
10
- * the Free Software Foundation; either version 2 of the License, or
11
- * (at your option) any later version
12
- *
13
- * For a license to use the ser software under conditions
14
- * other than those described here, or to purchase support for this
15
- * software, please contact iptel.org by e-mail at the following addresses:
16
- *    info@iptel.org
17
- *
18
- * ser is distributed in the hope that it will be useful,
19
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
20
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21
- * GNU General Public License for more details.
22
- *
23
- * You should have received a copy of the GNU General Public License
24
- * along with this program; if not, write to the Free Software
25
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26
- *
27
- */
28
-
29
-static void
30
-pingClients(unsigned int ticks, void *param)
31
-{
32
-    static char pingbuf[4] = "\0\0\0\0";
33
-    static int length = 256;
34
-    struct hostent* hostent;
35
-    struct dest_info dst;
36
-    struct sip_uri uri;
37
-    void *buf, *ptr;
38
-    str contact;
39
-    int needed;
40
-    char proto;
41
-
42
-    buf = pkg_malloc(length);
43
-    if (buf == NULL) {
44
-        LOG(L_ERR, "error: mediaproxy/pingClients(): out of memory\n");
45
-        return;
46
-    }
47
-    needed = userLocation.get_all_ucontacts(buf, length, FL_NAT);
48
-    if (needed > 0) {
49
-        // make sure we alloc more than actually we were told is missing
50
-        // (some clients may register while we are making these calls)
51
-        length = (length + needed) * 2;
52
-        ptr = pkg_realloc(buf, length);
53
-        if (ptr == NULL) {
54
-            LOG(L_ERR, "error: mediaproxy/pingClients(): out of memory\n");
55
-            pkg_free(buf);
56
-            return;
57
-        } else {
58
-            buf = ptr;
59
-        }
60
-        // try again. we may fail again if _many_ clients register in between
61
-        needed = userLocation.get_all_ucontacts(buf, length, FL_NAT);
62
-        if (needed != 0) {
63
-            pkg_free(buf);
64
-            return;
65
-        }
66
-    }
67
-
68
-    ptr = buf;
69
-    while (1) {
70
-        memcpy(&(contact.len), ptr, sizeof(contact.len));
71
-        if (contact.len == 0)
72
-            break;
73
-        contact.s = (char*)ptr + sizeof(contact.len);
74
-        ptr = contact.s + contact.len;
75
-		init_dest_info(&dst);
76
-	memcpy(&dst.send_sock, ptr, sizeof(dst.send_sock));
77
-	ptr += sizeof(dst.send_sock);
78
-        if (parse_uri(contact.s, contact.len, &uri) < 0) {
79
-            LOG(L_ERR, "error: mediaproxy/pingClients(): can't parse contact uri\n");
80
-            continue;
81
-        }
82
-        if (uri.proto != PROTO_UDP && uri.proto != PROTO_NONE)
83
-            continue;
84
-        if (uri.port_no == 0)
85
-            uri.port_no = SIP_PORT;
86
-        proto=PROTO_UDP;
87
-        hostent = sip_resolvehost(&uri.host, &uri.port_no, &proto);
88
-        if (hostent == NULL){
89
-            LOG(L_ERR, "error: mediaproxy/pingClients(): can't resolve host\n");
90
-            continue;
91
-        }
92
-        hostent2su(&dst.to, hostent, 0, uri.port_no);
93
-	if (dst.send_sock==0) {
94
- 		dst.send_sock = get_send_socket(0, &dst.to, PROTO_UDP);
95
-        	if (dst.send_sock == NULL) {
96
-			LOG(L_ERR, "error: mediaproxy/pingClients(): can't get "
97
-			    "sending socket\n");
98
-			continue;
99
-		}
100
-        }
101
-		dst.proto=PROTO_UDP;
102
-        udp_send(&dst, pingbuf, sizeof(pingbuf));
103
-    }
104
-    pkg_free(buf);
105
-}
106
-
107
-
108
-// Replace IP:Port in Contact field with the source address of the packet.
109
-// Preserve port for SIP asymmetric clients
110
-static int
111
-FixContact(struct sip_msg* msg, char* str1, char* str2)
112
-{
113
-    str beforeHost, after, agent;
114
-    contact_t* contact;
115
-    struct lump* anchor;
116
-    struct sip_uri uri;
117
-    char *newip, *buf;
118
-    int len, newiplen, offset;
119
-    Bool asymmetric;
120
-
121
-    if (!getContactURI(msg, &uri, &contact))
122
-        return -1;
123
-
124
-    newip = ip_addr2a(&msg->rcv.src_ip);
125
-    newiplen = strlen(newip);
126
-
127
-    /* Don't do anything if the IP's are the same. Return success. */
128
-    if (newiplen==uri.host.len && memcmp(uri.host.s, newip, newiplen)==0) {
129
-        return 1;
130
-    }
131
-
132
-    if (uri.port.len == 0)
133
-        uri.port.s = uri.host.s + uri.host.len;
134
-
135
-    agent = getUserAgent(msg);
136
-    asymmetric = isSIPAsymmetric(agent);
137
-
138
-    beforeHost.s   = contact->uri.s;
139
-    beforeHost.len = uri.host.s - contact->uri.s;
140
-    if (asymmetric) {
141
-        // for asymmetrics we preserve the original port
142
-        after.s   = uri.port.s;
143
-        after.len = contact->uri.s + contact->uri.len - after.s;
144
-    } else {
145
-        after.s   = uri.port.s + uri.port.len;
146
-        after.len = contact->uri.s + contact->uri.len - after.s;
147
-    }
148
-
149
-    len = beforeHost.len + newiplen + after.len + 20;
150
-
151
-    // first try to alloc mem. if we fail we don't want to have the lump
152
-    // deleted and not replaced. at least this way we keep the original.
153
-    buf = pkg_malloc(len);
154
-    if (buf == NULL) {
155
-        LOG(L_ERR, "error: fix_contact(): out of memory\n");
156
-        return -1;
157
-    }
158
-
159
-    offset = contact->uri.s - msg->buf;
160
-    anchor = del_lump(msg, offset, contact->uri.len, HDR_CONTACT_T);
161
-
162
-    if (!anchor) {
163
-        pkg_free(buf);
164
-        return -1;
165
-    }
166
-
167
-    if (asymmetric && uri.port.len==0) {
168
-        len = sprintf(buf, "%.*s%s%.*s", beforeHost.len, beforeHost.s,
169
-                      newip, after.len, after.s);
170
-    } else if (asymmetric) {
171
-        len = sprintf(buf, "%.*s%s:%.*s", beforeHost.len, beforeHost.s,
172
-                      newip, after.len, after.s);
173
-    } else {
174
-        len = sprintf(buf, "%.*s%s:%d%.*s", beforeHost.len, beforeHost.s,
175
-                      newip, msg->rcv.src_port, after.len, after.s);
176
-    }
177
-
178
-    if (insert_new_lump_after(anchor, buf, len, HDR_CONTACT_T) == 0) {
179
-        pkg_free(buf);
180
-        return -1;
181
-    }
182
-
183
-    contact->uri.s   = buf;
184
-    contact->uri.len = len;
185
-
186
-    if (asymmetric) {
187
-        LOG(L_INFO, "info: fix_contact(): preserved port for SIP "
188
-            "asymmetric client: `%.*s'\n", agent.len, agent.s);
189
-    }
190
-
191
-    return 1;
192
-}
193
-
194
-
195 0
deleted file mode 100644
... ...
@@ -1,1604 +0,0 @@
1
-/* $Id$
2
- *
3
- * Copyright (C) 2004 Dan Pascu
4
- *
5
- * This file is part of ser, a free SIP server.
6
- *
7
- * ser is free software; you can redistribute it and/or modify
8
- * it under the terms of the GNU General Public License as published by
9
- * the Free Software Foundation; either version 2 of the License, or
10
- * (at your option) any later version
11
- *
12
- * For a license to use the ser software under conditions
13
- * other than those described here, or to purchase support for this
14
- * software, please contact iptel.org by e-mail at the following addresses:
15
- *    info@iptel.org
16
- *
17
- * ser is distributed in the hope that it will be useful,
18
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
- * GNU General Public License for more details.
21
- *
22
- * You should have received a copy of the GNU General Public License
23
- * along with this program; if not, write to the Free Software
24
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
25
- *
26
- */
27
-
28
-// TODO
29
-//
30
-// - make the asymmetric files use CFG_DIR
31
-// - find a way to install the config files with make install
32
-
33
-#include "../../sr_module.h"
34
-#include "../../dprint.h"
35
-#include "../../str.h"
36
-#include "../../error.h"
37
-#include "../../data_lump.h"
38
-#include "../../forward.h"
39
-#include "../../mem/mem.h"
40
-#include "../../resolve.h"
41
-#include "../../timer.h"
42
-#include "../../ut.h"
43
-#include "../../parser/parse_from.h"
44
-#include "../../parser/parse_to.h"
45
-#include "../../parser/parse_uri.h"
46
-#include "../../msg_translator.h"
47
-#include "../../id.h"
48
-#include "../registrar/sip_msg.h"
49
-#include "../usrloc/usrloc.h"
50
-
51
-#include <stdio.h>
52
-#include <stdlib.h>
53
-#include <unistd.h>
54
-#include <string.h>
55
-#include <ctype.h>
56
-#include <errno.h>
57
-#include <regex.h>
58
-#include <sys/types.h>
59
-#include <sys/stat.h>
60
-#include <sys/socket.h>
61
-#include <netinet/in.h>
62
-#include <arpa/inet.h>
63
-#include <sys/un.h>
64
-
65
-
66
-MODULE_VERSION
67
-
68
-
69
-// Although `AF_LOCAL' is mandated by POSIX.1g, `AF_UNIX' is portable to
70
-// more systems.  `AF_UNIX' was the traditional name stemming from BSD, so
71
-// even most POSIX systems support it.  It is also the name of choice in
72
-// the Unix98 specification. So if there's no AF_LOCAL fallback to AF_UNIX
73
-#ifndef AF_LOCAL
74
-# define AF_LOCAL AF_UNIX
75
-#endif
76
-
77
-
78
-#define min(x, y)         (((x) < (y)) ? (x) : (y))
79
-
80
-#define isAnyAddress(adr) ((adr).len==7 && memcmp("0.0.0.0", (adr).s, 7)==0)
81
-
82
-
83
-typedef int Bool;
84
-#define True  1
85
-#define False 0
86
-
87
-
88
-typedef int  (*CheckLocalPartyProc)(struct sip_msg* msg, char* s1, char* s2);
89
-
90
-typedef Bool (*NatTestProc)(struct sip_msg* msg);
91
-
92
-
93
-typedef enum {
94
-    NTNone=0,
95
-    NTPrivateContact=1,
96
-    NTSourceAddress=2,
97
-    NTPrivateVia=4
98
-} NatTestType;
99
-
100
-typedef enum {
101
-    STUnknown=0,
102
-    STAudio,
103
-    STVideo,
104
-    STAudioVideo
105
-} StreamType;
106
-
107
-typedef struct {
108
-    const char *name;
109
-    uint32_t address;
110
-    uint32_t mask;
111
-} NetInfo;
112
-
113
-typedef struct {
114
-    str ip;
115
-    str port;
116
-    str type;    // stream type (`audio', `video', ...)
117
-    int localIP; // true if the IP is locally defined inside this media stream
118
-} StreamInfo;
119
-
120
-typedef struct {
121
-    NatTestType test;
122
-    NatTestProc proc;
123
-} NatTest;
124
-
125
-typedef struct {
126
-    char *file;        // the file which lists the asymmetric clients
127
-    long timestamp;    // for checking if it was modified
128
-
129
-    regex_t **clients; // the asymmetric clients regular expressions
130
-    int size;          // size of array above
131
-    int count;         // how many clients are in array above
132
-} AsymmetricClients;
133
-
134
-
135
-/* Function prototypes */
136
-static int ClientNatTest(struct sip_msg *msg, char *str1, char *str2);
137
-static int FixContact(struct sip_msg *msg, char *str1, char *str2);
138
-static int UseMediaProxy(struct sip_msg *msg, char *str1, char *str2);
139
-static int EndMediaSession(struct sip_msg *msg, char *str1, char *str2);
140
-
141
-static int mod_init(void);
142
-
143
-static Bool testPrivateContact(struct sip_msg* msg);
144
-static Bool testSourceAddress(struct sip_msg* msg);
145
-static Bool testPrivateVia(struct sip_msg* msg);
146
-
147
-
148
-/* Local global variables */
149
-static char *mediaproxySocket = "/var/run/proxydispatcher.sock";
150
-
151
-static int natpingInterval = 60; // 60 seconds
152
-
153
-static usrloc_api_t userLocation;
154
-
155
-static AsymmetricClients sipAsymmetrics = {
156
-    "/etc/ser/sip-asymmetric-clients",
157
-    //CFG_DIR"/sip-asymmetric-clients",
158
-    0,
159
-    NULL,
160
-    0,
161
-    0
162
-};
163
-
164
-static AsymmetricClients rtpAsymmetrics = {
165
-    "/etc/ser/rtp-asymmetric-clients",
166
-    0,
167
-    NULL,
168
-    0,
169
-    0
170
-};
171
-
172
-//static CheckLocalPartyProc isToLocal;
173
-
174
-NetInfo rfc1918nets[] = {
175
-    {"10.0.0.0",    0x0a000000UL, 0xff000000UL},
176
-    {"172.16.0.0",  0xac100000UL, 0xfff00000UL},
177
-    {"192.168.0.0", 0xc0a80000UL, 0xffff0000UL},
178
-    {NULL,          0UL,          0UL}
179
-};
180
-
181
-NatTest natTests[] = {
182
-    {NTPrivateContact, testPrivateContact},
183
-    {NTSourceAddress,  testSourceAddress},
184
-    {NTPrivateVia,     testPrivateVia},
185
-    {NTNone,           NULL}
186
-};
187
-
188
-static cmd_export_t commands[] = {
189
-    {"fix_contact",       FixContact,      0, 0,             REQUEST_ROUTE | ONREPLY_ROUTE },
190
-    {"use_media_proxy",   UseMediaProxy,   0, 0,             REQUEST_ROUTE | ONREPLY_ROUTE },
191
-    {"end_media_session", EndMediaSession, 0, 0,             REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE },
192
-    {"client_nat_test",   ClientNatTest,   1, fixup_int_1, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE },
193
-    {0, 0, 0, 0, 0}
194
-};
195
-
196
-static param_export_t parameters[] = {
197
-    {"mediaproxy_socket", PARAM_STRING, &mediaproxySocket},
198
-    {"sip_asymmetrics",   PARAM_STRING, &(sipAsymmetrics.file)},
199
-    {"rtp_asymmetrics",   PARAM_STRING, &(rtpAsymmetrics.file)},
200
-    {"natping_interval",  PARAM_INT,    &natpingInterval},
201
-    {0, 0, 0}
202
-};
203
-
204
-struct module_exports exports = {
205
-    "mediaproxy", // module name
206
-    commands,     // module exported functions
207
-    0,            // RPC methods
208
-    parameters,   // module exported parameters
209
-    mod_init,     // module init (before any kid is created. kids will inherit)
210
-    NULL,         // reply processing
211
-    NULL,         // destroy function
212
-    NULL,         // on_break
213
-    NULL          // child_init
214
-};
215
-
216
-
217
-
218
-/* Helper functions */
219
-
220
-// Functions dealing with strings
221
-
222
-/*
223
- * strfind() finds the start of the first occurrence of the substring needle
224
- * of length nlen in the memory area haystack of length len.
225
- */
226
-static void*
227
-strfind(const void *haystack, size_t len, const void *needle, size_t nlen)
228
-{
229
-    char *sp;
230
-
231
-    /* Sanity check */
232
-    if(!(haystack && needle && nlen && len>=nlen))
233
-        return NULL;
234
-
235
-    for (sp = (char*)haystack; sp <= (char*)haystack + len - nlen; sp++) {
236
-        if (*sp == *(char*)needle && memcmp(sp, needle, nlen)==0) {
237
-            return sp;
238
-        }
239
-    }
240
-
241
-    return NULL;
242
-}
243
-
244
-/*
245
- * strcasefind() finds the start of the first occurrence of the substring
246
- * needle of length nlen in the memory area haystack of length len by doing
247
- * a case insensitive search
248
- */
249
-static void*
250
-strcasefind(const char *haystack, size_t len, const char *needle, size_t nlen)
251
-{
252
-    char *sp;
253
-
254
-    /* Sanity check */
255
-    if(!(haystack && needle && nlen && len>=nlen))
256
-        return NULL;
257
-
258
-    for (sp = (char*)haystack; sp <= (char*)haystack + len - nlen; sp++) {
259
-        if (tolower(*sp) == tolower(*(char*)needle) &&
260
-            strncasecmp(sp, needle, nlen)==0) {
261
-            return sp;
262
-        }
263
-    }
264
-
265
-    return NULL;
266
-}
267
-
268
-/* returns string with whitespace trimmed from left end */
269
-static inline void
270
-ltrim(str *string)
271
-{
272
-    while (string->len>0 && isspace((int)*(string->s))) {
273
-        string->len--;
274
-        string->s++;
275
-    }
276
-}
277
-
278
-/* returns string with whitespace trimmed from right end */
279
-static inline void
280
-rtrim(str *string)
281
-{
282
-    char *ptr;
283
-
284
-    ptr = string->s + string->len - 1;
285
-    while (string->len>0 && (*ptr==0 || isspace((int)*ptr))) {
286
-        string->len--;
287
-        ptr--;
288
-    }
289
-}
290
-
291
-/* returns string with whitespace trimmed from both ends */
292
-static inline void
293
-trim(str *string)
294
-{
295
-    ltrim(string);
296
-    rtrim(string);
297
-}
298
-
299
-/* returns a pointer to first CR or LF char found or the end of string */
300
-static char*
301
-findendline(char *string, int len)
302
-{
303
-    char *ptr = string;
304
-
305
-    while(ptr - string < len && *ptr != '\n' && *ptr != '\r')
306
-        ptr++;
307
-
308
-    return ptr;
309
-}
310
-
311
-
312
-static int
313
-strtoint(str *data)
314
-{
315
-    long int result;
316
-    char c;
317
-
318
-    // hack to avoid copying the string
319
-    c = data->s[data->len];
320
-    data->s[data->len] = 0;
321
-    result = strtol(data->s, NULL, 10);
322
-    data->s[data->len] = c;
323
-
324
-    return (int)result;
325
-}
326
-
327
-
328
-/* Free the returned string with pkg_free() after you've done with it */
329
-static char*
330
-encodeQuopri(str buf)
331
-{
332
-    char *result;
333
-    int i, j;
334
-    char c;
335
-
336
-    result = pkg_malloc(buf.len*3+1);
337
-    if (!result) {
338
-        LOG(L_ERR, "error: mediaproxy/encodeQuopri(): out of memory\n");
339
-        return NULL;
340
-    }
341
-
342
-    for (i=0, j=0; i<buf.len; i++) {
343
-        c = buf.s[i];
344
-        if ((c>0x20 && c<0x7f && c!='=') || c=='\n' || c=='\r') {
345
-            result[j++] = c;
346
-        } else {
347
-            result[j++] = '=';
348
-            sprintf(&result[j], "%02X", (c & 0xff));
349
-            j += 2;
350
-        }
351
-    }
352
-    result[j] = 0;
353
-
354
-    return result;
355
-}
356
-
357
-
358
-/* Find a line in str `block' that starts with `start'. */
359
-static char*
360
-findLineStartingWith(str *block, char *start, int ignoreCase)
361
-{
362
-    char *ptr, *bend;
363
-    str zone;
364
-    int tlen;
365
-
366
-    bend = block->s + block->len;
367
-    tlen = strlen(start);
368
-    ptr = NULL;
369
-
370
-    for (zone = *block; zone.len > 0; zone.len = bend - zone.s) {
371
-        if (ignoreCase)
372
-            ptr = strcasefind(zone.s, zone.len, start, tlen);
373
-        else
374
-            ptr = strfind(zone.s, zone.len, start, tlen);
375
-        if (!ptr || ptr==zone.s || ptr[-1]=='\n' || ptr[-1]=='\r')
376
-            break;
377
-        zone.s = ptr + tlen;
378
-    }
379
-
380
-    return ptr;
381
-}
382
-
383
-
384
-/* get up to `limit' whitespace separated tokens from `char *string' */
385
-static int
386
-getTokens(char *string, str *tokens, int limit)
387
-{
388
-    int i, len, size;
389
-    char *ptr;
390
-
391
-    if (!string) {
392
-        return 0;
393
-    }
394
-
395
-    len  = strlen(string);
396
-
397
-    for (ptr=string, i=0; i<limit && len>0; i++) {
398
-        size = strspn(ptr, " \t\n\r");
399
-        ptr += size;
400
-        len -= size;
401
-        if (len <= 0)
402
-            break;
403
-        size = strcspn(ptr, " \t\n\r");
404
-        if (size==0)
405
-            break;
406
-        tokens[i].s = ptr;
407
-        tokens[i].len = size;
408
-        ptr += size;
409
-        len -= size;
410
-    }
411
-
412
-    return i;
413
-}
414
-
415
-/* get up to `limit' whitespace separated tokens from `str *string' */
416
-static int
417
-getStrTokens(str *string, str *tokens, int limit)
418
-{
419
-    int count;
420
-    char c;
421
-
422
-    if (!string || !string->s) {
423
-        return 0;
424
-    }
425
-
426
-    c = string->s[string->len];
427
-    string->s[string->len] = 0;
428
-
429
-    count = getTokens(string->s, tokens, limit);
430
-
431
-    string->s[string->len] = c;
432
-
433
-    return count;
434
-}
435
-
436
-
437
-/* Functions to extract the info we need from the SIP/SDP message */
438
-
439
-/* Extract Call-ID value. */
440
-static Bool
441
-getCallId(struct sip_msg* msg, str *cid)
442
-{
443
-    if (msg->callid == NULL) {
444
-        if (parse_headers(msg, HDR_CALLID_F, 0) == -1) {
445
-            return False;
446
-        }
447
-        if (msg->callid == NULL) {
448
-            return False;
449
-        }
450
-    }
451
-
452
-    *cid = msg->callid->body;
453
-
454
-    trim(cid);
455
-
456
-    return True;
457
-}
458
-
459
-
460
-/* Get caller domain */
461
-static str
462
-getFromDomain(char** type, struct sip_msg* msg)
463
-{
464
-    static char buf[16] = "unknown"; // buf is here for a reason. don't
465
-    static str notfound = {buf, 7};  // use the constant string directly!
466
-    static struct sip_uri puri;
467
-    str uri, did;
468
-
469
-    if (get_from_did(&did, msg) == 1) {
470
-		*type = "local";
471
-		return did;
472
-    }
473
-
474
-    *type = "remote";
475
-
476
-    if (parse_from_header(msg) < 0) {
477
-        LOG(L_ERR, "error: mediaproxy/getFromDomain(): error parsing `From' header\n");
478
-        return notfound;
479
-    }
480
-
481
-    uri = get_from(msg)->uri;
482
-
483
-    if (parse_uri(uri.s, uri.len, &puri) < 0) {
484
-        LOG(L_ERR, "error: mediaproxy/getFromDomain(): error parsing `From' URI\n");
485
-        return notfound;
486
-    } else if (puri.host.len == 0) {
487
-        return notfound;
488
-    }
489
-
490
-    return puri.host;
491
-}
492
-
493
-/* Get called domain */
494
-static str
495
-getToDomain(char** type, struct sip_msg* msg)
496
-{
497
-    static char buf[16] = "unknown"; // buf is here for a reason. don't
498
-    static str notfound = {buf, 7};  // use the constant string directly!
499
-    static struct sip_uri puri;
500
-    str uri, did;
501
-
502
-    if (get_to_did(&did, msg) == 0) {
503
-	*type = "local";
504
-	return did;
505
-    }
506
-
507
-    *type = "remote";
508
-
509
-    uri = get_to(msg)->uri;
510
-
511
-    if (parse_uri(uri.s, uri.len, &puri) < 0) {
512
-        LOG(L_ERR, "error: mediaproxy/getToDomain(): error parsing `To' URI\n");
513
-        return notfound;
514
-    } else if (puri.host.len == 0) {
515
-        return notfound;
516
-    }
517
-
518
-    return puri.host;
519
-
520
-}
521
-
522
-/* Get destination domain */
523
-// This function only works when called for a request although it's more
524
-// reliable than the getToDomain function.
525
-static str
526
-getDestinationDomain(char** type, struct sip_msg* msg)
527
-{
528
-    static char buf[16] = "unknown"; // buf is here for a reason. don't
529
-    static str notfound = {buf, 7};  // use the constant string directly!
530
-    str did;
531
-
532
-    if (get_to_did(&did, msg) == 0) {
533
-	*type = "local";
534
-	return did;
535
-    }
536
-
537
-    *type = "remote";
538
-
539
-    if (parse_sip_msg_uri(msg) < 0) {
540
-        LOG(L_ERR, "error: mediaproxy/getDestinationDomain(): error parsing destination URI\n");
541
-        return notfound;
542
-    } else if (msg->parsed_uri.host.len==0) {
543
-        return notfound;
544
-    }
545
-
546
-    return msg->parsed_uri.host;
547
-}
548
-
549
-
550
-/* Get From tag */
551
-static str
552
-getFromAddress(struct sip_msg *msg)
553
-{
554
-    static char buf[16] = "unknown"; // buf is here for a reason. don't
555
-    static str notfound = {buf, 7};  // use the constant string directly!
556
-    str uri;
557
-    char *ptr;
558
-
559
-    if (parse_from_header(msg) == -1) {
560
-        LOG(L_ERR, "error: mediaproxy/getFromAddress(): error parsing From: field\n");
561
-        return notfound;
562
-    }
563
-
564
-    uri = get_from(msg)->uri;
565
-
566
-    if (uri.len == 0)
567
-        return notfound;
568
-
569
-    if (strncmp(uri.s, "sip:", 4)==0) {
570
-        uri.s += 4;
571
-        uri.len -= 4;
572
-    }
573
-
574
-    if ((ptr = strfind(uri.s, uri.len, ";", 1))!=NULL) {
575
-        uri.len = ptr - uri.s;
576
-    }
577
-
578
-    return uri;
579
-}
580
-
581
-
582
-/* Get To tag */
583
-static str
584
-getToAddress(struct sip_msg *msg)
585
-{
586
-    static char buf[16] = "unknown"; // buf is here for a reason. don't
587
-    static str notfound = {buf, 7};  // use the constant string directly!
588
-    str uri;
589
-    char *ptr;
590
-
591
-    if (!msg->to) {
592
-        LOG(L_ERR, "error: mediaproxy/getToAddress(): missing To: field\n");
593
-        return notfound;
594
-    }
595
-
596
-    uri = get_to(msg)->uri;
597
-
598
-    if (uri.len == 0)
599
-        return notfound;
600
-
601
-    if (strncmp(uri.s, "sip:", 4)==0) {
602
-        uri.s += 4;
603
-        uri.len -= 4;
604
-    }
605
-
606
-    if ((ptr = strfind(uri.s, uri.len, ";", 1))!=NULL) {
607
-        uri.len = ptr - uri.s;
608
-    }
609
-
610
-    return uri;
611
-}
612
-
613
-
614
-/* Get From tag */
615
-static str
616
-getFromTag(struct sip_msg *msg)
617
-{
618
-    static char buf[4] = "";        // buf is here for a reason. don't
619
-    static str notfound = {buf, 0}; // use the constant string directly!
620
-    str tag;
621
-
622
-    if (parse_from_header(msg) == -1) {
623
-        LOG(L_ERR, "error: mediaproxy/getFromTag(): error parsing From: field\n");
624
-        return notfound;
625
-    }
626
-
627
-    tag = get_from(msg)->tag_value;
628
-
629
-    if (tag.len == 0)
630
-        return notfound;
631
-
632
-    return tag;
633
-}
634
-
635
-
636
-/* Get To tag */
637
-static str
638
-getToTag(struct sip_msg *msg)
639
-{
640
-    static char buf[4] = "";        // buf is here for a reason. don't
641
-    static str notfound = {buf, 0}; // use the constant string directly!
642
-    str tag;
643
-
644
-    if (!msg->to) {
645
-        LOG(L_ERR, "error: mediaproxy/getToTag(): missing To: field\n");
646
-        return notfound;
647
-    }
648
-
649
-    tag = get_to(msg)->tag_value;
650
-
651
-    if (tag.len == 0)
652
-        return notfound;
653
-
654
-    return tag;
655
-}
656
-
657
-
658
-/* Extract User-Agent */
659
-static str
660
-getUserAgent(struct sip_msg* msg)
661
-{
662
-    static char buf[16] = "unknown-agent"; // buf is here for a reason. don't
663
-    static str notfound = {buf, 13};       // use the constant string directly!
664
-    str block, server;
665
-    char *ptr;
666
-
667
-    if ((parse_headers(msg, HDR_USERAGENT_F, 0)!=-1) && msg->user_agent &&
668
-        msg->user_agent->body.len>0) {
669
-        return msg->user_agent->body;
670
-    }
671
-
672
-    // If we can't find user-agent, look after the Server: field
673
-
674
-    // This is a temporary hack. Normally it should be extracted by ser
675
-    // (either as the Server field, or if User-Agent is missing in place
676
-    // of the User-Agent field)
677
-
678
-    block.s   = msg->buf;
679
-    block.len = msg->len;
680
-
681
-    ptr = findLineStartingWith(&block, "Server:", True);
682
-    if (!ptr)
683
-        return notfound;
684
-
685
-    server.s   = ptr + 7;
686
-    server.len = findendline(server.s, block.s+block.len-server.s) - server.s;
687
-
688
-    trim(&server);
689
-    if (server.len == 0)
690
-        return notfound;
691
-
692
-    return server;
693
-}
694
-
695
-// Get URI from the Contact: field.
696
-static Bool
697
-getContactURI(struct sip_msg* msg, struct sip_uri *uri, contact_t** _c)
698
-{
699
-
700
-    if ((parse_headers(msg, HDR_CONTACT_F, 0) == -1) || !msg->contact)
701
-        return False;
702
-
703
-    if (!msg->contact->parsed && parse_contact(msg->contact) < 0) {
704
-        LOG(L_ERR, "error: mediaproxy/getContactURI(): cannot parse Contact header\n");
705
-        return False;
706
-    }
707
-
708
-    *_c = ((contact_body_t*)msg->contact->parsed)->contacts;
709
-
710
-    if (*_c == NULL) {
711
-        return False;
712
-    }
713
-
714
-    if (parse_uri((*_c)->uri.s, (*_c)->uri.len, uri) < 0 || uri->host.len <= 0) {
715
-        LOG(L_ERR, "error: mediaproxy/getContactURI(): cannot parse Contact URI\n");
716
-        return False;
717
-    }
718
-
719
-    return True;
720
-}
721
-
722
-
723
-// Functions to manipulate the SDP message body
724
-
725
-static Bool
726
-checkContentType(struct sip_msg *msg)
727
-{
728
-    str type;
729
-
730
-    if (!msg->content_type) {
731
-        LOG(L_WARN, "warning: mediaproxy/checkContentType(): Content-Type "
732
-            "header missing! Let's assume the content is text/plain ;-)\n");
733
-        return True;
734
-    }
735
-
736
-    type = msg->content_type->body;
737
-    trim(&type);
738
-
739
-    if (strncasecmp(type.s, "application/sdp", 15) != 0) {
740
-        LOG(L_ERR, "error: mediaproxy/checkContentType(): invalid Content-Type "
741
-            "for SDP message\n");
742
-        return False;
743
-    }
744
-
745
-    if (!(isspace((int)type.s[15]) || type.s[15] == ';' || type.s[15] == 0)) {
746
-        LOG(L_ERR,"error: mediaproxy/checkContentType(): invalid character "
747
-            "after Content-Type!\n");
748
-        return False;
749
-    }
750
-
751
-    return True;