Ethernet test for tinydtls-0.5.0

Dependencies:   EthernetInterface mbed-rtos mbed tinydtls

Fork of tinydtls_test_ethernet by Ashley Mills

main.cpp

Committer:
ashleymills
Date:
2013-10-18
Revision:
4:4d466a913c11
Parent:
3:0caeed7fd9f0

File content as of revision 4:4d466a913c11:

#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 "dbg.h"

#include "EthernetInterface.h"
DigitalOut myled(LED1);

void fail(int code) {
   while(1) {
      myled = !myled;
      Thread::wait(100);
   }
}

static const unsigned char ecdsa_priv_key[] = {
            0x41, 0xC1, 0xCB, 0x6B, 0x51, 0x24, 0x7A, 0x14,
            0x43, 0x21, 0x43, 0x5B, 0x7A, 0x80, 0xE7, 0x14,
            0x89, 0x6A, 0x33, 0xBB, 0xAD, 0x72, 0x94, 0xCA,
            0x40, 0x14, 0x55, 0xA1, 0x94, 0xA9, 0x49, 0xFA};

static const unsigned char ecdsa_pub_key_x[] = {
            0x36, 0xDF, 0xE2, 0xC6, 0xF9, 0xF2, 0xED, 0x29,
            0xDA, 0x0A, 0x9A, 0x8F, 0x62, 0x68, 0x4E, 0x91,
            0x63, 0x75, 0xBA, 0x10, 0x30, 0x0C, 0x28, 0xC5,
            0xE4, 0x7C, 0xFB, 0xF2, 0x5F, 0xA5, 0x8F, 0x52};

static const unsigned char ecdsa_pub_key_y[] = {
            0x71, 0xA0, 0xD4, 0xFC, 0xDE, 0x1A, 0xB8, 0x78,
            0x5A, 0x3C, 0x78, 0x69, 0x35, 0xA7, 0xCF, 0xAB,
            0xE9, 0x3F, 0x98, 0x72, 0x09, 0xDA, 0xED, 0x0B,
            0x4F, 0xAB, 0xC3, 0x6F, 0xC7, 0x72, 0xF8, 0x29};


static const dtls_psk_key_t client_psk = {
    .id = (unsigned char *)"Client_identity",
    .id_length = 15,
    .key = (unsigned char *)"secretPSK",
    .key_length = 9
};

/* 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_psk_key(struct dtls_context_t *ctx,
        const session_t *session,
        const unsigned char *id, size_t id_len,
        const dtls_psk_key_t **result) {
  DBG("id: %d, len: %d",id,id_len);
  *result = &client_psk;

  return 0;
}

int
get_ecdsa_key(struct dtls_context_t *ctx,
          const session_t *session,
          const dtls_ecdsa_key_t **result) {
  static const dtls_ecdsa_key_t ecdsa_key = {
    .curve = DTLS_ECDH_CURVE_SECP256R1,
    .priv_key = ecdsa_priv_key,
    .pub_key_x = ecdsa_pub_key_x,
    .pub_key_y = ecdsa_pub_key_y
  };

  *result = &ecdsa_key;
  return 0;
}

int
verify_ecdsa_key(struct dtls_context_t *ctx,
         const session_t *session,
         const unsigned char *other_pub_x,
         const unsigned char *other_pub_y,
         size_t key_size) {
  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

sockaddr_in bindAddr,serverAddress;
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
  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;
}

int read_from_peer(struct dtls_context_t *ctx, session_t *session, uint8 *data, size_t len) {
  DBG("read_from_peer called: %d",len);
  size_t i;
  for (i = 0; i < len; i++)
    printf("%c", data[i]);
  return 0;
}

int send_to_peer(struct dtls_context_t *ctx, session_t *session, uint8 *data, size_t len) {
  DBG("send_to_peer called: %d",len);
  int fd = *(int *)dtls_get_app_data(ctx);
  return sendto(fd, data, len, MSG_DONTWAIT,
        &session->addr.sa, session->size);
}


int
dtls_handle_read(struct dtls_context_t *ctx) {
  DBG("dtls_handle_read called");
  int fd;
  session_t session;
#define MAX_READ_BUF 512
  static uint8 buf[MAX_READ_BUF];
  int len;

  fd = *(int *)dtls_get_app_data(ctx);
  /*
  if(!fd) {
     DBG("FD NULL");
     return -1;
  }*/

 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 {
#ifndef NDEBUG
    unsigned char addrbuf[72];
    dsrv_print_addr(&session, addrbuf, sizeof(addrbuf));
    DBG("got %d bytes from %s\n", 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);
}    
int gDTLSConnected = 0;

// 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;
}

static dtls_handler_t cb = {
  .write = send_to_peer,
  .read  = read_from_peer,
  .event = event_handler,
  .get_psk_key = get_psk_key,
  .get_ecdsa_key = NULL,// get_ecdsa_key,
  .verify_ecdsa_key = NULL//verify_ecdsa_key
};

int main() {
    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;
    fd_set rfds, wfds;
    struct timeval timeout;
    session_t dst;

    // 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);
    */
    EthernetInterface modem;
    DBG("Connecting to network interface");
    modem.init();
    if(modem.connect(10000)) {
       DBG("Error initialising ethernet interface");
    }
    DBG("DONE.");
    
    dtls_init();
    dtls_set_log_level(LOG_DEBUG);

    // setup socket to remote server
    int sockfd = NULL;
    
    
    //if(!connectToSocketUDP("109.74.199.96", 4433, &sockfd)) {
    if(!connectToSocketUDP("192.168.1.99", 4433, &sockfd)) {  
       DBG("Error connecting to socket");
       fail(1);
    }
    DBG("\"Connected\" to UDP socket, sockfd: %d",sockfd);
    
    int on = 1;
    if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) ) < 0) {
       dsrv_log(LOG_ALERT, "setsockopt SO_REUSEADDR: %s\n", strerror(errno));
    }
     
    // tinydtls stuff
    
    // destination address is stored in a session type
    
    memset(&dst, 0x00, sizeof(session_t));
    dst.size = sizeof(sockaddr_in);
    DBG("starting copy at offset: %d",(int)&dst.addr-(int)&dst);
    serverAddress.sin_len  = dst.size;
    memcpy(&dst.addr, &serverAddress, dst.size);
    
    
    //dst.addr.sin.sin_port = htons(4433);
    
    // dtls init must always be called for memory allocation
    
    // 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");
    int counter = 0;
    char outBuf[64];
    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 = 15;
        timeout.tv_usec = 0;
        DBG("Waiting for data");
        int result = select(sockfd+1, &rfds, &wfds, 0, &timeout);
    
        if(result < 0) { // error
        if (errno != EINTR)
            perror("select");
        } else if (result == 0) {
           // timeout
           if(gDTLSConnected) {
              DBG("Sending data");
              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();
        //}

       //if(len) {
       //  try_send(dtls_context, &dst);
       //}
  }

}