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.
Fork of HTTPD by
Revision 3:ebea8e061ae6, committed 2017-06-30
- Comitter:
- gulchi
- Date:
- Fri Jun 30 08:17:01 2017 +0000
- Parent:
- 2:fcd20e2cd110
- Child:
- 4:41ee166a0e6c
- Commit message:
- Working ModBusTCP Interface with Mbed-os
Changed in this revision
--- a/HTTPD_req.cpp Thu Jun 29 10:17:29 2017 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,332 +0,0 @@
-/* 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(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(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(buf, strlen(buf));
- sprintf(buf, "Content-Type: %s\r\n", mimetype(file));
- _state[id].client->send(buf, strlen(buf));
- sprintf(buf, "Content-Length: %d\r\n\r\n", len);
- _state[id].client->send(buf, strlen(buf));
-
- for (;;) {
- i = fread(buf, sizeof(char), sizeof(buf), fp);
- if (i <= 0) break;
- _state[id].client->send(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(buf, strlen(buf));
- strcpy(buf, "Content-Type: text/html\r\n\r\n");
- _state[id].client->send(buf, strlen(buf));
-
- sprintf(buf, "<html><head><title>%d %s</title></head>\r\n", err, msg);
- _state[id].client->send(buf, strlen(buf));
- sprintf(buf, "<body><h1>%s</h1></body></html>\r\n", msg);
- _state[id].client->send(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);
- printf("handler = %d, uri = %s\r\n", i, _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);
-}
--- a/HTTPD_util.cpp Thu Jun 29 10:17:29 2017 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,256 +0,0 @@
-/* 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(buf, strlen(buf));
- strcpy(buf, "Server: GSwifi httpd\r\n");
- _state[id].client->send(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(buf, strlen(buf));
- if (header) {
- _state[id].client->send((char*)header, strlen(header));
- }
- sprintf(buf, "Content-Length: %d\r\n\r\n", len);
- _state[id].client->send(buf, strlen(buf));
-
- return _state[id].client->send((char*)body, len);
-}
-
-int HTTPD::sendstr (int id, const char *buf) {
- return _state[id].client->send((char*)buf, strlen(buf));
-}
-
-
-int HTTPD::hprintf(int id, const char* format, ...) {
- //FIX ME: This could result in memory overruns if the buffer size is exceeded
- static Mutex _mtx;
- static char _buf[1024];
-
- std::va_list arg;
-
- _mtx.lock();
-
- va_start(arg, format);
- vsprintf(_buf, format, arg);
- va_end(arg);
-
- int r = _state[id].client->send(_buf, strlen(_buf));
-
- _mtx.unlock();
- return r;
-}
-
-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];
-}
--- a/HTTPD_ws.cpp Thu Jun 29 10:17:29 2017 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,198 +0,0 @@
-/* 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(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(buf, strlen(buf));
- strcpy(buf, "Upgrade: websocket\r\n");
- _state[id].client->send(buf, strlen(buf));
- strcpy(buf, "Connection: Upgrade\r\n");
- _state[id].client->send(buf, strlen(buf));
-
- strcpy(buf, "Sec-WebSocket-Accept: ");
- _state[id].client->send(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(buf, strlen(buf));
- strcpy(buf, "\r\n\r\n");
- _state[id].client->send(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(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(tmp2, len);
- } else {
- r = httpd->_state[id].client->send((char*)buf, len);
- }
- }
- return r;
-}
-
-
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ModBus-Req.cpp Fri Jun 30 08:17:01 2017 +0000
@@ -0,0 +1,96 @@
+
+
+#include "ModBus-TCP.h"
+
+void Modbus::recvData (int id, char buffer[], int size) {
+
+ int bytes_rec;
+ int returnLength;
+ unsigned short transaction_number;
+ unsigned short protokoll;
+ unsigned short number_of_bytes;
+ char adress;
+ int port;
+
+ transaction_number = buffer[0] + (buffer[1] << 8);
+ protokoll = buffer[2] + (buffer[3] << 8);
+ number_of_bytes = (buffer[4] << 8) + buffer[5] ;
+ adress = buffer[6];
+
+ if(protokoll != 0x0000) {
+ printf("No Modbus protkoll");
+ }
+
+ #ifdef DEBUG
+ //printf("tn: 0x%x, p: 0x%x, nb: %i, a: %i\r\n", transaction_number, protokoll, number_of_bytes, adress);
+ #endif
+
+ for(int i=0; i<8; i++) {
+ _state[id].start_message[i] = buffer[i];
+ }
+
+ //returnLength = mb_handle_data(buffer, number_of_bytes);
+
+ char fc;
+ fc = buffer[7];
+
+
+ unsigned short start_adress;
+ unsigned short number_of_registers;
+
+
+ switch(fc) {
+ case 0x04: //return mb_read_register(data_in, length);
+ //Read Requet received
+ // Getting Start Address and Length
+
+ //DBG("Read Request received\r\n");
+
+ start_adress = (buffer[8] << 8) + buffer[9];
+ number_of_registers = (buffer[10] << 8) + buffer[11];
+
+
+ int i = getHandler(0);
+ //DBG("GetHandler %i",i);
+
+ if(number_of_registers < 0x0001 || number_of_registers > 0x007d ) {
+ mb_exception_handler(id, buffer, number_of_registers, 0x03);
+ }
+
+ if(start_adress >= MODBUS_MAX_REGISTER) {
+ mb_exception_handler(id, buffer, number_of_registers, 0x02);
+ }
+
+ if(number_of_registers < 0x0001 || number_of_registers + start_adress > MODBUS_MAX_REGISTER) {
+ mb_exception_handler(id, buffer, number_of_registers, 0x04);
+ }
+
+
+
+ _handler[i].funcCgiRead(id, start_adress, number_of_registers);
+ break;
+ case 0x10: //return mb_write_register(data_in, length);
+ break;
+
+ default: mb_exception_handler(id, buffer, size, 0x01);
+
+ }
+}
+
+int Modbus::mb_exception_handler(int id, char data_in[], unsigned short length, char error) {
+ unsigned short number_of_bytes;
+
+ data_in[7] += 0x80;
+ data_in[8] += error;
+
+ number_of_bytes = 3;
+
+ data_in[4] = (char)(number_of_bytes >> 8);
+ data_in[5] = (char)(number_of_bytes & 0x00ff);
+
+ sendToClient(id, data_in, number_of_bytes + 7);
+
+ return 0;
+}
+
+
--- a/ModBus-TCP.cpp Thu Jun 29 10:17:29 2017 +0000
+++ b/ModBus-TCP.cpp Fri Jun 30 08:17:01 2017 +0000
@@ -26,13 +26,13 @@
_handler_count = 0;
}
-int Modbus::start (NetworkStack *ns, int port) {
+int Modbus::start (EthernetInterface *ns, int port) {
int i;
m_ns = ns;
for (i = 0; i < MODBUS_MAX_CLIENTS; i ++) {
- _state[i].buf = new CircBuffer<char>(MODBUS_BUF_SIZE);
+ // _state[i].buf = new CircBuffer<char>(MODBUS_BUF_SIZE);
_state[i].thread = new Thread(osPriorityNormal, MODBUS_STACK_SIZE);
_state[i].client = new TCPSocket();
_state[i].thread->start(callback(child, (void*)i));
@@ -46,7 +46,7 @@
_server.open(m_ns);
_server.bind(port);
_server.set_blocking(true);
- _server.listen();
+ _server.listen(MODBUS_MAX_CLIENTS);
_daemon = new Thread(osPriorityNormal, MODBUS_STACK_SIZE);
_daemon->start(Modbus::daemon);
return 0;
@@ -56,25 +56,27 @@
Modbus *modbus = Modbus::getInstance();
int i, t = 0;
- INFO("Wait for new connection...\r\n");
+
for (;;) {
+ //DBG("Wait for new connection... child %i",t);
if (t >= 0) {
if (modbus->_server.accept(modbus->_state[t].client) == 0) {
INFO("accept %d\r\n", t);
- modbus->_state[t].thread->signal_set(1);
+ modbus->_state[t].thread->signal_set(0x1);
}
} else {
#ifdef HTTPD_ENABLE_CLOSER
if (modbus->_server.accept(modbus->_state[MODBUS_MAX_CLIENTS].client) == 0) {
INFO("accept x\r\n");
- modbus->_state[MODBUS_MAX_CLIENTS].thread->signal_set(1);
+ modbus->_state[MODBUS_MAX_CLIENTS].thread->signal_set(0x1);
}
#endif
}
t = -1;
for (i = 0; i < MODBUS_MAX_CLIENTS; i ++) {
- if (modbus->_state[i].thread->get_state() == Thread::WaitingAnd) {
+ //DBG("Child %i in State : %u", i, modbus->_state[i].thread->get_state());
+ if ( modbus->_state[i].thread->get_state() == Thread::WaitingThreadFlag) {
if (t < 0) t = i; // next empty thread
}
}
@@ -82,42 +84,52 @@
}
void Modbus::child (void const *arg) {
- Modbus *modbus = ModBus::getInstance();
+ Modbus *modbus = Modbus::getInstance();
int id = (int)arg;
int i, n;
- char buf[ModBus_BUF_SIZE];
+ char buf[MODBUS_BUF_SIZE];
for (;;) {
- Thread::signal_wait(1);
- modbus->_state[id].mode = MODE_REQUEST;
- modbus->_state[id].buf->flush();
- modbus->_state[id].keepalive = 0;
- INFO("Connection from client\r\n");
+ //DBG("child %i waiting for connection",id);
+ Thread::signal_wait(0x1);
+
+
+
+ INFO("Connection from client on child %i", id);
// INFO("Connection from %s\r\n", httpd->_state[id].client->get_ip_address());
- modbus->_state[id].client->set_blocking(false);
- modbus->_state[id].client->set_timeout(HTTPD_TIMEOUT);
-
+ modbus->_state[id].client->set_blocking(true);
+ modbus->_state[id].client->set_timeout(15000);
+ time_t t1 = time(NULL);
for (;;) {
//if (! httpd->_state[id].client->is_connected()) break;
-
+ modbus->_state[id].client->set_blocking(true);
+ modbus->_state[id].client->set_timeout(15000);
n = modbus->_state[id].client->recv(buf, sizeof(buf));
if (n < 0 ) {
- printf("HTTPD::child breaking n = %d\r\n", n);
+ printf("Modbus::child breaking n = %d\r\n", n);
break;
}
- buf[n] = 0;
- //DBG("Recv %d ", n);
- DBG("Recv %d '%s'", n, buf);
-
- for (i = 0; i < n; i ++) {
- modbus->recvData(id, buf[i]);
+
+ if( n > 0 ) { // We received something
+
+ t1 = time(NULL);
+
+ //DBG("Recv %d bytes Content: %x", n, buf)
+
+ modbus->recvData(id, buf, n);
}
+
+ if(abs((int)(time(NULL) - t1))> 15) {
+ DBG("Timeout in child %i",id);
+ break;
+ }
+
}
modbus->_state[id].client->close(); // Needs to bere moved
- INFO("Closed client connection\r\n");
+ INFO("Closed client connection");
//INFO("Close %s\r\n", httpd->_state[id].client->get_ip_address());
}
}
--- a/ModBus-TCP.h Thu Jun 29 10:17:29 2017 +0000
+++ b/ModBus-TCP.h Fri Jun 30 08:17:01 2017 +0000
@@ -22,21 +22,24 @@
#include "mbed.h"
#include "rtos.h"
#include "NetworkStack.h"
-#include "EthInterface.h"
-#include "CBuffer.h"
+#include "EthernetInterface.h"
+//#include "CBuffer.h"
-#define DEBUG
+//#define DEBUG
#define MODBUS_TCP_PORT 502
-#define MODBUS_MAX_CLIENTS 5
+#define MODBUS_MAX_CLIENTS 3
#define MODBUS_KEEPALIVE 10
-#define MODBUS_TIMEOUT 15000
-#define MODBUS_MAX_HANDLES 10
+#define MODBUS_TIMEOUT 50000
+#define MODBUS_MAX_HANDLES 2
+
+#define MODBUS_MAX_REGISTER 256
+
#define MODBUS_CMD_SIZE 100
-#define MODBUS_BUF_SIZE 256
+#define MODBUS_BUF_SIZE 128
#define MODBUS_STACK_SIZE (1024 * 6)
-//#define HTTPD_ENABLE_CLOSER
+//efine HTTPD_ENABLE_CLOSER
//Debug is disabled by default
#if defined(DEBUG) and (!defined(TARGET_LPC11U24))
@@ -55,58 +58,32 @@
class Modbus {
public:
- 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;
TCPSocket *client;
- volatile Request req;
- volatile Mode mode;
- CircBuffer <char>*buf;
+ //volatile Request req;
+ //CircBuffer <char>*buf;
-
- char *querystring;
- int enter;
- int length;
- int n;
- int keepalive;
+ char start_message[8];
};
Modbus ();
- int start (NetworkStack *ns, int port = MODBUS_TCP_PORT);
+ int start (EthernetInterface *ns, int port = MODBUS_TCP_PORT);
// --- HTTPD_req.cpp ---
void httpdError (int id, int err);
// --- HTTPD_util.cpp ---
-
-
-
TCPSocket *getClientSocket(int id) {
- if (id >= HTTPD_MAX_CLIENTS) return NULL;
+ if (id >= MODBUS_MAX_CLIENTS) return NULL;
return _state[id].client;
}
- int send (int id, const char *body, int len, const char *header = NULL);
- int sendstr (int id, const char *buf);
- int hprintf(int id, const char* format, ...);
- 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 send (int id, unsigned short buffer[], int len);
+
+ int attachRead (void (*funcCgi)(int id, unsigned short start_address, unsigned short length), int startRegister = 0);
static Modbus * getInstance() {
return _inst;
@@ -117,7 +94,7 @@
Thread *_daemon;
TCPServer _server;
- NetworkStack *m_ns;
+ EthernetInterface *m_ns;
#ifdef MODBUS_ENABLE_CLOSER
struct STATE _state[MODBUS_MAX_CLIENTS + 1];
@@ -126,9 +103,9 @@
#endif
struct HANDLER {
- char *uri;
- char *dir;
- void (*funcCgi)(int id);
+ int startRegister;
+ void (*funcCgiRead)(int id, unsigned short start_address, unsigned short length);
+ void (*funcCgiWrite)(int id);
} _handler[MODBUS_MAX_HANDLES];
int _handler_count;
@@ -138,22 +115,15 @@
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);
+
+ void recvData (int id, char buf[], int size);
+ int mb_exception_handler(int id, char data_in[], unsigned short length, char error);
// --- HTTPD_util.cpp ---
- int getHandler (const char *uri);
- char *mimetype (char *file);
- int strnicmp (const char *p1, const char *p2, int n);
+ int getHandler (int startRegister);
+ int sendToClient(int id, char buffer[], unsigned short len);
int from_hex (int ch);
int to_hex (int code);
};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ModBus_util.cpp Fri Jun 30 08:17:01 2017 +0000
@@ -0,0 +1,104 @@
+/* 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 "ModBus-TCP.h"
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+
+int Modbus::getHandler (int startRegister) {
+ int i;
+
+ for (i = 0; i < _handler_count; i ++) {
+ if (_handler[i].startRegister == startRegister) {
+ // found
+ return i;
+ }
+ }
+ return -1;
+}
+
+
+int Modbus::attachRead (void (*funcCgi)(int, unsigned short, unsigned short), int startRegister) {
+ if (_handler_count < MODBUS_MAX_HANDLES) {
+ _handler[_handler_count].startRegister = startRegister;
+ _handler[_handler_count].funcCgiRead = funcCgi;
+ _handler_count ++;
+ return 0;
+ } else {
+ return -1;
+ }
+}
+
+
+int Modbus::send (int id, unsigned short buffer[], int len) {
+
+ char out[MODBUS_BUF_SIZE];
+
+
+ // Build MBAP Header
+ //Transaction Number :: Copy from Org message
+ out[0] = _state[id].start_message[0];
+ out[1] = _state[id].start_message[1];
+
+ //Protcoll Identifier :: Always 0x0000
+ out[2] = 0x00;
+ out[3] = 0x00;
+
+ // Length (bytes to follow after length bytes) of TCP Frame
+ out[4] = (char)(((len*2)+3)>> 8);
+ out[5] = (char)(((len*2)+3) & 0x00ff);
+
+ //unit identifier (normally 0xff, but 0x00 is allowed
+ out[6] = 0xff;
+
+ //MBAP Header build finished
+
+ // Now the ModBus response
+ //Function code :: Copy from org message
+ out[7] = _state[id].start_message[7];
+
+ //Byte count of Modbus response
+ out[8] = len*2;
+
+ for(int i=0; i<len; i++) {
+ out[(i*2)+9] = (char)(buffer[i] >> 8);
+ out[(i*2)+10] = (char)(buffer[i] & 0x00ff);
+ }
+
+
+
+ DBG("sending anser on child %i", id);
+ return _state[id].client->send(out, (len*2)+9);
+}
+
+int Modbus::sendToClient(int id, char buffer[], unsigned short len) {
+ return _state[id].client->send(buffer, len);
+ }
+
+
+int Modbus::from_hex (int ch) {
+ return isdigit(ch) ? ch - '0' : tolower(ch) - 'a' + 10;
+}
+
+int Modbus::to_hex (int code) {
+ static char hex[] = "0123456789abcdef";
+ return hex[code & 15];
+}
