2 * Copyright (C) 2011-2012 Free Software Foundation, Inc.
4 * This file is part of GnuTLS.
6 * GnuTLS is free software: you can redistribute it and/or modify
7 * it 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.
11 * GnuTLS is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # include <sys/socket.h>
26 # include <ws2tcpip.h>
28 #include <arpa/inet.h>
30 # include <netinet/in.h>
32 #include <sys/select.h>
42 gnutls_session_t session
;
44 struct sockaddr
* cli_addr
;
45 socklen_t cli_addr_size
;
48 static int pull_timeout_func(gnutls_transport_ptr_t ptr
, unsigned int ms
);
49 static ssize_t
push_func (gnutls_transport_ptr_t p
, const void * data
, size_t size
);
50 static ssize_t
pull_func(gnutls_transport_ptr_t p
, void * data
, size_t size
);
52 #define MAX_BUFFER 255 /* Longest string to echo */
54 void udp_server(const char* name
, int port
, int mtu
)
57 struct sockaddr_in cli_addr
;
58 socklen_t cli_addr_size
;
59 char buffer
[MAX_BUFFER
];
61 gnutls_session_t session
;
62 gnutls_datum_t cookie_key
;
63 gnutls_dtls_prestate_st prestate
;
64 unsigned char sequence
[8];
66 ret
= gnutls_key_generate(&cookie_key
, GNUTLS_COOKIE_KEY_SIZE
);
69 fprintf(stderr
, "Cannot generate key\n");
73 ret
= listen_socket (name
, port
, SOCK_DGRAM
);
76 fprintf(stderr
, "Cannot listen\n");
82 printf("Waiting for connection...\n");
83 sock
= wait_for_connection();
87 cli_addr_size
= sizeof(cli_addr
);
88 ret
= recvfrom(sock
, buffer
, sizeof(buffer
), MSG_PEEK
, (struct sockaddr
*)&cli_addr
, &cli_addr_size
);
91 memset(&prestate
, 0, sizeof(prestate
));
92 ret
= gnutls_dtls_cookie_verify(&cookie_key
, &cli_addr
, sizeof(cli_addr
), buffer
, ret
, &prestate
);
93 if (ret
< 0) /* cookie not valid */
97 memset(&s
,0,sizeof(s
));
99 s
.cli_addr
= (void*)&cli_addr
;
100 s
.cli_addr_size
= sizeof(cli_addr
);
102 printf("Sending hello verify request to %s\n", human_addr ((struct sockaddr
*)
103 &cli_addr
, sizeof(cli_addr
), buffer
, sizeof(buffer
)));
104 gnutls_dtls_cookie_send(&cookie_key
, &cli_addr
, sizeof(cli_addr
), &prestate
, (gnutls_transport_ptr_t
)&s
, push_func
);
106 /* discard peeked data*/
107 recvfrom(sock
, buffer
, sizeof(buffer
), 0, (struct sockaddr
*)&cli_addr
, &cli_addr_size
);
110 printf ("Accepted connection from %s\n",
111 human_addr ((struct sockaddr
*)
112 &cli_addr
, sizeof(cli_addr
), buffer
,
118 session
= initialize_session(1);
119 gnutls_dtls_prestate_set(session
, &prestate
);
120 if (mtu
) gnutls_dtls_set_mtu(session
, mtu
);
122 priv
.session
= session
;
124 priv
.cli_addr
= (struct sockaddr
*)&cli_addr
;
125 priv
.cli_addr_size
= sizeof(cli_addr
);
127 gnutls_transport_set_ptr (session
, &priv
);
128 gnutls_transport_set_push_function (session
, push_func
);
129 gnutls_transport_set_pull_function (session
, pull_func
);
130 gnutls_transport_set_pull_timeout_function (session
, pull_timeout_func
);
134 ret
= gnutls_handshake(session
);
136 while(ret
== GNUTLS_E_AGAIN
|| ret
== GNUTLS_E_INTERRUPTED
);
140 fprintf(stderr
, "Error in handshake(): %s\n", gnutls_strerror(ret
));
141 gnutls_deinit(session
);
149 ret
= gnutls_record_recv_seq(session
, buffer
, MAX_BUFFER
, sequence
);
150 if (ret
== GNUTLS_E_HEARTBEAT_PING_RECEIVED
)
151 gnutls_heartbeat_pong(session
, 0);
153 while (ret
== GNUTLS_E_INTERRUPTED
|| ret
== GNUTLS_E_AGAIN
|| ret
== GNUTLS_E_HEARTBEAT_PING_RECEIVED
);
155 if (ret
== GNUTLS_E_REHANDSHAKE
)
157 fprintf (stderr
, "*** Received hello message\n");
160 ret
= gnutls_handshake (session
);
162 while (ret
== GNUTLS_E_INTERRUPTED
||
163 ret
== GNUTLS_E_AGAIN
);
165 if (ret
== 0) continue;
169 fprintf(stderr
, "Error in recv(): %s\n", gnutls_strerror(ret
));
179 printf("received[%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x]: %s\n", sequence
[0], sequence
[1], sequence
[2],
180 sequence
[3], sequence
[4], sequence
[5], sequence
[6], sequence
[7], buffer
);
182 if (check_command(session
, buffer
) == 0)
185 ret
= gnutls_record_send(session
, buffer
, ret
);
188 fprintf(stderr
, "Error in send(): %s\n", gnutls_strerror(ret
));
194 gnutls_deinit(session
);
197 /* Wait for data to be received within a timeout period in milliseconds
199 static int pull_timeout_func(gnutls_transport_ptr_t ptr
, unsigned int ms
)
203 priv_data_st
*priv
= ptr
;
204 struct sockaddr_in cli_addr
;
205 socklen_t cli_addr_size
;
210 FD_SET(priv
->fd
, &rfds
);
213 tv
.tv_usec
= ms
* 1000;
215 while(tv
.tv_usec
>= 1000000)
217 tv
.tv_usec
-= 1000000;
221 ret
= select(priv
->fd
+1, &rfds
, NULL
, NULL
, &tv
);
226 /* only report ok if the next message is from the peer we expect
229 cli_addr_size
= sizeof(cli_addr
);
230 ret
= recvfrom(priv
->fd
, &c
, 1, MSG_PEEK
, (struct sockaddr
*)&cli_addr
, &cli_addr_size
);
233 if (cli_addr_size
== priv
->cli_addr_size
&& memcmp(&cli_addr
, priv
->cli_addr
, sizeof(cli_addr
))==0)
240 static ssize_t
push_func (gnutls_transport_ptr_t p
, const void * data
, size_t size
)
242 priv_data_st
*priv
= p
;
244 return sendto(priv
->fd
, data
, size
, 0, priv
->cli_addr
, priv
->cli_addr_size
);
247 static ssize_t
pull_func(gnutls_transport_ptr_t p
, void * data
, size_t size
)
249 priv_data_st
*priv
= p
;
250 struct sockaddr_in cli_addr
;
251 socklen_t cli_addr_size
;
255 cli_addr_size
= sizeof(cli_addr
);
256 ret
= recvfrom(priv
->fd
, data
, size
, 0, (struct sockaddr
*)&cli_addr
, &cli_addr_size
);
260 if (cli_addr_size
== priv
->cli_addr_size
&& memcmp(&cli_addr
, priv
->cli_addr
, sizeof(cli_addr
))==0)
263 printf ("Denied connection from %s\n",
264 human_addr ((struct sockaddr
*)
265 &cli_addr
, sizeof(cli_addr
), buffer
,
268 gnutls_transport_set_errno(priv
->session
, EAGAIN
);