blob: a16c03cc26cff5ec94c521184b8cc166e44b2fcd [file] [log] [blame]
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +02001/* A Media Gateway Control Protocol Media Gateway: RFC 3435 */
2
3/*
4 * (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
5 * (C) 2009 by on-waves.com
6 * All Rights Reserved
7 *
8 * This program 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 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 *
22 */
23
24#include <ctype.h>
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28#include <time.h>
29#include <limits.h>
30#include <unistd.h>
31
32#include <sys/socket.h>
33#include <arpa/inet.h>
34
35#include <openbsc/debug.h>
36#include <openbsc/msgb.h>
37#include <openbsc/talloc.h>
38#include <openbsc/gsm_data.h>
39#include <openbsc/select.h>
40#include <openbsc/mgcp.h>
Holger Hans Peter Freyther338fa562009-11-19 15:03:39 +010041#include <openbsc/telnet_interface.h>
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +020042
43#include <vty/command.h>
44#include <vty/vty.h>
45
46/* this is here for the vty... it will never be called */
47void subscr_put() { abort(); }
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +020048
49#define _GNU_SOURCE
50#include <getopt.h>
51
52#warning "Make use of the rtp proxy code"
53
54static int source_port = 2427;
55static const char *local_ip = NULL;
56static const char *source_addr = "0.0.0.0";
57static struct bsc_fd bfd;
Holger Hans Peter Freyther4ec389e2009-11-20 11:10:31 +010058static unsigned int number_endpoints = 0;
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +020059static const char *bts_ip = NULL;
60static struct in_addr bts_in;
61static int first_request = 1;
62static const char *audio_name = "GSM-EFR/8000";
63static int audio_payload = 97;
Holger Hans Peter Freyther138b7ec2009-11-18 18:32:31 +010064static int audio_loop = 0;
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +020065static int early_bind = 0;
66
Holger Hans Peter Freyther14083be2010-01-05 12:21:36 +010067static char *forward_ip = NULL;
Holger Hans Peter Freytherbd5130d2010-01-13 23:36:53 +010068static int forward_port = 0;
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +020069static char *config_file = "mgcp.cfg";
70
71/* used by msgb and mgcp */
72void *tall_bsc_ctx = NULL;
73
74enum mgcp_connection_mode {
75 MGCP_CONN_NONE = 0,
76 MGCP_CONN_RECV_ONLY = 1,
77 MGCP_CONN_SEND_ONLY = 2,
78 MGCP_CONN_RECV_SEND = MGCP_CONN_RECV_ONLY | MGCP_CONN_SEND_ONLY,
79};
80
Holger Hans Peter Freyther138b7ec2009-11-18 18:32:31 +010081enum {
82 DEST_NETWORK = 0,
83 DEST_BTS = 1,
84};
85
86enum {
87 PROTO_RTP,
88 PROTO_RTCP,
89};
90
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +020091#define CI_UNUSED 0
92static unsigned int last_call_id = 0;
93
94struct mgcp_endpoint {
95 int ci;
96 char *callid;
97 char *local_options;
98 int conn_mode;
99
Holger Hans Peter Freyther6c796462010-01-13 22:49:55 +0100100 /* the local rtp port we are binding to */
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +0200101 int rtp_port;
102
103 /*
104 * RTP mangling:
105 * - we get RTP and RTCP to us and need to forward to the BTS
106 * - we get RTP and RTCP from the BTS and forward to the network
107 */
108 struct bsc_fd local_rtp;
109 struct bsc_fd local_rtcp;
110
111 struct in_addr remote;
Holger Hans Peter Freyther601a67e2010-01-13 16:37:32 +0100112 struct in_addr bts;
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +0200113
114 /* in network byte order */
Holger Hans Peter Freyther6c796462010-01-13 22:49:55 +0100115 int net_rtp, net_rtcp;
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +0200116 int bts_rtp, bts_rtcp;
117};
118
119static struct mgcp_endpoint *endpoints = NULL;
120#define ENDPOINT_NUMBER(endp) abs(endp - endpoints)
121
122/**
123 * Macro for tokenizing MGCP messages and SDP in one go.
124 *
125 */
126#define MSG_TOKENIZE_START \
127 line_start = 0; \
128 for (i = 0; i < msgb_l3len(msg); ++i) { \
129 /* we have a line end */ \
130 if (msg->l3h[i] == '\n') { \
131 /* skip the first line */ \
132 if (line_start == 0) { \
133 line_start = i + 1; \
134 continue; \
135 } \
136 \
137 /* check if we have a proper param */ \
138 if (i - line_start == 1 && msg->l3h[line_start] == '\r') { \
139 } else if (i - line_start > 2 \
140 && islower(msg->l3h[line_start]) \
141 && msg->l3h[line_start + 1] == '=') { \
142 } else if (i - line_start < 3 \
143 || msg->l3h[line_start + 1] != ':' \
144 || msg->l3h[line_start + 2] != ' ') \
145 goto error; \
146 \
147 msg->l3h[i] = '\0'; \
148 if (msg->l3h[i-1] == '\r') \
149 msg->l3h[i-1] = '\0';
150
151#define MSG_TOKENIZE_END \
152 line_start = i + 1; \
153 } \
154 }
155
156
157struct mgcp_msg_ptr {
158 unsigned int start;
159 unsigned int length;
160};
161
162struct mgcp_request {
163 char *name;
164 void (*handle_request) (struct msgb *msg, struct sockaddr_in *source);
165 char *debug_name;
166};
167
168#define MGCP_REQUEST(NAME, REQ, DEBUG_NAME) \
169 { .name = NAME, .handle_request = REQ, .debug_name = DEBUG_NAME },
170
171static void handle_audit_endpoint(struct msgb *msg, struct sockaddr_in *source);
172static void handle_create_con(struct msgb *msg, struct sockaddr_in *source);
173static void handle_delete_con(struct msgb *msg, struct sockaddr_in *source);
174static void handle_modify_con(struct msgb *msg, struct sockaddr_in *source);
175
176static int generate_call_id()
177{
178 int i;
179
180 /* use the call id */
181 ++last_call_id;
182
183 /* handle wrap around */
184 if (last_call_id == CI_UNUSED)
185 ++last_call_id;
186
187 /* callstack can only be of size number_of_endpoints */
188 /* verify that the call id is free, e.g. in case of overrun */
189 for (i = 1; i < number_endpoints; ++i)
190 if (endpoints[i].ci == last_call_id)
191 return generate_call_id();
192
193 return last_call_id;
194}
195
196/* FIXIME/TODO: need to have a list of pending transactions and check that */
197static unsigned int generate_transaction_id()
198{
199 return abs(rand());
200}
201
202static int _send(int fd, struct in_addr *addr, int port, char *buf, int len)
203{
204 struct sockaddr_in out;
205 out.sin_family = AF_INET;
206 out.sin_port = port;
207 memcpy(&out.sin_addr, addr, sizeof(*addr));
208
209 return sendto(fd, buf, len, 0, (struct sockaddr *)&out, sizeof(out));
210}
211
212/*
213 * There is data coming. We will have to figure out if it
214 * came from the BTS or the MediaGateway of the MSC. On top
215 * of that we need to figure out if it was RTP or RTCP.
216 *
217 * Currently we do not communicate with the BSC so we have
218 * no idea where the BTS is listening for RTP and need to
219 * do the classic routing trick. Wait for the first packet
220 * from the BTS and then go ahead.
221 */
222static int rtp_data_cb(struct bsc_fd *fd, unsigned int what)
223{
224 char buf[4096];
225 struct sockaddr_in addr;
226 socklen_t slen = sizeof(addr);
227 struct mgcp_endpoint *endp;
Holger Hans Peter Freyther138b7ec2009-11-18 18:32:31 +0100228 int rc, dest, proto;
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +0200229
230 endp = (struct mgcp_endpoint *) fd->data;
231
232 rc = recvfrom(fd->fd, &buf, sizeof(buf), 0,
233 (struct sockaddr *) &addr, &slen);
234 if (rc < 0) {
235 DEBUGP(DMGCP, "Failed to receive message on: 0x%x\n",
236 ENDPOINT_NUMBER(endp));
237 return -1;
238 }
239
Holger Hans Peter Freyther48ecad42009-11-19 16:04:10 +0100240 /* do not forward aynthing... maybe there is a packet from the bts */
Holger Hans Peter Freyther9b28fc82010-01-13 23:53:59 +0100241 if (endp->ci == CI_UNUSED) {
242 DEBUGP(DMGCP, "Unknown message on endpoint: 0x%x\n", ENDPOINT_NUMBER(endp));
Holger Hans Peter Freyther48ecad42009-11-19 16:04:10 +0100243 return -1;
Holger Hans Peter Freyther9b28fc82010-01-13 23:53:59 +0100244 }
Holger Hans Peter Freyther48ecad42009-11-19 16:04:10 +0100245
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +0200246 /*
247 * Figure out where to forward it to. This code assumes that we
248 * have received the Connection Modify and know who is a legitimate
249 * partner. According to the spec we could attempt to forward even
250 * after the Create Connection but we will not as we are not really
251 * able to tell if this is legitimate.
252 */
253 #warning "Slight spec violation. With connection mode recvonly we should attempt to forward."
Holger Hans Peter Freyther138b7ec2009-11-18 18:32:31 +0100254 dest = memcmp(&addr.sin_addr, &endp->remote, sizeof(addr.sin_addr)) == 0
255 ? DEST_BTS : DEST_NETWORK;
256 proto = fd == &endp->local_rtp ? PROTO_RTP : PROTO_RTCP;
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +0200257
258 /* We have no idea who called us, maybe it is the BTS. */
Holger Hans Peter Freyther138b7ec2009-11-18 18:32:31 +0100259 if (dest == DEST_NETWORK && endp->bts_rtp == 0) {
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +0200260 /* it was the BTS... */
Holger Hans Peter Freyther601a67e2010-01-13 16:37:32 +0100261 if (!bts_ip || memcmp(&addr.sin_addr, &bts_in, sizeof(bts_in)) == 0) {
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +0200262 if (fd == &endp->local_rtp) {
263 endp->bts_rtp = addr.sin_port;
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +0200264 } else {
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +0200265 endp->bts_rtcp = addr.sin_port;
266 }
267
Holger Hans Peter Freyther601a67e2010-01-13 16:37:32 +0100268 endp->bts = addr.sin_addr;
Holger Hans Peter Freyther8ea4b562009-11-19 16:25:53 +0100269 DEBUGP(DMGCP, "Found BTS for endpoint: 0x%x on port: %d/%d\n",
270 ENDPOINT_NUMBER(endp), ntohs(endp->bts_rtp), ntohs(endp->bts_rtcp));
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +0200271 }
272 }
273
Holger Hans Peter Freyther138b7ec2009-11-18 18:32:31 +0100274 /* dispatch */
275 if (audio_loop)
276 dest = !dest;
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +0200277
Holger Hans Peter Freyther138b7ec2009-11-18 18:32:31 +0100278 if (dest == DEST_NETWORK) {
279 return _send(fd->fd, &endp->remote,
Holger Hans Peter Freyther6c796462010-01-13 22:49:55 +0100280 proto == PROTO_RTP ? endp->net_rtp : endp->net_rtcp,
Holger Hans Peter Freyther138b7ec2009-11-18 18:32:31 +0100281 buf, rc);
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +0200282 } else {
Holger Hans Peter Freyther601a67e2010-01-13 16:37:32 +0100283 return _send(fd->fd, &endp->bts,
Holger Hans Peter Freyther138b7ec2009-11-18 18:32:31 +0100284 proto == PROTO_RTP ? endp->bts_rtp : endp->bts_rtcp,
285 buf, rc);
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +0200286 }
287}
288
289static int create_bind(struct bsc_fd *fd, int port)
290{
291 struct sockaddr_in addr;
292 int on = 1;
293
294 fd->fd = socket(AF_INET, SOCK_DGRAM, 0);
295 if (fd->fd < 0)
296 return -1;
297
298 setsockopt(fd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
299 memset(&addr, 0, sizeof(addr));
300 addr.sin_family = AF_INET;
301 addr.sin_port = htons(port);
302 inet_aton(source_addr, &addr.sin_addr);
303
304 if (bind(fd->fd, (struct sockaddr *) &addr, sizeof(addr)) < 0)
305 return -1;
306
307 return 0;
308}
309
310static int bind_rtp(struct mgcp_endpoint *endp)
311{
312 /* set to zero until we get the info */
313 memset(&endp->remote, 0, sizeof(endp->remote));
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +0200314
315 if (create_bind(&endp->local_rtp, endp->rtp_port) != 0) {
316 DEBUGP(DMGCP, "Failed to create RTP port: %d on 0x%x\n",
317 endp->rtp_port, ENDPOINT_NUMBER(endp));
318 goto cleanup0;
319 }
320
321 if (create_bind(&endp->local_rtcp, endp->rtp_port + 1) != 0) {
322 DEBUGP(DMGCP, "Failed to create RTCP port: %d on 0x%x\n",
323 endp->rtp_port + 1, ENDPOINT_NUMBER(endp));
324 goto cleanup1;
325 }
326
327 endp->local_rtp.cb = rtp_data_cb;
328 endp->local_rtp.data = endp;
329 endp->local_rtp.when = BSC_FD_READ;
330 if (bsc_register_fd(&endp->local_rtp) != 0) {
331 DEBUGP(DMGCP, "Failed to register RTP port %d on 0x%x\n",
332 endp->rtp_port, ENDPOINT_NUMBER(endp));
333 goto cleanup2;
334 }
335
336 endp->local_rtcp.cb = rtp_data_cb;
337 endp->local_rtcp.data = endp;
338 endp->local_rtcp.when = BSC_FD_READ;
339 if (bsc_register_fd(&endp->local_rtcp) != 0) {
340 DEBUGP(DMGCP, "Failed to register RTCP port %d on 0x%x\n",
341 endp->rtp_port + 1, ENDPOINT_NUMBER(endp));
342 goto cleanup3;
343 }
344
345 return 0;
346
347cleanup3:
348 bsc_unregister_fd(&endp->local_rtp);
349cleanup2:
350 close(endp->local_rtcp.fd);
351 endp->local_rtcp.fd = -1;
352cleanup1:
353 close(endp->local_rtp.fd);
354 endp->local_rtp.fd = -1;
355cleanup0:
356 return -1;
357}
358
359/*
360 * array of function pointers for handling various
361 * messages. In the future this might be binary sorted
362 * for performance reasons.
363 */
364static const struct mgcp_request mgcp_requests [] = {
365 MGCP_REQUEST("AUEP", handle_audit_endpoint, "AuditEndpoint")
366 MGCP_REQUEST("CRCX", handle_create_con, "CreateConnection")
367 MGCP_REQUEST("DLCX", handle_delete_con, "DeleteConnection")
368 MGCP_REQUEST("MDCX", handle_modify_con, "ModifiyConnection")
369};
370
371static void send_response_with_data(int code, const char *msg, const char *trans,
372 const char *data, struct sockaddr_in *source)
373{
374 char buf[4096];
375 int len;
376
377 if (data) {
378 len = snprintf(buf, sizeof(buf), "%d %s\n%s", code, trans, data);
379 } else {
380 len = snprintf(buf, sizeof(buf), "%d %s\n", code, trans);
381 }
382 DEBUGP(DMGCP, "Sending response: code: %d for '%s'\n", code, msg);
383
384 sendto(bfd.fd, buf, len, 0, (struct sockaddr *)source, sizeof(*source));
385}
386
387static void send_response(int code, const char *msg, const char *trans, struct sockaddr_in *source)
388{
389 send_response_with_data(code, msg, trans, NULL, source);
390}
391
392static void send_with_sdp(struct mgcp_endpoint *endp, const char *msg, const char *trans_id, struct sockaddr_in *source)
393{
394 const char *addr = local_ip;
395 char sdp_record[4096];
396
397 if (!addr)
398 addr = source_addr;
399
400 snprintf(sdp_record, sizeof(sdp_record) - 1,
401 "I: %d\n\n"
402 "v=0\r\n"
403 "c=IN IP4 %s\r\n"
404 "m=audio %d RTP/AVP %d\r\n"
405 "a=rtpmap:%d %s\r\n",
406 endp->ci, addr, endp->rtp_port,
407 audio_payload, audio_payload, audio_name);
408 return send_response_with_data(200, msg, trans_id, sdp_record, source);
409}
410
411/* send a static record */
412static void send_rsip(struct sockaddr_in *source)
413{
414 char reset[4096];
415 int len, rc;
416
417 len = snprintf(reset, sizeof(reset) - 1,
418 "RSIP %u *@mgw MGCP 1.0\n"
419 "RM: restart\n", generate_transaction_id());
420 rc = sendto(bfd.fd, reset, len, 0, (struct sockaddr *) source, sizeof(*source));
421 if (rc < 0) {
422 DEBUGP(DMGCP, "Failed to send RSIP: %d\n", rc);
423 }
424}
425
426/*
427 * handle incoming messages:
428 * - this can be a command (four letters, space, transaction id)
429 * - or a response (three numbers, space, transaction id)
430 */
431static void handle_message(struct msgb *msg, struct sockaddr_in *source)
432{
433 int code;
434
435 if (msg->len < 4) {
436 DEBUGP(DMGCP, "mgs too short: %d\n", msg->len);
437 return;
438 }
439
440 /* attempt to treat it as a response */
441 if (sscanf((const char *)&msg->data[0], "%3d %*s", &code) == 1) {
442 DEBUGP(DMGCP, "Response: Code: %d\n", code);
443 } else {
444 int i, handled = 0;
445 msg->l3h = &msg->l2h[4];
446 for (i = 0; i < ARRAY_SIZE(mgcp_requests); ++i)
447 if (strncmp(mgcp_requests[i].name, (const char *) &msg->data[0], 4) == 0) {
448 handled = 1;
449 mgcp_requests[i].handle_request(msg, source);
450 }
451 if (!handled) {
452 DEBUGP(DMGCP, "MSG with type: '%.4s' not handled\n", &msg->data[0]);
453 }
454 }
455}
456
457/* string tokenizer for the poor */
458static int find_msg_pointers(struct msgb *msg, struct mgcp_msg_ptr *ptrs, int ptrs_length)
459{
460 int i, found = 0;
461
462 int whitespace = 1;
463 for (i = 0; i < msgb_l3len(msg) && ptrs_length > 0; ++i) {
464 /* if we have a space we found an end */
465 if (msg->l3h[i] == ' ' || msg->l3h[i] == '\r' || msg->l3h[i] == '\n') {
466 if (!whitespace) {
467 ++found;
468 whitespace = 1;
469 ptrs->length = i - ptrs->start - 1;
470 ++ptrs;
471 --ptrs_length;
472 } else {
473 /* skip any number of whitespace */
474 }
475
476 /* line end... stop */
477 if (msg->l3h[i] == '\r' || msg->l3h[i] == '\n')
478 break;
479 } else if (msg->l3h[i] == '\r' || msg->l3h[i] == '\n') {
480 /* line end, be done */
481 break;
482 } else if (whitespace) {
483 whitespace = 0;
484 ptrs->start = i;
485 }
486 }
487
488 if (ptrs_length == 0)
489 return -1;
490 return found;
491}
492
493static struct mgcp_endpoint *find_endpoint(const char *mgcp)
494{
495 char *endptr = NULL;
496 unsigned int gw = INT_MAX;
497
498 gw = strtoul(mgcp, &endptr, 16);
499 if (gw == 0 || gw >= number_endpoints || strcmp(endptr, "@mgw") != 0) {
500 DEBUGP(DMGCP, "Not able to find endpoint: '%s'\n", mgcp);
501 return NULL;
502 }
503
504 return &endpoints[gw];
505}
506
507static int analyze_header(struct msgb *msg, struct mgcp_msg_ptr *ptr, int size,
508 const char **transaction_id, struct mgcp_endpoint **endp)
509{
510 int found;
511
512 if (size < 3) {
513 DEBUGP(DMGCP, "Not enough space in ptr\n");
514 return -1;
515 }
516
517 found = find_msg_pointers(msg, ptr, size);
518
519 if (found < 3) {
520 DEBUGP(DMGCP, "Gateway: Not enough params. Found: %d\n", found);
521 return -1;
522 }
523
524 /*
525 * replace the space with \0. the main method gurantess that
526 * we still have + 1 for null termination
527 */
528 msg->l3h[ptr[3].start + ptr[3].length + 1] = '\0';
529 msg->l3h[ptr[2].start + ptr[2].length + 1] = '\0';
530 msg->l3h[ptr[1].start + ptr[1].length + 1] = '\0';
531 msg->l3h[ptr[0].start + ptr[0].length + 1] = '\0';
532
533 if (strncmp("1.0", (const char *)&msg->l3h[ptr[3].start], 3) != 0
534 || strncmp("MGCP", (const char *)&msg->l3h[ptr[2].start], 4) != 0) {
535 DEBUGP(DMGCP, "Wrong MGCP version. Not handling: '%s' '%s'\n",
536 (const char *)&msg->l3h[ptr[3].start],
537 (const char *)&msg->l3h[ptr[2].start]);
538 return -1;
539 }
540
541 *transaction_id = (const char *)&msg->l3h[ptr[0].start];
542 *endp = find_endpoint((const char *)&msg->l3h[ptr[1].start]);
543 return *endp == NULL;
544}
545
546static int verify_call_id(const struct mgcp_endpoint *endp,
547 const char *callid)
548{
549 if (strcmp(endp->callid, callid) != 0) {
550 DEBUGP(DMGCP, "CallIDs does not match on 0x%x. '%s' != '%s'\n",
551 ENDPOINT_NUMBER(endp), endp->callid, callid);
552 return -1;
553 }
554
555 return 0;
556}
557
558static int verify_ci(const struct mgcp_endpoint *endp,
559 const char *ci)
560{
561 if (atoi(ci) != endp->ci) {
562 DEBUGP(DMGCP, "ConnectionIdentifiers do not match on 0x%x. %d != %s\n",
563 ENDPOINT_NUMBER(endp), endp->ci, ci);
564 return -1;
565 }
566
567 return 0;
568}
569
570static void handle_audit_endpoint(struct msgb *msg, struct sockaddr_in *source)
571{
572 struct mgcp_msg_ptr data_ptrs[6];
573 int found, response;
574 const char *trans_id;
575 struct mgcp_endpoint *endp;
576
577 found = analyze_header(msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp);
578 if (found != 0)
579 response = 500;
580 else
581 response = 200;
582
583 return send_response(response, "AUEP", trans_id, source);
584}
585
586static int parse_conn_mode(const char* msg, int *conn_mode)
587{
588 int ret = 0;
589 if (strcmp(msg, "recvonly") == 0)
590 *conn_mode = MGCP_CONN_RECV_ONLY;
591 else if (strcmp(msg, "sendrecv") == 0)
592 *conn_mode = MGCP_CONN_RECV_SEND;
593 else {
594 DEBUGP(DMGCP, "Unknown connection mode: '%s'\n", msg);
595 ret = -1;
596 }
597
598 return ret;
599}
600
601static void handle_create_con(struct msgb *msg, struct sockaddr_in *source)
602{
603 struct mgcp_msg_ptr data_ptrs[6];
604 int found, i, line_start;
605 const char *trans_id;
606 struct mgcp_endpoint *endp;
607 int error_code = 500;
608
609 found = analyze_header(msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp);
610 if (found != 0)
611 return send_response(500, "CRCX", trans_id, source);
612
613 if (endp->ci != CI_UNUSED) {
614 DEBUGP(DMGCP, "Endpoint is already used. 0x%x\n", ENDPOINT_NUMBER(endp));
615 return send_response(500, "CRCX", trans_id, source);
616 }
617
618 /* parse CallID C: and LocalParameters L: */
619 MSG_TOKENIZE_START
620 switch (msg->l3h[line_start]) {
621 case 'L':
622 endp->local_options = talloc_strdup(endpoints,
623 (const char *)&msg->l3h[line_start + 3]);
624 break;
625 case 'C':
626 endp->callid = talloc_strdup(endpoints,
627 (const char *)&msg->l3h[line_start + 3]);
628 break;
629 case 'M':
630 if (parse_conn_mode((const char *)&msg->l3h[line_start + 3],
631 &endp->conn_mode) != 0) {
632 error_code = 517;
633 goto error2;
634 }
635 break;
636 default:
637 DEBUGP(DMGCP, "Unhandled option: '%c'/%d on 0x%x\n",
638 msg->l3h[line_start], msg->l3h[line_start],
639 ENDPOINT_NUMBER(endp));
640 break;
641 }
642 MSG_TOKENIZE_END
643
Holger Hans Peter Freyther48ecad42009-11-19 16:04:10 +0100644 /* initialize */
Holger Hans Peter Freyther6c796462010-01-13 22:49:55 +0100645 endp->net_rtp = endp->net_rtcp = endp->bts_rtp = endp->bts_rtcp = 0;
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +0200646
647 /* bind to the port now */
648 endp->rtp_port = rtp_calculate_port(ENDPOINT_NUMBER(endp), rtp_base_port);
649 if (!early_bind && bind_rtp(endp) != 0)
650 goto error2;
651
652 /* assign a local call identifier or fail */
653 endp->ci = generate_call_id();
654 if (endp->ci == CI_UNUSED)
655 goto error2;
656
657 DEBUGP(DMGCP, "Creating endpoint on: 0x%x CI: %u port: %u\n",
658 ENDPOINT_NUMBER(endp), endp->ci, endp->rtp_port);
659 return send_with_sdp(endp, "CRCX", trans_id, source);
660error:
661 DEBUGP(DMGCP, "Malformed line: %s on 0x%x with: line_start: %d %d\n",
662 hexdump(msg->l3h, msgb_l3len(msg)),
663 ENDPOINT_NUMBER(endp), line_start, i);
664 return send_response(error_code, "CRCX", trans_id, source);
665
666error2:
667 DEBUGP(DMGCP, "Resource error on 0x%x\n", ENDPOINT_NUMBER(endp));
668 return send_response(error_code, "CRCX", trans_id, source);
669}
670
671static void handle_modify_con(struct msgb *msg, struct sockaddr_in *source)
672{
673 struct mgcp_msg_ptr data_ptrs[6];
674 int found, i, line_start;
675 const char *trans_id;
676 struct mgcp_endpoint *endp;
677 int error_code = 500;
678
679 found = analyze_header(msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp);
680 if (found != 0)
681 return send_response(error_code, "MDCX", trans_id, source);
682
683 if (endp->ci == CI_UNUSED) {
684 DEBUGP(DMGCP, "Endpoint is not holding a connection. 0x%x\n", ENDPOINT_NUMBER(endp));
685 return send_response(error_code, "MDCX", trans_id, source);
686 }
687
688 MSG_TOKENIZE_START
689 switch (msg->l3h[line_start]) {
690 case 'C': {
691 if (verify_call_id(endp, (const char *)&msg->l3h[line_start + 3]) != 0)
692 goto error3;
693 break;
694 }
695 case 'I': {
696 if (verify_ci(endp, (const char *)&msg->l3h[line_start + 3]) != 0)
697 goto error3;
698 break;
699 }
700 case 'L':
701 /* skip */
702 break;
703 case 'M':
704 if (parse_conn_mode((const char *)&msg->l3h[line_start + 3],
705 &endp->conn_mode) != 0) {
706 error_code = 517;
707 goto error3;
708 }
709 break;
710 case '\0':
711 /* SDP file begins */
712 break;
713 case 'a':
714 case 'o':
715 case 's':
716 case 't':
717 case 'v':
718 /* skip these SDP attributes */
719 break;
720 case 'm': {
721 int port;
722 const char *param = (const char *)&msg->l3h[line_start];
723
724 if (sscanf(param, "m=audio %d RTP/AVP %*d", &port) == 1) {
Holger Hans Peter Freyther6c796462010-01-13 22:49:55 +0100725 endp->net_rtp = htons(port);
726 endp->net_rtcp = htons(port + 1);
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +0200727 }
728 break;
729 }
730 case 'c': {
731 char ipv4[16];
732 const char *param = (const char *)&msg->l3h[line_start];
733
734 if (sscanf(param, "c=IN IP4 %15s", ipv4) == 1) {
735 inet_aton(ipv4, &endp->remote);
736 }
737 break;
738 }
739 default:
740 DEBUGP(DMGCP, "Unhandled option: '%c'/%d on 0x%x\n",
741 msg->l3h[line_start], msg->l3h[line_start],
742 ENDPOINT_NUMBER(endp));
743 break;
744 }
745 MSG_TOKENIZE_END
746
747 /* modify */
748 DEBUGP(DMGCP, "Modified endpoint on: 0x%x Server: %s:%u\n",
Holger Hans Peter Freyther6c796462010-01-13 22:49:55 +0100749 ENDPOINT_NUMBER(endp), inet_ntoa(endp->remote), endp->net_rtp);
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +0200750 return send_with_sdp(endp, "MDCX", trans_id, source);
751
752error:
753 DEBUGP(DMGCP, "Malformed line: %s on 0x%x with: line_start: %d %d %d\n",
754 hexdump(msg->l3h, msgb_l3len(msg)),
755 ENDPOINT_NUMBER(endp), line_start, i, msg->l3h[line_start]);
756 return send_response(error_code, "MDCX", trans_id, source);
757
758error3:
759 return send_response(error_code, "MDCX", trans_id, source);
760}
761
762static void handle_delete_con(struct msgb *msg, struct sockaddr_in *source)
763{
764 struct mgcp_msg_ptr data_ptrs[6];
765 int found, i, line_start;
766 const char *trans_id;
767 struct mgcp_endpoint *endp;
768 int error_code = 500;
769
770 found = analyze_header(msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp);
771 if (found != 0)
772 return send_response(error_code, "DLCX", trans_id, source);
773
774 if (endp->ci == CI_UNUSED) {
775 DEBUGP(DMGCP, "Endpoint is not used. 0x%x\n", ENDPOINT_NUMBER(endp));
776 return send_response(error_code, "DLCX", trans_id, source);
777 }
778
779 MSG_TOKENIZE_START
780 switch (msg->l3h[line_start]) {
781 case 'C': {
782 if (verify_call_id(endp, (const char *)&msg->l3h[line_start + 3]) != 0)
783 goto error3;
784 break;
785 }
786 case 'I': {
787 if (verify_ci(endp, (const char *)&msg->l3h[line_start + 3]) != 0)
788 goto error3;
789 break;
790 }
791 default:
792 DEBUGP(DMGCP, "Unhandled option: '%c'/%d on 0x%x\n",
793 msg->l3h[line_start], msg->l3h[line_start],
794 ENDPOINT_NUMBER(endp));
795 break;
796 }
797 MSG_TOKENIZE_END
798
799
800 /* free the connection */
801 DEBUGP(DMGCP, "Deleting endpoint on: 0x%x\n", ENDPOINT_NUMBER(endp));
802 endp->ci= CI_UNUSED;
803 talloc_free(endp->callid);
804 talloc_free(endp->local_options);
805
806 if (!early_bind) {
807 bsc_unregister_fd(&endp->local_rtp);
808 bsc_unregister_fd(&endp->local_rtcp);
809 }
810
Holger Hans Peter Freyther6c796462010-01-13 22:49:55 +0100811 endp->net_rtp = endp->net_rtcp = endp->bts_rtp = endp->bts_rtcp = 0;
Holger Hans Peter Freyther48ecad42009-11-19 16:04:10 +0100812
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +0200813 return send_response(250, "DLCX", trans_id, source);
814
815error:
816 DEBUGP(DMGCP, "Malformed line: %s on 0x%x with: line_start: %d %d\n",
817 hexdump(msg->l3h, msgb_l3len(msg)),
818 ENDPOINT_NUMBER(endp), line_start, i);
819 return send_response(error_code, "DLCX", trans_id, source);
820
821error3:
822 return send_response(error_code, "DLCX", trans_id, source);
823}
824
825static void print_help()
826{
827 printf("Some useful help...\n");
828 printf(" -h --help is printing this text.\n");
829 printf(" -c --config-file filename The config file to use.\n");
830}
831
832static void handle_options(int argc, char** argv)
833{
834 while (1) {
835 int option_index = 0, c;
836 static struct option long_options[] = {
837 {"help", 0, 0, 'h'},
838 {"config-file", 1, 0, 'c'},
839 {0, 0, 0, 0},
840 };
841
842 c = getopt_long(argc, argv, "hc:", long_options, &option_index);
843
844 if (c == -1)
845 break;
846
847 switch(c) {
848 case 'h':
849 print_help();
850 exit(0);
851 break;
852 case 'c':
853 config_file = talloc_strdup(tall_bsc_ctx, optarg);
854 break;
855 default:
856 /* ignore */
857 break;
858 };
859 }
860}
861
862static int read_call_agent(struct bsc_fd *fd, unsigned int what)
863{
864 struct sockaddr_in addr;
865 socklen_t slen = sizeof(addr);
866 struct msgb *msg;
867
868 msg = (struct msgb *) fd->data;
869
870 /* read one less so we can use it as a \0 */
871 int rc = recvfrom(bfd.fd, msg->data, msg->data_len - 1, 0,
872 (struct sockaddr *) &addr, &slen);
873 if (rc < 0) {
874 perror("Gateway failed to read");
875 return -1;
876 } else if (slen > sizeof(addr)) {
877 fprintf(stderr, "Gateway received message from outerspace: %d %d\n",
878 slen, sizeof(addr));
879 return -1;
880 }
881
882 if (first_request) {
883 first_request = 0;
884 send_rsip(&addr);
885 return 0;
886 }
887
888 /* handle message now */
889 msg->l2h = msgb_put(msg, rc);
890 handle_message(msg, &addr);
891 msgb_reset(msg);
892 return 0;
893}
894
895/*
896 * vty code for mgcp below
897 */
898struct cmd_node mgcp_node = {
899 MGCP_NODE,
900 "%s(mgcp)#",
901 1,
902};
903
904static int config_write_mgcp(struct vty *vty)
905{
906 vty_out(vty, "mgcp%s", VTY_NEWLINE);
907 if (local_ip)
908 vty_out(vty, " local ip %s%s", local_ip, VTY_NEWLINE);
Holger Hans Peter Freyther601a67e2010-01-13 16:37:32 +0100909 if (bts_ip)
910 vty_out(vty, " bts ip %s%s", bts_ip, VTY_NEWLINE);
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +0200911 vty_out(vty, " bind ip %s%s", source_addr, VTY_NEWLINE);
912 vty_out(vty, " bind port %u%s", source_port, VTY_NEWLINE);
Holger Hans Peter Freyther5fddf472009-11-19 15:08:02 +0100913 vty_out(vty, " bind early %u%s", !!early_bind, VTY_NEWLINE);
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +0200914 vty_out(vty, " rtp base %u%s", rtp_base_port, VTY_NEWLINE);
Holger Hans Peter Freyther5fddf472009-11-19 15:08:02 +0100915 vty_out(vty, " sdp audio payload number %u%s", audio_payload, VTY_NEWLINE);
916 vty_out(vty, " sdp audio payload name %s%s", audio_name, VTY_NEWLINE);
917 vty_out(vty, " loop %u%s", !!audio_loop, VTY_NEWLINE);
Holger Hans Peter Freyther4ec389e2009-11-20 11:10:31 +0100918 vty_out(vty, " endpoints %u%s", number_endpoints, VTY_NEWLINE);
Holger Hans Peter Freyther2c492ed2010-01-05 12:29:36 +0100919 if (forward_ip)
Holger Hans Peter Freytherbd5130d2010-01-13 23:36:53 +0100920 vty_out(vty, " forward audio ip %s%s", forward_ip, VTY_NEWLINE);
921 if (forward_port != 0)
922 vty_out(vty, " forward audio port %d%s", forward_port, VTY_NEWLINE);
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +0200923
924 return CMD_SUCCESS;
925}
926
Holger Hans Peter Freyther17e79162009-11-19 15:20:48 +0100927DEFUN(show_mcgp, show_mgcp_cmd, "show mgcp",
928 SHOW_STR "Display information about the MGCP Media Gateway")
929{
930 int i;
931
932 vty_out(vty, "MGCP is up and running with %u endpoints:%s", number_endpoints - 1, VTY_NEWLINE);
933 for (i = 1; i < number_endpoints; ++i) {
934 struct mgcp_endpoint *endp = &endpoints[i];
935 vty_out(vty, " Endpoint 0x%.2x: CI: %d net: %u/%u bts: %u/%u%s",
936 i, endp->ci,
Holger Hans Peter Freyther6c796462010-01-13 22:49:55 +0100937 ntohs(endp->net_rtp), ntohs(endp->net_rtcp),
Holger Hans Peter Freyther17e79162009-11-19 15:20:48 +0100938 ntohs(endp->bts_rtp), ntohs(endp->bts_rtcp), VTY_NEWLINE);
939 }
940
941 return CMD_SUCCESS;
942}
943
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +0200944DEFUN(cfg_mgcp,
945 cfg_mgcp_cmd,
946 "mgcp",
947 "Configure the MGCP")
948{
949 vty->node = MGCP_NODE;
950 return CMD_SUCCESS;
951}
952
953DEFUN(cfg_mgcp_local_ip,
954 cfg_mgcp_local_ip_cmd,
955 "local ip IP",
956 "Set the IP to be used in SDP records")
957{
958 local_ip = talloc_strdup(tall_bsc_ctx, argv[0]);
959 return CMD_SUCCESS;
960}
961
962DEFUN(cfg_mgcp_bts_ip,
963 cfg_mgcp_bts_ip_cmd,
964 "bts ip IP",
965 "Set the IP of the BTS for RTP forwarding")
966{
967 bts_ip = talloc_strdup(tall_bsc_ctx, argv[0]);
968 inet_aton(bts_ip, &bts_in);
969 return CMD_SUCCESS;
970}
971
972DEFUN(cfg_mgcp_bind_ip,
973 cfg_mgcp_bind_ip_cmd,
974 "bind ip IP",
975 "Bind the MGCP to this local addr")
976{
977 source_addr = talloc_strdup(tall_bsc_ctx, argv[0]);
978 return CMD_SUCCESS;
979}
980
981DEFUN(cfg_mgcp_bind_port,
982 cfg_mgcp_bind_port_cmd,
983 "bind port <0-65534>",
984 "Bind the MGCP to this port")
985{
986 unsigned int port = atoi(argv[0]);
987 if (port > 65534) {
988 vty_out(vty, "%% wrong bind port '%s'%s", argv[0], VTY_NEWLINE);
989 return CMD_WARNING;
990 }
991
992 source_port = port;
993 return CMD_SUCCESS;
994}
995
996DEFUN(cfg_mgcp_bind_early,
997 cfg_mgcp_bind_early_cmd,
998 "bind early (0|1)",
999 "Bind all RTP ports early")
1000{
1001 unsigned int bind = atoi(argv[0]);
1002 if (bind != 0 && bind != 1) {
1003 vty_out(vty, "%% param must be 0 or 1.%s", VTY_NEWLINE);
1004 return CMD_WARNING;
1005 }
1006
1007 early_bind = bind == 1;
1008 return CMD_SUCCESS;
1009}
1010
1011DEFUN(cfg_mgcp_rtp_base_port,
1012 cfg_mgcp_rtp_base_port_cmd,
1013 "rtp base <0-65534>",
1014 "Base port to use")
1015{
1016 unsigned int port = atoi(argv[0]);
1017 if (port > 65534) {
1018 vty_out(vty, "%% wrong base port '%s'%s", argv[0], VTY_NEWLINE);
1019 return CMD_WARNING;
1020 }
1021
1022 rtp_base_port = port;
1023 return CMD_SUCCESS;
1024}
1025
1026DEFUN(cfg_mgcp_sdp_payload_number,
1027 cfg_mgcp_sdp_payload_number_cmd,
1028 "sdp audio payload number <1-255>",
1029 "Set the audio codec to use")
1030{
1031 unsigned int payload = atoi(argv[0]);
1032 if (payload > 255) {
1033 vty_out(vty, "%% wrong payload number '%s'%s", argv[0], VTY_NEWLINE);
1034 return CMD_WARNING;
1035 }
1036
1037 audio_payload = payload;
1038 return CMD_SUCCESS;
1039}
1040
1041DEFUN(cfg_mgcp_sdp_payload_name,
1042 cfg_mgcp_sdp_payload_name_cmd,
1043 "sdp audio payload name NAME",
1044 "Set the audio name to use")
1045{
1046 audio_name = talloc_strdup(tall_bsc_ctx, argv[0]);
1047 return CMD_SUCCESS;
1048}
1049
Holger Hans Peter Freyther138b7ec2009-11-18 18:32:31 +01001050DEFUN(cfg_mgcp_loop,
1051 cfg_mgcp_loop_cmd,
1052 "loop (0|1)",
1053 "Loop the audio")
1054{
1055 audio_loop = atoi(argv[0]);
1056 return CMD_SUCCESS;
1057}
1058
Holger Hans Peter Freyther4ec389e2009-11-20 11:10:31 +01001059DEFUN(cfg_mgcp_number_endp,
1060 cfg_mgcp_number_endp_cmd,
1061 "number endpoints <0-65534>",
1062 "The number of endpoints to allocate. This is not dynamic.")
1063{
1064 /* + 1 as we start counting at one */
1065 number_endpoints = atoi(argv[0]) + 1;
1066 return CMD_SUCCESS;
1067}
1068
Holger Hans Peter Freytherbd5130d2010-01-13 23:36:53 +01001069DEFUN(cfg_mgcp_forward_ip,
1070 cfg_mgcp_forward_ip_cmd,
1071 "forward audio ip IP",
Holger Hans Peter Freyther14083be2010-01-05 12:21:36 +01001072 "Forward packets from and to the IP. This disables most of the MGCP feature.")
1073{
1074 if (forward_ip)
1075 talloc_free(forward_ip);
1076 forward_ip = talloc_strdup(tall_bsc_ctx, argv[0]);
1077 return CMD_SUCCESS;
1078}
1079
Holger Hans Peter Freytherbd5130d2010-01-13 23:36:53 +01001080DEFUN(cfg_mgcp_forward_port,
1081 cfg_mgcp_forward_port_cmd,
1082 "forward audio port <1-15000>",
1083 "Forward packets from and to the port. This disables most of the MGCP feature.")
1084{
1085 forward_port = atoi(argv[0]);
1086 return CMD_SUCCESS;
1087}
1088
Holger Hans Peter Freyther338fa562009-11-19 15:03:39 +01001089int bsc_vty_init(struct gsm_network *dummy)
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +02001090{
1091 cmd_init(1);
1092 vty_init();
1093
Holger Hans Peter Freyther17e79162009-11-19 15:20:48 +01001094 install_element(VIEW_NODE, &show_mgcp_cmd);
1095
1096
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +02001097 install_element(CONFIG_NODE, &cfg_mgcp_cmd);
1098 install_node(&mgcp_node, config_write_mgcp);
1099 install_default(MGCP_NODE);
1100 install_element(MGCP_NODE, &cfg_mgcp_local_ip_cmd);
1101 install_element(MGCP_NODE, &cfg_mgcp_bts_ip_cmd);
1102 install_element(MGCP_NODE, &cfg_mgcp_bind_ip_cmd);
1103 install_element(MGCP_NODE, &cfg_mgcp_bind_port_cmd);
1104 install_element(MGCP_NODE, &cfg_mgcp_bind_early_cmd);
1105 install_element(MGCP_NODE, &cfg_mgcp_rtp_base_port_cmd);
1106 install_element(MGCP_NODE, &cfg_mgcp_sdp_payload_number_cmd);
1107 install_element(MGCP_NODE, &cfg_mgcp_sdp_payload_name_cmd);
Holger Hans Peter Freyther138b7ec2009-11-18 18:32:31 +01001108 install_element(MGCP_NODE, &cfg_mgcp_loop_cmd);
Holger Hans Peter Freyther4ec389e2009-11-20 11:10:31 +01001109 install_element(MGCP_NODE, &cfg_mgcp_number_endp_cmd);
Holger Hans Peter Freytherbd5130d2010-01-13 23:36:53 +01001110 install_element(MGCP_NODE, &cfg_mgcp_forward_ip_cmd);
1111 install_element(MGCP_NODE, &cfg_mgcp_forward_port_cmd);
Holger Hans Peter Freyther338fa562009-11-19 15:03:39 +01001112 return 0;
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +02001113}
1114
1115int main(int argc, char** argv)
1116{
Holger Hans Peter Freyther338fa562009-11-19 15:03:39 +01001117 struct gsm_network dummy_network;
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +02001118 struct sockaddr_in addr;
1119 int on = 1, i, rc;
Holger Hans Peter Freytherb61e3b22009-12-22 22:32:51 +01001120 struct debug_target *stderr_target;
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +02001121
1122 tall_bsc_ctx = talloc_named_const(NULL, 1, "mgcp-callagent");
Holger Hans Peter Freytherb61e3b22009-12-22 22:32:51 +01001123
1124 debug_init();
1125 stderr_target = debug_target_create_stderr();
1126 debug_add_target(stderr_target);
1127 debug_set_all_filter(stderr_target, 1);
1128
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +02001129 handle_options(argc, argv);
1130
Holger Hans Peter Freyther338fa562009-11-19 15:03:39 +01001131 telnet_init(&dummy_network, 4243);
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +02001132 rc = vty_read_config_file(config_file);
1133 if (rc < 0) {
1134 fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file);
1135 return rc;
1136 }
1137
1138
Holger Hans Peter Freyther601a67e2010-01-13 16:37:32 +01001139 if (!bts_ip)
1140 fprintf(stderr, "No BTS ip address specified. This will allow everyone to connect.\n");
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +02001141
1142 endpoints = _talloc_zero_array(tall_bsc_ctx,
1143 sizeof(struct mgcp_endpoint),
1144 number_endpoints, "endpoints");
1145 if (!endpoints) {
1146 fprintf(stderr, "Failed to allocate endpoints: %d. Quitting.\n", number_endpoints);
1147 return -1;
1148 }
1149
1150 /* Initialize all endpoints */
1151 for (i = 0; i < number_endpoints; ++i) {
1152 endpoints[i].local_rtp.fd = -1;
1153 endpoints[i].local_rtcp.fd = -1;
1154 endpoints[i].ci = CI_UNUSED;
1155 }
1156
Holger Hans Peter Freyther14083be2010-01-05 12:21:36 +01001157 /*
1158 * This application supports two modes.
1159 * 1.) a true MGCP gateway with support for AUEP, CRCX, MDCX, DLCX
1160 * 2.) plain forwarding of RTP packets on the endpoints.
1161 * both modes are mutual exclusive
1162 */
1163 if (forward_ip) {
Holger Hans Peter Freytherbd5130d2010-01-13 23:36:53 +01001164 int port = rtp_base_port;
1165 if (forward_port != 0)
1166 port = forward_port;
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +02001167
Holger Hans Peter Freyther14083be2010-01-05 12:21:36 +01001168 if (!early_bind) {
1169 DEBUGP(DMGCP, "Forwarding requires early bind.\n");
1170 return -1;
1171 }
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +02001172
Holger Hans Peter Freyther14083be2010-01-05 12:21:36 +01001173 /*
1174 * Store the forward IP and assign a ci. For early bind
1175 * the sockets will be created after this.
1176 */
1177 for (i = 1; i < number_endpoints; ++i) {
1178 struct mgcp_endpoint *endp = &endpoints[i];
1179 inet_aton(forward_ip, &endp->remote);
1180 endp->ci = CI_UNUSED + 23;
Holger Hans Peter Freytherbd5130d2010-01-13 23:36:53 +01001181 endp->net_rtp = htons(rtp_calculate_port(ENDPOINT_NUMBER(endp), port));
1182 endp->net_rtcp = htons(rtp_calculate_port(ENDPOINT_NUMBER(endp), port) + 1);
Holger Hans Peter Freyther14083be2010-01-05 12:21:36 +01001183 }
Holger Hans Peter Freytherf986cfc2010-01-05 12:25:25 +01001184
1185 DEBUGP(DMGCP, "Configured for Audio Forwarding.\n");
Holger Hans Peter Freyther14083be2010-01-05 12:21:36 +01001186 } else {
1187 bfd.when = BSC_FD_READ;
1188 bfd.cb = read_call_agent;
1189 bfd.fd = socket(AF_INET, SOCK_DGRAM, 0);
1190 if (bfd.fd < 0) {
1191 perror("Gateway failed to listen");
1192 return -1;
1193 }
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +02001194
Holger Hans Peter Freyther14083be2010-01-05 12:21:36 +01001195 setsockopt(bfd.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +02001196
Holger Hans Peter Freyther14083be2010-01-05 12:21:36 +01001197 memset(&addr, 0, sizeof(addr));
1198 addr.sin_family = AF_INET;
1199 addr.sin_port = htons(source_port);
1200 inet_aton(source_addr, &addr.sin_addr);
1201
1202 if (bind(bfd.fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
1203 perror("Gateway failed to bind");
1204 return -1;
1205 }
1206
1207 bfd.data = msgb_alloc(4096, "mgcp-msg");
1208 if (!bfd.data) {
1209 fprintf(stderr, "Gateway memory error.\n");
1210 return -1;
1211 }
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +02001212
1213
Holger Hans Peter Freyther14083be2010-01-05 12:21:36 +01001214 if (bsc_register_fd(&bfd) != 0) {
1215 DEBUGP(DMGCP, "Failed to register the fd\n");
1216 return -1;
1217 }
Holger Hans Peter Freytherf986cfc2010-01-05 12:25:25 +01001218
1219 DEBUGP(DMGCP, "Configured for MGCP.\n");
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +02001220 }
1221
1222 /* initialisation */
1223 srand(time(NULL));
1224
1225 /* early bind */
1226 if (early_bind) {
1227 for (i = 1; i < number_endpoints; ++i) {
1228 struct mgcp_endpoint *endp = &endpoints[i];
1229 endp->rtp_port = rtp_calculate_port(ENDPOINT_NUMBER(endp), rtp_base_port);
1230 if (bind_rtp(endp) != 0)
1231 return -1;
1232 }
1233 }
1234
1235 /* main loop */
1236 while (1) {
1237 bsc_select_main(0);
1238 }
1239
1240
1241 return 0;
1242}