Skip to content

Problems with getData() #21

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.DS_Store
133 changes: 133 additions & 0 deletions Base64.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
#include "Base64.h"

const char b64_alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";

/* 'Private' declarations */
inline void a3_to_a4(unsigned char * a4, unsigned char * a3);
inline void a4_to_a3(unsigned char * a3, unsigned char * a4);
inline unsigned char b64_lookup(char c);

int base64_encode(char *output, char *input, int inputLen) {
int i = 0, j = 0;
int encLen = 0;
unsigned char a3[3];
unsigned char a4[4];

while(inputLen--) {
a3[i++] = *(input++);
if(i == 3) {
a3_to_a4(a4, a3);

for(i = 0; i < 4; i++) {
output[encLen++] = b64_alphabet[a4[i]];
}

i = 0;
}
}

if(i) {
for(j = i; j < 3; j++) {
a3[j] = '\0';
}

a3_to_a4(a4, a3);

for(j = 0; j < i + 1; j++) {
output[encLen++] = b64_alphabet[a4[j]];
}

while((i++ < 3)) {
output[encLen++] = '=';
}
}
output[encLen] = '\0';
return encLen;
}

int base64_decode(char * output, char * input, int inputLen) {
int i = 0, j = 0;
int decLen = 0;
unsigned char a3[3];
unsigned char a4[4];


while (inputLen--) {
if(*input == '=') {
break;
}

a4[i++] = *(input++);
if (i == 4) {
for (i = 0; i <4; i++) {
a4[i] = b64_lookup(a4[i]);
}

a4_to_a3(a3,a4);

for (i = 0; i < 3; i++) {
output[decLen++] = a3[i];
}
i = 0;
}
}

if (i) {
for (j = i; j < 4; j++) {
a4[j] = '\0';
}

for (j = 0; j <4; j++) {
a4[j] = b64_lookup(a4[j]);
}

a4_to_a3(a3,a4);

for (j = 0; j < i - 1; j++) {
output[decLen++] = a3[j];
}
}
output[decLen] = '\0';
return decLen;
}

int base64_enc_len(int plainLen) {
int n = plainLen;
return (n + 2 - ((n + 2) % 3)) / 3 * 4;
}

int base64_dec_len(char * input, int inputLen) {
int i = 0;
int numEq = 0;
for(i = inputLen - 1; input[i] == '='; i--) {
numEq++;
}

return ((6 * inputLen) / 8) - numEq;
}

inline void a3_to_a4(unsigned char * a4, unsigned char * a3) {
a4[0] = (a3[0] & 0xfc) >> 2;
a4[1] = ((a3[0] & 0x03) << 4) + ((a3[1] & 0xf0) >> 4);
a4[2] = ((a3[1] & 0x0f) << 2) + ((a3[2] & 0xc0) >> 6);
a4[3] = (a3[2] & 0x3f);
}

inline void a4_to_a3(unsigned char * a3, unsigned char * a4) {
a3[0] = (a4[0] << 2) + ((a4[1] & 0x30) >> 4);
a3[1] = ((a4[1] & 0xf) << 4) + ((a4[2] & 0x3c) >> 2);
a3[2] = ((a4[2] & 0x3) << 6) + a4[3];
}

inline unsigned char b64_lookup(char c) {
int i;
for(i = 0; i < 64; i++) {
if(b64_alphabet[i] == c) {
return i;
}
}

return -1;
}
75 changes: 75 additions & 0 deletions Base64.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#ifndef _BASE64_H
#define _BASE64_H

/* b64_alphabet:
* Description: Base64 alphabet table, a mapping between integers
* and base64 digits
* Notes: This is an extern here but is defined in Base64.c
*/
extern const char b64_alphabet[];

/* base64_encode:
* Description:
* Encode a string of characters as base64
* Parameters:
* output: the output buffer for the encoding, stores the encoded string
* input: the input buffer for the encoding, stores the binary to be encoded
* inputLen: the length of the input buffer, in bytes
* Return value:
* Returns the length of the encoded string
* Requirements:
* 1. output must not be null or empty
* 2. input must not be null
* 3. inputLen must be greater than or equal to 0
*/
int base64_encode(char *output, char *input, int inputLen);

/* base64_decode:
* Description:
* Decode a base64 encoded string into bytes
* Parameters:
* output: the output buffer for the decoding,
* stores the decoded binary
* input: the input buffer for the decoding,
* stores the base64 string to be decoded
* inputLen: the length of the input buffer, in bytes
* Return value:
* Returns the length of the decoded string
* Requirements:
* 1. output must not be null or empty
* 2. input must not be null
* 3. inputLen must be greater than or equal to 0
*/
int base64_decode(char *output, char *input, int inputLen);

/* base64_enc_len:
* Description:
* Returns the length of a base64 encoded string whose decoded
* form is inputLen bytes long
* Parameters:
* inputLen: the length of the decoded string
* Return value:
* The length of a base64 encoded string whose decoded form
* is inputLen bytes long
* Requirements:
* None
*/
int base64_enc_len(int inputLen);

/* base64_dec_len:
* Description:
* Returns the length of the decoded form of a
* base64 encoded string
* Parameters:
* input: the base64 encoded string to be measured
* inputLen: the length of the base64 encoded string
* Return value:
* Returns the length of the decoded form of a
* base64 encoded string
* Requirements:
* 1. input must not be null
* 2. input must be greater than or equal to zero
*/
int base64_dec_len(char *input, int inputLen);

#endif // _BASE64_H
16 changes: 8 additions & 8 deletions MD5.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,10 @@ static unsigned char PADDING[64] = {
};

/* F, G, H and I are basic MD5 functions. */
#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
#define H(x, y, z) ((x) ^ (y) ^ (z))
#define I(x, y, z) ((y) ^ ((x) | (~z)))
#define MF(x, y, z) (((x) & (y)) | ((~x) & (z)))
#define MG(x, y, z) (((x) & (z)) | ((y) & (~z)))
#define MH(x, y, z) ((x) ^ (y) ^ (z))
#define MI(x, y, z) ((y) ^ ((x) | (~z)))

/* ROTATE_LEFT rotates x left n bits. */
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
Expand All @@ -68,22 +68,22 @@ static unsigned char PADDING[64] = {
* Rotation is separate from addition to prevent recomputation.
*/
#define FF(a, b, c, d, x, s, ac) { \
(a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) += MF ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define GG(a, b, c, d, x, s, ac) { \
(a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) += MG ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define HH(a, b, c, d, x, s, ac) { \
(a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) += MH ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define II(a, b, c, d, x, s, ac) { \
(a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) += MI ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
Expand Down
62 changes: 10 additions & 52 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,65 +1,23 @@
## Websocket Server for Arduino
## Websocket Client and Server for Arduino

This is a simple library that implements a Websocket server running on an Arduino. The Websocket specification is a moving target and this implementation is based on a [draft specification][1] which expired i February 2011. But this is the version that has support by a few browsers and so is what's usable now. The protocol will change slightly as indicated by the [current draft][2] into something that looks nicer to your eye, if you're into staring at Request Headers.

The implementation in this library has restrictions as the Arduino platform resources are quite limited. Most notably, the handshake headers are case sensitive while the specification state they should be case _insensitive_, and, after a header field name and it's trailing colon, there **must** be one and only one space before the header value while the specification only "prefers" one space but allows 0-n.

This will most likely not be a problem as current implementations in Safari, Chrome and Firefox formats the request in that particular way. See below for what it looks like.

_Header example:_

Upgrade: WebSocket
Connection: Upgrade
Host: example.com
Origin: http://example.com
Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5
Sec-WebSocket-Key2: 12998 5 Y3 1 .P00

^n:ds[4U

The last line, the somewhat cryptic `^n:ds[4U` is the third key sent by the client, is always 8 bytes long and not terminated by a newline.

_Response example:_

Upgrade: WebSocket
Connection: Upgrade
Sec-WebSocket-Origin: http://example.com
Sec-WebSocket-Location: ws://example.com/demo
Sec-WebSocket-Protocol: sample

8jKS'y:G*Co,Wxa-

The last line is the MD5 Digest, always 16 bytes and not terminated by a newline.

The next version of the specification will get rid of those butt-ugly keys, keeping everything readable. Or at least not looking broken like the keys above.

Other limitations and assumptions in the current implementation:

* The server requires all received data to be UTF-8 only.
* The server only accepts frames starting with 0x00 and ending with 0xFF. That is, the alternative frame definition in the websocket standard with 0xFF followed by specified length, is not supported. (If I got that part of the spec right.)
* The server assumes all data sent to client is UTF-8 only. No encoding is done by the server.
* The server handles incoming frames of limited lengths (default setting is 256). Remember, an Arduino is not an ocean of free memory cells. Don't even think about trying 2^32 - 1...
This is a simple library that implements a Websocket client and server running on an Arduino.

### Getting started

The example websockets.html file should be served from any web server you have access to. Remember to change the ws://... URL in it to your Arduino.
The example WebSocketServer.html file should be served from any web server you have access to. Remember to change the URL in it to your Arduino. The examples are based on using a WiFly wireless card to connect. If you're using ethernet instead you'll need to swap out the client class.

Install the library to "libraries" folder in your Arduino sketchbook folder. For example, on a mac that's `~/Documents/Arduino/libraries`.

Try one of the examples to ensure that things work.
Try the examples to ensure that things work.

Start playing with your own code!

### The Future

As the Websocket specification matures, the implementations in various browsers will follow and this library will need to change accordingly. I will try to keep up, but I'm not monitoring the Websocket World daily so do file an issue for attention. Or bugs! Or corrections on where I've failed to understand the specification! Or any wish!

_Enjoy!_

Oh by the way, quoting myself:
### Notes
Inside of the WebSocketServer class there is a compiler directive to turn on support for the older "Hixie76" standard. If you don't need it, leave it off as it greatly increases the memory required.

> Don't forget to place a big ***fat*** disclaimer in the README. There is most certainly bugs in the code and I may well have misunderstood some things in the specification which I have only skimmed through and not slept with. So _please_ do not use this code in appliancies where people or pets could get hurt, like space shuttles, dog tread mills and Large Hadron Colliders.
Because of limitations of the current Arduino platform (Uno at the time of this writing), this library does not support messages larger than 65535 characters. In addition, this library only supports single-frame text frames. It currently does not recognize continuation frames, binary frames, or ping/pong frames.

### Credits
Thank you to github user ejeklint for the excellent starting point for this library. From his original Hixie76-only code I was able to add support for RFC 6455 and create the WebSocket client.

[1]: http://www.whatwg.org/specs/web-socket-protocol/ "Protol version implemented here"
[2]: http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol "Latest specification"
- Branden
Loading