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