Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: HTTPD_sample ch5_mbed_lightweight_Web_server_dust_sensor ch8_mbed_websocket_client Renesas_GR-Peach_LCD
Revision 0:d18dff347122, committed 2013-11-13
- Comitter:
- okini3939
- Date:
- Wed Nov 13 01:58:04 2013 +0000
- Commit message:
- 1st build;
Changed in this revision
diff -r 000000000000 -r d18dff347122 CBuffer.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/CBuffer.h Wed Nov 13 01:58:04 2013 +0000
@@ -0,0 +1,75 @@
+/* Copyright (C) 2012 mbed.org, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef CIRCBUFFER_H_
+#define CIRCBUFFER_H_
+
+template <class T>
+class CircBuffer {
+public:
+ CircBuffer(int length) {
+ write = 0;
+ read = 0;
+ size = length + 1;
+ buf = (T *)malloc(size * sizeof(T));
+ };
+
+ bool isFull() {
+ return (((write + 1) % size) == read);
+ };
+
+ bool isEmpty() {
+ return (read == write);
+ };
+
+ void queue(T k) {
+ if (isFull()) {
+ read++;
+ read %= size;
+ }
+ buf[write++] = k;
+ write %= size;
+ }
+
+ void flush() {
+ read = 0;
+ write = 0;
+ }
+
+
+ uint32_t available() {
+ return (write >= read) ? write - read : size - read + write;
+ };
+
+ bool dequeue(T * c) {
+ bool empty = isEmpty();
+ if (!empty) {
+ *c = buf[read++];
+ read %= size;
+ }
+ return(!empty);
+ };
+
+private:
+ volatile uint32_t write;
+ volatile uint32_t read;
+ uint32_t size;
+ T * buf;
+};
+
+#endif
diff -r 000000000000 -r d18dff347122 HTTPD.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/HTTPD.cpp Wed Nov 13 01:58:04 2013 +0000
@@ -0,0 +1,120 @@
+/* Copyright (C) 2013 Hiroshi Suga, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "HTTPD.h"
+
+HTTPD * HTTPD::_inst;
+
+HTTPD::HTTPD () {
+ _inst = this;
+ memset(_state, 0, sizeof(_state));
+ _handler_count = 0;
+}
+
+int HTTPD::start (int port) {
+ int i;
+
+ for (i = 0; i < HTTPD_MAX_CLIENTS; i ++) {
+ _state[i].buf = new CircBuffer<char>(HTTPD_BUF_SIZE);
+ _state[i].thread = new Thread(child, (void*)i, osPriorityNormal, HTTPD_STACK_SIZE);
+ _state[i].client = new TCPSocketConnection;
+ }
+#ifdef HTTPD_ENABLE_CLOSER
+ _state[HTTPD_MAX_CLIENTS].thread = new Thread(closer, (void*)HTTPD_MAX_CLIENTS, osPriorityNormal, 128);
+ _state[HTTPD_MAX_CLIENTS].client = new TCPSocketConnection;
+#endif
+
+ _server.bind(port);
+ _server.listen();
+ _daemon = new Thread(daemon, NULL, osPriorityNormal, 256);
+ return 0;
+}
+
+void HTTPD::daemon (void const *args) {
+ HTTPD *httpd = HTTPD::getInstance();
+ int i, t = 0;
+
+ INFO("Wait for new connection...\r\n");
+ for (;;) {
+ if (t >= 0) {
+ if (httpd->_server.accept(*httpd->_state[t].client) == 0) {
+ INFO("accept %d\r\n", t);
+ httpd->_state[t].thread->signal_set(1);
+ }
+ } else {
+#ifdef HTTPD_ENABLE_CLOSER
+ if (httpd->_server.accept(*httpd->_state[HTTPD_MAX_CLIENTS].client) == 0) {
+ INFO("accept x\r\n");
+ httpd->_state[HTTPD_MAX_CLIENTS].thread->signal_set(1);
+ }
+#endif
+ }
+
+ t = -1;
+ for (i = 0; i < HTTPD_MAX_CLIENTS; i ++) {
+ if (httpd->_state[i].thread->get_state() == Thread::WaitingAnd) {
+ if (t < 0) t = i; // next empty thread
+ }
+ }
+ }
+}
+
+void HTTPD::child (void const *arg) {
+ HTTPD *httpd = HTTPD::getInstance();
+ int id = (int)arg;
+ int i, n;
+ char buf[HTTPD_BUF_SIZE];
+
+ for (;;) {
+ Thread::signal_wait(1);
+
+ httpd->_state[id].mode = MODE_REQUEST;
+ httpd->_state[id].buf->flush();
+ httpd->_state[id].keepalive = 0;
+ INFO("Connection from %s\r\n", httpd->_state[id].client->get_address());
+ httpd->_state[id].client->set_blocking(false, HTTPD_TIMEOUT);
+ for (;;) {
+ if (! httpd->_state[id].client->is_connected()) break;
+
+ n = httpd->_state[id].client->receive(buf, sizeof(buf));
+ if (n < 0) break;
+ buf[n] = 0;
+// DBG("Recv %d '%s'", n, buf);
+
+ for (i = 0; i < n; i ++) {
+ httpd->recvData(id, buf[i]);
+ }
+ }
+
+ httpd->_state[id].client->close();
+ INFO("Close %s\r\n", httpd->_state[id].client->get_address());
+ }
+}
+
+void HTTPD::closer (void const *arg) {
+ HTTPD *httpd = HTTPD::getInstance();
+ int id = (int)arg;
+
+ for (;;) {
+ Thread::signal_wait(1);
+
+ httpd->_state[id].client->close();
+ INFO("Close %s\r\n", httpd->_state[id].client->get_address());
+ }
+}
+
diff -r 000000000000 -r d18dff347122 HTTPD.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/HTTPD.h Wed Nov 13 01:58:04 2013 +0000
@@ -0,0 +1,171 @@
+/* Copyright (C) 2013 Hiroshi Suga, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef HTTPD_H
+#define HTTPD_H
+
+#include "mbed.h"
+#include "rtos.h"
+#include "EthernetInterface.h"
+#include "CBuffer.h"
+
+//#define DEBUG
+
+#define HTTPD_PORT 80
+#define HTTPD_MAX_CLIENTS 2
+#define HTTPD_KEEPALIVE 10
+#define HTTPD_TIMEOUT 15000
+#define HTTPD_MAX_HANDLES 10
+
+#define HTTPD_CMD_SIZE 100
+#define HTTPD_BUF_SIZE 256
+#define HTTPD_STACK_SIZE (1024 * 6)
+//#define HTTPD_ENABLE_CLOSER
+
+//Debug is disabled by default
+#if defined(DEBUG) and (!defined(TARGET_LPC11U24))
+#define DBG(x, ...) std::printf("[DBG]" x "\r\n", ##__VA_ARGS__);
+#define WARN(x, ...) std::printf("[WARN]" x "\r\n", ##__VA_ARGS__);
+#define ERR(x, ...) std::printf("[ERR]" x "\r\n", ##__VA_ARGS__);
+#define INFO(x, ...) std::printf("[INFO]" x "\r\n", ##__VA_ARGS__);
+#else
+#define DBG(x, ...)
+#define WARN(x, ...)
+#define ERR(x, ...)
+#define INFO(x, ...)
+#endif
+
+
+class HTTPD {
+public:
+
+ enum Request {
+ REQ_HTTPGET,
+ REQ_HTTPPOST,
+ REQ_PUT,
+ };
+
+ enum Mode {
+ MODE_REQUEST,
+ MODE_REQSTR,
+ MODE_HEADER,
+ MODE_BODY,
+ MODE_ENTER,
+ MODE_ERROR,
+ MODE_WEBSOCKET,
+ MODE_WEBSOCKET_MASK,
+ MODE_WEBSOCKET_BODY,
+ MODE_WEBSOCKET_ENTER,
+ };
+
+ struct STATE {
+ Thread *thread;
+ TCPSocketConnection *client;
+ volatile Request req;
+ volatile Mode mode;
+ CircBuffer <char>*buf;
+ char uri[HTTPD_CMD_SIZE];
+ char *filename;
+ char *querystring;
+ int enter;
+ int length;
+ int n;
+ int keepalive;
+ int websocket;
+ char *websocket_key;
+ int websocket_opcode;
+ int websocket_flg;
+ char websocket_mask[4];
+ int websocket_payload;
+ int (*sendws)(int id, const char *buf, int len, const char *mask);
+ };
+
+ HTTPD ();
+
+ int start (int port = HTTPD_PORT);
+
+ // --- HTTPD_req.cpp ---
+ void httpdError (int id, int err);
+
+ // --- HTTPD_ws.cpp ---
+ static int sendWebsocket (int id, const char *buf, int len, const char *mask = NULL);
+
+ // --- HTTPD_util.cpp ---
+ char *getUri (int id);
+ char *getFilename (int id);
+ char *getQueryString (int id);
+ int send (int id, const char *body, int len, const char *header = NULL);
+ int receive (int id, char *buf, int len);
+ int attach (const char *uri, const char *dir);
+ int attach (const char *uri, void (*funcCgi)(int id));
+ int base64encode (const char *input, int length, char *output, int len);
+ int urlencode (const char *str, char *buf, int len);
+ int urldecode (const char *str, char *buf, int len);
+
+ static HTTPD * getInstance() {
+ return _inst;
+ };
+
+private :
+ static HTTPD *_inst;
+ Thread *_daemon;
+ TCPSocketServer _server;
+
+#ifdef HTTPD_ENABLE_CLOSER
+ struct STATE _state[HTTPD_MAX_CLIENTS + 1];
+#else
+ struct STATE _state[HTTPD_MAX_CLIENTS];
+#endif
+
+ struct HANDLER {
+ char *uri;
+ char *dir;
+ void (*funcCgi)(int id);
+ } _handler[HTTPD_MAX_HANDLES];
+
+ int _handler_count;
+
+ static void daemon (void const *arg);
+ static void child (void const *arg);
+ static void closer (void const *arg);
+
+ // --- HTTPD_req.cpp ---
+ int httpdFile (int id, char *dir);
+ void recvData (int id, char c);
+ int parseRequest (int id);
+ int parseHeader (int id);
+ void reqContentLength (int id, const char *buf);
+ void reqConnection (int id, const char *buf);
+ void reqUpgrade (int id, const char *buf);
+ void reqWebSocketVersion (int id, const char *buf);
+ void reqWebSocketKey (int id, const char *buf);
+
+ // --- HTTPD_ws.cpp ---
+ void recvWS (int id, char c);
+ int parseWebsocket (int id);
+ int acceptWebsocket (int id);
+
+ // --- HTTPD_util.cpp ---
+ int getHandler (const char *uri);
+ char *mimetype (char *file);
+ int strnicmp (const char *p1, const char *p2, int n);
+ int from_hex (int ch);
+ int to_hex (int code);
+};
+
+#endif
diff -r 000000000000 -r d18dff347122 HTTPD_req.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/HTTPD_req.cpp Wed Nov 13 01:58:04 2013 +0000
@@ -0,0 +1,333 @@
+/* Copyright (C) 2013 Hiroshi Suga, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "HTTPD.h"
+
+
+int HTTPD::httpdFile (int id, char *dir) {
+ FILE *fp;
+ int i, len;
+ char buf[HTTPD_BUF_SIZE];
+ char file[HTTPD_CMD_SIZE];
+
+ INFO("httpdFile %d %s", id, dir);
+
+ strcpy(file, dir);
+ strcat(file, _state[id].filename);
+ if (file[strlen(file) - 1] == '/') {
+ strcat(file, "index.html");
+ }
+ DBG("file: %s\r\n", file);
+
+ fp = fopen(file, "r");
+ if (fp) {
+ strcpy(buf, "HTTP/1.1 200 OK\r\n");
+ _state[id].client->send_all(buf, strlen(buf));
+ {
+ // file size
+ i = ftell(fp);
+ fseek(fp, 0, SEEK_END);
+ len = ftell(fp);
+ fseek(fp, i, SEEK_SET);
+ }
+
+ strcpy(buf, "Server: GSwifi httpd\r\n");
+ _state[id].client->send_all(buf, strlen(buf));
+ if (_state[id].keepalive) {
+ strcpy(buf, "Connection: Keep-Alive\r\n");
+ } else {
+ strcpy(buf, "Connection: close\r\n");
+ }
+ _state[id].client->send_all(buf, strlen(buf));
+ sprintf(buf, "Content-Type: %s\r\n", mimetype(file));
+ _state[id].client->send_all(buf, strlen(buf));
+ sprintf(buf, "Content-Length: %d\r\n\r\n", len);
+ _state[id].client->send_all(buf, strlen(buf));
+
+ for (;;) {
+ i = fread(buf, sizeof(char), sizeof(buf), fp);
+ if (i <= 0) break;
+ _state[id].client->send_all(buf, i);
+#if defined(TARGET_LPC1768) || defined(TARGET_LPC2368)
+ if (feof(fp)) break;
+#endif
+ }
+ fclose(fp);
+ return 0;
+ }
+
+ httpdError(id, 404);
+ return -1;
+}
+
+void HTTPD::httpdError (int id, int err) {
+ char buf[HTTPD_CMD_SIZE], msg[30];
+
+ switch (err) {
+ case 400:
+ strcpy(msg, "Bad Request");
+ break;
+ case 403:
+ strcpy(msg, "Forbidden");
+ break;
+ case 404:
+ strcpy(msg, "Not Found");
+ break;
+ case 500:
+ default:
+ strcpy(msg, "Internal Server Error");
+ break;
+ }
+ DBG("httpd error: %d %d %s\r\n", id, err, msg);
+
+ sprintf(buf, "HTTP/1.1 %d %s\r\n", err, msg);
+ _state[id].client->send_all(buf, strlen(buf));
+ strcpy(buf, "Content-Type: text/html\r\n\r\n");
+ _state[id].client->send_all(buf, strlen(buf));
+
+ sprintf(buf, "<html><head><title>%d %s</title></head>\r\n", err, msg);
+ _state[id].client->send_all(buf, strlen(buf));
+ sprintf(buf, "<body><h1>%s</h1></body></html>\r\n", msg);
+ _state[id].client->send_all(buf, strlen(buf));
+ wait_ms(100);
+ _state[id].client->close();
+// WARN("%d.%d.%d.%d ", _httpd[cid].host.getIp()[0], _httpd[cid].host.getIp()[1], _httpd[cid].host.getIp()[2], _httpd[cid].host.getIp()[3]);
+// WARN("%s %s %d %d -\r\n", _httpd[cid].type == GSPROT_HTTPGET ? "GET" : "POST", _httpd[cid].uri, _httpd[cid].length, err);
+}
+
+
+void HTTPD::recvData (int id, char c) {
+
+ switch (_state[id].mode) {
+ case MODE_REQUEST:
+ if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) {
+ _state[id].buf->flush();
+ _state[id].buf->queue(c);
+ _state[id].mode = MODE_REQSTR;
+ } else {
+ _state[id].buf->flush();
+ }
+ break;
+ case MODE_REQSTR:
+ switch (c) {
+ case 0:
+ break;
+ case 0x0a: // LF
+ case 0x0d: // CR
+ if (parseRequest(id)) {
+ _state[id].mode = MODE_REQSTR;
+ } else {
+ _state[id].mode = MODE_HEADER;
+ }
+ _state[id].enter = 0;
+ break;
+ default:
+ _state[id].buf->queue(c);
+ break;
+ }
+ break;
+ case MODE_HEADER:
+ switch (c) {
+ case 0:
+ break;
+ case 0x0a: // LF
+ case 0x0d: // CR
+ if (_state[id].buf->available() == 0) {
+ if ((_state[id].enter == 0x0d && c == 0x0a) || (_state[id].enter == 0x0a && c == 0x0a)) {
+ _state[id].buf->flush();
+ if (_state[id].websocket) {
+ INFO("MODE_WEBSOCKET");
+ acceptWebsocket(id);
+ _state[id].mode = MODE_WEBSOCKET;
+ } else
+ if (_state[id].length) {
+ INFO("MODE_BODY");
+ _state[id].mode = MODE_BODY;
+ } else {
+ INFO("MODE_ENTER");
+ _state[id].mode = MODE_ENTER;
+ }
+ }
+ _state[id].enter = c;
+ _state[id].buf->flush();
+ break;
+ }
+
+ parseHeader(id);
+ _state[id].enter = 0;
+ break;
+ default:
+ _state[id].buf->queue(c);
+ _state[id].enter = 0;
+ break;
+ }
+ break;
+ case MODE_BODY:
+ _state[id].buf->queue(c);
+ if (_state[id].buf->available() >= _state[id].length) {
+ _state[id].mode = MODE_ENTER;
+ }
+ break;
+ case MODE_WEBSOCKET:
+ case MODE_WEBSOCKET_MASK:
+ case MODE_WEBSOCKET_BODY:
+ recvWS(id, c);
+ break;
+ }
+
+ if (_state[id].mode == MODE_ENTER) {
+ int i = getHandler(_state[id].uri);
+ if (i >= 0) {
+ if (_handler[i].dir) {
+ // file
+ httpdFile(id, _handler[i].dir);
+ } else
+ if (_handler[i].funcCgi) {
+ // cgi
+ _handler[i].funcCgi(id);
+// _state[id].keepalive = 0;
+ } else {
+ httpdError(id, 403);
+ }
+ } else {
+ httpdError(id, 404);
+ }
+
+ if (_state[id].keepalive) {
+ DBG("keepalive %d", _state[id].keepalive);
+ _state[id].keepalive --;
+ } else {
+ _state[id].client->close();
+ }
+ _state[id].mode = MODE_REQUEST;
+ } else
+ if (_state[id].mode == MODE_WEBSOCKET_ENTER) {
+ parseWebsocket(id);
+ _state[id].mode = MODE_WEBSOCKET;
+ }
+}
+
+int HTTPD::parseRequest (int id) {
+ int i, j, len;
+ char buf[HTTPD_CMD_SIZE];
+
+ for (len = 0; len < sizeof(buf); len++) {
+ if (_state[id].buf->dequeue(&buf[len]) == false) break;
+ }
+ buf[len] = 0;
+
+ if (strnicmp(buf, "GET ", 4) == 0) {
+ _state[id].req = REQ_HTTPGET;
+ j = 4;
+ } else
+ if (strnicmp(buf, "POST ", 5) == 0) {
+ _state[id].req = REQ_HTTPPOST;
+ j = 5;
+ } else {
+ return -1;
+ }
+
+ for (i = 0; i < len - j; i ++) {
+ _state[id].uri[i] = buf[i + j];
+ if (buf[i + j] == ' ' || i >= sizeof(buf) - 1) {
+ _state[id].uri[i] = 0;
+ INFO("URI %d '%s'", _state[id].req, _state[id].uri);
+ _state[id].mode = MODE_HEADER;
+ _state[id].buf->flush();
+ _state[id].length = 0;
+ _state[id].n = 0;
+ _state[id].websocket = 0;
+ _state[id].filename = NULL;
+ _state[id].querystring = NULL;
+ break;
+ }
+ }
+
+ i = getHandler(_state[id].uri);
+ if (i >= 0) {
+ _state[id].filename = &_state[id].uri[strlen(_handler[i].uri)];
+ for (i = 0; i < strlen(_state[id].filename); i ++) {
+ if (_state[id].filename[i] == '?') {
+ _state[id].filename[i] = 0;
+ _state[id].querystring = _state[id].filename + i + 1;
+ break;
+ }
+ }
+ INFO("FILE '%s' QUERY '%s'", _state[id].filename, _state[id].querystring);
+ }
+ return 0;
+}
+
+#define HEADER_TABLE_NUM 5
+int HTTPD::parseHeader (int id) {
+ int i;
+ char buf[HTTPD_CMD_SIZE];
+ static const struct HEADER_TABLE {
+ const char header[24];
+ void (HTTPD::*func)(int id, const char*);
+ } header_table[HEADER_TABLE_NUM] = {
+ {"Content-Length:", &HTTPD::reqContentLength},
+ {"Connection:", &HTTPD::reqConnection},
+ {"Upgrade: websocket", &HTTPD::reqUpgrade},
+ {"Sec-WebSocket-Version:", &HTTPD::reqWebSocketVersion},
+ {"Sec-WebSocket-Key:", &HTTPD::reqWebSocketKey},
+ };
+ for (i = 0; i < sizeof(buf); i++) {
+ if (_state[id].buf->dequeue(&buf[i]) == false) break;
+ }
+ buf[i] = 0;
+
+ for (i = 0; i < HEADER_TABLE_NUM; i ++) {
+ if (strnicmp(buf, header_table[i].header, strlen(header_table[i].header)) == 0) {
+ DBG("parse header %d '%s'\r\n", i, buf);
+ if (header_table[i].func != NULL) {
+ (this->*(header_table[i].func))(id, buf);
+ }
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+void HTTPD::reqContentLength (int id, const char *buf) {
+ _state[id].length = atoi(&buf[16]);
+}
+
+void HTTPD::reqConnection (int id, const char *buf) {
+ if (strnicmp(&buf[12], "Keep-Alive", 10) == 0 && _state[id].keepalive == 0) {
+ _state[id].keepalive = HTTPD_KEEPALIVE;
+ } else {
+ _state[id].keepalive = 0;
+ }
+}
+
+void HTTPD::reqUpgrade (int id, const char *buf) {
+ if (! _state[id].websocket) _state[id].websocket = 1;
+}
+
+void HTTPD::reqWebSocketVersion (int id, const char *buf) {
+ _state[id].websocket = atoi(&buf[23]);
+}
+
+void HTTPD::reqWebSocketKey (int id, const char *buf) {
+ if (_state[id].websocket_key == NULL) {
+ _state[id].websocket_key = (char*)malloc(30);
+ }
+ strncpy(_state[id].websocket_key, &buf[19], 30);
+}
diff -r 000000000000 -r d18dff347122 HTTPD_util.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/HTTPD_util.cpp Wed Nov 13 01:58:04 2013 +0000
@@ -0,0 +1,232 @@
+/* Copyright (C) 2013 Hiroshi Suga, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "HTTPD.h"
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define MIMETABLE_NUM 9
+static const struct {
+ char ext[5];
+ char type[24];
+} mimetable[MIMETABLE_NUM] = {
+ {"txt", "text/plain"}, // default
+ {"html", "text/html"},
+ {"htm", "text/html"},
+ {"css", "text/css"},
+ {"js", "application/javascript"},
+ {"jpg", "image/jpeg"},
+ {"png", "image/png"},
+ {"gif", "image/gif"},
+ {"ico", "image/x-icon"},
+};
+
+char *HTTPD::getUri (int id) {
+ return _state[id].uri;
+}
+
+char *HTTPD::getFilename (int id) {
+ return _state[id].filename;
+}
+
+char *HTTPD::getQueryString (int id) {
+ return _state[id].querystring;
+}
+
+int HTTPD::receive (int id, char *buf, int len) {
+ int i;
+
+ for (i = 0; i < len; i ++) {
+ if (_state[id].buf->dequeue(&buf[i]) == false) break;
+ }
+ return i;
+}
+
+int HTTPD::send (int id, const char *body, int len, const char *header) {
+ char buf[HTTPD_CMD_SIZE];
+
+ strcpy(buf, "HTTP/1.1 200 OK\r\n");
+ _state[id].client->send_all(buf, strlen(buf));
+ strcpy(buf, "Server: GSwifi httpd\r\n");
+ _state[id].client->send_all(buf, strlen(buf));
+ if (_state[id].keepalive) {
+ strcpy(buf, "Connection: Keep-Alive\r\n");
+ } else {
+ strcpy(buf, "Connection: close\r\n");
+ }
+ _state[id].client->send_all(buf, strlen(buf));
+ if (header) {
+ _state[id].client->send_all((char*)header, strlen(header));
+ }
+ sprintf(buf, "Content-Length: %d\r\n\r\n", len);
+ _state[id].client->send_all(buf, strlen(buf));
+
+ return _state[id].client->send_all((char*)body, len);
+}
+
+int HTTPD::getHandler (const char *uri) {
+ int i;
+
+ for (i = 0; i < _handler_count; i ++) {
+ if (strncmp(uri, _handler[i].uri, strlen(_handler[i].uri)) == NULL) {
+ // found
+ return i;
+ }
+ }
+ return -1;
+}
+
+int HTTPD::attach (const char *uri, const char *dir) {
+ if (_handler_count < HTTPD_MAX_HANDLES) {
+ _handler[_handler_count].uri = (char*)malloc(strlen(uri) + 1);
+ strcpy(_handler[_handler_count].uri, uri);
+ _handler[_handler_count].dir = (char*)malloc(strlen(dir) + 1);
+ strcpy(_handler[_handler_count].dir, dir);
+ _handler[_handler_count].funcCgi = NULL;
+ _handler_count ++;
+ return 0;
+ } else {
+ return -1;
+ }
+}
+
+int HTTPD::attach (const char *uri, void (*funcCgi)(int)) {
+ if (_handler_count < HTTPD_MAX_HANDLES) {
+ _handler[_handler_count].uri = (char*)malloc(strlen(uri) + 1);
+ strcpy(_handler[_handler_count].uri, uri);
+ _handler[_handler_count].dir = NULL;
+ _handler[_handler_count].funcCgi = funcCgi;
+ _handler_count ++;
+ return 0;
+ } else {
+ return -1;
+ }
+}
+
+
+char *HTTPD::mimetype (char *file) {
+ int i, j;
+
+ for (i = 0; i < MIMETABLE_NUM; i ++) {
+ j = strlen(mimetable[i].ext);
+ if (file[strlen(file) - j - 1] == '.' &&
+ strnicmp(&file[strlen(file) - j], mimetable[i].ext, j) == NULL) {
+ return (char*)mimetable[i].type;
+ }
+ }
+ return (char*)mimetable[0].type;
+}
+
+int HTTPD::strnicmp (const char *p1, const char *p2, int n) {
+ int i, r = -1;
+ char c1, c2;
+
+ for (i = 0; i < n; i ++) {
+ c1 = (p1[i] >= 'a' && p1[i] <= 'z') ? p1[i] - ('a' - 'A'): p1[i];
+ c2 = (p2[i] >= 'a' && p2[i] <= 'z') ? p2[i] - ('a' - 'A'): p2[i];
+ r = c1 - c2;
+ if (r) break;
+ }
+ return r;
+}
+
+
+/* base64encode code from
+ * Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ */
+int HTTPD::base64encode (const char *input, int length, char *output, int len) {
+ static const char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+ unsigned int c, c1, c2, c3;
+
+ if (len < ((((length-1)/3)+1)<<2)) return -1;
+ for(unsigned int i = 0, j = 0; i<length; i+=3,j+=4) {
+ c1 = ((((unsigned char)*((unsigned char *)&input[i]))));
+ c2 = (length>i+1)?((((unsigned char)*((unsigned char *)&input[i+1])))):0;
+ c3 = (length>i+2)?((((unsigned char)*((unsigned char *)&input[i+2])))):0;
+
+ c = ((c1 & 0xFC) >> 2);
+ output[j+0] = base64[c];
+ c = ((c1 & 0x03) << 4) | ((c2 & 0xF0) >> 4);
+ output[j+1] = base64[c];
+ c = ((c2 & 0x0F) << 2) | ((c3 & 0xC0) >> 6);
+ output[j+2] = (length>i+1)?base64[c]:'=';
+ c = (c3 & 0x3F);
+ output[j+3] = (length>i+2)?base64[c]:'=';
+ }
+ output[(((length-1)/3)+1)<<2] = '\0';
+ return 0;
+}
+
+
+/* urlencode code from
+ * Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ */
+int HTTPD::urlencode (const char *str, char *buf, int len) {
+// char *pstr = str, *buf = (char*)malloc(strlen(str) * 3 + 1), *pbuf = buf;
+ const char *pstr = str;
+ char *pbuf = buf;
+
+ if (len < (strlen(str) * 3 + 1)) return -1;
+ while (*pstr) {
+ if (isalnum(*pstr) || *pstr == '-' || *pstr == '_' || *pstr == '.' || *pstr == '~')
+ *pbuf++ = *pstr;
+ else if (*pstr == ' ')
+ *pbuf++ = '+';
+ else
+ *pbuf++ = '%', *pbuf++ = to_hex(*pstr >> 4), *pbuf++ = to_hex(*pstr & 15);
+ pstr++;
+ }
+ *pbuf = '\0';
+ return 0;
+}
+
+/* urldecode code from
+ * Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
+ */
+int HTTPD::urldecode (const char *str, char *buf, int len) {
+// char *pstr = str, *buf = (char*)malloc(strlen(str) + 1), *pbuf = buf;
+ const char *pstr = str;
+ char *pbuf = buf;
+
+ if (len < (strlen(str) / 3 - 1)) return -1;
+ while (*pstr) {
+ if (*pstr == '%') {
+ if (pstr[1] && pstr[2]) {
+ *pbuf++ = from_hex(pstr[1]) << 4 | from_hex(pstr[2]);
+ pstr += 2;
+ }
+ } else if (*pstr == '+') {
+ *pbuf++ = ' ';
+ } else {
+ *pbuf++ = *pstr;
+ }
+ pstr++;
+ }
+ *pbuf = '\0';
+ return 0;
+}
+
+int HTTPD::from_hex (int ch) {
+ return isdigit(ch) ? ch - '0' : tolower(ch) - 'a' + 10;
+}
+
+int HTTPD::to_hex (int code) {
+ static char hex[] = "0123456789abcdef";
+ return hex[code & 15];
+}
diff -r 000000000000 -r d18dff347122 HTTPD_ws.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/HTTPD_ws.cpp Wed Nov 13 01:58:04 2013 +0000
@@ -0,0 +1,198 @@
+/* Copyright (C) 2013 Hiroshi Suga, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "HTTPD.h"
+#include "sha1.h"
+
+void HTTPD::recvWS (int id, char c) {
+
+ switch (_state[id].mode) {
+ case MODE_WEBSOCKET:
+ if (_state[id].n == 0) {
+ // flag
+ _state[id].websocket_opcode = c & 0x0f;
+ _state[id].websocket_flg = c << 8;
+ _state[id].n ++;
+ } else
+ if (_state[id].n == 1) {
+ // length 7bit
+ _state[id].websocket_flg |= c;
+ _state[id].length = c & 0x7f;
+ _state[id].n ++;
+ if (_state[id].length < 126) {
+ _state[id].n = 0;
+ if (_state[id].length) {
+ if (_state[id].websocket_flg & 0x0080) {
+ _state[id].mode = MODE_WEBSOCKET_MASK;
+ } else {
+ _state[id].mode = MODE_WEBSOCKET_BODY;
+ }
+ } else {
+ _state[id].mode = MODE_WEBSOCKET_ENTER;
+ }
+ DBG("ws length %d\r\n", _state[id].length);
+ }
+ } else {
+ // length 16bit,64bit
+ if (_state[id].n == 2) {
+ _state[id].length = c;
+ _state[id].n ++;
+ } else
+ if (_state[id].n < 9 && (_state[id].websocket_flg & 0x7f) == 127) {
+ // 64bit
+ _state[id].length = (_state[id].length << 8) | c;
+ _state[id].n ++;
+ } else {
+ // end
+ _state[id].length = (_state[id].length << 8) | c;
+ _state[id].n = 0;
+ if (_state[id].websocket_flg & 0x0080) {
+ _state[id].mode = MODE_WEBSOCKET_MASK;
+ } else {
+ _state[id].mode = MODE_WEBSOCKET_BODY;
+ }
+ DBG("ws length2 %d\r\n", _state[id].length);
+ }
+ }
+ break;
+ case MODE_WEBSOCKET_MASK:
+ // masking key
+ _state[id].websocket_mask[_state[id].n] = c;
+ _state[id].n ++;
+ if (_state[id].n >= 4) {
+ _state[id].n = 0;
+ _state[id].mode = MODE_WEBSOCKET_BODY;
+ DBG("ws mask\r\n");
+ }
+ break;
+ case MODE_WEBSOCKET_BODY:
+ // payload
+ if (_state[id].websocket_flg & 0x0080) {
+ // un-mask
+ _state[id].buf->queue(c ^ _state[id].websocket_mask[_state[id].n & 0x03]);
+ } else {
+ _state[id].buf->queue(c);
+ }
+ _state[id].n ++;
+ if (_state[id].n >= _state[id].length) {
+ _state[id].mode = MODE_WEBSOCKET_ENTER;
+ }
+ break;
+ }
+}
+
+int HTTPD::parseWebsocket (int id) {
+ int i;
+
+ DBG("ws opcode %d\r\n", _state[id].websocket_opcode);
+ switch (_state[id].websocket_opcode) {
+ case 0x00: // continuation
+ break;
+ case 0x01: // text
+ case 0x02: // binary
+ i = getHandler(_state[id].uri);
+ if (i >= 0) {
+ if (_handler[i].funcCgi) {
+ // cgi
+ _handler[i].funcCgi(id);
+ }
+ }
+ break;
+ case 0x08: // close
+ _state[id].client->close();
+ break;
+ case 0x09: // ping
+ {
+ char pong[_state[id].n + 2];
+ pong[0] = 0x8a;
+ pong[1] = 0x04;
+ for (i = 0; i < _state[id].length; i ++) {
+ if (_state[id].buf->dequeue(&pong[i + 2]) == false) break;
+ }
+ _state[id].client->send_all(pong, _state[id].length + 2);
+ }
+ break;
+ case 0x0a: // pong
+ break;
+ default:
+ break;
+ }
+ _state[id].n = 0;
+ _state[id].length = 0;
+ return 0;
+}
+
+int HTTPD::acceptWebsocket (int id) {
+ char buf[HTTPD_CMD_SIZE], buf2[HTTPD_CMD_SIZE];
+
+ DBG("websocket accept: %d\r\n", id);
+
+ strcpy(buf, "HTTP/1.1 101 Switching Protocols\r\n");
+ _state[id].client->send_all(buf, strlen(buf));
+ strcpy(buf, "Upgrade: websocket\r\n");
+ _state[id].client->send_all(buf, strlen(buf));
+ strcpy(buf, "Connection: Upgrade\r\n");
+ _state[id].client->send_all(buf, strlen(buf));
+
+ strcpy(buf, "Sec-WebSocket-Accept: ");
+ _state[id].client->send_all(buf, strlen(buf));
+ strcpy(buf, _state[id].websocket_key);
+ strcat(buf, "258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
+ sha1(buf, strlen(buf), buf2);
+ base64encode(buf2, 20, buf, sizeof(buf));
+ _state[id].client->send_all(buf, strlen(buf));
+ strcpy(buf, "\r\n\r\n");
+ _state[id].client->send_all(buf, strlen(buf));
+ _state[id].client->set_blocking(true, HTTPD_TIMEOUT * 100);
+ return 0;
+}
+
+int HTTPD::sendWebsocket (int id, const char *buf, int len, const char *mask) {
+ HTTPD *httpd = HTTPD::getInstance();
+ int i = 0, r;
+ char tmp[10];
+
+ tmp[i++] = 0x81; // single, text frame
+ if (len < 126) {
+ tmp[i++] = (mask == NULL ? 0 : 0x80) | len;
+ } else {
+ tmp[i++] = (mask == NULL ? 0 : 0x80) | 126;
+ tmp[i++] = (len >> 8) & 0xff;
+ tmp[i++] = len & 0xff;
+ }
+ if (mask) {
+ memcpy(&tmp[i], mask, 4);
+ i += 4;
+ }
+ r = httpd->_state[id].client->send_all(tmp, i);
+
+ if (r >= 0) {
+ if (mask) {
+ char tmp2[len];
+ for (i = 0; i < len; i ++) {
+ tmp2[i] = buf[i] ^ mask[i & 0x03];
+ }
+ r = httpd->_state[id].client->send_all(tmp2, len);
+ } else {
+ r = httpd->_state[id].client->send_all((char*)buf, len);
+ }
+ }
+ return r;
+}
+
+
diff -r 000000000000 -r d18dff347122 sha1.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/sha1.cpp Wed Nov 13 01:58:04 2013 +0000
@@ -0,0 +1,364 @@
+/*
+ * source from http://www.ipa.go.jp/security/rfc/RFC3174JA.html
+ */
+#include "sha1.h"
+
+/*
+ * Define the SHA1 circular left shift macro
+ */
+#define SHA1CircularShift(bits,word) \
+ (((word) << (bits)) | ((word) >> (32-(bits))))
+
+/* Local Function Prototyptes */
+void SHA1PadMessage(SHA1Context *);
+void SHA1ProcessMessageBlock(SHA1Context *);
+
+/*
+ * SHA1Reset
+ *
+ * Description:
+ * This function will initialize the SHA1Context in preparation
+ * for computing a new SHA1 message digest.
+ *
+ * Parameters:
+ * context: [in/out]
+ * The context to reset.
+ *
+ * Returns:
+ * sha Error Code.
+ *
+ */
+int SHA1Reset(SHA1Context *context)
+{
+ if (!context)
+ {
+ return shaNull;
+ }
+
+ context->Length_Low = 0;
+ context->Length_High = 0;
+ context->Message_Block_Index = 0;
+
+ context->Intermediate_Hash[0] = 0x67452301;
+ context->Intermediate_Hash[1] = 0xEFCDAB89;
+ context->Intermediate_Hash[2] = 0x98BADCFE;
+ context->Intermediate_Hash[3] = 0x10325476;
+ context->Intermediate_Hash[4] = 0xC3D2E1F0;
+
+ context->Computed = 0;
+ context->Corrupted = 0;
+
+ return shaSuccess;
+}
+
+/*
+ * SHA1Result
+ *
+ * Description:
+ * This function will return the 160-bit message digest into the
+ * Message_Digest array provided by the caller.
+ * NOTE: The first octet of hash is stored in the 0th element,
+ * the last octet of hash in the 19th element.
+ *
+ * Parameters:
+ * context: [in/out]
+ * The context to use to calculate the SHA-1 hash.
+ * Message_Digest: [out]
+ * Where the digest is returned.
+ *
+ * Returns:
+ * sha Error Code.
+ *
+ */
+int SHA1Result( SHA1Context *context,
+ uint8_t Message_Digest[SHA1HashSize])
+{
+ int i;
+
+ if (!context || !Message_Digest)
+ {
+ return shaNull;
+ }
+
+ if (context->Corrupted)
+ {
+ return context->Corrupted;
+ }
+
+ if (!context->Computed)
+ {
+ SHA1PadMessage(context);
+ for(i=0; i<64; ++i)
+ {
+ /* message may be sensitive, clear it out */
+ context->Message_Block[i] = 0;
+ }
+ context->Length_Low = 0; /* and clear length */
+ context->Length_High = 0;
+ context->Computed = 1;
+ }
+
+ for(i = 0; i < SHA1HashSize; ++i)
+ {
+ Message_Digest[i] = context->Intermediate_Hash[i>>2]
+ >> 8 * ( 3 - ( i & 0x03 ) );
+ }
+
+ return shaSuccess;
+}
+
+/*
+ * SHA1Input
+ *
+ * Description:
+ * This function accepts an array of octets as the next portion
+ * of the message.
+ *
+ * Parameters:
+ * context: [in/out]
+ * The SHA context to update
+ * message_array: [in]
+ * An array of characters representing the next portion of
+ * the message.
+ * length: [in]
+ * The length of the message in message_array
+ *
+ * Returns:
+ * sha Error Code.
+ *
+ */
+int SHA1Input( SHA1Context *context,
+ const uint8_t *message_array,
+ unsigned length)
+{
+ if (!length)
+ {
+ return shaSuccess;
+ }
+
+ if (!context || !message_array)
+ {
+ return shaNull;
+ }
+
+ if (context->Computed)
+ {
+ context->Corrupted = shaStateError;
+ return shaStateError;
+ }
+
+ if (context->Corrupted)
+ {
+ return context->Corrupted;
+ }
+ while(length-- && !context->Corrupted)
+ {
+ context->Message_Block[context->Message_Block_Index++] =
+ (*message_array & 0xFF);
+
+ context->Length_Low += 8;
+ if (context->Length_Low == 0)
+ {
+ context->Length_High++;
+ if (context->Length_High == 0)
+ {
+ /* Message is too long */
+ context->Corrupted = 1;
+ }
+ }
+
+ if (context->Message_Block_Index == 64)
+ {
+ SHA1ProcessMessageBlock(context);
+ }
+
+ message_array++;
+ }
+
+ return shaSuccess;
+}
+
+/*
+ * SHA1ProcessMessageBlock
+ *
+ * Description:
+ * This function will process the next 512 bits of the message
+ * stored in the Message_Block array.
+ *
+ * Parameters:
+ * None.
+ *
+ * Returns:
+ * Nothing.
+ *
+ * Comments:
+ * Many of the variable names in this code, especially the
+ * single character names, were used because those were the
+ * names used in the publication.
+ *
+ *
+ */
+void SHA1ProcessMessageBlock(SHA1Context *context)
+{
+ const uint32_t K[] = { /* Constants defined in SHA-1 */
+ 0x5A827999,
+ 0x6ED9EBA1,
+ 0x8F1BBCDC,
+ 0xCA62C1D6
+ };
+ int t; /* Loop counter */
+ uint32_t temp; /* Temporary word value */
+ uint32_t W[80]; /* Word sequence */
+ uint32_t A, B, C, D, E; /* Word buffers */
+
+ /*
+ * Initialize the first 16 words in the array W
+ */
+ for(t = 0; t < 16; t++)
+ {
+ W[t] = context->Message_Block[t * 4] << 24;
+ W[t] |= context->Message_Block[t * 4 + 1] << 16;
+ W[t] |= context->Message_Block[t * 4 + 2] << 8;
+ W[t] |= context->Message_Block[t * 4 + 3];
+ }
+
+ for(t = 16; t < 80; t++)
+ {
+ W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);
+ }
+
+ A = context->Intermediate_Hash[0];
+ B = context->Intermediate_Hash[1];
+ C = context->Intermediate_Hash[2];
+ D = context->Intermediate_Hash[3];
+ E = context->Intermediate_Hash[4];
+
+ for(t = 0; t < 20; t++)
+ {
+ temp = SHA1CircularShift(5,A) +
+ ((B & C) | ((~B) & D)) + E + W[t] + K[0];
+ E = D;
+ D = C;
+ C = SHA1CircularShift(30,B);
+ B = A;
+ A = temp;
+ }
+
+ for(t = 20; t < 40; t++)
+ {
+ temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1];
+ E = D;
+ D = C;
+ C = SHA1CircularShift(30,B);
+ B = A;
+ A = temp;
+ }
+
+ for(t = 40; t < 60; t++)
+ {
+ temp = SHA1CircularShift(5,A) +
+ ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2];
+ E = D;
+ D = C;
+ C = SHA1CircularShift(30,B);
+ B = A;
+ A = temp;
+ }
+
+ for(t = 60; t < 80; t++)
+ {
+ temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3];
+ E = D;
+ D = C;
+ C = SHA1CircularShift(30,B);
+ B = A;
+ A = temp;
+ }
+
+ context->Intermediate_Hash[0] += A;
+ context->Intermediate_Hash[1] += B;
+ context->Intermediate_Hash[2] += C;
+ context->Intermediate_Hash[3] += D;
+ context->Intermediate_Hash[4] += E;
+
+ context->Message_Block_Index = 0;
+}
+
+
+/*
+ * SHA1PadMessage
+ *
+ * Description:
+ * According to the standard, the message must be padded to an even
+ * 512 bits. The first padding bit must be a '1'. The last 64
+ * bits represent the length of the original message. All bits in
+ * between should be 0. This function will pad the message
+ * according to those rules by filling the Message_Block array
+ * accordingly. It will also call the ProcessMessageBlock function
+ * provided appropriately. When it returns, it can be assumed that
+ * the message digest has been computed.
+ *
+ * Parameters:
+ * context: [in/out]
+ * The context to pad
+ * ProcessMessageBlock: [in]
+ * The appropriate SHA*ProcessMessageBlock function
+ * Returns:
+ * Nothing.
+ *
+ */
+
+void SHA1PadMessage(SHA1Context *context)
+{
+ /*
+ * Check to see if the current message block is too small to hold
+ * the initial padding bits and length. If so, we will pad the
+ * block, process it, and then continue padding into a second
+ * block.
+ */
+ if (context->Message_Block_Index > 55)
+ {
+ context->Message_Block[context->Message_Block_Index++] = 0x80;
+ while(context->Message_Block_Index < 64)
+ {
+ context->Message_Block[context->Message_Block_Index++] = 0;
+ }
+
+ SHA1ProcessMessageBlock(context);
+
+ while(context->Message_Block_Index < 56)
+ {
+ context->Message_Block[context->Message_Block_Index++] = 0;
+ }
+ }
+ else
+ {
+ context->Message_Block[context->Message_Block_Index++] = 0x80;
+ while(context->Message_Block_Index < 56)
+ {
+ context->Message_Block[context->Message_Block_Index++] = 0;
+ }
+ }
+
+ /*
+ * Store the message length as the last 8 octets
+ */
+ context->Message_Block[56] = context->Length_High >> 24;
+ context->Message_Block[57] = context->Length_High >> 16;
+ context->Message_Block[58] = context->Length_High >> 8;
+ context->Message_Block[59] = context->Length_High;
+ context->Message_Block[60] = context->Length_Low >> 24;
+ context->Message_Block[61] = context->Length_Low >> 16;
+ context->Message_Block[62] = context->Length_Low >> 8;
+ context->Message_Block[63] = context->Length_Low;
+
+ SHA1ProcessMessageBlock(context);
+}
+
+void sha1 (const char *input, int len, char *output) {
+ SHA1Context sha;
+
+ SHA1Reset(&sha);
+ SHA1Input(&sha, (unsigned char*)input, len);
+ SHA1Result(&sha, (uint8_t*)output);
+ }
diff -r 000000000000 -r d18dff347122 sha1.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/sha1.h Wed Nov 13 01:58:04 2013 +0000
@@ -0,0 +1,78 @@
+/*
+ * source from http://www.ipa.go.jp/security/rfc/RFC3174JA.html
+ */
+/*
+ * sha1.h
+ *
+ * Description:
+ * This is the header file for code which implements the Secure
+ * Hashing Algorithm 1 as defined in FIPS PUB 180-1 published
+ * April 17, 1995.
+ *
+ * Many of the variable names in this code, especially the
+ * single character names, were used because those were the names
+ * used in the publication.
+ *
+ * Please read the file sha1.c for more information.
+ *
+ */
+
+#ifndef _SHA1_H_
+#define _SHA1_H_
+
+#include "mbed.h"
+/*
+ * If you do not have the ISO standard stdint.h header file, then you
+ * must typdef the following:
+ * name meaning
+ * uint32_t unsigned 32 bit integer
+ * uint8_t unsigned 8 bit integer (i.e., unsigned char)
+ * int_least16_t integer of >= 16 bits
+ *
+ */
+
+#ifndef _SHA_enum_
+#define _SHA_enum_
+enum
+{
+ shaSuccess = 0,
+ shaNull, /* Null pointer parameter */
+ shaInputTooLong, /* input data too long */
+ shaStateError /* called Input after Result */
+};
+#endif
+#define SHA1HashSize 20
+
+/*
+ * This structure will hold context information for the SHA-1
+ * hashing operation
+ */
+typedef struct SHA1Context
+{
+ uint32_t Intermediate_Hash[SHA1HashSize/4]; /* Message Digest */
+
+ uint32_t Length_Low; /* Message length in bits */
+ uint32_t Length_High; /* Message length in bits */
+
+ /* Index into message block array */
+ int_least16_t Message_Block_Index;
+ uint8_t Message_Block[64]; /* 512-bit message blocks */
+
+ int Computed; /* Is the digest computed? */
+ int Corrupted; /* Is the message digest corrupted? */
+} SHA1Context;
+
+/*
+ * Function Prototypes
+ */
+
+int SHA1Reset( SHA1Context *);
+int SHA1Input( SHA1Context *,
+ const uint8_t *,
+ unsigned int);
+int SHA1Result( SHA1Context *,
+ uint8_t Message_Digest[SHA1HashSize]);
+
+
+void sha1 (const char *input, int len, char *output);
+#endif