A client for the SmartREST protocol from Cumulocity.

Dependencies:   SmartRest

Fork of MbedSmartRest by Vincent Wochnik

Files at this revision

API Documentation at this revision

Comitter:
vwochnik
Date:
Fri Apr 11 09:33:45 2014 +0000
Parent:
12:788dd934f283
Child:
14:dc3f8dd5c02b
Commit message:
fix

Changed in this revision

HTTPBuffer.cpp Show diff for this revision Revisions of this file
HTTPBuffer.h Show diff for this revision Revisions of this file
HTTPClient.lib Show diff for this revision Revisions of this file
HTTPGeneratorWrapper.cpp Show diff for this revision Revisions of this file
HTTPGeneratorWrapper.h Show diff for this revision Revisions of this file
MbedClient.cpp Show annotated file Show diff for this revision Revisions of this file
MbedClient.h Show annotated file Show diff for this revision Revisions of this file
MbedDataSink.cpp Show annotated file Show diff for this revision Revisions of this file
MbedDataSink.h Show annotated file Show diff for this revision Revisions of this file
MbedDataSource.cpp Show annotated file Show diff for this revision Revisions of this file
MbedDataSource.h Show annotated file Show diff for this revision Revisions of this file
MbedSmartRest.cpp Show annotated file Show diff for this revision Revisions of this file
MbedSmartRest.h Show annotated file Show diff for this revision Revisions of this file
b64.cpp Show annotated file Show diff for this revision Revisions of this file
b64.h Show annotated file Show diff for this revision Revisions of this file
--- a/HTTPBuffer.cpp	Wed Apr 02 12:23:46 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,78 +0,0 @@
-#include "HTTPBuffer.h"
-#include <stdlib.h>
-#include <string.h>
-
-HTTPBuffer::HTTPBuffer()
-{
-    _rptr = _wptr = _buf = NULL;
-    bufferSize(HTTPBUFFER_INITIAL_SIZE);
-}
-
-HTTPBuffer::~HTTPBuffer()
-{
-    if (_buf != NULL)
-        free(_buf);
-}
-
-char HTTPBuffer::read()
-{
-    if (_rptr == _wptr)
-        return 0;
-    return *_rptr++;
-}
-
-uint8_t HTTPBuffer::status()
-{
-    if (_rptr == _wptr)
-        return DS_STATUS_CLOSED;
-    return DS_STATUS_OK;
-}
-
-void HTTPBuffer::writeReset()
-{
-    _rptr = _wptr = _buf;
-    bufferSize(HTTPBUFFER_INITIAL_SIZE);
-}
-
-int HTTPBuffer::write(const char* buf, size_t len)
-{
-    if (_wptr - _buf + len > _len) {
-        size_t newLen = _len;
-        while (_wptr - _buf + len > newLen)
-            newLen += HTTPBUFFER_INCREMENT;
-        bufferSize(newLen);
-    }
-    memcpy(_wptr, buf, len);
-    _wptr += len;
-}
-
-void HTTPBuffer::setDataType(const char* type)
-{
-}
-
-void HTTPBuffer::setIsChunked(bool chunked)
-{
-}
-
-void HTTPBuffer::setDataLen(size_t len)
-{
-    bufferSize(len);
-}
-
-
-void HTTPBuffer::bufferSize(size_t length)
-{
-    if (_len == length)
-        return;
-    
-    char *buf = (char*)realloc(_buf, length);
-    if (buf == NULL)
-        return;
-    
-    // set pointers
-    _wptr = buf + (_wptr - _buf);
-    _rptr = buf + (_rptr - _buf);
-    _buf = buf;
-
-    _len = length;
-}
--- a/HTTPBuffer.h	Wed Apr 02 12:23:46 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,36 +0,0 @@
-#ifndef HTTPBUFFER_H
-#define HTTPBUFFER_H
-
-#include <stddef.h>
-#include "IHTTPData.h"
-#include "AbstractDataSource.h"
-
-#define HTTPBUFFER_INITIAL_SIZE 128
-#define HTTPBUFFER_INCREMENT 64
-static int x = 123;
-class HTTPBuffer : public IHTTPDataIn, public AbstractDataSource
-{
-public:
-    HTTPBuffer();
-    ~HTTPBuffer();
-
-    char read();
-    uint8_t status();
-    
-    void writeReset();
-
-protected:
-    int write(const char* buf, size_t len);
-    void setDataType(const char* type);
-    void setIsChunked(bool chunked);
-    void setDataLen(size_t len);
-    void bufferSize(size_t length);
-
-//private:
-public:
-    // buffer, write and read pointers
-    char *_buf, *_wptr, *_rptr;
-    size_t _len;
-};
-
-#endif
\ No newline at end of file
--- a/HTTPClient.lib	Wed Apr 02 12:23:46 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-http://mbed.org/users/vwochnik/code/HTTPClient/#9386b15b0820
--- a/HTTPGeneratorWrapper.cpp	Wed Apr 02 12:23:46 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +0,0 @@
-#include "HTTPGeneratorWrapper.h"
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-
-HTTPGeneratorWrapper::HTTPGeneratorWrapper(DataGenerator& generator) : _sink(generator.writtenLength())
-{
-    generator.writeTo(_sink);
-    _len = _sink.length();
-    _pos = 0;
-    
-    char *p = (char*)_sink.buffer();
-    size_t i = 0;
-    while (i < _len) {
-        putchar(*p++);
-        i++;
-    }
-}
-
-void HTTPGeneratorWrapper::readReset()
-{
-    _pos = 0;
-}
-
-int HTTPGeneratorWrapper::read(char* buf, size_t len, size_t* pReadLen)
-{
-    *pReadLen = len;
-    if (len > _len - _pos)
-        *pReadLen = _len - _pos;
-    else
-        *pReadLen = len;
-    memcpy(buf, _sink.buffer()+_pos, *pReadLen);
-    _pos += *pReadLen;
-    return 0;
-}
-
-int HTTPGeneratorWrapper::getDataType(char* type, size_t maxTypeLen)
-{
-    return 1;
-}
-
-bool HTTPGeneratorWrapper::getIsChunked()
-{
-    return false;
-}
-
-size_t HTTPGeneratorWrapper::getDataLen()
-{
-    return _len;
-}
--- a/HTTPGeneratorWrapper.h	Wed Apr 02 12:23:46 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,26 +0,0 @@
-#ifndef HTTPGENERATORWRAPPER_H
-#define HTTPGENERATORWRAPPER_H
-
-#include "DataGenerator.h"
-#include "MbedDataSink.h"
-#include "IHTTPData.h"
-
-class HTTPGeneratorWrapper : public IHTTPDataOut
-{
-public:
-    HTTPGeneratorWrapper(DataGenerator& generator);
-
-protected:
-    void readReset();
-    int read(char* buf, size_t len, size_t* pReadLen);
-    int getDataType(char* type, size_t maxTypeLen);
-    bool getIsChunked();
-    size_t getDataLen();
-
-private:
-    MbedDataSink _sink;
-    size_t _len;
-    size_t _pos;
-};
-
-#endif
\ No newline at end of file
--- a/MbedClient.cpp	Wed Apr 02 12:23:46 2014 +0000
+++ b/MbedClient.cpp	Fri Apr 11 09:33:45 2014 +0000
@@ -1,100 +1,204 @@
 #include "MbedClient.h"
 #include <stdlib.h>
-
 #include <stdio.h>
+#include <string.h>
+#include "b64.h"
+#include "mbed.h"
 
-#define STATE_INIT 0
-#define STATE_IN_REQUEST 1
-#define STATE_SENT_ID 2
-#define STATE_SENT_DATA 3
-#define STATE_REQ_COMPLETE 4
-#define STATE_RECVD_RESPONSE 5
-#define STATE_RECV_DATA 6
+const char *cExpectedStatus = "HTTP/1.* 200 OK";
 
-const char * const cXidHeader = "X-Id";
-
-MbedClient::MbedClient(const char* url, const char* username, const char* password)
-    : _url(url), _username(username), _password(password)
+MbedClient::MbedClient(const char* host, uint16_t port, const char* username, const char* password)
+    : _host(host), _port(port), _username(username), _password(password), _source(_sock), _sink(_sock), _sock()
 {
-    _state = STATE_INIT;
-    _headers[0] = cXidHeader;
-    _headers[1] = NULL;
+    _state = MBED_STATE_INIT;
 }
 
 MbedClient::~MbedClient()
 {
-    if (_generator != NULL)
-        delete _generator;
 }
 
 uint8_t MbedClient::beginRequest()
 {
-    if (_state != STATE_INIT)
+    if (_state != MBED_STATE_INIT)
         return CLIENT_INTERNAL_ERROR;
-    _client.basicAuth(_username, _password);
-    _client.customHeaders(NULL, 0);
-    _state = STATE_IN_REQUEST;
+
+    if (_sock.connect(_host, _port) < 0) {
+        stop();
+        return CLIENT_CONNECTION_ERROR;
+    }
+
+    if ((!send("POST /s HTTP/1.0\r\n")) ||
+        (!send("Host: ")) ||
+        (!send(_host)) ||
+        (!send("\r\n")))
+        return CLIENT_CONNECTION_ERROR;
+    
+    if (!sendBasicAuth())
+        return CLIENT_CONNECTION_ERROR;
+
+    _state = MBED_STATE_IN_REQUEST;
     return CLIENT_OK;
 }
 
 uint8_t MbedClient::sendIdentifier(const char* identifier)
 {
-    if (_state != STATE_IN_REQUEST)
+    if (_state != MBED_STATE_IN_REQUEST)
         return CLIENT_INTERNAL_ERROR;
-    _headers[1] = identifier;
-    _client.customHeaders(_headers, 1);
-    _state = STATE_SENT_ID;
+
+    if ((!send("X-Id: ")) ||
+        (!send(identifier)) ||
+        (!send("\r\n")))
+        return CLIENT_CONNECTION_ERROR;
+
+    _state = MBED_STATE_SENT_ID;
     return CLIENT_OK;
 }
 
 uint8_t MbedClient::sendData(DataGenerator& generator)
 {
-    puts("Send called.");
-    if ((_state != STATE_IN_REQUEST) && (_state != STATE_SENT_ID))
+    char len[8];
+    
+    if ((_state != MBED_STATE_IN_REQUEST) && (_state != MBED_STATE_SENT_ID))
         return CLIENT_INTERNAL_ERROR;
-    puts("Setting gen.");
-    _generator = new HTTPGeneratorWrapper(generator);
-    _state = STATE_SENT_DATA;
+    
+    snprintf(len, 8, "%ld", generator.writtenLength());
+
+    if ((!send("Content-Length: ")) ||
+        (!send(len)) ||
+        (!send("\r\n\r\n")))
+        return CLIENT_CONNECTION_ERROR;
+
+    if (generator.writeTo(_sink) != generator.writtenLength()) {
+        stop();
+        return CLIENT_CONNECTION_ERROR;
+    }
+    
+    _state = MBED_STATE_SENT_DATA;
     return CLIENT_OK;
 }
 
 uint8_t MbedClient::endRequest()
 {
-    if ((_state != STATE_IN_REQUEST) && (_state != STATE_SENT_ID) && (_state != STATE_SENT_DATA))
+    if ((_state != MBED_STATE_IN_REQUEST) && (_state != MBED_STATE_SENT_ID) && (_state != MBED_STATE_SENT_DATA))
         return CLIENT_INTERNAL_ERROR;
-    _state = STATE_REQ_COMPLETE;
+    
+    if (_state != MBED_STATE_SENT_DATA) {
+        // send end of headers
+        if (!send("\r\n"))
+            return CLIENT_CONNECTION_ERROR;
+    }
+    
+    if (!_sink.flush()) {
+        stop();
+        return CLIENT_CONNECTION_ERROR;
+    }
+    
+    _state = MBED_STATE_REQ_COMPLETE;
     return CLIENT_OK;
 }
 
 uint8_t MbedClient::awaitResponse()
 {
-    HTTPResult result;
+    int8_t state = 0; char c; size_t offset = 0;
 
-    puts("Action");
-    if (_state != STATE_REQ_COMPLETE)
+    if (_state != MBED_STATE_REQ_COMPLETE)
         return CLIENT_INTERNAL_ERROR;
-    puts("Calling");
-    result = _client.post(_url, *_generator, &_buffer);
-    if (result != 0)
+    
+    while ((state >= 0) && (state < 20) && (((c = _source.read()) > 0) || (_source.status() == DS_STATUS_OK))) {
+        switch (state) {
+        case 0: // read expected status line
+            if ((cExpectedStatus[offset] != c) && (cExpectedStatus[offset] != '*'))
+                state = -1;
+            offset++;
+            if (offset == strlen(cExpectedStatus))
+                state = 1;
+            break;
+        linebrk:
+        case 1:
+            if (c == '\n')
+                state = 2;
+            else if (c != '\r')
+                state = -1;
+            break;
+        case 2:
+            if (c == '\n') {
+                state = 20;
+                break;
+            } else if (c == '\r') {
+                break;
+            } else {
+                state = 3;
+                goto random;
+            }
+        random:
+        case 3:
+            if ((c == '\r') || (c == '\n')) {
+                state = 1;
+                goto linebrk;
+            }
+        }
+    }
+    
+    if (state != 20) {
+        stop();
         return CLIENT_CONNECTION_ERROR;
-    char *p = _buffer._buf;
-    while (p != _buffer._wptr)
-        putchar(*p++);
-    _state = STATE_RECVD_RESPONSE;
+    }
+    
+    _state = MBED_STATE_RECVD_RESPONSE;
     return CLIENT_OK;
 }
 
 AbstractDataSource& MbedClient::receiveData()
 {
-    return _buffer;
+    return _source;
 }
 
 void MbedClient::stop()
 {
-    _buffer.writeReset();
-    _headers[1] = NULL;
-    if (_generator != NULL)
-        delete _generator;
-    _generator = NULL;
-    _state = STATE_INIT;
+    _sock.close();
+    _source.reset();
+    _sink.reset();
+    _state = MBED_STATE_INIT;
+}
+
+bool MbedClient::send(const char *str)
+{
+    if (_sink.write(str) != strlen(str)) {
+        stop();
+        return false;
+    }
+    return true;
 }
+
+bool MbedClient::sendBasicAuth()
+{
+    size_t ul, pl; unsigned char input[3]; unsigned char output[5];
+    int inputOffset = 0;
+
+    if (!send("Authorization: Basic "))
+        return false;
+        
+    ul = strlen(_username);
+    pl = strlen(_password);
+
+    for (int i = 0; i < (ul+1+pl); i++) {
+        if (i < ul)
+            input[inputOffset++] = _username[i];
+        else if (i == ul)
+            input[inputOffset++] = ':';
+        else
+            input[inputOffset++] = _password[i-(ul+1)];
+
+        if ((inputOffset == 3) || (i == ul+pl)) {
+            b64_encode(input, inputOffset, output, 4);
+            output[4] = '\0';
+            if (!send((char*)output))
+                return false;
+            inputOffset = 0;
+        }
+    }
+    
+    if (!send("\r\n"))
+        return false;
+    return true;
+}
\ No newline at end of file
--- a/MbedClient.h	Wed Apr 02 12:23:46 2014 +0000
+++ b/MbedClient.h	Fri Apr 11 09:33:45 2014 +0000
@@ -1,14 +1,23 @@
 #ifndef MBEDCLIENT_H
 #define MBEDCLIENT_H
 
+#include <stdint.h>
 #include "AbstractClient.h"
-#include "HTTPBuffer.h"
-#include "HTTPGeneratorWrapper.h"
-#include "HTTPClient.h"
+#include "TCPSocketConnection.h"
+#include "MbedDataSource.h"
+#include "MbedDataSink.h"
+
+#define MBED_STATE_INIT 0
+#define MBED_STATE_IN_REQUEST 1
+#define MBED_STATE_SENT_ID 2
+#define MBED_STATE_SENT_DATA 3
+#define MBED_STATE_REQ_COMPLETE 4
+#define MBED_STATE_RECVD_RESPONSE 5
+#define MBED_STATE_RECV_DATA 6
 
 class MbedClient : public AbstractClient {
 public:
-    MbedClient(const char*, const char*, const char*);
+    MbedClient(const char*, uint16_t, const char*, const char*);
     ~MbedClient();
 
     uint8_t beginRequest();
@@ -19,13 +28,16 @@
     AbstractDataSource& receiveData();
     void stop();
 
+protected:
+    bool send(const char *str);
+    bool sendBasicAuth();
+
 private:
-    const char *_url, *_username, *_password;
-    HTTPClient _client;
-    HTTPGeneratorWrapper *_generator;
-    HTTPBuffer _buffer;
-    uint8_t _state;
-    const char *_headers[2];
+    const char *_host, *_username, *_password;
+    uint16_t _port, _state;
+    TCPSocketConnection _sock;
+    MbedDataSource _source;
+    MbedDataSink _sink;
 };
 
 #endif
\ No newline at end of file
--- a/MbedDataSink.cpp	Wed Apr 02 12:23:46 2014 +0000
+++ b/MbedDataSink.cpp	Fri Apr 11 09:33:45 2014 +0000
@@ -1,65 +1,104 @@
 #include "MbedDataSink.h"
+#include "MbedClient.h"
 #include <stdlib.h>
 #include <stdio.h>
+#include <string.h>
 
-MbedDataSink::MbedDataSink(size_t length)
+#include "mbed.h"
+
+MbedDataSink::MbedDataSink(TCPSocketConnection& sock) : _len(0), _sock(sock)
 {
-    _len = length;
-    _ptr = _buf = (char*)malloc(length);
 }
 
 MbedDataSink::~MbedDataSink()
 {
-    free(_buf);
 }
 
 size_t MbedDataSink::write(char c)
 {
-    if (_ptr - _buf == _len)
-        return 0;
-    *_ptr++ = c;
+    while (MBED_SINK_BUFFER_SIZE - _len < 1) {
+        if (!send())
+            return 0;
+    }
+    
+    putchar(c);
+    _buf[_len++] = c;
     return 1;
 }
 
 size_t MbedDataSink::write(void *buf, size_t length)
 {
-    size_t written = 0;
-    char *b = (char*)buf;
+    size_t sent = 0, len;
     
-    while ((length-- > 0) && (write(*b++)))
-        written++;
-
-    return written;
+    while (sent < length) {
+        while (MBED_SINK_BUFFER_SIZE - _len < 1) {
+            if (!send())
+                return 0;
+        }
+        
+        if (MBED_SINK_BUFFER_SIZE - _len >= length-sent)
+            len = length-sent;
+        else
+            len = MBED_SINK_BUFFER_SIZE - _len;
+        
+        memcpy(_buf+_len, (char*)buf+sent, len);
+        _len += len;
+        sent += len;
+    }
+    
+    return length;
 }
 
 size_t MbedDataSink::write(const char *str)
 {
-    size_t written = 0;
-    
-    for (char c, *p = (char*)str; (c = *p) > 0; ++p) {
-        if (!write(c))
-            break;
-        written++;
-    }
-    return written;
+    return write((void*)str, strlen(str));
 }
 
 size_t MbedDataSink::write(unsigned long number)
 {
-    size_t left, len;
+    char str[24];
     
-    left = _len - (_ptr - _buf);
-    len = snprintf(_ptr, left, "%ld", number);
-    _ptr += len;
-    return len;
+    snprintf(str, 24, "%uld", number);
+    return write(str);
+}
+
+bool MbedDataSink::flush()
+{
+    while (_len > 0) {
+        if (!send())
+            return false;
+    }
+    
+    return true;
 }
 
-const char * MbedDataSink::buffer()
+bool MbedDataSink::send()
 {
-    return _buf;
+    int ret;
+    
+    if (!_sock.is_connected())
+        return false;
+    
+    _sock.set_blocking(true);
+    ret = _sock.send(_buf, _len);
+    
+    //TODO: fix bug in u-blox so no longer wait is needed
+    wait(0.5);
+    
+    if (ret < 0){
+        puts("Send failed.");
+        return false;
+    }
+    
+    // move rest of buffer
+    if ((ret > 0) && (ret < _len))
+        memmove(_buf, _buf+ret, _len-ret);
+    
+    _len -= ret;
+    return true;
 }
 
-size_t MbedDataSink::length()
+void MbedDataSink::reset()
 {
-    return _ptr - _buf;
-}
+    _len = 0;
+}
\ No newline at end of file
--- a/MbedDataSink.h	Wed Apr 02 12:23:46 2014 +0000
+++ b/MbedDataSink.h	Fri Apr 11 09:33:45 2014 +0000
@@ -3,13 +3,16 @@
 
 #include <stddef.h>
 #include "AbstractDataSink.h"
+#include "TCPSocketConnection.h"
 
-class HTTPGeneratorWrapper;
+#define MBED_SINK_BUFFER_SIZE 60
+
+class MbedClient;
 
 class MbedDataSink : public AbstractDataSink
 {
 public:
-    MbedDataSink(size_t length);
+    MbedDataSink(TCPSocketConnection& sock);
     ~MbedDataSink();
     
     size_t write(char c);
@@ -17,15 +20,18 @@
     size_t write(const char *str);
     size_t write(unsigned long number);
     
+    
 protected:
-    const char * buffer();
-    size_t length();
+    bool flush();
+    bool send();
+    void reset();
 
 private:
-    char *_buf, *_ptr;
+    TCPSocketConnection& _sock;
+    char _buf[MBED_SINK_BUFFER_SIZE];
     size_t _len;
 
-friend class HTTPGeneratorWrapper;
+friend class MbedClient;
 };
 
 #endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MbedDataSource.cpp	Fri Apr 11 09:33:45 2014 +0000
@@ -0,0 +1,60 @@
+#include "MbedDataSource.h"
+#include "stdio.h"
+
+MbedDataSource::MbedDataSource(TCPSocketConnection& sock) : _sock(sock)
+{
+    _offset = _len = 0;
+    _timeout = false;
+}
+
+MbedDataSource::~MbedDataSource()
+{
+}
+
+char MbedDataSource::read()
+{
+    while (_offset == _len) {
+        if (!receive())
+            return 0;
+    }
+    
+    return _buf[_offset++];
+}
+
+uint8_t MbedDataSource::status()
+{
+    if (!_sock.is_connected())
+        return DS_STATUS_CLOSED;
+    
+    if (_timeout)
+        return DS_STATUS_TIMEOUT;
+    
+    return DS_STATUS_OK;
+}
+
+bool MbedDataSource::receive()
+{
+    int ret;
+
+    if (status() != DS_STATUS_OK)
+        return false;
+    
+    _sock.set_blocking(true, 60000);
+    ret = _sock.receive(_buf, MBED_SOURCE_BUFFER_SIZE);
+    
+    if (ret < 0) {
+        _timeout = true;
+        return false;
+    }
+    
+    _len = (size_t)ret;
+    _offset = 0;
+    
+    return true;
+}
+
+void MbedDataSource::reset()
+{
+    _len = _offset = 0;
+    _timeout = false;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MbedDataSource.h	Fri Apr 11 09:33:45 2014 +0000
@@ -0,0 +1,34 @@
+#ifndef MBEDDATASOURCE_H
+#define MBEDDATASOURCE_H
+
+#include <stddef.h>
+#include "AbstractDataSource.h"
+#include "TCPSocketConnection.h"
+
+#define MBED_SOURCE_BUFFER_SIZE 60
+
+class MbedClient;
+
+class MbedDataSource : public AbstractDataSource
+{
+public:
+    MbedDataSource(TCPSocketConnection& sock);
+    ~MbedDataSource();
+
+    char read();
+    uint8_t status();
+
+protected:
+    bool receive();
+    void reset();
+
+private:
+    TCPSocketConnection& _sock;
+    char _buf[MBED_SOURCE_BUFFER_SIZE];
+    size_t _len, _offset;
+    bool _timeout;
+
+friend class MbedClient;
+};
+
+#endif
--- a/MbedSmartRest.cpp	Wed Apr 02 12:23:46 2014 +0000
+++ b/MbedSmartRest.cpp	Fri Apr 11 09:33:45 2014 +0000
@@ -1,5 +1,5 @@
  #include "MbedSmartRest.h"
 
-MbedSmartRest::MbedSmartRest(const char* url, const char* username, const char* password, const char* identifier) : SmartRest(_client, identifier), _client(url, username, password)
+MbedSmartRest::MbedSmartRest(const char* host, uint16_t port, const char* username, const char* password, const char* identifier) : SmartRest(_client, identifier), _client(host, port, username, password)
 {
 }
\ No newline at end of file
--- a/MbedSmartRest.h	Wed Apr 02 12:23:46 2014 +0000
+++ b/MbedSmartRest.h	Fri Apr 11 09:33:45 2014 +0000
@@ -7,7 +7,7 @@
 class MbedSmartRest : public SmartRest
 {
 public:
-    MbedSmartRest(const char*, const char*, const char*, const char*);
+    MbedSmartRest(const char*, uint16_t, const char*, const char*, const char*);
 
 private:
     MbedClient _client;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/b64.cpp	Fri Apr 11 09:33:45 2014 +0000
@@ -0,0 +1,70 @@
+// Simple Base64 code
+// (c) Copyright 2010 MCQN Ltd.
+// Released under Apache License, version 2.0
+
+#include "b64.h"
+
+/* Simple test program
+#include <stdio.h>
+void main()
+{
+    char* in = "amcewen";
+    char out[22];
+
+    b64_encode(in, 15, out, 22);
+    out[21] = '\0';
+
+    printf(out);
+}
+*/
+
+int b64_encode(const unsigned char* aInput, int aInputLen, unsigned char* aOutput, int aOutputLen)
+{
+    // Work out if we've got enough space to encode the input
+    // Every 6 bits of input becomes a byte of output
+    if (aOutputLen < (aInputLen*8)/6)
+    {
+        // FIXME Should we return an error here, or just the length
+        return (aInputLen*8)/6;
+    }
+
+    // If we get here we've got enough space to do the encoding
+
+    const char* b64_dictionary = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+    if (aInputLen == 3)
+    {
+        aOutput[0] = b64_dictionary[aInput[0] >> 2];
+        aOutput[1] = b64_dictionary[(aInput[0] & 0x3)<<4|(aInput[1]>>4)];
+        aOutput[2] = b64_dictionary[(aInput[1]&0x0F)<<2|(aInput[2]>>6)];
+        aOutput[3] = b64_dictionary[aInput[2]&0x3F];
+    }
+    else if (aInputLen == 2)
+    {
+        aOutput[0] = b64_dictionary[aInput[0] >> 2];
+        aOutput[1] = b64_dictionary[(aInput[0] & 0x3)<<4|(aInput[1]>>4)];
+        aOutput[2] = b64_dictionary[(aInput[1]&0x0F)<<2];
+        aOutput[3] = '=';
+    }
+    else if (aInputLen == 1)
+    {
+        aOutput[0] = b64_dictionary[aInput[0] >> 2];
+        aOutput[1] = b64_dictionary[(aInput[0] & 0x3)<<4];
+        aOutput[2] = '=';
+        aOutput[3] = '=';
+    }
+    else
+    {
+        // Break the input into 3-byte chunks and process each of them
+        int i;
+        for (i = 0; i < aInputLen/3; i++)
+        {
+            b64_encode(&aInput[i*3], 3, &aOutput[i*4], 4);
+        }
+        if (aInputLen % 3 > 0)
+        {
+            // It doesn't fit neatly into a 3-byte chunk, so process what's left
+            b64_encode(&aInput[i*3], aInputLen % 3, &aOutput[i*4], aOutputLen - (i*4));
+        }
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/b64.h	Fri Apr 11 09:33:45 2014 +0000
@@ -0,0 +1,6 @@
+#ifndef b64_h
+#define b64_h
+
+int b64_encode(const unsigned char* aInput, int aInputLen, unsigned char* aOutput, int aOutputLen);
+
+#endif