1 /**
2  * @file stun.c  STUN stack
3  *
4  * Copyright (C) 2010 Creytiv.com
5  */
6 #include <re_types.h>
7 #include <re_fmt.h>
8 #include <re_mem.h>
9 #include <re_mbuf.h>
10 #include <re_sa.h>
11 #include <re_udp.h>
12 #include <re_tcp.h>
13 #include <re_srtp.h>
14 #include <re_tls.h>
15 #include <re_sys.h>
16 #include <re_list.h>
17 #include <re_stun.h>
18 #include "stun.h"
19 
20 
21 const char *stun_software = "libre v" VERSION " (" ARCH "/" OS ")";
22 
23 
24 static const struct stun_conf conf_default = {
25 	STUN_DEFAULT_RTO,
26 	STUN_DEFAULT_RC,
27 	STUN_DEFAULT_RM,
28 	STUN_DEFAULT_TI,
29 	0x00
30 };
31 
32 
destructor(void * arg)33 static void destructor(void *arg)
34 {
35 	struct stun *stun = arg;
36 
37 	stun_ctrans_close(stun);
38 }
39 
40 
41 /**
42  * Allocate a new STUN instance
43  *
44  * @param stunp Pointer to allocated STUN instance
45  * @param conf  STUN configuration (optional)
46  * @param indh  STUN Indication handler (optional)
47  * @param arg   STUN Indication handler argument
48  *
49  * @return 0 if success, otherwise errorcode
50  */
stun_alloc(struct stun ** stunp,const struct stun_conf * conf,stun_ind_h * indh,void * arg)51 int stun_alloc(struct stun **stunp, const struct stun_conf *conf,
52 	       stun_ind_h *indh, void *arg)
53 {
54 	struct stun *stun;
55 
56 	if (!stunp)
57 		return EINVAL;
58 
59 	stun = mem_zalloc(sizeof(*stun), destructor);
60 	if (!stun)
61 		return ENOMEM;
62 
63 	stun->conf = conf ? *conf : conf_default;
64 	stun->indh = indh;
65 	stun->arg  = arg;
66 
67 	*stunp = stun;
68 
69 	return 0;
70 }
71 
72 
73 /**
74  * Get STUN configuration object
75  *
76  * @param stun STUN Instance
77  *
78  * @return STUN configuration
79  */
stun_conf(struct stun * stun)80 struct stun_conf *stun_conf(struct stun *stun)
81 {
82 	return stun ? &stun->conf : NULL;
83 }
84 
85 
86 /**
87  * Send a STUN message
88  *
89  * @param proto Transport protocol (IPPROTO_UDP or IPPROTO_TCP)
90  * @param sock  Socket, UDP (struct udp_sock) or TCP (struct tcp_conn)
91  * @param dst   Destination network address (UDP only)
92  * @param mb    Buffer containing the STUN message
93  *
94  * @return 0 if success, otherwise errorcode
95  */
stun_send(int proto,void * sock,const struct sa * dst,struct mbuf * mb)96 int stun_send(int proto, void *sock, const struct sa *dst, struct mbuf *mb)
97 {
98 	int err;
99 
100 	if (!sock || !mb)
101 		return EINVAL;
102 
103 	switch (proto) {
104 
105 	case IPPROTO_UDP:
106 		err = udp_send(sock, dst, mb);
107 		break;
108 
109 	case IPPROTO_TCP:
110 		err = tcp_send(sock, mb);
111 		break;
112 
113 #ifdef USE_DTLS
114 	case STUN_TRANSP_DTLS:
115 		err = dtls_send(sock, mb);
116 		break;
117 #endif
118 
119 	default:
120 		err = EPROTONOSUPPORT;
121 		break;
122 	}
123 
124 	return err;
125 }
126 
127 
128 /**
129  * Receive a STUN message
130  *
131  * @param stun STUN Instance
132  * @param mb   Buffer containing STUN message
133  *
134  * @return 0 if success, otherwise errorcode
135  */
stun_recv(struct stun * stun,struct mbuf * mb)136 int stun_recv(struct stun *stun, struct mbuf *mb)
137 {
138 	struct stun_unknown_attr ua;
139 	struct stun_msg *msg;
140 	int err;
141 
142 	if (!stun || !mb)
143 		return EINVAL;
144 
145 	err = stun_msg_decode(&msg, mb, &ua);
146 	if (err)
147 		return err;
148 
149 	switch (stun_msg_class(msg)) {
150 
151 	case STUN_CLASS_INDICATION:
152 		if (ua.typec > 0)
153 			break;
154 
155 		if (stun->indh)
156 			stun->indh(msg, stun->arg);
157 		break;
158 
159 	case STUN_CLASS_ERROR_RESP:
160 	case STUN_CLASS_SUCCESS_RESP:
161 		err = stun_ctrans_recv(stun, msg, &ua);
162 		break;
163 
164 	default:
165 		break;
166 	}
167 
168 	mem_deref(msg);
169 
170 	return err;
171 }
172 
173 
174 /**
175  * Print STUN instance debug information
176  *
177  * @param pf   Print function
178  * @param stun STUN Instance
179  *
180  * @return 0 if success, otherwise errorcode
181  */
stun_debug(struct re_printf * pf,const struct stun * stun)182 int stun_debug(struct re_printf *pf, const struct stun *stun)
183 {
184 	if (!stun)
185 		return 0;
186 
187 	return re_hprintf(pf, "STUN debug:\n%H", stun_ctrans_debug, stun);
188 }
189