codec: dvbsub: remove usage of bs_show
[vlc.git] / src / network / tls.c
blob00193eeec8d2d10bb71758b42e4f88f18d5e2c20
1 /*****************************************************************************
2 * tls.c
3 *****************************************************************************
4 * Copyright © 2004-2016 Rémi Denis-Courmont
5 * $Id$
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as published by
9 * the Free Software Foundation; either version 2.1 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with this program; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
20 *****************************************************************************/
22 /**
23 * @ingroup tls
24 * @file
25 * Transport Layer Session protocol API.
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
32 #ifdef HAVE_POLL
33 # include <poll.h>
34 #endif
35 #include <assert.h>
36 #include <errno.h>
37 #ifndef SOL_TCP
38 # define SOL_TCP IPPROTO_TCP
39 #endif
41 #include <vlc_common.h>
42 #include "libvlc.h"
44 #include <vlc_tls.h>
45 #include <vlc_modules.h>
46 #include <vlc_interrupt.h>
48 /*** TLS credentials ***/
50 static int tls_server_load(void *func, va_list ap)
52 int (*activate) (vlc_tls_creds_t *, const char *, const char *) = func;
53 vlc_tls_creds_t *crd = va_arg (ap, vlc_tls_creds_t *);
54 const char *cert = va_arg (ap, const char *);
55 const char *key = va_arg (ap, const char *);
57 return activate (crd, cert, key);
60 static int tls_client_load(void *func, va_list ap)
62 int (*activate) (vlc_tls_creds_t *) = func;
63 vlc_tls_creds_t *crd = va_arg (ap, vlc_tls_creds_t *);
65 return activate (crd);
68 static void tls_unload(void *func, va_list ap)
70 void (*deactivate) (vlc_tls_creds_t *) = func;
71 vlc_tls_creds_t *crd = va_arg (ap, vlc_tls_creds_t *);
73 deactivate (crd);
76 vlc_tls_creds_t *
77 vlc_tls_ServerCreate (vlc_object_t *obj, const char *cert_path,
78 const char *key_path)
80 vlc_tls_creds_t *srv = vlc_custom_create (obj, sizeof (*srv),
81 "tls server");
82 if (unlikely(srv == NULL))
83 return NULL;
85 if (key_path == NULL)
86 key_path = cert_path;
88 srv->module = vlc_module_load (srv, "tls server", NULL, false,
89 tls_server_load, srv, cert_path, key_path);
90 if (srv->module == NULL)
92 msg_Err (srv, "TLS server plugin not available");
93 vlc_object_release (srv);
94 return NULL;
97 return srv;
100 vlc_tls_creds_t *vlc_tls_ClientCreate (vlc_object_t *obj)
102 vlc_tls_creds_t *crd = vlc_custom_create (obj, sizeof (*crd),
103 "tls client");
104 if (unlikely(crd == NULL))
105 return NULL;
107 crd->module = vlc_module_load (crd, "tls client", NULL, false,
108 tls_client_load, crd);
109 if (crd->module == NULL)
111 msg_Err (crd, "TLS client plugin not available");
112 vlc_object_release (crd);
113 return NULL;
116 return crd;
119 void vlc_tls_Delete (vlc_tls_creds_t *crd)
121 if (crd == NULL)
122 return;
124 vlc_module_unload(crd, crd->module, tls_unload, crd);
125 vlc_object_release (crd);
129 /*** TLS session ***/
131 static vlc_tls_t *vlc_tls_SessionCreate(vlc_tls_creds_t *crd,
132 vlc_tls_t *sock,
133 const char *host,
134 const char *const *alpn)
136 vlc_tls_t *session;
137 int canc = vlc_savecancel();
138 session = crd->open(crd, sock, host, alpn);
139 vlc_restorecancel(canc);
140 if (session != NULL)
141 session->p = sock;
142 return session;
145 void vlc_tls_SessionDelete (vlc_tls_t *session)
147 int canc = vlc_savecancel();
148 session->ops->close(session);
149 vlc_restorecancel(canc);
152 static void cleanup_tls(void *data)
154 vlc_tls_t *session = data;
156 vlc_tls_SessionDelete (session);
159 vlc_tls_t *vlc_tls_ClientSessionCreate(vlc_tls_creds_t *crd, vlc_tls_t *sock,
160 const char *host, const char *service,
161 const char *const *alpn, char **alp)
163 int val;
165 vlc_tls_t *session = vlc_tls_SessionCreate(crd, sock, host, alpn);
166 if (session == NULL)
167 return NULL;
169 int canc = vlc_savecancel();
170 vlc_tick_t deadline = vlc_tick_now ();
171 deadline += VLC_TICK_FROM_MS( var_InheritInteger (crd, "ipv4-timeout") );
173 struct pollfd ufd[1];
174 ufd[0].fd = vlc_tls_GetFD(sock);
176 vlc_cleanup_push (cleanup_tls, session);
177 while ((val = crd->handshake(crd, session, host, service, alp)) != 0)
179 if (val < 0 || vlc_killed() )
181 if (val < 0)
182 msg_Err(crd, "TLS session handshake error");
183 error:
184 vlc_tls_SessionDelete (session);
185 session = NULL;
186 break;
189 vlc_tick_t now = vlc_tick_now ();
190 if (now > deadline)
191 now = deadline;
193 assert (val <= 2);
194 ufd[0] .events = (val == 1) ? POLLIN : POLLOUT;
196 vlc_restorecancel(canc);
197 val = vlc_poll_i11e(ufd, 1, MS_FROM_VLC_TICK(deadline - now));
198 canc = vlc_savecancel();
199 if (val == 0)
201 msg_Err(crd, "TLS session handshake timeout");
202 goto error;
205 vlc_cleanup_pop();
206 vlc_restorecancel(canc);
207 return session;
210 vlc_tls_t *vlc_tls_ServerSessionCreate(vlc_tls_creds_t *crd,
211 vlc_tls_t *sock,
212 const char *const *alpn)
214 return vlc_tls_SessionCreate(crd, sock, NULL, alpn);
217 vlc_tls_t *vlc_tls_SocketOpenTLS(vlc_tls_creds_t *creds, const char *name,
218 unsigned port, const char *service,
219 const char *const *alpn, char **alp)
221 struct addrinfo hints =
223 .ai_socktype = SOCK_STREAM,
224 .ai_protocol = IPPROTO_TCP,
225 }, *res;
227 msg_Dbg(creds, "resolving %s ...", name);
229 int val = vlc_getaddrinfo_i11e(name, port, &hints, &res);
230 if (val != 0)
231 { /* TODO: C locale for gai_strerror() */
232 msg_Err(creds, "cannot resolve %s port %u: %s", name, port,
233 gai_strerror(val));
234 return NULL;
237 for (const struct addrinfo *p = res; p != NULL; p = p->ai_next)
239 vlc_tls_t *tcp = vlc_tls_SocketOpenAddrInfo(p, true);
240 if (tcp == NULL)
242 msg_Err(creds, "socket error: %s", vlc_strerror_c(errno));
243 continue;
246 vlc_tls_t *tls = vlc_tls_ClientSessionCreate(creds, tcp, name, service,
247 alpn, alp);
248 if (tls != NULL)
249 { /* Success! */
250 freeaddrinfo(res);
251 return tls;
254 msg_Err(creds, "connection error: %s", vlc_strerror_c(errno));
255 vlc_tls_SessionDelete(tcp);
258 /* Failure! */
259 freeaddrinfo(res);
260 return NULL;