Test of tinydtls over cellular

Dependencies:   VodafoneUSBModem mbed-rtos mbed tinydtls

Revision:
1:1dd9b8218515
Parent:
0:6ae42a2aff75
Child:
2:fe574f2c2b6a
--- a/main.cpp	Wed Oct 09 14:48:52 2013 +0000
+++ b/main.cpp	Fri Oct 11 14:01:57 2013 +0000
@@ -1,16 +1,300 @@
+#define __DEBUG__ 4
+
+#ifndef __MODULE__
+#define __MODULE__ "main.cpp"
+#endif
+
 #include "mbed.h"
 #include "rtos.h"
+#include "bsd_socket.h"
+
+#include <dtls.h>
+#include "global.h"
+#include "debug.h"
+#include "errno.h"
+
 #include "VodafoneUSBModem.h"
-#include "bsd_socket.h"
-#include "dtls.h"
-
 DigitalOut myled(LED1);
 
+void fail(int code) {
+   while(1) {
+      myled = !myled;
+      Thread::wait(100);
+   }
+}
+
+/* This function is the "key store" for tinyDTLS. It is called to
+ * retrieve a key for the given identiy within this particular
+ * session. */
+int get_key(struct dtls_context_t *ctx, 
+    const session_t *session, 
+    const unsigned char *id, size_t id_len, 
+    const dtls_key_t **result) {
+    DBG("get_key called");
+
+  static const dtls_key_t psk = {
+    .type = DTLS_KEY_PSK,
+    .key.psk.id = (unsigned char *)"Client_identity", 
+    .key.psk.id_length = 15,
+    .key.psk.key = (unsigned char *)"secretPSK", 
+    .key.psk.key_length = 9
+  };
+   
+  *result = &psk;
+  return 0;
+}
+
+//#define APN_GDSP
+#define APN_CONTRACT
+
+#ifdef APN_GDSP
+   #define APN "ppinternetd.gdsp" 
+   #define APN_USERNAME ""
+   #define APN_PASSWORD ""
+#endif
+
+#ifdef APN_CONTRACT
+   #define APN "internet" 
+   #define APN_USERNAME "web"
+   #define APN_PASSWORD "web"
+#endif
+
+// globals
+int gDTLSConnected = 0;
+sockaddr_in bindAddr,serverAddress;
+
+// this is used to setup sockaddr_in structures for a remote host
+// it also listens for incoming UDP packets on the local interface on port
+bool connectToSocketUDP(char *ipAddress, int port, int *sockfd) {
+  *sockfd = -1;
+  // create the socket
+  if((*sockfd=socket(AF_INET,SOCK_DGRAM,0))<0) {
+     DBG("Error opening socket");
+     return false;
+  }
+  socklen_t sockAddrInLen = sizeof(struct sockaddr_in);
+   
+  // bind socket to 11111
+  memset(&bindAddr,  0x00, sockAddrInLen);
+  bindAddr.sin_family = AF_INET; // IP family
+  bindAddr.sin_port = htons(port);
+  bindAddr.sin_addr.s_addr = IPADDR_ANY; // 32 bit IP representation
+  // call bind
+  if(bind(*sockfd,(const struct sockaddr *)&bindAddr,sockAddrInLen)!=0) {
+     DBG("Error binding socket");
+     perror(NULL);
+  }
+
+  INFO("UDP socket created and bound to: %s:%d",inet_ntoa(bindAddr.sin_addr),ntohs(bindAddr.sin_port));
+         
+  // create the socket address
+  memset(&serverAddress, 0x00, sizeof(struct sockaddr_in));
+  serverAddress.sin_addr.s_addr = inet_addr(ipAddress);
+  serverAddress.sin_family = AF_INET;
+  serverAddress.sin_port = htons(port);
+
+  // do socket connect
+  //LOG("Connecting socket to %s:%d", inet_ntoa(serverAddress.sin_addr), ntohs(serverAddress.sin_port));
+  if(connect(*sockfd, (const struct sockaddr *)&serverAddress, sizeof(serverAddress))<0) {
+     shutdown(*sockfd,SHUT_RDWR);
+     close(*sockfd);
+     DBG("Could not connect");
+     return false;
+  }
+  return true;
+}
+// this is a required callback for tinydtls it is called
+// whenever tinydtls handles a raw buffer through dtls_handle_message.
+// tinydtls extracts the unencrypted data and passes it onto this function
+int read_from_peer(struct dtls_context_t *ctx, session_t *session, uint8 *data, size_t len) {
+  DBG("read_from_peer called");
+  size_t i;
+  for (i = 0; i < len; i++)
+    printf("%c", data[i]);
+  return 0;
+}
+
+/// this is a required callback for tinydtls it is called
+// whenever tinydtls needs to send a raw buffer (i.e whenever dtls_write is called by the application)
+int send_to_peer(struct dtls_context_t *ctx, session_t *session, uint8 *data, size_t len) {
+  DBG("send_to_peer called");
+  int fd = *(int *)dtls_get_app_data(ctx);
+  return sendto(fd, data, len, MSG_DONTWAIT,
+        &session->addr.sa, session->size);
+}
+
+// this is used to handle incoming packets for tinydtls
+// raw buffers are passed to dtls_handle_message, who
+// processes them and passes the data onto the read callback
+int dtls_handle_read(struct dtls_context_t *ctx) {
+  DBG("dtls_handle_read called");
+  int fd;
+  session_t session;
+  #define MAX_READ_BUF 256
+  static uint8 buf[MAX_READ_BUF];
+  int len;
+
+  fd = *(int *)dtls_get_app_data(ctx);
+
+  memset(&session, 0, sizeof(session_t));
+  session.size = sizeof(session.addr);
+  len = recvfrom(fd, buf, MAX_READ_BUF, 0, 
+         &session.addr.sa, &session.size);
+  
+  if(len < 0) {
+    DBG("Got nothing from read");
+    perror("recvfrom");
+    return -1;
+  } else {
+    #if __DEBUG__ > 0
+    unsigned char addrbuf[72];
+    dsrv_print_addr(&session, addrbuf, sizeof(addrbuf));
+    DBG("Got %d bytes from %s", len, (char *)addrbuf);
+    dump((unsigned char *)&session, sizeof(session_t));
+    DBGX("\r\n");
+    dump(buf, len);
+    DBGX("\r\n");
+    #endif
+  }
+
+  return dtls_handle_message(ctx, &session, buf, len);
+} 
+
+// callback called on tinydtls events (currently only ever called for DTLS_EVENT_CONNECTED)
+int event_handler(
+   struct dtls_context_t *ctx,
+   session_t *session, 
+   dtls_alert_level_t level,
+   unsigned short code) {
+   DBG("DTLS SESSION SETUP COMPLETE");
+   gDTLSConnected = 1;
+   return 0;
+}
+
+// structure for required tinydtls callbacks
+static dtls_handler_t cb = {
+  .write = send_to_peer,
+  .read  = read_from_peer,
+  .event = event_handler,
+  .get_key = get_key
+};
+
 int main() {
-    while(1) {
-        myled = 1;
-        wait(0.2);
-        myled = 0;
-        wait(0.2);
+    DBG_INIT();
+    DBG_SET_SPEED(115200);
+    DBG_SET_NEWLINE("\r\n");
+    
+    DBG("Tiny DTLS test");
+
+    // DTLS context struct    
+    dtls_context_t *dtls_context = NULL;
+    int ret = 0, counter = 0;
+    fd_set rfds, wfds;
+    struct timeval timeout;
+    char outBuf[64];
+    
+    // structure for getting address of incoming packets
+    sockaddr_in fromAddr;
+    socklen_t fromAddrLen = sizeof(struct sockaddr_in);
+    memset(&fromAddr,0x00,fromAddrLen);
+    
+    // connect to cellular network
+    VodafoneUSBModem modem;
+    modem.connect(APN,APN_USERNAME,APN_PASSWORD);
+
+    // setup socket to remote server
+    int sockfd = NULL;
+    if(!connectToSocketUDP("109.74.199.96", 5683, &sockfd)) {
+       DBG("Error connecting to socket");
+       fail(1);
+    }
+    DBG("\"Connected\" to UDP socket");
+    int on = 1;
+    if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) ) < 0) {
+       DBG("setsockopt SO_REUSEADDR: %s", strerror(errno));
+    }
+    
+    // tinydtls stuff
+    
+    // destination address is stored in a session type
+    session_t dst;
+    memset(&dst, 0, sizeof(session_t));
+    dst.size = sizeof(sockaddr_in);
+    serverAddress.sin_len  = dst.size;
+    memcpy(&dst.addr.sa, &serverAddress, dst.size);
+    //dst.addr.sin.sin_port = htons(4433);
+    
+    // dtls init must always be called for memory allocation
+    dtls_init();
+    dtls_set_log_level(LOG_DEBUG);
+    // setup DTLS context
+    DBG("Creating DTLS context");
+    dtls_context = dtls_new_context(&sockfd);
+    if(!dtls_context) {
+       DBG("Cannot create context");
+       fail(3);
     }
+    DBG("DTLS context created");
+    
+    // forced to use this call back system
+    
+    dtls_set_handler(dtls_context, &cb);
+    
+    DBG("Issuing dtls_connect");
+    ret = dtls_connect(dtls_context, &dst);
+    if(ret<0) {
+       DBG("Error in dtls_connect: %d",ret);
+       modem.disconnect();
+       fail(4);
+    }
+    if(ret==0) {
+       DBG("Channel already exists");
+       modem.disconnect();
+       fail(5);
+    }
+    DBG("dtls_connect successfull");
+    while (1) {
+        // setup file descriptor lists for select
+        FD_ZERO(&rfds);
+        FD_ZERO(&wfds);
+        //FD_SET(fileno(stdin), &rfds);
+        FD_SET(sockfd, &rfds);
+        // FD_SET(sockfd, &wfds);
+    
+        timeout.tv_sec = 5;
+        timeout.tv_usec = 0;
+    
+        int result = select(sockfd+1, &rfds, &wfds, 0, &timeout);
+    
+        if(result < 0) { // error
+        if (errno != EINTR)
+            perror("select");
+        } else if (result == 0) {
+           // timeout
+           DBG("select timeout");
+           // if we are connected, send some random data (every time select times out)
+           // heh, abusing select as a timer
+           if(gDTLSConnected) {
+              sprintf(outBuf,"This is a pointless test message: %d\r\n",counter++);
+              dtls_write(dtls_context, &dst, (uint8 *)outBuf, strlen(outBuf));
+              //try_send(dtls_context, &dst);
+           }
+        } else {
+           // OK
+           // check which file descriptor had an event
+           if(FD_ISSET(sockfd, &wfds)) {
+              // FIXME (from tinydtls)
+           } else if (FD_ISSET(sockfd, &rfds))
+              if(dtls_handle_read(dtls_context)<0) {
+                 modem.disconnect();
+                 fail(6);
+              }
+           } 
+        //else if (FD_ISSET(fileno(stdin), &rfds))
+           //handle_stdin();
+        //}
+
+       
+  }
+
 }