blob: 16e74c82ed6b68efc9244203a5d50aa85db80634 [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 Freytherf67945f2009-10-09 07:08:11 +020068static char *config_file = "mgcp.cfg";
69
70/* used by msgb and mgcp */
71void *tall_bsc_ctx = NULL;
72
73enum mgcp_connection_mode {
74 MGCP_CONN_NONE = 0,
75 MGCP_CONN_RECV_ONLY = 1,
76 MGCP_CONN_SEND_ONLY = 2,
77 MGCP_CONN_RECV_SEND = MGCP_CONN_RECV_ONLY | MGCP_CONN_SEND_ONLY,
78};
79
Holger Hans Peter Freyther138b7ec2009-11-18 18:32:31 +010080enum {
81 DEST_NETWORK = 0,
82 DEST_BTS = 1,
83};
84
85enum {
86 PROTO_RTP,
87 PROTO_RTCP,
88};
89
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +020090#define CI_UNUSED 0
91static unsigned int last_call_id = 0;
92
93struct mgcp_endpoint {
94 int ci;
95 char *callid;
96 char *local_options;
97 int conn_mode;
98
99 /* the local rtp port */
100 int rtp_port;
101
102 /*
103 * RTP mangling:
104 * - we get RTP and RTCP to us and need to forward to the BTS
105 * - we get RTP and RTCP from the BTS and forward to the network
106 */
107 struct bsc_fd local_rtp;
108 struct bsc_fd local_rtcp;
109
110 struct in_addr remote;
Holger Hans Peter Freyther601a67e2010-01-13 16:37:32 +0100111 struct in_addr bts;
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +0200112
113 /* in network byte order */
114 int rtp, rtcp;
115 int bts_rtp, bts_rtcp;
116};
117
118static struct mgcp_endpoint *endpoints = NULL;
119#define ENDPOINT_NUMBER(endp) abs(endp - endpoints)
120
121/**
122 * Macro for tokenizing MGCP messages and SDP in one go.
123 *
124 */
125#define MSG_TOKENIZE_START \
126 line_start = 0; \
127 for (i = 0; i < msgb_l3len(msg); ++i) { \
128 /* we have a line end */ \
129 if (msg->l3h[i] == '\n') { \
130 /* skip the first line */ \
131 if (line_start == 0) { \
132 line_start = i + 1; \
133 continue; \
134 } \
135 \
136 /* check if we have a proper param */ \
137 if (i - line_start == 1 && msg->l3h[line_start] == '\r') { \
138 } else if (i - line_start > 2 \
139 && islower(msg->l3h[line_start]) \
140 && msg->l3h[line_start + 1] == '=') { \
141 } else if (i - line_start < 3 \
142 || msg->l3h[line_start + 1] != ':' \
143 || msg->l3h[line_start + 2] != ' ') \
144 goto error; \
145 \
146 msg->l3h[i] = '\0'; \
147 if (msg->l3h[i-1] == '\r') \
148 msg->l3h[i-1] = '\0';
149
150#define MSG_TOKENIZE_END \
151 line_start = i + 1; \
152 } \
153 }
154
155
156struct mgcp_msg_ptr {
157 unsigned int start;
158 unsigned int length;
159};
160
161struct mgcp_request {
162 char *name;
163 void (*handle_request) (struct msgb *msg, struct sockaddr_in *source);
164 char *debug_name;
165};
166
167#define MGCP_REQUEST(NAME, REQ, DEBUG_NAME) \
168 { .name = NAME, .handle_request = REQ, .debug_name = DEBUG_NAME },
169
170static void handle_audit_endpoint(struct msgb *msg, struct sockaddr_in *source);
171static void handle_create_con(struct msgb *msg, struct sockaddr_in *source);
172static void handle_delete_con(struct msgb *msg, struct sockaddr_in *source);
173static void handle_modify_con(struct msgb *msg, struct sockaddr_in *source);
174
175static int generate_call_id()
176{
177 int i;
178
179 /* use the call id */
180 ++last_call_id;
181
182 /* handle wrap around */
183 if (last_call_id == CI_UNUSED)
184 ++last_call_id;
185
186 /* callstack can only be of size number_of_endpoints */
187 /* verify that the call id is free, e.g. in case of overrun */
188 for (i = 1; i < number_endpoints; ++i)
189 if (endpoints[i].ci == last_call_id)
190 return generate_call_id();
191
192 return last_call_id;
193}
194
195/* FIXIME/TODO: need to have a list of pending transactions and check that */
196static unsigned int generate_transaction_id()
197{
198 return abs(rand());
199}
200
201static int _send(int fd, struct in_addr *addr, int port, char *buf, int len)
202{
203 struct sockaddr_in out;
204 out.sin_family = AF_INET;
205 out.sin_port = port;
206 memcpy(&out.sin_addr, addr, sizeof(*addr));
207
208 return sendto(fd, buf, len, 0, (struct sockaddr *)&out, sizeof(out));
209}
210
211/*
212 * There is data coming. We will have to figure out if it
213 * came from the BTS or the MediaGateway of the MSC. On top
214 * of that we need to figure out if it was RTP or RTCP.
215 *
216 * Currently we do not communicate with the BSC so we have
217 * no idea where the BTS is listening for RTP and need to
218 * do the classic routing trick. Wait for the first packet
219 * from the BTS and then go ahead.
220 */
221static int rtp_data_cb(struct bsc_fd *fd, unsigned int what)
222{
223 char buf[4096];
224 struct sockaddr_in addr;
225 socklen_t slen = sizeof(addr);
226 struct mgcp_endpoint *endp;
Holger Hans Peter Freyther138b7ec2009-11-18 18:32:31 +0100227 int rc, dest, proto;
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +0200228
229 endp = (struct mgcp_endpoint *) fd->data;
230
231 rc = recvfrom(fd->fd, &buf, sizeof(buf), 0,
232 (struct sockaddr *) &addr, &slen);
233 if (rc < 0) {
234 DEBUGP(DMGCP, "Failed to receive message on: 0x%x\n",
235 ENDPOINT_NUMBER(endp));
236 return -1;
237 }
238
Holger Hans Peter Freyther48ecad42009-11-19 16:04:10 +0100239 /* do not forward aynthing... maybe there is a packet from the bts */
240 if (endp->ci == CI_UNUSED)
241 return -1;
242
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +0200243 /*
244 * Figure out where to forward it to. This code assumes that we
245 * have received the Connection Modify and know who is a legitimate
246 * partner. According to the spec we could attempt to forward even
247 * after the Create Connection but we will not as we are not really
248 * able to tell if this is legitimate.
249 */
250 #warning "Slight spec violation. With connection mode recvonly we should attempt to forward."
Holger Hans Peter Freyther138b7ec2009-11-18 18:32:31 +0100251 dest = memcmp(&addr.sin_addr, &endp->remote, sizeof(addr.sin_addr)) == 0
252 ? DEST_BTS : DEST_NETWORK;
253 proto = fd == &endp->local_rtp ? PROTO_RTP : PROTO_RTCP;
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +0200254
255 /* We have no idea who called us, maybe it is the BTS. */
Holger Hans Peter Freyther138b7ec2009-11-18 18:32:31 +0100256 if (dest == DEST_NETWORK && endp->bts_rtp == 0) {
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +0200257 /* it was the BTS... */
Holger Hans Peter Freyther601a67e2010-01-13 16:37:32 +0100258 if (!bts_ip || memcmp(&addr.sin_addr, &bts_in, sizeof(bts_in)) == 0) {
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +0200259 if (fd == &endp->local_rtp) {
260 endp->bts_rtp = addr.sin_port;
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +0200261 } else {
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +0200262 endp->bts_rtcp = addr.sin_port;
263 }
264
Holger Hans Peter Freyther601a67e2010-01-13 16:37:32 +0100265 endp->bts = addr.sin_addr;
Holger Hans Peter Freyther8ea4b562009-11-19 16:25:53 +0100266 DEBUGP(DMGCP, "Found BTS for endpoint: 0x%x on port: %d/%d\n",
267 ENDPOINT_NUMBER(endp), ntohs(endp->bts_rtp), ntohs(endp->bts_rtcp));
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +0200268 }
269 }
270
Holger Hans Peter Freyther138b7ec2009-11-18 18:32:31 +0100271 /* dispatch */
272 if (audio_loop)
273 dest = !dest;
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +0200274
Holger Hans Peter Freyther138b7ec2009-11-18 18:32:31 +0100275 if (dest == DEST_NETWORK) {
276 return _send(fd->fd, &endp->remote,
277 proto == PROTO_RTP ? endp->rtp : endp->rtcp,
278 buf, rc);
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +0200279 } else {
Holger Hans Peter Freyther601a67e2010-01-13 16:37:32 +0100280 return _send(fd->fd, &endp->bts,
Holger Hans Peter Freyther138b7ec2009-11-18 18:32:31 +0100281 proto == PROTO_RTP ? endp->bts_rtp : endp->bts_rtcp,
282 buf, rc);
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +0200283 }
284}
285
286static int create_bind(struct bsc_fd *fd, int port)
287{
288 struct sockaddr_in addr;
289 int on = 1;
290
291 fd->fd = socket(AF_INET, SOCK_DGRAM, 0);
292 if (fd->fd < 0)
293 return -1;
294
295 setsockopt(fd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
296 memset(&addr, 0, sizeof(addr));
297 addr.sin_family = AF_INET;
298 addr.sin_port = htons(port);
299 inet_aton(source_addr, &addr.sin_addr);
300
301 if (bind(fd->fd, (struct sockaddr *) &addr, sizeof(addr)) < 0)
302 return -1;
303
304 return 0;
305}
306
307static int bind_rtp(struct mgcp_endpoint *endp)
308{
309 /* set to zero until we get the info */
310 memset(&endp->remote, 0, sizeof(endp->remote));
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +0200311
312 if (create_bind(&endp->local_rtp, endp->rtp_port) != 0) {
313 DEBUGP(DMGCP, "Failed to create RTP port: %d on 0x%x\n",
314 endp->rtp_port, ENDPOINT_NUMBER(endp));
315 goto cleanup0;
316 }
317
318 if (create_bind(&endp->local_rtcp, endp->rtp_port + 1) != 0) {
319 DEBUGP(DMGCP, "Failed to create RTCP port: %d on 0x%x\n",
320 endp->rtp_port + 1, ENDPOINT_NUMBER(endp));
321 goto cleanup1;
322 }
323
324 endp->local_rtp.cb = rtp_data_cb;
325 endp->local_rtp.data = endp;
326 endp->local_rtp.when = BSC_FD_READ;
327 if (bsc_register_fd(&endp->local_rtp) != 0) {
328 DEBUGP(DMGCP, "Failed to register RTP port %d on 0x%x\n",
329 endp->rtp_port, ENDPOINT_NUMBER(endp));
330 goto cleanup2;
331 }
332
333 endp->local_rtcp.cb = rtp_data_cb;
334 endp->local_rtcp.data = endp;
335 endp->local_rtcp.when = BSC_FD_READ;
336 if (bsc_register_fd(&endp->local_rtcp) != 0) {
337 DEBUGP(DMGCP, "Failed to register RTCP port %d on 0x%x\n",
338 endp->rtp_port + 1, ENDPOINT_NUMBER(endp));
339 goto cleanup3;
340 }
341
342 return 0;
343
344cleanup3:
345 bsc_unregister_fd(&endp->local_rtp);
346cleanup2:
347 close(endp->local_rtcp.fd);
348 endp->local_rtcp.fd = -1;
349cleanup1:
350 close(endp->local_rtp.fd);
351 endp->local_rtp.fd = -1;
352cleanup0:
353 return -1;
354}
355
356/*
357 * array of function pointers for handling various
358 * messages. In the future this might be binary sorted
359 * for performance reasons.
360 */
361static const struct mgcp_request mgcp_requests [] = {
362 MGCP_REQUEST("AUEP", handle_audit_endpoint, "AuditEndpoint")
363 MGCP_REQUEST("CRCX", handle_create_con, "CreateConnection")
364 MGCP_REQUEST("DLCX", handle_delete_con, "DeleteConnection")
365 MGCP_REQUEST("MDCX", handle_modify_con, "ModifiyConnection")
366};
367
368static void send_response_with_data(int code, const char *msg, const char *trans,
369 const char *data, struct sockaddr_in *source)
370{
371 char buf[4096];
372 int len;
373
374 if (data) {
375 len = snprintf(buf, sizeof(buf), "%d %s\n%s", code, trans, data);
376 } else {
377 len = snprintf(buf, sizeof(buf), "%d %s\n", code, trans);
378 }
379 DEBUGP(DMGCP, "Sending response: code: %d for '%s'\n", code, msg);
380
381 sendto(bfd.fd, buf, len, 0, (struct sockaddr *)source, sizeof(*source));
382}
383
384static void send_response(int code, const char *msg, const char *trans, struct sockaddr_in *source)
385{
386 send_response_with_data(code, msg, trans, NULL, source);
387}
388
389static void send_with_sdp(struct mgcp_endpoint *endp, const char *msg, const char *trans_id, struct sockaddr_in *source)
390{
391 const char *addr = local_ip;
392 char sdp_record[4096];
393
394 if (!addr)
395 addr = source_addr;
396
397 snprintf(sdp_record, sizeof(sdp_record) - 1,
398 "I: %d\n\n"
399 "v=0\r\n"
400 "c=IN IP4 %s\r\n"
401 "m=audio %d RTP/AVP %d\r\n"
402 "a=rtpmap:%d %s\r\n",
403 endp->ci, addr, endp->rtp_port,
404 audio_payload, audio_payload, audio_name);
405 return send_response_with_data(200, msg, trans_id, sdp_record, source);
406}
407
408/* send a static record */
409static void send_rsip(struct sockaddr_in *source)
410{
411 char reset[4096];
412 int len, rc;
413
414 len = snprintf(reset, sizeof(reset) - 1,
415 "RSIP %u *@mgw MGCP 1.0\n"
416 "RM: restart\n", generate_transaction_id());
417 rc = sendto(bfd.fd, reset, len, 0, (struct sockaddr *) source, sizeof(*source));
418 if (rc < 0) {
419 DEBUGP(DMGCP, "Failed to send RSIP: %d\n", rc);
420 }
421}
422
423/*
424 * handle incoming messages:
425 * - this can be a command (four letters, space, transaction id)
426 * - or a response (three numbers, space, transaction id)
427 */
428static void handle_message(struct msgb *msg, struct sockaddr_in *source)
429{
430 int code;
431
432 if (msg->len < 4) {
433 DEBUGP(DMGCP, "mgs too short: %d\n", msg->len);
434 return;
435 }
436
437 /* attempt to treat it as a response */
438 if (sscanf((const char *)&msg->data[0], "%3d %*s", &code) == 1) {
439 DEBUGP(DMGCP, "Response: Code: %d\n", code);
440 } else {
441 int i, handled = 0;
442 msg->l3h = &msg->l2h[4];
443 for (i = 0; i < ARRAY_SIZE(mgcp_requests); ++i)
444 if (strncmp(mgcp_requests[i].name, (const char *) &msg->data[0], 4) == 0) {
445 handled = 1;
446 mgcp_requests[i].handle_request(msg, source);
447 }
448 if (!handled) {
449 DEBUGP(DMGCP, "MSG with type: '%.4s' not handled\n", &msg->data[0]);
450 }
451 }
452}
453
454/* string tokenizer for the poor */
455static int find_msg_pointers(struct msgb *msg, struct mgcp_msg_ptr *ptrs, int ptrs_length)
456{
457 int i, found = 0;
458
459 int whitespace = 1;
460 for (i = 0; i < msgb_l3len(msg) && ptrs_length > 0; ++i) {
461 /* if we have a space we found an end */
462 if (msg->l3h[i] == ' ' || msg->l3h[i] == '\r' || msg->l3h[i] == '\n') {
463 if (!whitespace) {
464 ++found;
465 whitespace = 1;
466 ptrs->length = i - ptrs->start - 1;
467 ++ptrs;
468 --ptrs_length;
469 } else {
470 /* skip any number of whitespace */
471 }
472
473 /* line end... stop */
474 if (msg->l3h[i] == '\r' || msg->l3h[i] == '\n')
475 break;
476 } else if (msg->l3h[i] == '\r' || msg->l3h[i] == '\n') {
477 /* line end, be done */
478 break;
479 } else if (whitespace) {
480 whitespace = 0;
481 ptrs->start = i;
482 }
483 }
484
485 if (ptrs_length == 0)
486 return -1;
487 return found;
488}
489
490static struct mgcp_endpoint *find_endpoint(const char *mgcp)
491{
492 char *endptr = NULL;
493 unsigned int gw = INT_MAX;
494
495 gw = strtoul(mgcp, &endptr, 16);
496 if (gw == 0 || gw >= number_endpoints || strcmp(endptr, "@mgw") != 0) {
497 DEBUGP(DMGCP, "Not able to find endpoint: '%s'\n", mgcp);
498 return NULL;
499 }
500
501 return &endpoints[gw];
502}
503
504static int analyze_header(struct msgb *msg, struct mgcp_msg_ptr *ptr, int size,
505 const char **transaction_id, struct mgcp_endpoint **endp)
506{
507 int found;
508
509 if (size < 3) {
510 DEBUGP(DMGCP, "Not enough space in ptr\n");
511 return -1;
512 }
513
514 found = find_msg_pointers(msg, ptr, size);
515
516 if (found < 3) {
517 DEBUGP(DMGCP, "Gateway: Not enough params. Found: %d\n", found);
518 return -1;
519 }
520
521 /*
522 * replace the space with \0. the main method gurantess that
523 * we still have + 1 for null termination
524 */
525 msg->l3h[ptr[3].start + ptr[3].length + 1] = '\0';
526 msg->l3h[ptr[2].start + ptr[2].length + 1] = '\0';
527 msg->l3h[ptr[1].start + ptr[1].length + 1] = '\0';
528 msg->l3h[ptr[0].start + ptr[0].length + 1] = '\0';
529
530 if (strncmp("1.0", (const char *)&msg->l3h[ptr[3].start], 3) != 0
531 || strncmp("MGCP", (const char *)&msg->l3h[ptr[2].start], 4) != 0) {
532 DEBUGP(DMGCP, "Wrong MGCP version. Not handling: '%s' '%s'\n",
533 (const char *)&msg->l3h[ptr[3].start],
534 (const char *)&msg->l3h[ptr[2].start]);
535 return -1;
536 }
537
538 *transaction_id = (const char *)&msg->l3h[ptr[0].start];
539 *endp = find_endpoint((const char *)&msg->l3h[ptr[1].start]);
540 return *endp == NULL;
541}
542
543static int verify_call_id(const struct mgcp_endpoint *endp,
544 const char *callid)
545{
546 if (strcmp(endp->callid, callid) != 0) {
547 DEBUGP(DMGCP, "CallIDs does not match on 0x%x. '%s' != '%s'\n",
548 ENDPOINT_NUMBER(endp), endp->callid, callid);
549 return -1;
550 }
551
552 return 0;
553}
554
555static int verify_ci(const struct mgcp_endpoint *endp,
556 const char *ci)
557{
558 if (atoi(ci) != endp->ci) {
559 DEBUGP(DMGCP, "ConnectionIdentifiers do not match on 0x%x. %d != %s\n",
560 ENDPOINT_NUMBER(endp), endp->ci, ci);
561 return -1;
562 }
563
564 return 0;
565}
566
567static void handle_audit_endpoint(struct msgb *msg, struct sockaddr_in *source)
568{
569 struct mgcp_msg_ptr data_ptrs[6];
570 int found, response;
571 const char *trans_id;
572 struct mgcp_endpoint *endp;
573
574 found = analyze_header(msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp);
575 if (found != 0)
576 response = 500;
577 else
578 response = 200;
579
580 return send_response(response, "AUEP", trans_id, source);
581}
582
583static int parse_conn_mode(const char* msg, int *conn_mode)
584{
585 int ret = 0;
586 if (strcmp(msg, "recvonly") == 0)
587 *conn_mode = MGCP_CONN_RECV_ONLY;
588 else if (strcmp(msg, "sendrecv") == 0)
589 *conn_mode = MGCP_CONN_RECV_SEND;
590 else {
591 DEBUGP(DMGCP, "Unknown connection mode: '%s'\n", msg);
592 ret = -1;
593 }
594
595 return ret;
596}
597
598static void handle_create_con(struct msgb *msg, struct sockaddr_in *source)
599{
600 struct mgcp_msg_ptr data_ptrs[6];
601 int found, i, line_start;
602 const char *trans_id;
603 struct mgcp_endpoint *endp;
604 int error_code = 500;
605
606 found = analyze_header(msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp);
607 if (found != 0)
608 return send_response(500, "CRCX", trans_id, source);
609
610 if (endp->ci != CI_UNUSED) {
611 DEBUGP(DMGCP, "Endpoint is already used. 0x%x\n", ENDPOINT_NUMBER(endp));
612 return send_response(500, "CRCX", trans_id, source);
613 }
614
615 /* parse CallID C: and LocalParameters L: */
616 MSG_TOKENIZE_START
617 switch (msg->l3h[line_start]) {
618 case 'L':
619 endp->local_options = talloc_strdup(endpoints,
620 (const char *)&msg->l3h[line_start + 3]);
621 break;
622 case 'C':
623 endp->callid = talloc_strdup(endpoints,
624 (const char *)&msg->l3h[line_start + 3]);
625 break;
626 case 'M':
627 if (parse_conn_mode((const char *)&msg->l3h[line_start + 3],
628 &endp->conn_mode) != 0) {
629 error_code = 517;
630 goto error2;
631 }
632 break;
633 default:
634 DEBUGP(DMGCP, "Unhandled option: '%c'/%d on 0x%x\n",
635 msg->l3h[line_start], msg->l3h[line_start],
636 ENDPOINT_NUMBER(endp));
637 break;
638 }
639 MSG_TOKENIZE_END
640
Holger Hans Peter Freyther48ecad42009-11-19 16:04:10 +0100641 /* initialize */
642 endp->rtp = endp->rtcp = endp->bts_rtp = endp->bts_rtcp = 0;
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +0200643
644 /* bind to the port now */
645 endp->rtp_port = rtp_calculate_port(ENDPOINT_NUMBER(endp), rtp_base_port);
646 if (!early_bind && bind_rtp(endp) != 0)
647 goto error2;
648
649 /* assign a local call identifier or fail */
650 endp->ci = generate_call_id();
651 if (endp->ci == CI_UNUSED)
652 goto error2;
653
654 DEBUGP(DMGCP, "Creating endpoint on: 0x%x CI: %u port: %u\n",
655 ENDPOINT_NUMBER(endp), endp->ci, endp->rtp_port);
656 return send_with_sdp(endp, "CRCX", trans_id, source);
657error:
658 DEBUGP(DMGCP, "Malformed line: %s on 0x%x with: line_start: %d %d\n",
659 hexdump(msg->l3h, msgb_l3len(msg)),
660 ENDPOINT_NUMBER(endp), line_start, i);
661 return send_response(error_code, "CRCX", trans_id, source);
662
663error2:
664 DEBUGP(DMGCP, "Resource error on 0x%x\n", ENDPOINT_NUMBER(endp));
665 return send_response(error_code, "CRCX", trans_id, source);
666}
667
668static void handle_modify_con(struct msgb *msg, struct sockaddr_in *source)
669{
670 struct mgcp_msg_ptr data_ptrs[6];
671 int found, i, line_start;
672 const char *trans_id;
673 struct mgcp_endpoint *endp;
674 int error_code = 500;
675
676 found = analyze_header(msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp);
677 if (found != 0)
678 return send_response(error_code, "MDCX", trans_id, source);
679
680 if (endp->ci == CI_UNUSED) {
681 DEBUGP(DMGCP, "Endpoint is not holding a connection. 0x%x\n", ENDPOINT_NUMBER(endp));
682 return send_response(error_code, "MDCX", trans_id, source);
683 }
684
685 MSG_TOKENIZE_START
686 switch (msg->l3h[line_start]) {
687 case 'C': {
688 if (verify_call_id(endp, (const char *)&msg->l3h[line_start + 3]) != 0)
689 goto error3;
690 break;
691 }
692 case 'I': {
693 if (verify_ci(endp, (const char *)&msg->l3h[line_start + 3]) != 0)
694 goto error3;
695 break;
696 }
697 case 'L':
698 /* skip */
699 break;
700 case 'M':
701 if (parse_conn_mode((const char *)&msg->l3h[line_start + 3],
702 &endp->conn_mode) != 0) {
703 error_code = 517;
704 goto error3;
705 }
706 break;
707 case '\0':
708 /* SDP file begins */
709 break;
710 case 'a':
711 case 'o':
712 case 's':
713 case 't':
714 case 'v':
715 /* skip these SDP attributes */
716 break;
717 case 'm': {
718 int port;
719 const char *param = (const char *)&msg->l3h[line_start];
720
721 if (sscanf(param, "m=audio %d RTP/AVP %*d", &port) == 1) {
722 endp->rtp = htons(port);
723 endp->rtcp = htons(port + 1);
724 }
725 break;
726 }
727 case 'c': {
728 char ipv4[16];
729 const char *param = (const char *)&msg->l3h[line_start];
730
731 if (sscanf(param, "c=IN IP4 %15s", ipv4) == 1) {
732 inet_aton(ipv4, &endp->remote);
733 }
734 break;
735 }
736 default:
737 DEBUGP(DMGCP, "Unhandled option: '%c'/%d on 0x%x\n",
738 msg->l3h[line_start], msg->l3h[line_start],
739 ENDPOINT_NUMBER(endp));
740 break;
741 }
742 MSG_TOKENIZE_END
743
744 /* modify */
745 DEBUGP(DMGCP, "Modified endpoint on: 0x%x Server: %s:%u\n",
746 ENDPOINT_NUMBER(endp), inet_ntoa(endp->remote), endp->rtp);
747 return send_with_sdp(endp, "MDCX", trans_id, source);
748
749error:
750 DEBUGP(DMGCP, "Malformed line: %s on 0x%x with: line_start: %d %d %d\n",
751 hexdump(msg->l3h, msgb_l3len(msg)),
752 ENDPOINT_NUMBER(endp), line_start, i, msg->l3h[line_start]);
753 return send_response(error_code, "MDCX", trans_id, source);
754
755error3:
756 return send_response(error_code, "MDCX", trans_id, source);
757}
758
759static void handle_delete_con(struct msgb *msg, struct sockaddr_in *source)
760{
761 struct mgcp_msg_ptr data_ptrs[6];
762 int found, i, line_start;
763 const char *trans_id;
764 struct mgcp_endpoint *endp;
765 int error_code = 500;
766
767 found = analyze_header(msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp);
768 if (found != 0)
769 return send_response(error_code, "DLCX", trans_id, source);
770
771 if (endp->ci == CI_UNUSED) {
772 DEBUGP(DMGCP, "Endpoint is not used. 0x%x\n", ENDPOINT_NUMBER(endp));
773 return send_response(error_code, "DLCX", trans_id, source);
774 }
775
776 MSG_TOKENIZE_START
777 switch (msg->l3h[line_start]) {
778 case 'C': {
779 if (verify_call_id(endp, (const char *)&msg->l3h[line_start + 3]) != 0)
780 goto error3;
781 break;
782 }
783 case 'I': {
784 if (verify_ci(endp, (const char *)&msg->l3h[line_start + 3]) != 0)
785 goto error3;
786 break;
787 }
788 default:
789 DEBUGP(DMGCP, "Unhandled option: '%c'/%d on 0x%x\n",
790 msg->l3h[line_start], msg->l3h[line_start],
791 ENDPOINT_NUMBER(endp));
792 break;
793 }
794 MSG_TOKENIZE_END
795
796
797 /* free the connection */
798 DEBUGP(DMGCP, "Deleting endpoint on: 0x%x\n", ENDPOINT_NUMBER(endp));
799 endp->ci= CI_UNUSED;
800 talloc_free(endp->callid);
801 talloc_free(endp->local_options);
802
803 if (!early_bind) {
804 bsc_unregister_fd(&endp->local_rtp);
805 bsc_unregister_fd(&endp->local_rtcp);
806 }
807
Holger Hans Peter Freyther48ecad42009-11-19 16:04:10 +0100808 endp->rtp = endp->rtcp = endp->bts_rtp = endp->bts_rtcp = 0;
809
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +0200810 return send_response(250, "DLCX", trans_id, source);
811
812error:
813 DEBUGP(DMGCP, "Malformed line: %s on 0x%x with: line_start: %d %d\n",
814 hexdump(msg->l3h, msgb_l3len(msg)),
815 ENDPOINT_NUMBER(endp), line_start, i);
816 return send_response(error_code, "DLCX", trans_id, source);
817
818error3:
819 return send_response(error_code, "DLCX", trans_id, source);
820}
821
822static void print_help()
823{
824 printf("Some useful help...\n");
825 printf(" -h --help is printing this text.\n");
826 printf(" -c --config-file filename The config file to use.\n");
827}
828
829static void handle_options(int argc, char** argv)
830{
831 while (1) {
832 int option_index = 0, c;
833 static struct option long_options[] = {
834 {"help", 0, 0, 'h'},
835 {"config-file", 1, 0, 'c'},
836 {0, 0, 0, 0},
837 };
838
839 c = getopt_long(argc, argv, "hc:", long_options, &option_index);
840
841 if (c == -1)
842 break;
843
844 switch(c) {
845 case 'h':
846 print_help();
847 exit(0);
848 break;
849 case 'c':
850 config_file = talloc_strdup(tall_bsc_ctx, optarg);
851 break;
852 default:
853 /* ignore */
854 break;
855 };
856 }
857}
858
859static int read_call_agent(struct bsc_fd *fd, unsigned int what)
860{
861 struct sockaddr_in addr;
862 socklen_t slen = sizeof(addr);
863 struct msgb *msg;
864
865 msg = (struct msgb *) fd->data;
866
867 /* read one less so we can use it as a \0 */
868 int rc = recvfrom(bfd.fd, msg->data, msg->data_len - 1, 0,
869 (struct sockaddr *) &addr, &slen);
870 if (rc < 0) {
871 perror("Gateway failed to read");
872 return -1;
873 } else if (slen > sizeof(addr)) {
874 fprintf(stderr, "Gateway received message from outerspace: %d %d\n",
875 slen, sizeof(addr));
876 return -1;
877 }
878
879 if (first_request) {
880 first_request = 0;
881 send_rsip(&addr);
882 return 0;
883 }
884
885 /* handle message now */
886 msg->l2h = msgb_put(msg, rc);
887 handle_message(msg, &addr);
888 msgb_reset(msg);
889 return 0;
890}
891
892/*
893 * vty code for mgcp below
894 */
895struct cmd_node mgcp_node = {
896 MGCP_NODE,
897 "%s(mgcp)#",
898 1,
899};
900
901static int config_write_mgcp(struct vty *vty)
902{
903 vty_out(vty, "mgcp%s", VTY_NEWLINE);
904 if (local_ip)
905 vty_out(vty, " local ip %s%s", local_ip, VTY_NEWLINE);
Holger Hans Peter Freyther601a67e2010-01-13 16:37:32 +0100906 if (bts_ip)
907 vty_out(vty, " bts ip %s%s", bts_ip, VTY_NEWLINE);
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +0200908 vty_out(vty, " bind ip %s%s", source_addr, VTY_NEWLINE);
909 vty_out(vty, " bind port %u%s", source_port, VTY_NEWLINE);
Holger Hans Peter Freyther5fddf472009-11-19 15:08:02 +0100910 vty_out(vty, " bind early %u%s", !!early_bind, VTY_NEWLINE);
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +0200911 vty_out(vty, " rtp base %u%s", rtp_base_port, VTY_NEWLINE);
Holger Hans Peter Freyther5fddf472009-11-19 15:08:02 +0100912 vty_out(vty, " sdp audio payload number %u%s", audio_payload, VTY_NEWLINE);
913 vty_out(vty, " sdp audio payload name %s%s", audio_name, VTY_NEWLINE);
914 vty_out(vty, " loop %u%s", !!audio_loop, VTY_NEWLINE);
Holger Hans Peter Freyther4ec389e2009-11-20 11:10:31 +0100915 vty_out(vty, " endpoints %u%s", number_endpoints, VTY_NEWLINE);
Holger Hans Peter Freyther2c492ed2010-01-05 12:29:36 +0100916 if (forward_ip)
917 vty_out(vty, " forward audio %s%s", forward_ip, VTY_NEWLINE);
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +0200918
919 return CMD_SUCCESS;
920}
921
Holger Hans Peter Freyther17e79162009-11-19 15:20:48 +0100922DEFUN(show_mcgp, show_mgcp_cmd, "show mgcp",
923 SHOW_STR "Display information about the MGCP Media Gateway")
924{
925 int i;
926
927 vty_out(vty, "MGCP is up and running with %u endpoints:%s", number_endpoints - 1, VTY_NEWLINE);
928 for (i = 1; i < number_endpoints; ++i) {
929 struct mgcp_endpoint *endp = &endpoints[i];
930 vty_out(vty, " Endpoint 0x%.2x: CI: %d net: %u/%u bts: %u/%u%s",
931 i, endp->ci,
932 ntohs(endp->rtp), ntohs(endp->rtcp),
933 ntohs(endp->bts_rtp), ntohs(endp->bts_rtcp), VTY_NEWLINE);
934 }
935
936 return CMD_SUCCESS;
937}
938
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +0200939DEFUN(cfg_mgcp,
940 cfg_mgcp_cmd,
941 "mgcp",
942 "Configure the MGCP")
943{
944 vty->node = MGCP_NODE;
945 return CMD_SUCCESS;
946}
947
948DEFUN(cfg_mgcp_local_ip,
949 cfg_mgcp_local_ip_cmd,
950 "local ip IP",
951 "Set the IP to be used in SDP records")
952{
953 local_ip = talloc_strdup(tall_bsc_ctx, argv[0]);
954 return CMD_SUCCESS;
955}
956
957DEFUN(cfg_mgcp_bts_ip,
958 cfg_mgcp_bts_ip_cmd,
959 "bts ip IP",
960 "Set the IP of the BTS for RTP forwarding")
961{
962 bts_ip = talloc_strdup(tall_bsc_ctx, argv[0]);
963 inet_aton(bts_ip, &bts_in);
964 return CMD_SUCCESS;
965}
966
967DEFUN(cfg_mgcp_bind_ip,
968 cfg_mgcp_bind_ip_cmd,
969 "bind ip IP",
970 "Bind the MGCP to this local addr")
971{
972 source_addr = talloc_strdup(tall_bsc_ctx, argv[0]);
973 return CMD_SUCCESS;
974}
975
976DEFUN(cfg_mgcp_bind_port,
977 cfg_mgcp_bind_port_cmd,
978 "bind port <0-65534>",
979 "Bind the MGCP to this port")
980{
981 unsigned int port = atoi(argv[0]);
982 if (port > 65534) {
983 vty_out(vty, "%% wrong bind port '%s'%s", argv[0], VTY_NEWLINE);
984 return CMD_WARNING;
985 }
986
987 source_port = port;
988 return CMD_SUCCESS;
989}
990
991DEFUN(cfg_mgcp_bind_early,
992 cfg_mgcp_bind_early_cmd,
993 "bind early (0|1)",
994 "Bind all RTP ports early")
995{
996 unsigned int bind = atoi(argv[0]);
997 if (bind != 0 && bind != 1) {
998 vty_out(vty, "%% param must be 0 or 1.%s", VTY_NEWLINE);
999 return CMD_WARNING;
1000 }
1001
1002 early_bind = bind == 1;
1003 return CMD_SUCCESS;
1004}
1005
1006DEFUN(cfg_mgcp_rtp_base_port,
1007 cfg_mgcp_rtp_base_port_cmd,
1008 "rtp base <0-65534>",
1009 "Base port to use")
1010{
1011 unsigned int port = atoi(argv[0]);
1012 if (port > 65534) {
1013 vty_out(vty, "%% wrong base port '%s'%s", argv[0], VTY_NEWLINE);
1014 return CMD_WARNING;
1015 }
1016
1017 rtp_base_port = port;
1018 return CMD_SUCCESS;
1019}
1020
1021DEFUN(cfg_mgcp_sdp_payload_number,
1022 cfg_mgcp_sdp_payload_number_cmd,
1023 "sdp audio payload number <1-255>",
1024 "Set the audio codec to use")
1025{
1026 unsigned int payload = atoi(argv[0]);
1027 if (payload > 255) {
1028 vty_out(vty, "%% wrong payload number '%s'%s", argv[0], VTY_NEWLINE);
1029 return CMD_WARNING;
1030 }
1031
1032 audio_payload = payload;
1033 return CMD_SUCCESS;
1034}
1035
1036DEFUN(cfg_mgcp_sdp_payload_name,
1037 cfg_mgcp_sdp_payload_name_cmd,
1038 "sdp audio payload name NAME",
1039 "Set the audio name to use")
1040{
1041 audio_name = talloc_strdup(tall_bsc_ctx, argv[0]);
1042 return CMD_SUCCESS;
1043}
1044
Holger Hans Peter Freyther138b7ec2009-11-18 18:32:31 +01001045DEFUN(cfg_mgcp_loop,
1046 cfg_mgcp_loop_cmd,
1047 "loop (0|1)",
1048 "Loop the audio")
1049{
1050 audio_loop = atoi(argv[0]);
1051 return CMD_SUCCESS;
1052}
1053
Holger Hans Peter Freyther4ec389e2009-11-20 11:10:31 +01001054DEFUN(cfg_mgcp_number_endp,
1055 cfg_mgcp_number_endp_cmd,
1056 "number endpoints <0-65534>",
1057 "The number of endpoints to allocate. This is not dynamic.")
1058{
1059 /* + 1 as we start counting at one */
1060 number_endpoints = atoi(argv[0]) + 1;
1061 return CMD_SUCCESS;
1062}
1063
Holger Hans Peter Freyther14083be2010-01-05 12:21:36 +01001064DEFUN(cfg_mgcp_forward,
1065 cfg_mgcp_forward_cmd,
1066 "forward audio IP",
1067 "Forward packets from and to the IP. This disables most of the MGCP feature.")
1068{
1069 if (forward_ip)
1070 talloc_free(forward_ip);
1071 forward_ip = talloc_strdup(tall_bsc_ctx, argv[0]);
1072 return CMD_SUCCESS;
1073}
1074
Holger Hans Peter Freyther338fa562009-11-19 15:03:39 +01001075int bsc_vty_init(struct gsm_network *dummy)
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +02001076{
1077 cmd_init(1);
1078 vty_init();
1079
Holger Hans Peter Freyther17e79162009-11-19 15:20:48 +01001080 install_element(VIEW_NODE, &show_mgcp_cmd);
1081
1082
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +02001083 install_element(CONFIG_NODE, &cfg_mgcp_cmd);
1084 install_node(&mgcp_node, config_write_mgcp);
1085 install_default(MGCP_NODE);
1086 install_element(MGCP_NODE, &cfg_mgcp_local_ip_cmd);
1087 install_element(MGCP_NODE, &cfg_mgcp_bts_ip_cmd);
1088 install_element(MGCP_NODE, &cfg_mgcp_bind_ip_cmd);
1089 install_element(MGCP_NODE, &cfg_mgcp_bind_port_cmd);
1090 install_element(MGCP_NODE, &cfg_mgcp_bind_early_cmd);
1091 install_element(MGCP_NODE, &cfg_mgcp_rtp_base_port_cmd);
1092 install_element(MGCP_NODE, &cfg_mgcp_sdp_payload_number_cmd);
1093 install_element(MGCP_NODE, &cfg_mgcp_sdp_payload_name_cmd);
Holger Hans Peter Freyther138b7ec2009-11-18 18:32:31 +01001094 install_element(MGCP_NODE, &cfg_mgcp_loop_cmd);
Holger Hans Peter Freyther4ec389e2009-11-20 11:10:31 +01001095 install_element(MGCP_NODE, &cfg_mgcp_number_endp_cmd);
Holger Hans Peter Freyther14083be2010-01-05 12:21:36 +01001096 install_element(MGCP_NODE, &cfg_mgcp_forward_cmd);
Holger Hans Peter Freyther338fa562009-11-19 15:03:39 +01001097 return 0;
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +02001098}
1099
1100int main(int argc, char** argv)
1101{
Holger Hans Peter Freyther338fa562009-11-19 15:03:39 +01001102 struct gsm_network dummy_network;
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +02001103 struct sockaddr_in addr;
1104 int on = 1, i, rc;
Holger Hans Peter Freytherb61e3b22009-12-22 22:32:51 +01001105 struct debug_target *stderr_target;
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +02001106
1107 tall_bsc_ctx = talloc_named_const(NULL, 1, "mgcp-callagent");
Holger Hans Peter Freytherb61e3b22009-12-22 22:32:51 +01001108
1109 debug_init();
1110 stderr_target = debug_target_create_stderr();
1111 debug_add_target(stderr_target);
1112 debug_set_all_filter(stderr_target, 1);
1113
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +02001114 handle_options(argc, argv);
1115
Holger Hans Peter Freyther338fa562009-11-19 15:03:39 +01001116 telnet_init(&dummy_network, 4243);
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +02001117 rc = vty_read_config_file(config_file);
1118 if (rc < 0) {
1119 fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file);
1120 return rc;
1121 }
1122
1123
Holger Hans Peter Freyther601a67e2010-01-13 16:37:32 +01001124 if (!bts_ip)
1125 fprintf(stderr, "No BTS ip address specified. This will allow everyone to connect.\n");
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +02001126
1127 endpoints = _talloc_zero_array(tall_bsc_ctx,
1128 sizeof(struct mgcp_endpoint),
1129 number_endpoints, "endpoints");
1130 if (!endpoints) {
1131 fprintf(stderr, "Failed to allocate endpoints: %d. Quitting.\n", number_endpoints);
1132 return -1;
1133 }
1134
1135 /* Initialize all endpoints */
1136 for (i = 0; i < number_endpoints; ++i) {
1137 endpoints[i].local_rtp.fd = -1;
1138 endpoints[i].local_rtcp.fd = -1;
1139 endpoints[i].ci = CI_UNUSED;
1140 }
1141
Holger Hans Peter Freyther14083be2010-01-05 12:21:36 +01001142 /*
1143 * This application supports two modes.
1144 * 1.) a true MGCP gateway with support for AUEP, CRCX, MDCX, DLCX
1145 * 2.) plain forwarding of RTP packets on the endpoints.
1146 * both modes are mutual exclusive
1147 */
1148 if (forward_ip) {
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +02001149
Holger Hans Peter Freyther14083be2010-01-05 12:21:36 +01001150 if (!early_bind) {
1151 DEBUGP(DMGCP, "Forwarding requires early bind.\n");
1152 return -1;
1153 }
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +02001154
Holger Hans Peter Freyther14083be2010-01-05 12:21:36 +01001155 /*
1156 * Store the forward IP and assign a ci. For early bind
1157 * the sockets will be created after this.
1158 */
1159 for (i = 1; i < number_endpoints; ++i) {
1160 struct mgcp_endpoint *endp = &endpoints[i];
1161 inet_aton(forward_ip, &endp->remote);
1162 endp->ci = CI_UNUSED + 23;
Holger Hans Peter Freyther62096192010-01-05 12:35:16 +01001163 endp->rtp = htons(rtp_calculate_port(ENDPOINT_NUMBER(endp), rtp_base_port));
1164 endp->rtcp = htons(rtp_calculate_port(ENDPOINT_NUMBER(endp), rtp_base_port) + 1);
Holger Hans Peter Freyther14083be2010-01-05 12:21:36 +01001165 }
Holger Hans Peter Freytherf986cfc2010-01-05 12:25:25 +01001166
1167 DEBUGP(DMGCP, "Configured for Audio Forwarding.\n");
Holger Hans Peter Freyther14083be2010-01-05 12:21:36 +01001168 } else {
1169 bfd.when = BSC_FD_READ;
1170 bfd.cb = read_call_agent;
1171 bfd.fd = socket(AF_INET, SOCK_DGRAM, 0);
1172 if (bfd.fd < 0) {
1173 perror("Gateway failed to listen");
1174 return -1;
1175 }
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +02001176
Holger Hans Peter Freyther14083be2010-01-05 12:21:36 +01001177 setsockopt(bfd.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +02001178
Holger Hans Peter Freyther14083be2010-01-05 12:21:36 +01001179 memset(&addr, 0, sizeof(addr));
1180 addr.sin_family = AF_INET;
1181 addr.sin_port = htons(source_port);
1182 inet_aton(source_addr, &addr.sin_addr);
1183
1184 if (bind(bfd.fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
1185 perror("Gateway failed to bind");
1186 return -1;
1187 }
1188
1189 bfd.data = msgb_alloc(4096, "mgcp-msg");
1190 if (!bfd.data) {
1191 fprintf(stderr, "Gateway memory error.\n");
1192 return -1;
1193 }
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +02001194
1195
Holger Hans Peter Freyther14083be2010-01-05 12:21:36 +01001196 if (bsc_register_fd(&bfd) != 0) {
1197 DEBUGP(DMGCP, "Failed to register the fd\n");
1198 return -1;
1199 }
Holger Hans Peter Freytherf986cfc2010-01-05 12:25:25 +01001200
1201 DEBUGP(DMGCP, "Configured for MGCP.\n");
Holger Hans Peter Freytherf67945f2009-10-09 07:08:11 +02001202 }
1203
1204 /* initialisation */
1205 srand(time(NULL));
1206
1207 /* early bind */
1208 if (early_bind) {
1209 for (i = 1; i < number_endpoints; ++i) {
1210 struct mgcp_endpoint *endp = &endpoints[i];
1211 endp->rtp_port = rtp_calculate_port(ENDPOINT_NUMBER(endp), rtp_base_port);
1212 if (bind_rtp(endp) != 0)
1213 return -1;
1214 }
1215 }
1216
1217 /* main loop */
1218 while (1) {
1219 bsc_select_main(0);
1220 }
1221
1222
1223 return 0;
1224}