Imported Upstream version 3.3.5
[platform/upstream/gnutls.git] / tests / mini-dtls-large.c
1 /*
2  * Copyright (C) 2013 Nikos Mavrogiannopoulos
3  *
4  * This file is part of GnuTLS.
5  *
6  * GnuTLS is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuTLS is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with GnuTLS; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24
25 #include <stdio.h>
26 #include <stdlib.h>
27
28 #if defined(_WIN32) || !defined(ENABLE_HEARTBEAT)
29
30 int main()
31 {
32         exit(77);
33 }
34
35 #else
36
37 #include <string.h>
38 #include <sys/types.h>
39 #include <netinet/in.h>
40 #include <sys/socket.h>
41 #include <sys/wait.h>
42 #include <arpa/inet.h>
43 #include <unistd.h>
44 #include <gnutls/gnutls.h>
45 #include <gnutls/dtls.h>
46
47 #include "utils.h"
48
49 static void terminate(void);
50
51 /* This program tests large packet sending in DTLS
52  */
53
54 static void server_log_func(int level, const char *str)
55 {
56         fprintf(stderr, "server|<%d>| %s", level, str);
57 }
58
59 static void client_log_func(int level, const char *str)
60 {
61         fprintf(stderr, "client|<%d>| %s", level, str);
62 }
63
64 /* These are global */
65 static pid_t child;
66
67 /* A very basic DTLS client, with anonymous authentication, that exchanges heartbeats.
68  */
69
70 #define MAX_BUF 24*1024
71 #define MAX_MTU 20*1024
72
73 static void client(int fd)
74 {
75         gnutls_session_t session;
76         int ret;
77         char buffer[MAX_BUF + 1];
78         gnutls_anon_client_credentials_t anoncred;
79         /* Need to enable anonymous KX specifically. */
80
81         global_init();
82
83         if (debug) {
84                 gnutls_global_set_log_function(client_log_func);
85                 gnutls_global_set_log_level(4711);
86         }
87
88         gnutls_anon_allocate_client_credentials(&anoncred);
89
90         /* Initialize TLS session
91          */
92         gnutls_init(&session, GNUTLS_CLIENT | GNUTLS_DATAGRAM);
93         gnutls_heartbeat_enable(session, GNUTLS_HB_PEER_ALLOWED_TO_SEND);
94         gnutls_dtls_set_mtu(session, 1500);
95
96         /* Use default priorities */
97         gnutls_priority_set_direct(session,
98                                    "NONE:+VERS-DTLS1.0:+CIPHER-ALL:+MAC-ALL:+SIGN-ALL:+COMP-ALL:+ANON-ECDH:+CURVE-ALL",
99                                    NULL);
100
101         /* put the anonymous credentials to the current session
102          */
103         gnutls_credentials_set(session, GNUTLS_CRD_ANON, anoncred);
104
105         gnutls_transport_set_int(session, fd);
106
107         /* Perform the TLS handshake
108          */
109         do {
110                 ret = gnutls_handshake(session);
111         }
112         while (ret < 0 && gnutls_error_is_fatal(ret) == 0);
113
114         if (ret < 0) {
115                 fail("client: Handshake failed\n");
116                 gnutls_perror(ret);
117                 exit(1);
118         } else {
119                 if (debug)
120                         success("client: Handshake was completed\n");
121         }
122
123         if (debug)
124                 success("client: DTLS version is: %s\n",
125                         gnutls_protocol_get_name
126                         (gnutls_protocol_get_version(session)));
127
128         do {
129                 ret = gnutls_record_recv(session, buffer, sizeof(buffer));
130         }
131         while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED || ret > 0);
132
133         if (ret < 0) {
134                 fail("recv: %s\n", gnutls_strerror(ret));
135                 terminate();
136         }
137
138         close(fd);
139
140         gnutls_deinit(session);
141
142         gnutls_anon_free_client_credentials(anoncred);
143
144         gnutls_global_deinit();
145 }
146
147 static void terminate(void)
148 {
149         int status;
150
151         kill(child, SIGTERM);
152         wait(&status);
153 }
154
155 static void server(int fd)
156 {
157         int ret;
158         char buffer[MAX_BUF + 1];
159         gnutls_session_t session;
160         gnutls_anon_server_credentials_t anoncred;
161         /* this must be called once in the program
162          */
163         global_init();
164
165         if (debug) {
166                 gnutls_global_set_log_function(server_log_func);
167                 gnutls_global_set_log_level(4711);
168         }
169
170         gnutls_anon_allocate_server_credentials(&anoncred);
171
172         gnutls_init(&session, GNUTLS_SERVER | GNUTLS_DATAGRAM);
173         gnutls_dtls_set_mtu(session, 1500);
174
175         /* avoid calling all the priority functions, since the defaults
176          * are adequate.
177          */
178         gnutls_priority_set_direct(session,
179                                    "NONE:+VERS-DTLS1.0:+CIPHER-ALL:+MAC-ALL:+SIGN-ALL:+COMP-ALL:+ANON-ECDH:+CURVE-ALL",
180                                    NULL);
181
182         gnutls_credentials_set(session, GNUTLS_CRD_ANON, anoncred);
183
184         gnutls_transport_set_int(session, fd);
185
186         do {
187                 ret = gnutls_handshake(session);
188         }
189         while (ret < 0 && gnutls_error_is_fatal(ret) == 0);
190         if (ret < 0) {
191                 close(fd);
192                 gnutls_deinit(session);
193                 terminate();
194                 fail("server: Handshake has failed (%s)\n\n",
195                      gnutls_strerror(ret));
196         }
197         if (debug)
198                 success("server: Handshake was completed\n");
199
200         if (debug)
201                 success("server: TLS version is: %s\n",
202                         gnutls_protocol_get_name
203                         (gnutls_protocol_get_version(session)));
204
205         /* see the Getting peer's information example */
206         /* print_info(session); */
207
208         /* avoid uninitialized warnings */
209         memset(buffer, 1, sizeof(buffer));
210
211         ret =
212             gnutls_record_send(session, buffer,
213                                gnutls_dtls_get_data_mtu(session) + 12);
214         if (ret != GNUTLS_E_LARGE_PACKET) {
215                 terminate();
216                 fail("send[%d]: %s\n", __LINE__, gnutls_strerror(ret));
217         }
218
219         ret =
220             gnutls_record_send(session, buffer,
221                                gnutls_dtls_get_data_mtu(session) + 5048);
222         if (ret != GNUTLS_E_LARGE_PACKET) {
223                 terminate();
224                 fail("send[%d]: %s\n", __LINE__, gnutls_strerror(ret));
225         }
226
227         ret =
228             gnutls_record_send(session, buffer,
229                                gnutls_dtls_get_data_mtu(session));
230         if (ret < 0) {
231                 terminate();
232                 fail("send[%d]: %s\n", __LINE__, gnutls_strerror(ret));
233         }
234
235         gnutls_dtls_set_mtu(session, MAX_MTU);
236         ret =
237             gnutls_record_send(session, buffer,
238                                gnutls_dtls_get_data_mtu(session) + 12);
239         if (ret != GNUTLS_E_LARGE_PACKET) {
240                 terminate();
241                 fail("send[%d]: %s\n", __LINE__, gnutls_strerror(ret));
242         }
243
244         ret =
245             gnutls_record_send(session, buffer,
246                                gnutls_dtls_get_data_mtu(session) + 5048);
247         if (ret != GNUTLS_E_LARGE_PACKET) {
248                 terminate();
249                 fail("send[%d]: %s\n", __LINE__, gnutls_strerror(ret));
250         }
251
252         ret =
253             gnutls_record_send(session, buffer,
254                                gnutls_dtls_get_data_mtu(session));
255         if (ret > 16384 || ret < 0) {
256                 terminate();
257                 fail("send[%d]: %s\n", __LINE__, gnutls_strerror(ret));
258         }
259
260         /* test cork and uncork */
261         gnutls_record_cork(session);
262
263         ret =
264             gnutls_record_send(session, buffer,
265                                gnutls_dtls_get_data_mtu(session));
266         if (ret < 0) {
267                 terminate();
268                 fail("send[%d]: %s\n", __LINE__, gnutls_strerror(ret));
269         }
270
271         ret = gnutls_record_uncork(session, 0);
272         if (ret < 0) {
273                 terminate();
274                 fail("send[%d]: %s\n", __LINE__, gnutls_strerror(ret));
275         }
276
277         gnutls_record_cork(session);
278
279         ret =
280             gnutls_record_send(session, buffer,
281                                gnutls_dtls_get_data_mtu(session) - 16);
282         if (ret < 0) {
283                 terminate();
284                 fail("send[%d]: %s\n", __LINE__, gnutls_strerror(ret));
285         }
286
287         ret =
288             gnutls_record_send(session, buffer,
289                                gnutls_dtls_get_data_mtu(session));
290         if (ret != GNUTLS_E_LARGE_PACKET) {
291                 terminate();
292                 fail("send[%d]: %s\n", __LINE__, gnutls_strerror(ret));
293         }
294
295         ret = gnutls_record_uncork(session, GNUTLS_RECORD_WAIT);
296         if (ret < 0) {
297                 terminate();
298                 fail("send[%d]: %s\n", __LINE__, gnutls_strerror(ret));
299         }
300
301         /* do not wait for the peer to close the connection.
302          */
303         gnutls_bye(session, GNUTLS_SHUT_WR);
304
305         close(fd);
306         gnutls_deinit(session);
307
308         gnutls_anon_free_server_credentials(anoncred);
309
310         gnutls_global_deinit();
311
312         if (debug)
313                 success("server: finished\n");
314 }
315
316 static void start(void)
317 {
318         int fd[2];
319         int ret;
320
321         ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fd);
322         if (ret < 0) {
323                 perror("socketpair");
324                 exit(1);
325         }
326
327         child = fork();
328         if (child < 0) {
329                 perror("fork");
330                 fail("fork");
331                 exit(1);
332         }
333
334         if (child) {
335                 int status;
336                 /* parent */
337
338                 server(fd[0]);
339                 wait(&status);
340                 if (WEXITSTATUS(status) != 0)
341                         fail("Child died with status %d\n",
342                              WEXITSTATUS(status));
343         } else {
344                 close(fd[0]);
345                 client(fd[1]);
346                 exit(0);
347         }
348 }
349
350 void doit(void)
351 {
352         start();
353 }
354
355 #endif                          /* _WIN32 */