HTTP Server, WebSocket support
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