1 /**
2 * @file bfcp.c BFCP client
3 *
4 * Copyright (C) 2011 Creytiv.com
5 */
6 #include <stdlib.h>
7 #include <re.h>
8 #include <baresip.h>
9 #include "core.h"
10
11
12 struct bfcp {
13 struct bfcp_conn *conn;
14 struct sdp_media *sdpm;
15 struct mnat_media *mnat_st;
16 bool active;
17
18 /* server */
19 uint32_t lconfid;
20 uint16_t luserid;
21 };
22
23
destructor(void * arg)24 static void destructor(void *arg)
25 {
26 struct bfcp *bfcp = arg;
27
28 mem_deref(bfcp->mnat_st);
29 mem_deref(bfcp->sdpm);
30 mem_deref(bfcp->conn);
31 }
32
33
bfcp_sdp_transp(enum bfcp_transp tp)34 static const char *bfcp_sdp_transp(enum bfcp_transp tp)
35 {
36 switch (tp) {
37
38 case BFCP_UDP: return "UDP/BFCP";
39 case BFCP_DTLS: return "UDP/TLS/BFCP";
40 default: return NULL;
41 }
42 }
43
44
str2tp(const char * proto)45 static enum bfcp_transp str2tp(const char *proto)
46 {
47 if (0 == str_casecmp(proto, "udp"))
48 return BFCP_UDP;
49 else if (0 == str_casecmp(proto, "dtls"))
50 return BFCP_DTLS;
51 else {
52 warning("unsupported BFCP protocol: %s\n", proto);
53 return -1;
54 }
55 }
56
57
bfcp_resp_handler(int err,const struct bfcp_msg * msg,void * arg)58 static void bfcp_resp_handler(int err, const struct bfcp_msg *msg, void *arg)
59 {
60 struct bfcp *bfcp = arg;
61 (void)bfcp;
62
63 if (err) {
64 warning("bfcp: error response: %m\n", err);
65 return;
66 }
67
68 info("bfcp: received BFCP response: '%s'\n",
69 bfcp_prim_name(msg->prim));
70 }
71
72
bfcp_msg_handler(const struct bfcp_msg * msg,void * arg)73 static void bfcp_msg_handler(const struct bfcp_msg *msg, void *arg)
74 {
75 struct bfcp *bfcp = arg;
76
77 info("bfcp: received BFCP message '%s'\n", bfcp_prim_name(msg->prim));
78
79 switch (msg->prim) {
80
81 case BFCP_HELLO:
82 (void)bfcp_reply(bfcp->conn, msg, BFCP_HELLO_ACK, 0);
83 break;
84
85 default:
86 (void)bfcp_ereply(bfcp->conn, msg, BFCP_UNKNOWN_PRIM);
87 break;
88 }
89 }
90
91
bfcp_alloc(struct bfcp ** bfcpp,struct sdp_session * sdp_sess,const char * proto,bool offerer,const struct mnat * mnat,struct mnat_sess * mnat_sess)92 int bfcp_alloc(struct bfcp **bfcpp, struct sdp_session *sdp_sess,
93 const char *proto, bool offerer,
94 const struct mnat *mnat, struct mnat_sess *mnat_sess)
95 {
96 struct bfcp *bfcp;
97 struct sa laddr;
98 enum bfcp_transp transp;
99 int err;
100
101 if (!bfcpp || !sdp_sess)
102 return EINVAL;
103
104 transp = str2tp(proto);
105
106 bfcp = mem_zalloc(sizeof(*bfcp), destructor);
107 if (!bfcp)
108 return ENOMEM;
109
110 bfcp->active = offerer;
111
112 sa_init(&laddr, AF_INET);
113
114 err = bfcp_listen(&bfcp->conn, transp, &laddr, uag_tls(),
115 bfcp_msg_handler, bfcp);
116 if (err)
117 goto out;
118
119 err = sdp_media_add(&bfcp->sdpm, sdp_sess, "application",
120 sa_port(&laddr), bfcp_sdp_transp(transp));
121 if (err)
122 goto out;
123
124 err = sdp_format_add(NULL, bfcp->sdpm, false, "*", NULL,
125 0, 0, NULL, NULL, NULL, false, NULL);
126 if (err)
127 goto out;
128
129 err |= sdp_media_set_lattr(bfcp->sdpm, true, "floorctrl", "c-s");
130 err |= sdp_media_set_lattr(bfcp->sdpm, true, "setup",
131 bfcp->active ? "active" : "actpass");
132
133 if (bfcp->active) {
134 err |= sdp_media_set_lattr(bfcp->sdpm, true,
135 "connection", "new");
136 }
137 else {
138 bfcp->lconfid = 1000 + (rand_u16() & 0xf);
139 bfcp->luserid = 1 + (rand_u16() & 0x7);
140
141 err |= sdp_media_set_lattr(bfcp->sdpm, true, "confid",
142 "%u", bfcp->lconfid);
143 err |= sdp_media_set_lattr(bfcp->sdpm, true, "userid",
144 "%u", bfcp->luserid);
145 }
146
147 if (err)
148 goto out;
149
150 if (mnat) {
151 info("bfcp: enabled medianat '%s' on UDP socket\n", mnat->id);
152
153 err = mnat->mediah(&bfcp->mnat_st, mnat_sess, IPPROTO_UDP,
154 bfcp_sock(bfcp->conn), NULL, bfcp->sdpm);
155 if (err)
156 goto out;
157 }
158
159 info("bfcp: %s BFCP agent protocol '%s' on port %d\n",
160 bfcp->active ? "Active" : "Passive",
161 proto, sa_port(&laddr));
162
163 out:
164 if (err)
165 mem_deref(bfcp);
166 else
167 *bfcpp = bfcp;
168
169 return err;
170 }
171
172
bfcp_start(struct bfcp * bfcp)173 int bfcp_start(struct bfcp *bfcp)
174 {
175 const struct sa *paddr;
176 uint32_t confid = 0;
177 uint16_t userid = 0;
178 int err = 0;
179
180 if (!bfcp)
181 return EINVAL;
182
183 if (!sdp_media_rport(bfcp->sdpm)) {
184 info("bfcp channel is disabled\n");
185 return 0;
186 }
187
188 if (bfcp->active) {
189
190 paddr = sdp_media_raddr(bfcp->sdpm);
191 confid = sdp_media_rattr_u32(bfcp->sdpm, "confid");
192 userid = sdp_media_rattr_u32(bfcp->sdpm, "userid");
193
194 err = bfcp_request(bfcp->conn, paddr, BFCP_VER2, BFCP_HELLO,
195 confid, userid, bfcp_resp_handler, bfcp, 0);
196 }
197
198 return err;
199 }
200