Test of tinydtls over cellular
Dependencies: VodafoneUSBModem mbed-rtos mbed tinydtls
Diff: main.cpp
- 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(); + //} + + + } + }