Merge "Enable building C Samples using scons"
[platform/upstream/iotivity.git] / extlibs / tinydtls / tests / secure-server.c
1 /* secure-server -- A (broken) DTLS server example
2  *
3  * Copyright (C) 2011 Olaf Bergmann <bergmann@tzi.org>
4  *
5  * Permission is hereby granted, free of charge, to any person
6  * obtaining a copy of this software and associated documentation
7  * files (the "Software"), to deal in the Software without
8  * restriction, including without limitation the rights to use, copy,
9  * modify, merge, publish, distribute, sublicense, and/or sell copies
10  * of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be
14  * included in all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23  * SOFTWARE.
24  */
25
26 #include <string.h>
27 #include <stdlib.h>
28 #include <unistd.h>
29 #include <fcntl.h>
30 #include <stdio.h>
31 #include <ctype.h>
32 #include <sys/select.h>
33 #include <sys/types.h>
34 #include <sys/socket.h>
35 #include <netinet/in.h>
36 #include <arpa/inet.h>
37 #include <netdb.h>
38 #include <sys/stat.h>
39 #include <errno.h>
40 #include <signal.h>
41
42 #include <openssl/ssl.h>
43 #include <openssl/bio.h>
44 #include <openssl/err.h>
45 #include <openssl/rand.h>
46
47 #ifdef WITH_DTLS
48 #define SERVER_CERT_PEM "./server-cert.pem"
49 #define SERVER_KEY_PEM  "./server-key.pem"
50 #define CA_CERT_PEM     "./ca-cert.pem"
51 #endif
52
53 #ifdef HAVE_ASSERT_H
54 # include <assert.h>
55 #else
56 # define assert(x)
57 #endif /* HAVE_ASSERT_H */
58
59 static int quit=0;
60
61 /* SIGINT handler: set quit to 1 for graceful termination */
62 void
63 handle_sigint(int signum) {
64   quit = 1;
65 }
66
67 int 
68 check_connect(int sockfd, char *buf, int buflen, 
69            struct sockaddr *src, int *ifindex) {
70
71   /* for some reason, the definition in netinet/in.h is not exported */
72 #ifndef IN6_PKTINFO
73   struct in6_pktinfo
74   {
75     struct in6_addr ipi6_addr;  /* src/dst IPv6 address */
76     unsigned int ipi6_ifindex;  /* send/recv interface index */
77   };
78 #endif
79
80   size_t bytes;
81
82   struct iovec iov[1] = { {buf, buflen} };
83   char cmsgbuf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
84   struct in6_pktinfo *p = NULL;
85   
86   struct msghdr msg = { 0 };
87   struct cmsghdr *cmsg;
88
89   msg.msg_name = src;
90   msg.msg_namelen = sizeof(struct sockaddr_in6);
91   msg.msg_iov = iov;
92   msg.msg_iovlen = 1;
93   msg.msg_control = cmsgbuf;
94   msg.msg_controllen = sizeof(cmsgbuf);
95
96   bytes = recvmsg(sockfd, &msg, MSG_DONTWAIT | MSG_PEEK);
97   if (bytes < 0) {
98     perror("recvmsg");
99     return bytes;
100   }
101
102   /* TODO: handle msg.msg_flags & MSG_TRUNC */
103   if (msg.msg_flags & MSG_CTRUNC) {
104     fprintf(stderr, "control was truncated!\n");
105     return -1;
106   }
107
108   if (ifindex) {
109     /* Here we try to retrieve the interface index where the packet was received */
110     *ifindex = 0;
111     for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
112          cmsg = CMSG_NXTHDR(&msg, cmsg)) {
113
114       if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) {
115         p = (struct in6_pktinfo *)(CMSG_DATA(cmsg));
116         *ifindex = p->ipi6_ifindex;
117         break;
118       }
119     }
120   }
121
122   return bytes;
123 }
124
125 typedef enum { UNKNOWN=0, DTLS=1 } protocol_t;
126
127 protocol_t
128 demux_protocol(const char *buf, int len) {
129   return DTLS;
130 }
131
132 #ifdef WITH_DTLS
133 typedef enum { 
134   PEER_ST_ESTABLISHED, PEER_ST_PENDING, PEER_ST_CLOSED 
135  } peer_state_t;
136 typedef struct {
137   peer_state_t state;
138   unsigned long h;
139   SSL *ssl;
140 } ssl_peer_t;
141
142 #define MAX_SSL_PENDING      2  /* must be less than MAX_SSL_PEERS */
143 #define MAX_SSL_PEERS       10  /* MAX_SSL_PENDING of these might be pending  */
144 ssl_peer_t *ssl_peer_storage[MAX_SSL_PEERS];
145 static int pending = 0;
146
147 void
148 check_peers() {
149 typedef struct bio_dgram_data_st
150         {
151         union {
152                 struct sockaddr sa;
153                 struct sockaddr_in sa_in;
154                 struct sockaddr_in6 sa_in6;
155         } peer;
156         unsigned int connected;
157         unsigned int _errno;
158         unsigned int mtu;
159         struct timeval next_timeout;
160         struct timeval socket_timeout;
161         } bio_dgram_data;
162
163   struct sockaddr_in6 peer;
164   int i;
165   BIO *bio;
166   for (i = 0; i < MAX_SSL_PEERS; i++) {
167     if (ssl_peer_storage[i]) {
168       if (!ssl_peer_storage[i]->ssl)
169         fprintf(stderr, "invalid SSL object for peer %d!\n",i);
170       else {
171         bio = SSL_get_rbio(ssl_peer_storage[i]->ssl);
172         if (bio) {
173           (void) BIO_dgram_get_peer(bio, (struct sockaddr *)&peer);
174           if (peer.sin6_port && ssl_peer_storage[i]->h != ntohs(peer.sin6_port)) {
175             fprintf(stderr, "   bio %p: port differs from hash: %d != %d! (%sconnected)\n", bio,
176                     ssl_peer_storage[i]->h, 
177                     ntohs(((struct sockaddr_in6 *)&peer)->sin6_port),
178                     ((bio_dgram_data *)bio->ptr)->connected ? "" : "not ");
179           }
180
181         }
182       }
183     }
184   }
185 }
186
187 /** Creates a hash value from the first num bytes of s, taking init as
188  * initialization value. */
189 static inline unsigned long
190 _hash(unsigned long init, const char *s, int num) {
191   int c;
192
193   while (num--)
194     while ( (c = *s++) ) {
195       init = ((init << 7) + init) + c;
196     }
197
198   return init;
199 }
200
201 static inline unsigned long
202 hash_peer(const struct sockaddr *peer, int ifindex) {
203   unsigned long h;
204
205   /* initialize hash value to interface index */
206   h = _hash(0, (char *)&ifindex, sizeof(int));
207
208 #define CAST(TYPE,VAR) ((TYPE)VAR)
209
210   assert(peer);
211   switch (peer->sa_family) {
212   case AF_INET: 
213     return ntohs(CAST(const struct sockaddr_in *, peer)->sin_port);
214     h = _hash(h, (char *) &CAST(const struct sockaddr_in *, peer)->sin_addr, 
215               sizeof(struct in_addr));
216     h = _hash(h, (char *) &CAST(const struct sockaddr_in *, peer)->sin_port, 
217               sizeof(in_port_t));
218     break;
219   case AF_INET6:
220     return ntohs(CAST(const struct sockaddr_in6 *, peer)->sin6_port);
221     h = _hash(h, 
222               (char *) &CAST(const struct sockaddr_in6 *, peer)->sin6_addr, 
223               sizeof(struct in6_addr));
224     h = _hash(h, 
225               (char *) &CAST(const struct sockaddr_in6 *, peer)->sin6_port, 
226               sizeof(in_port_t));
227     break;
228   default:
229     /* last resort */
230     h = _hash(h, (char *)peer, sizeof(struct sockaddr));
231   }
232
233   return 42;
234   return h;
235 }
236
237 /* Returns index of peer object for specified address/ifindex pair. */
238 int
239 get_index_of_peer(const struct sockaddr *peer, int ifindex) {
240   unsigned long h;
241   int idx;
242 #ifndef NDEBUG
243   char addr[INET6_ADDRSTRLEN];
244   char port[6];
245 #endif
246
247   if (!peer)
248     return -1;
249
250   h = hash_peer(peer,ifindex);
251
252   for (idx = 0; idx < MAX_SSL_PEERS; idx++) {
253     if (ssl_peer_storage[idx] && ssl_peer_storage[idx]->h == h) {
254 #ifndef NDEBUG
255       getnameinfo((struct sockaddr *)peer, sizeof(struct sockaddr_in6), 
256                   addr, sizeof(addr), port, sizeof(port), 
257                   NI_NUMERICHOST | NI_NUMERICSERV);
258
259       fprintf(stderr, "get_index_of_peer: [%s]:%s  =>  %lu\n",
260               addr, port, h);
261 #endif
262       return idx;
263     }
264   }
265   return -1;
266 }
267
268 SSL *
269 get_ssl(SSL_CTX *ctx, int sockfd, struct sockaddr *src, int ifindex) {
270   int idx;
271   BIO *bio;
272   SSL *ssl;
273 #ifndef NDEBUG
274   struct sockaddr_storage peer;
275   char addr[INET6_ADDRSTRLEN];
276   char port[6];
277   int i;
278 #endif
279
280   idx = get_index_of_peer(src,ifindex);
281   if (idx >= 0) {
282     fprintf(stderr,"found peer %d ",idx);
283     switch (ssl_peer_storage[idx]->state) {
284     case PEER_ST_ESTABLISHED: fprintf(stderr,"established\n"); break;
285     case PEER_ST_PENDING:     fprintf(stderr,"pending\n"); break;
286     case PEER_ST_CLOSED:      fprintf(stderr,"closed\n"); break;
287     default:
288       OPENSSL_assert(0);
289     }
290
291 #ifndef NDEBUG
292     memset(&peer, 0, sizeof(peer));
293     (void) BIO_dgram_get_peer(SSL_get_rbio(ssl_peer_storage[idx]->ssl), &peer);
294
295     getnameinfo((struct sockaddr *)&peer, sizeof(peer), 
296                 addr, sizeof(addr), port, sizeof(port), 
297                 NI_NUMERICHOST | NI_NUMERICSERV);
298
299     fprintf(stderr,"      [%s]:%s   \n", addr, port);
300 #endif
301     return ssl_peer_storage[idx]->ssl;
302   }
303
304   /* none found, create new if sufficient space available */
305   if (pending < MAX_SSL_PENDING) {
306     for (idx = 0; idx < MAX_SSL_PEERS; idx++) {
307       if (ssl_peer_storage[idx] == NULL) { /* found space */
308         ssl = SSL_new(ctx);
309         
310         if (ssl) {
311           bio = BIO_new_dgram(sockfd, BIO_NOCLOSE);
312           if (!bio) {
313             SSL_free(ssl);
314             return NULL;
315           }
316           
317           SSL_set_bio(ssl, bio, bio);
318           SSL_set_options(ssl, SSL_OP_COOKIE_EXCHANGE);
319           
320           SSL_set_accept_state(ssl);
321           ssl_peer_storage[idx] = (ssl_peer_t *) malloc(sizeof(ssl_peer_t));
322           if (!ssl_peer_storage[idx]) {
323             SSL_free(ssl);
324             return NULL;
325           }
326           ssl_peer_storage[idx]->state = PEER_ST_PENDING;
327           ssl_peer_storage[idx]->h = hash_peer(src,ifindex);
328           ssl_peer_storage[idx]->ssl = ssl;
329           
330           pending++;
331           
332           fprintf(stderr,
333                   "created new SSL peer %d for ssl object %p (storage: %p)\n", 
334                  idx, ssl, ssl_peer_storage[idx]);
335 #ifndef NDEBUG
336     if (getnameinfo((struct sockaddr *)&src, sizeof(src), 
337                 addr, sizeof(addr), port, sizeof(port), 
338                     NI_NUMERICHOST | NI_NUMERICSERV) != 0) {
339       perror("getnameinfo");
340       fprintf(stderr, "port was %u\n", ntohs(((struct sockaddr_in6 *)src)->sin6_port));
341     } else {
342     fprintf(stderr,"      [%s]:%s   \n", addr, port);
343       }
344 #endif
345     OPENSSL_assert(ssl_peer_storage[idx]->ssl == ssl);
346           fprintf(stderr,"%d objects pending\n", pending);
347           check_peers();
348           return ssl;
349         }
350       }
351     }
352   } else {
353     fprintf(stderr, "too many pending SSL objects\n");
354     return NULL;
355   }
356
357   fprintf(stderr, "too many peers\n");
358   return NULL;
359 }
360
361 /** Deletes peer stored at index idx and frees allocated memory. */
362 static inline void
363 delete_peer(int idx) {
364   if (idx < 0 || !ssl_peer_storage[idx])
365     return;
366
367   if (ssl_peer_storage[idx]->state == PEER_ST_PENDING)
368     pending--;
369
370   OPENSSL_assert(ssl_peer_storage[idx]->ssl);
371   SSL_free(ssl_peer_storage[idx]->ssl);
372     
373   free(ssl_peer_storage[idx]);
374   ssl_peer_storage[idx] = NULL;
375
376   printf("deleted peer %d\n",idx);
377 }
378
379 /** Deletes all closed objects from ssl_peer_storage. */
380 void
381 remove_closed() {
382   int idx;
383
384   for (idx = 0; idx < MAX_SSL_PEERS; idx++)
385     if (ssl_peer_storage[idx] 
386         && ssl_peer_storage[idx]->state == PEER_ST_CLOSED)
387       delete_peer(idx);
388 }
389
390 #define min(a,b) ((a) < (b) ? (a) : (b))
391
392 unsigned int
393 psk_server_callback(SSL *ssl, const char *identity,
394                     unsigned char *psk, unsigned int max_psk_len) {
395   static char keybuf[] = "secretPSK";
396
397   printf("psk_server_callback: check identity of client %s\n", identity);
398   memcpy(psk, keybuf, min(strlen(keybuf), max_psk_len));
399
400   return min(strlen(keybuf), max_psk_len);
401 }
402
403 #endif
404
405 #ifdef WITH_DTLS
406 /**
407  * This function tracks the status changes from libssl to manage local
408  * object state.
409  */
410 void
411 info_callback(const SSL *ssl, int where, int ret) {
412   int idx, i;
413   struct sockaddr_storage peer;
414   struct sockaddr_storage peer2;
415   char addr[INET6_ADDRSTRLEN];
416   char port[6];
417
418   if (where & SSL_CB_LOOP)  /* do not care for intermediary states */
419     return;
420
421   memset(&peer, 0, sizeof(peer));
422   (void) BIO_dgram_get_peer(SSL_get_rbio(ssl), &peer);
423
424   /* lookup SSL object */   /* FIXME: need to get the ifindex */
425   idx = get_index_of_peer((struct sockaddr *)&peer, 0);
426   
427   if (idx >= 0)
428     fprintf(stderr, "info_callback: assert: %d < 0 || %p == %p (storage: %p)\n",
429             idx, ssl, ssl_peer_storage[idx]->ssl, ssl_peer_storage[idx]); 
430   if (idx >= 0 && ssl != ssl_peer_storage[idx]->ssl) {
431     getnameinfo((struct sockaddr *)&peer, sizeof(peer), 
432                 addr, sizeof(addr), port, sizeof(port), 
433                 NI_NUMERICHOST | NI_NUMERICSERV);
434
435     fprintf(stderr," ssl: [%s]:%s   ", addr, port);
436     
437     (void) BIO_dgram_get_peer(SSL_get_rbio(ssl_peer_storage[idx]->ssl), &peer2);
438     getnameinfo((struct sockaddr *)&peer2, sizeof(peer2), 
439                 addr, sizeof(addr), port, sizeof(port), 
440                 NI_NUMERICHOST | NI_NUMERICSERV);
441
442     fprintf(stderr," ssl_peer_storage[idx]->ssl: [%s]:%s\n", addr, port);
443
444     fprintf(stderr, " hash:%lu     h: %lu\n",
445             hash_peer((const struct sockaddr *)&peer, 0),
446             ssl_peer_storage[idx]->h);
447
448     for (i = 0; i < MAX_SSL_PEERS; i++) {
449       if (ssl_peer_storage[i]) {
450         fprintf(stderr, "%02d: %p ssl: %p  ",
451                 i, ssl_peer_storage[i] ,ssl_peer_storage[i]->ssl);
452
453         (void) BIO_dgram_get_peer(SSL_get_rbio(ssl_peer_storage[i]->ssl), &peer2);
454         getnameinfo((struct sockaddr *)&peer2, sizeof(peer2), 
455                     addr, sizeof(addr), port, sizeof(port), 
456                     NI_NUMERICHOST | NI_NUMERICSERV);
457         
458         fprintf(stderr," peer: [%s]:%s    h: %lu\n", addr, port, ssl_peer_storage[i]->h);
459       }
460     }
461     fprintf(stderr, "***** ASSERT FAILED ******\n");
462
463     memset(&peer, 0, sizeof(peer));
464     (void) BIO_dgram_get_peer(SSL_get_wbio(ssl), &peer);
465
466     idx = get_index_of_peer((struct sockaddr *)&peer, 0);
467     fprintf(stderr, "  get_index_of_peer for wbio returns %d, type is %04x\n",
468             idx, where);    
469   }
470 #if 1
471           check_peers();
472   OPENSSL_assert((idx < 0) || (ssl == ssl_peer_storage[idx]->ssl));
473 #endif
474
475   if (where & SSL_CB_ALERT) {
476 #ifndef NDEBUG
477     if (ret != 0)
478       fprintf(stderr,"%s:%s:%s\n", SSL_alert_type_string(ret),
479               SSL_alert_desc_string(ret), SSL_alert_desc_string_long(ret));
480 #endif
481
482     /* examine alert type */
483     switch (*SSL_alert_type_string(ret)) {
484     case 'F':
485       /* move SSL object from pending to close */
486       if (idx >= 0) {
487         ssl_peer_storage[idx]->state = PEER_ST_CLOSED;
488         pending--;
489       }
490       break;
491     case 'W': 
492       if ((ret & 0xff) == SSL_AD_CLOSE_NOTIFY) {
493         if (where == SSL_CB_WRITE_ALERT) 
494           fprintf(stderr,"sent CLOSE_NOTIFY\n");
495         else /* received CN */
496           fprintf(stderr,"received CLOSE_NOTIFY\n");
497       }
498       break;
499     default:                    /* handle unknown alert types */
500 #ifndef NDEBUG
501       printf("not handled!\n");
502 #endif
503     }
504   }
505
506   if (where & SSL_CB_HANDSHAKE_DONE) {
507     /* move SSL object from pending to established */
508     printf("HANDSHAKE_DONE ");
509     if (idx >= 0) {
510       
511       if (ssl_peer_storage[idx]->state == PEER_ST_PENDING) {
512         ssl_peer_storage[idx]->state = PEER_ST_ESTABLISHED;
513         pending--;
514         printf("moved SSL object %d to ESTABLISHED\n", idx);
515         printf("%d objects pending\n", pending);
516       } else {
517 #ifndef NDEBUG
518         printf("huh, object %d was not pending? (%d)\n", idx,
519                ssl_peer_storage[idx]->state);
520 #endif
521       }
522       return;
523     }
524     return;
525   }
526
527   return;
528 }
529 #endif
530
531 #ifdef WITH_DTLS
532 /* checks if ssl object was closed and can be removed */
533 int 
534 check_close(SSL *ssl) {
535   int res, err, idx;
536   struct sockaddr_storage peer;
537   
538   memset(&peer, 0, sizeof(peer));
539   (void)BIO_dgram_get_peer(SSL_get_rbio(ssl), &peer);
540
541   res = 0;
542   if (SSL_get_shutdown(ssl) & SSL_RECEIVED_SHUTDOWN) {
543     printf("SSL_RECEIVED_SHUTDOWN\n");
544     res = SSL_shutdown(ssl);
545     if (res == 0) {
546       printf("must call SSL_shutdown again\n");
547       res = SSL_shutdown(ssl);
548     }
549     if (res < 0) {
550         err = SSL_get_error(ssl,res);   
551         fprintf(stderr, "shutdown: SSL error %d: %s\n", err,
552                 ERR_error_string(err, NULL));
553     } 
554
555     /* we can close the SSL object anyway */
556     /* FIXME: need to get ifindex from somewhere */
557     idx = get_index_of_peer((struct sockaddr *)&peer, 0);
558     OPENSSL_assert(idx < 0 || ssl == ssl_peer_storage[idx]->ssl);
559     if (idx >= 0) {
560       ssl_peer_storage[idx]->state = PEER_ST_CLOSED;
561       printf("moved SSL object %d to CLOSED\n",idx);
562     }
563   }
564   
565   return res;
566 }
567
568 int 
569 check_timeout() {
570   int i, result, err;
571
572   for (i = 0; i < MAX_SSL_PEERS; i++) {
573     if (ssl_peer_storage[i]) {
574       OPENSSL_assert(ssl_peer_storage[i]->ssl);
575       result = DTLSv1_handle_timeout(ssl_peer_storage[i]->ssl);
576       if (result < 0) {
577         err = SSL_get_error(ssl_peer_storage[i]->ssl,result);
578         fprintf(stderr, "dtls1_handle_timeout (%d): %s\n",
579                 err, ERR_error_string(err, NULL));
580       }
581     }
582   }
583
584   /* remove outdated obbjects? */
585   
586   return 0;
587 }
588 #endif /* WITH_DTLS */
589   
590 int 
591 _read(SSL_CTX *ctx, int sockfd) {
592   char buf[2000];
593   struct sockaddr_in6 src;
594   int len, ifindex, i;
595   char addr[INET6_ADDRSTRLEN];
596   char port[6];
597   socklen_t sz = sizeof(struct sockaddr_in6);
598 #ifdef WITH_DTLS
599   SSL *ssl;
600   int err;
601 #endif
602
603   /* Retrieve remote address and interface index as well as the first
604      few bytes of the message to demultiplex protocols. */
605   memset(&src, 0, sizeof(struct sockaddr_in6));
606   len = check_connect(sockfd, buf, 4, (struct sockaddr *)&src, &ifindex);
607
608   if (len < 0)                  /* error */
609     return len;
610
611 #ifndef NDEBUG
612   fprintf(stderr,"received packet");
613   
614   if (getnameinfo((struct sockaddr *)&src, sizeof(src), 
615                   addr, sizeof(addr), port, sizeof(port), 
616                   NI_NUMERICHOST | NI_NUMERICSERV) == 0)
617     fprintf(stderr," from [%s]:%s", addr, port);
618   
619   fprintf(stderr," on interface %d\n", ifindex);
620 #endif
621
622   switch (demux_protocol(buf, len)) {
623 #ifdef WITH_DTLS
624   case DTLS :
625     ssl = get_ssl(ctx, sockfd, (struct sockaddr *)&src, ifindex);
626     if (!ssl) {
627       fprintf(stderr, "cannot create new SSL object\n");
628       /*      return recv(sockfd, buf, sizeof(buf), MSG_DONTWAIT);*/
629       len = recvfrom(sockfd, buf, sizeof(buf), MSG_DONTWAIT,
630                      (struct sockaddr *)&src, &sz);
631       getnameinfo((struct sockaddr *)&src, sz, 
632                   addr, sizeof(addr), port, sizeof(port), 
633                   NI_NUMERICHOST | NI_NUMERICSERV);
634       printf("discarded %d bytes from [%s]:%s\n", len, addr, port);      
635       return len;
636     }
637     len = SSL_read(ssl, buf, sizeof(buf));
638     break;
639 #endif
640   case UNKNOWN:
641   default :
642     len = recv(sockfd, buf, sizeof(buf), MSG_DONTWAIT);
643   }
644
645   if (len > 0) {
646     printf("here is the data:\n");
647     for (i=0; i<len; i++)
648       printf("%c",buf[i]);
649   } if (len == 0) {             /* session closed? */
650 #ifdef WITH_DTLS
651     if (check_close(ssl) <= 0) {
652       fprintf(stderr, "not closed\n");
653     }
654 #endif
655   } else {
656 #ifdef WITH_DTLS
657     err = SSL_get_error(ssl,len);
658     switch (err) {
659     case SSL_ERROR_WANT_READ:
660       fprintf(stderr, "SSL_ERROR_WANT_READ\n");
661       return 0;
662     case SSL_ERROR_WANT_WRITE:
663       fprintf(stderr, "SSL_ERROR_WANT_WRITE\n");
664       return 0;
665     default:
666       fprintf(stderr, "read: SSL error %d: %s\n", err,
667               ERR_error_string(err, NULL));
668       return 0;
669     }
670 #else
671     perror("recv");
672 #endif
673   }
674
675   return len;
676 }
677
678 int 
679 _write(SSL_CTX *ctx, int sockfd) {
680   int res = 0;
681 #ifdef WITH_DTLS
682   SSL *ssl;
683   int err;
684
685   ssl = get_ssl(ctx, sockfd, NULL, 1);
686   if (!ssl) {
687     fprintf(stderr, "no SSL object for writing");
688     return 0;
689   }
690   res = SSL_write(ssl, NULL, 0);
691   if (res < 0) {
692     /*
693     if (SSL_want_write(ssl))
694       return 0;
695     */
696     /* FIXME: check SSL_want_read(ssl) */
697
698     err = SSL_get_error(ssl,res);
699     fprintf(stderr,"SSL_write returned %d (%s)\n", err, ERR_error_string(err, NULL));
700   } else {
701     printf("SSL_write successful\n");
702   }
703 #else
704 #endif
705   
706   return res;
707 }
708
709
710 int 
711 generate_cookie(SSL *ssl, unsigned char *cookie, unsigned int *cookie_len) {
712   /* FIXME: generate secure client-specific cookie */
713 #define DUMMYSTR "ABCDEFGHIJKLMNOP"
714   *cookie_len = strlen(DUMMYSTR);
715   memcpy(cookie, DUMMYSTR, *cookie_len);
716
717   return 1;
718 }
719
720 int 
721 verify_cookie(SSL *ssl, unsigned char *cookie, unsigned int cookie_len) {
722   /* FIXME */
723   return 1;
724 }
725
726 enum { READ, WRITE };
727
728 int
729 main(int argc, char **argv) {
730   int sockfd = 0;
731   int on = 1;
732   struct sockaddr_in6 listen_addr = { AF_INET6, htons(20220), 0, IN6ADDR_ANY_INIT, 0 };
733   size_t addr_size = sizeof(struct sockaddr_in6);
734   fd_set fds[2];
735   int result, flags;
736   int idx, res = 0;
737   struct timeval timeout;
738   struct sigaction act, oact;
739   
740 #ifdef WITH_DTLS
741   SSL_CTX *ctx;
742
743   memset(ssl_peer_storage, 0, sizeof(ssl_peer_storage));
744
745   SSL_load_error_strings();
746   SSL_library_init();
747   ctx = SSL_CTX_new(DTLSv1_server_method());
748
749   SSL_CTX_set_cipher_list(ctx, "ALL");
750   SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
751
752   res = SSL_CTX_use_certificate_file(ctx, SERVER_CERT_PEM, SSL_FILETYPE_PEM);
753   if (res != 1) {
754     fprintf(stderr, "cannot read server certificate from file '%s' (%s)\n", 
755             SERVER_CERT_PEM, ERR_error_string(res,NULL));
756     goto end;
757   }
758
759   res = SSL_CTX_use_PrivateKey_file(ctx, SERVER_KEY_PEM, SSL_FILETYPE_PEM);
760   if (res != 1) {
761     fprintf(stderr, "cannot read server key from file '%s' (%s)\n", 
762             SERVER_KEY_PEM, ERR_error_string(res,NULL));
763     goto end;
764   }
765
766   res = SSL_CTX_check_private_key (ctx);
767   if (res != 1) {
768     fprintf(stderr, "invalid private key\n");
769     goto end;
770   }
771
772   res = SSL_CTX_load_verify_locations(ctx, CA_CERT_PEM, NULL);
773   if (res != 1) {
774     fprintf(stderr, "cannot read ca file '%s'\n", CA_CERT_PEM);
775     goto end;
776   }
777
778   /* Client has to authenticate */
779
780   /* Client has to authenticate */
781   SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, NULL);
782
783   SSL_CTX_set_read_ahead(ctx, 1); /* disable read-ahead */
784   SSL_CTX_set_cookie_generate_cb(ctx, generate_cookie);
785   SSL_CTX_set_cookie_verify_cb(ctx, verify_cookie);
786
787   SSL_CTX_use_psk_identity_hint(ctx, "Enter password for CoAP-Gateway");
788   SSL_CTX_set_psk_server_callback(ctx, psk_server_callback);
789
790   SSL_CTX_set_info_callback(ctx, info_callback);
791 #endif
792
793   sockfd = socket(listen_addr.sin6_family, SOCK_DGRAM, 0);
794   if ( sockfd < 0 ) {
795     perror("socket");
796     return -1;
797   }
798
799   if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) ) < 0)
800     perror("setsockopt SO_REUSEADDR");
801
802   flags = fcntl(sockfd, F_GETFL, 0);
803   if (flags < 0 || fcntl(sockfd, F_SETFL, flags | O_NONBLOCK) < 0) {
804     perror("fcntl");
805     return -1;
806   }
807
808   on = 1;
809   if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on) ) < 0) {
810     perror("setsockopt IPV6_PKTINFO");
811   }
812
813   if (bind (sockfd, (const struct sockaddr *)&listen_addr, addr_size) < 0) {
814     perror("bind");
815     res = -2;
816     goto end;
817   }
818
819   act.sa_handler = handle_sigint;
820   sigemptyset(&act.sa_mask);
821   act.sa_flags = 0;
822   sigaction(SIGINT, &act, &oact);
823
824   while (!quit) {
825     FD_ZERO(&fds[READ]);
826     FD_ZERO(&fds[WRITE]);
827     FD_SET(sockfd, &fds[READ]);
828
829     timeout.tv_sec = 1;
830     timeout.tv_usec = 0;
831     result = select( FD_SETSIZE, &fds[READ], &fds[WRITE], 0, &timeout);
832
833     if (result < 0) {           /* error */
834       if (errno != EINTR)
835         perror("select");
836     } else if (result > 0) {    /* read from socket */
837       if ( FD_ISSET( sockfd, &fds[READ]) ) {
838         _read(ctx, sockfd);     /* read received data */
839       } else if ( FD_ISSET( sockfd, &fds[WRITE]) ) { /* write to socket */
840         _write(ctx, sockfd);            /* write data */
841       }
842     } else {                    /* timeout */
843       check_timeout();
844     }
845     remove_closed();
846   }
847   
848  end:
849 #ifdef WITH_DTLS
850   for (idx = 0; idx < MAX_SSL_PEERS; idx++) {
851     if (ssl_peer_storage[idx] && ssl_peer_storage[idx]->ssl) {
852       if (ssl_peer_storage[idx]->state == PEER_ST_ESTABLISHED)
853         SSL_shutdown(ssl_peer_storage[idx]->ssl);
854       SSL_free(ssl_peer_storage[idx]->ssl);
855     }
856   }
857
858   SSL_CTX_free(ctx);
859 #endif
860   close(sockfd);                /* don't care if we close stdin at this point */
861   return res;
862 }