_gnutls_strdatum_to_buf() will account for NULL input.
[gnutls.git] / src / udp-serv.c
blob08d2677a881737aa94a4097013334af9a956a58d
1 /*
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/>.
20 #include <config.h>
22 #include <stdio.h>
23 #if HAVE_SYS_SOCKET_H
24 # include <sys/socket.h>
25 #elif HAVE_WS2TCPIP_H
26 # include <ws2tcpip.h>
27 #endif
28 #include <arpa/inet.h>
29 #ifndef _WIN32
30 # include <netinet/in.h>
31 #endif
32 #include <sys/select.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <unistd.h>
36 #include <errno.h>
37 #include <common.h>
38 #include "udp-serv.h"
39 #include "list.h"
41 typedef struct {
42 gnutls_session_t session;
43 int fd;
44 struct sockaddr * cli_addr;
45 socklen_t cli_addr_size;
46 } priv_data_st;
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)
56 int sock, ret;
57 struct sockaddr_in cli_addr;
58 socklen_t cli_addr_size;
59 char buffer[MAX_BUFFER];
60 priv_data_st priv;
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);
67 if (ret < 0)
69 fprintf(stderr, "Cannot generate key\n");
70 exit(1);
73 ret = listen_socket (name, port, SOCK_DGRAM);
74 if (ret < 0)
76 fprintf(stderr, "Cannot listen\n");
77 exit (1);
80 for (;;)
82 printf("Waiting for connection...\n");
83 sock = wait_for_connection();
84 if (sock < 0)
85 continue;
87 cli_addr_size = sizeof(cli_addr);
88 ret = recvfrom(sock, buffer, sizeof(buffer), MSG_PEEK, (struct sockaddr*)&cli_addr, &cli_addr_size);
89 if (ret > 0)
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 */
95 priv_data_st s;
97 memset(&s,0,sizeof(s));
98 s.fd = sock;
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);
108 continue;
110 printf ("Accepted connection from %s\n",
111 human_addr ((struct sockaddr *)
112 &cli_addr, sizeof(cli_addr), buffer,
113 sizeof (buffer)));
115 else
116 continue;
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;
123 priv.fd = sock;
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);
138 if (ret < 0)
140 fprintf(stderr, "Error in handshake(): %s\n", gnutls_strerror(ret));
141 gnutls_deinit(session);
142 continue;
145 for(;;)
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;
167 if (ret < 0)
169 fprintf(stderr, "Error in recv(): %s\n", gnutls_strerror(ret));
170 break;
172 if (ret == 0)
174 printf("EOF\n\n");
175 break;
178 buffer[ret] = 0;
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)
184 /* reply back */
185 ret = gnutls_record_send(session, buffer, ret);
186 if (ret < 0)
188 fprintf(stderr, "Error in send(): %s\n", gnutls_strerror(ret));
189 break;
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)
201 fd_set rfds;
202 struct timeval tv;
203 priv_data_st *priv = ptr;
204 struct sockaddr_in cli_addr;
205 socklen_t cli_addr_size;
206 int ret;
207 char c;
209 FD_ZERO(&rfds);
210 FD_SET(priv->fd, &rfds);
212 tv.tv_sec = 0;
213 tv.tv_usec = ms * 1000;
215 while(tv.tv_usec >= 1000000)
217 tv.tv_usec -= 1000000;
218 tv.tv_sec++;
221 ret = select(priv->fd+1, &rfds, NULL, NULL, &tv);
223 if (ret <= 0)
224 return ret;
226 /* only report ok if the next message is from the peer we expect
227 * from
229 cli_addr_size = sizeof(cli_addr);
230 ret = recvfrom(priv->fd, &c, 1, MSG_PEEK, (struct sockaddr*)&cli_addr, &cli_addr_size);
231 if (ret > 0)
233 if (cli_addr_size == priv->cli_addr_size && memcmp(&cli_addr, priv->cli_addr, sizeof(cli_addr))==0)
234 return 1;
237 return 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;
252 char buffer[64];
253 int ret;
255 cli_addr_size = sizeof(cli_addr);
256 ret = recvfrom(priv->fd, data, size, 0, (struct sockaddr*)&cli_addr, &cli_addr_size);
257 if (ret == -1)
258 return ret;
260 if (cli_addr_size == priv->cli_addr_size && memcmp(&cli_addr, priv->cli_addr, sizeof(cli_addr))==0)
261 return ret;
263 printf ("Denied connection from %s\n",
264 human_addr ((struct sockaddr *)
265 &cli_addr, sizeof(cli_addr), buffer,
266 sizeof (buffer)));
268 gnutls_transport_set_errno(priv->session, EAGAIN);
269 return -1;