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