├── LICENSE ├── Makefile ├── README.md ├── ReleaseNotes.md ├── apps ├── Makefile ├── api_server │ ├── Makefile │ ├── api_server.c │ ├── db_plugin.h │ ├── db_plugin_sqlite.c │ ├── sqlite3.c │ ├── sqlite3.h │ ├── unit_test.sh │ └── web_root │ │ └── index.html └── load_balancer │ ├── Dockerfile │ ├── Makefile │ ├── README.md │ ├── load_balancer.c │ └── unit_test.sh ├── examples ├── Makefile ├── arduino_restful_client │ ├── Makefile │ ├── README.md │ └── arduino_restful_client.ino ├── arduino_restful_server │ ├── Makefile │ ├── README.md │ └── arduino_restful_server.ino ├── captive_dns_server │ ├── Makefile │ └── captive_dns_server.c ├── coap_client │ ├── Makefile │ └── coap_client.c ├── coap_server │ ├── Makefile │ └── coap_server.c ├── http_client │ ├── Makefile │ └── http_client.c ├── json_rpc_server │ ├── Makefile │ └── json_rpc_server.c ├── mqtt_broker │ ├── Makefile │ └── mqtt_broker.c ├── mqtt_client │ ├── Makefile │ └── mqtt_client.c ├── multithreaded_restful_server │ ├── Makefile │ └── multithreaded_restful_server.c ├── netcat │ ├── Makefile │ └── nc.c ├── publish_subscribe │ ├── Makefile │ └── publish_subscribe.c ├── raspberry_pi_mjpeg_led │ ├── Makefile │ ├── README.adoc │ ├── cloud_side.c │ ├── device_side.c │ ├── docs │ │ └── arch.png │ └── web_root │ │ ├── doc.html │ │ ├── docs │ │ └── arch.png │ │ ├── framework7.min.css │ │ ├── framework7.min.js │ │ └── index.html ├── restful_client │ ├── Makefile │ └── restful_client.c ├── restful_server │ ├── Makefile │ ├── index.html │ └── restful_server.c ├── restful_server_s3 │ ├── Makefile │ ├── README.md │ ├── index.html │ └── restful_server_s3.c ├── rules.mk ├── settings_panel_for_a_device │ ├── Makefile │ ├── settings_panel.c │ └── web_root │ │ ├── fossa.jpg │ │ ├── index.shtml │ │ └── jquery-1.11.3.min.js ├── simplest_web_server │ ├── Makefile │ └── simplest_web_server.c ├── tcp_echo_server │ ├── Makefile │ └── echo_server.c └── websocket_chat │ ├── Makefile │ ├── index.html │ └── websocket_chat.c ├── fossa.c ├── fossa.h ├── platforms ├── Makefile ├── arduino_common │ ├── avrdebug.cpp │ ├── avrdebug.h │ ├── avrlibc_compat.cpp │ └── avrlibc_compat.h ├── arduino_ethernet_W5100 │ ├── Makefile │ ├── avrsupport.cpp │ ├── avrsupport.h │ └── src │ │ ├── W5100_sockets.cpp │ │ └── W5100_sockets.h └── arduino_wifi_CC3000 │ ├── Makefile │ ├── adafruit_CC3000_lib_fossa │ ├── Adafruit_CC3000.cpp │ ├── Adafruit_CC3000.h │ ├── Adafruit_CC3000_Server.cpp │ ├── Adafruit_CC3000_Server.h │ ├── README.md │ ├── ccspi.cpp │ ├── ccspi.h │ ├── library.json │ ├── library.properties │ ├── license.txt │ └── utility │ │ ├── cc3000_common.cpp │ │ ├── cc3000_common.h │ │ ├── data_types.h │ │ ├── debug.cpp │ │ ├── debug.h │ │ ├── error_codes.h │ │ ├── evnt_handler.cpp │ │ ├── evnt_handler.h │ │ ├── hci.cpp │ │ ├── hci.h │ │ ├── host_driver_version.h │ │ ├── netapp.cpp │ │ ├── netapp.h │ │ ├── nvmem.cpp │ │ ├── nvmem.h │ │ ├── security.cpp │ │ ├── security.h │ │ ├── sntp.cpp │ │ ├── sntp.h │ │ ├── socket.cpp │ │ ├── socket.h │ │ ├── wlan.cpp │ │ └── wlan.h │ ├── avrsupport.cpp │ ├── avrsupport.h │ └── src │ ├── CC3000_utils.cpp │ └── CC3000_utils.h ├── src ├── CPPLINT.cfg ├── Makefile ├── coap.c ├── coap.h ├── common.h ├── dns-server.c ├── dns-server.h ├── dns.c ├── dns.h ├── http.c ├── http.h ├── internal.h ├── json-rpc.c ├── json-rpc.h ├── modules.mk ├── mqtt-broker.c ├── mqtt-broker.h ├── mqtt.c ├── mqtt.h ├── multithreading.c ├── net.c ├── net.h ├── resolv.c ├── resolv.h ├── util.c └── util.h └── test ├── Makefile ├── ca.pem ├── client.pem ├── data ├── auth │ ├── a.txt │ └── passwords.txt ├── cgi │ └── index.cgi ├── dav │ ├── a.txt │ └── hidden_file.txt ├── dir_no_index │ └── some_file ├── dir_with_index │ └── index.html ├── dummy.xml ├── multipart.txt ├── range.txt ├── rewrites │ ├── foo.com │ │ └── index.html │ └── msg.txt └── ssi │ ├── f1.txt │ ├── index.shtml │ └── nested.shtml ├── osdep.h ├── server.pem ├── test_util.c ├── test_util.h ├── unit_test.c └── unit_test.h /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Cesanta Software Limited 2 | All rights reserved 3 | 4 | This software is dual-licensed: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License version 2 as 6 | published by the Free Software Foundation. For the terms of this 7 | license, see . 8 | 9 | You are free to use this software under the terms of the GNU General 10 | Public License, but WITHOUT ANY WARRANTY; without even the implied 11 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 12 | See the GNU General Public License for more details. 13 | 14 | Alternatively, you can license this software under a commercial 15 | license, as set out in . 16 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2014 Cesanta Software 2 | # All rights reserved 3 | 4 | SUBDIRS = test examples apps 5 | 6 | .PHONY: $(SUBDIRS) 7 | 8 | all: $(SUBDIRS) 9 | 10 | $(SUBDIRS): %: 11 | @$(MAKE) -C $@ 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Fossa: Multi-Protocol Networking Library 2 | 3 | # Note: As of September 21st 2015, Fossa project has been merged back into [Mongoose](http://t.sidekickopen21.com/e1t/c/5/f18dQhb0S7lM8dDMPbW2n0x6l2B9nMJW7t5XX45w2sgKVcVW4q2BgH-gMQszCH1tQDwf61QVLl03?t=https%3A%2F%2Fgithub.com%2Fcesanta%2Fmongoose&si=4999990023290880&pi=5cbfa88b-4d9d-475f-f33d-494b2b8f6ccf) project 4 | 5 | ![](https://img.shields.io/badge/license-GPL_2-green.svg "License") 6 | 7 | [Fossa](https://www.cesanta.com/fossa) is a 8 | multi-protocol networking library written in C. 9 | It provides easy to use event-driven interface that allows to implement 10 | network protocols or scalable network applications with little effort. 11 | Fossa helps developers to manage the complexity of network programming 12 | and let them concentrate on the logic, saving time and money. 13 | 14 | Fossa has built-in support for several protocols, like 15 | HTTP, Websocket, MQTT, mDNS. Example applications include 16 | Websocket-based chat server, JSON-RPC server, 17 | database server with RESTful API, MQTT broker, netcat with SSL and hexdump, 18 | Raspberry PI camera video feed + led control, and more. 19 | 20 | Fossa is ideal for the embedded environments, it has been designed as 21 | an open source platform for connecting devices and bringing them online. 22 | 23 | ## Features 24 | 25 | * Cross-platform: works on Linux/UNIX, QNX, eCos, Windows, Android, iPhone, etc 26 | * Single-threaded, asynchronous, non-blocking core with simple event-based API 27 | * Builtin protocols: 28 | - plain TCP, plain UDP, SSL/TLS (over TCP, one-way or two-way) 29 | - HTTP client, HTTP server 30 | - Websocket client, Websocket server 31 | - JSON-RPC client, JSON-RPC server 32 | - MQTT client, MQTT broker 33 | - CoAP client, CoAP server 34 | - DNS client, DNS server, async DNS resolver 35 | * Tiny static and run-time footprint 36 | * Source code is both ISO C and ISO C++ compliant 37 | * Very easy to integrate: just copy 38 | [fossa.c](https://raw.githubusercontent.com/cesanta/fossa/master/fossa.c) and 39 | [fossa.h](https://raw.githubusercontent.com/cesanta/fossa/master/fossa.h) 40 | files to your build tree 41 | * Extensively tested and production-ready, trusted by many blue chip businesses 42 | 43 | ## Examples & Documentation 44 | 45 | - [User Guide](https://docs.cesanta.com/fossa) - Detailed User Guide and API reference 46 | - [examples](examples) - Collection of well-commented examples. To build any example, 47 | go into respective directory and type `make` 48 | 49 | ## Contributions 50 | 51 | People who have agreed to the 52 | [Cesanta CLA](https://docs.cesanta.com/contributors_la.shtml) 53 | can make contributions. Note that the CLA isn't a copyright 54 | _assigment_ but rather a copyright _license_. 55 | You retain the copyright on your contributions. 56 | 57 | ## License 58 | 59 | Fossa is released under 60 | [GNU GPL v.2](http://www.gnu.org/licenses/old-licenses/gpl-2.0.html). 61 | Businesses have an option to get non-restrictive, royalty-free commercial 62 | license and professional support from [Cesanta](https://www.cesanta.com). 63 | -------------------------------------------------------------------------------- /ReleaseNotes.md: -------------------------------------------------------------------------------- 1 | # Fossa Release Notes 2 | 3 | ## Release 2.0, 2015-01-19 4 | 5 | - Project renamed to Fossa 6 | - Simplifications 7 | - Modularisation 8 | - Lots of examples (Raspberry Pi, load balancer, RPC, ...) 9 | - Many HTTP improvements forward ported from Mongoose. 10 | - Embed dependencies (to https://github.com/cesanta/frozen[frozen]) 11 | - Async DNS client 12 | - DNS server 13 | - MQTT client (only QoS 0) 14 | - MQTT broker (in progress) 15 | - HTTP digest auth (#184) 16 | - API documentation 17 | - Build system overhaul 18 | - Continuous integration with CircleCI 19 | - Increased test coverage (97%) and report on coveralls.io 20 | - Changed wildcard bind syntax to `:` 21 | - Added `ns_connect_http()` helper function (#132) 22 | - Added `query_string` to parsed HTTP message (#99) 23 | - Added websocket defragmentation capability (02717d4) 24 | - Auto-PING idle websocket connections (#46) 25 | - Introduced ns_connection::proto_handler (87d46da) 26 | - Redefine SSL API (ee7847a) 27 | - Changed HTTP API to let setting HTTP to e.g. serial connection (ac02967) 28 | - QNX SSL upload fix (909df4f) 29 | - Fix binding to ipv6 wildcard (#2) 30 | - Set http_message::message.len correctly for replies with no Content-Length (#135) 31 | - Correct ID generation in RPC reply (#73) 32 | - Fix handling of incorrectly encoded URIs (#44) 33 | - Fix unintuitive order of NS_CLOSE and NS_HTTP_REPLY (#20) 34 | 35 | [issues resolved](https://github.com/cesanta/fossa/issues?q=milestone%3A"Release+2.0") | 36 | [pull requests](https://github.com/cesanta/fossa/pulls?q=created%3A>%3D2014-05-22++merged%3A<%3D2015-01-19) | 37 | [git tag](https://github.com/cesanta/fossa/releases/tag/2.0) | 38 | [full diff](https://github.com/cesanta/fossa/compare/1.1...2.0) 39 | 40 | ## Release 1.1, 2014-05-22 41 | 42 | [pull requests](https://github.com/cesanta/fossa/pulls?q=created%3A>%3D2014-03-03++merged%3A<%3D2014-05-22) | 43 | [git tag](https://github.com/cesanta/fossa/releases/tag/1.1) | 44 | [full diff](https://github.com/cesanta/fossa/compare/1.0...1.1) 45 | -------------------------------------------------------------------------------- /apps/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2014 Cesanta Software 2 | # All rights reserved 3 | 4 | SUBDIRS = $(sort $(dir $(wildcard */))) 5 | X = $(SUBDIRS) 6 | 7 | .PHONY: $(SUBDIRS) 8 | 9 | all: $(SUBDIRS) 10 | 11 | $(SUBDIRS): 12 | @$(MAKE) -C $@ 13 | 14 | clean: 15 | for d in $(SUBDIRS) ; do $(MAKE) -C $$d clean ; done 16 | -------------------------------------------------------------------------------- /apps/api_server/Makefile: -------------------------------------------------------------------------------- 1 | PROG = api_server 2 | SOURCES = $(PROG).c sqlite3.c db_plugin_sqlite.c ../../fossa.c 3 | CFLAGS = -W -Wall -pthread $(CFLAGS_EXTRA) 4 | 5 | ifeq ($(OS), Windows_NT) 6 | else 7 | UNAME_S := $(shell uname -s) 8 | ifeq ($(UNAME_S), Linux) 9 | CFLAGS += -ldl -lm 10 | endif 11 | endif 12 | 13 | all: $(PROG) 14 | 15 | $(PROG): $(SOURCES) 16 | $(CC) $(SOURCES) -o $@ $(CFLAGS) 17 | 18 | $(PROG).exe: $(SOURCES) 19 | cl $(SOURCES) /I.. /MD /Fe$@ 20 | 21 | test: $(PROG) 22 | sh unit_test.sh $$(pwd)/$(PROG) 23 | 24 | clean: 25 | rm -rf *.gc* *.dSYM *.exe *.obj *.o a.out $(PROG) 26 | -------------------------------------------------------------------------------- /apps/api_server/api_server.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 Cesanta Software Limited 3 | * All rights reserved 4 | */ 5 | 6 | #include "db_plugin.h" 7 | 8 | static const char *s_http_port = "8000"; 9 | static struct ns_serve_http_opts s_http_server_opts; 10 | static int s_sig_num = 0; 11 | static void *s_db_handle = NULL; 12 | static const char *s_db_path = "api_server.db"; 13 | static const struct ns_str s_get_method = NS_STR("GET"); 14 | static const struct ns_str s_put_method = NS_STR("PUT"); 15 | static const struct ns_str s_delele_method = NS_STR("DELETE"); 16 | 17 | static void signal_handler(int sig_num) { 18 | signal(sig_num, signal_handler); 19 | s_sig_num = sig_num; 20 | } 21 | 22 | static int has_prefix(const struct ns_str *uri, const struct ns_str *prefix) { 23 | return uri->len > prefix->len && memcmp(uri->p, prefix->p, prefix->len) == 0; 24 | } 25 | 26 | static int is_equal(const struct ns_str *s1, const struct ns_str *s2) { 27 | return s1->len == s2->len && memcmp(s1->p, s2->p, s2->len) == 0; 28 | } 29 | 30 | static void ev_handler(struct ns_connection *nc, int ev, void *ev_data) { 31 | static const struct ns_str api_prefix = NS_STR("/api/v1"); 32 | struct http_message *hm = (struct http_message *) ev_data; 33 | struct ns_str key; 34 | 35 | switch (ev) { 36 | case NS_HTTP_REQUEST: 37 | if (has_prefix(&hm->uri, &api_prefix)) { 38 | key.p = hm->uri.p + api_prefix.len; 39 | key.len = hm->uri.len - api_prefix.len; 40 | if (is_equal(&hm->method, &s_get_method)) { 41 | db_op(nc, hm, &key, s_db_handle, API_OP_GET); 42 | } else if (is_equal(&hm->method, &s_put_method)) { 43 | db_op(nc, hm, &key, s_db_handle, API_OP_SET); 44 | } else if (is_equal(&hm->method, &s_delele_method)) { 45 | db_op(nc, hm, &key, s_db_handle, API_OP_DEL); 46 | } else { 47 | ns_printf(nc, "%s", 48 | "HTTP/1.0 501 Not Implemented\r\n" 49 | "Content-Length: 0\r\n\r\n"); 50 | } 51 | } else { 52 | ns_serve_http(nc, hm, s_http_server_opts); /* Serve static content */ 53 | } 54 | break; 55 | default: 56 | break; 57 | } 58 | } 59 | 60 | int main(int argc, char *argv[]) { 61 | struct ns_mgr mgr; 62 | struct ns_connection *nc; 63 | int i; 64 | 65 | /* Open listening socket */ 66 | ns_mgr_init(&mgr, NULL); 67 | nc = ns_bind(&mgr, s_http_port, ev_handler); 68 | ns_set_protocol_http_websocket(nc); 69 | s_http_server_opts.document_root = "web_root"; 70 | 71 | /* Parse command line arguments */ 72 | for (i = 1; i < argc; i++) { 73 | if (strcmp(argv[i], "-D") == 0) { 74 | mgr.hexdump_file = argv[++i]; 75 | } else if (strcmp(argv[i], "-f") == 0) { 76 | s_db_path = argv[++i]; 77 | } else if (strcmp(argv[i], "-r") == 0) { 78 | s_http_server_opts.document_root = argv[++i]; 79 | } 80 | } 81 | 82 | signal(SIGINT, signal_handler); 83 | signal(SIGTERM, signal_handler); 84 | 85 | /* Open database */ 86 | if ((s_db_handle = db_open(s_db_path)) == NULL) { 87 | fprintf(stderr, "Cannot open DB [%s]\n", s_db_path); 88 | exit(EXIT_FAILURE); 89 | } 90 | 91 | /* Run event loop until signal is received */ 92 | printf("Starting RESTful server on port %s\n", s_http_port); 93 | while (s_sig_num == 0) { 94 | ns_mgr_poll(&mgr, 1000); 95 | } 96 | 97 | /* Cleanup */ 98 | ns_mgr_free(&mgr); 99 | db_close(&s_db_handle); 100 | 101 | printf("Exiting on signal %d\n", s_sig_num); 102 | 103 | return 0; 104 | } 105 | -------------------------------------------------------------------------------- /apps/api_server/db_plugin.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 Cesanta Software Limited 3 | * All rights reserved 4 | */ 5 | 6 | #ifndef DB_PLUGIN_HEADER_DEFINED 7 | #define DB_PLUGIN_HEADER_DEFINED 8 | 9 | #include "../../fossa.h" 10 | 11 | void *db_open(const char *db_path); 12 | void db_close(void **db_handle); 13 | 14 | enum { API_OP_GET, API_OP_SET, API_OP_DEL }; 15 | 16 | void db_op(struct ns_connection *nc, const struct http_message *hm, 17 | const struct ns_str *key, void *db, int op); 18 | 19 | #endif /* DB_PLUGIN_HEADER_DEFINED */ 20 | -------------------------------------------------------------------------------- /apps/api_server/db_plugin_sqlite.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 Cesanta Software Limited 3 | * All rights reserved 4 | */ 5 | 6 | #include "db_plugin.h" 7 | #include "sqlite3.h" 8 | 9 | void *db_open(const char *db_path) { 10 | sqlite3 *db = NULL; 11 | if (sqlite3_open_v2(db_path, &db, SQLITE_OPEN_READWRITE | 12 | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX, NULL) == SQLITE_OK) { 13 | sqlite3_exec(db, "CREATE TABLE IF NOT EXISTS kv(key PRIMARY KEY, val);", 14 | 0, 0, 0); 15 | } 16 | return db; 17 | } 18 | 19 | void db_close(void **db_handle) { 20 | if (db_handle != NULL && *db_handle != NULL) { 21 | sqlite3_close(*db_handle); 22 | *db_handle = NULL; 23 | } 24 | } 25 | 26 | static void op_set(struct ns_connection *nc, const struct http_message *hm, 27 | const struct ns_str *key, void *db) { 28 | sqlite3_stmt *stmt = NULL; 29 | char value[200]; 30 | const struct ns_str *body = hm->query_string.len > 0 ? 31 | &hm->query_string : &hm->body; 32 | 33 | ns_get_http_var(body, "value", value, sizeof(value)); 34 | if (sqlite3_prepare_v2(db, "INSERT OR REPLACE INTO kv VALUES (?, ?);", 35 | -1, &stmt, NULL) == SQLITE_OK) { 36 | sqlite3_bind_text(stmt, 1, key->p, key->len, SQLITE_STATIC); 37 | sqlite3_bind_text(stmt, 2, value, strlen(value), SQLITE_STATIC); 38 | sqlite3_step(stmt); 39 | sqlite3_finalize(stmt); 40 | } 41 | ns_printf(nc, "%s", "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"); 42 | } 43 | 44 | static void op_get(struct ns_connection *nc, const struct http_message *hm, 45 | const struct ns_str *key, void *db) { 46 | sqlite3_stmt *stmt = NULL; 47 | const char *data = NULL; 48 | int result; 49 | (void) hm; 50 | 51 | if (sqlite3_prepare_v2(db, "SELECT val FROM kv WHERE key = ?;", 52 | -1, &stmt, NULL) == SQLITE_OK) { 53 | sqlite3_bind_text(stmt, 1, key->p, key->len, SQLITE_STATIC); 54 | result = sqlite3_step(stmt); 55 | data = (char *) sqlite3_column_text(stmt, 0); 56 | if ((result == SQLITE_OK || result == SQLITE_ROW) && data != NULL) { 57 | ns_printf(nc, "HTTP/1.1 200 OK\r\n" 58 | "Content-Type: text/plain\r\n" 59 | "Content-Length: %d\r\n\r\n%s", 60 | (int) strlen(data), data); 61 | } else { 62 | ns_printf(nc, "%s", "HTTP/1.1 404 Not Found\r\n" 63 | "Content-Length: 0\r\n\r\n"); 64 | } 65 | sqlite3_finalize(stmt); 66 | } else { 67 | ns_printf(nc, "%s", "HTTP/1.1 500 Server Error\r\n" 68 | "Content-Length: 0\r\n\r\n"); 69 | } 70 | } 71 | 72 | static void op_del(struct ns_connection *nc, const struct http_message *hm, 73 | const struct ns_str *key, void *db) { 74 | sqlite3_stmt *stmt = NULL; 75 | int result; 76 | (void) hm; 77 | 78 | if (sqlite3_prepare_v2(db, "DELETE FROM kv WHERE key = ?;", 79 | -1, &stmt, NULL) == SQLITE_OK) { 80 | sqlite3_bind_text(stmt, 1, key->p, key->len, SQLITE_STATIC); 81 | result = sqlite3_step(stmt); 82 | if (result == SQLITE_OK || result == SQLITE_ROW) { 83 | ns_printf(nc, "%s", "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"); 84 | } else { 85 | ns_printf(nc, "%s", "HTTP/1.1 404 Not Found\r\n" 86 | "Content-Length: 0\r\n\r\n"); 87 | } 88 | sqlite3_finalize(stmt); 89 | } else { 90 | ns_printf(nc, "%s", "HTTP/1.1 500 Server Error\r\n" 91 | "Content-Length: 0\r\n\r\n"); 92 | } 93 | } 94 | 95 | void db_op(struct ns_connection *nc, const struct http_message *hm, 96 | const struct ns_str *key, void *db, int op) { 97 | switch (op) { 98 | case API_OP_GET: op_get(nc, hm, key, db); break; 99 | case API_OP_SET: op_set(nc, hm, key, db); break; 100 | case API_OP_DEL: op_del(nc, hm, key, db); break; 101 | default: 102 | ns_printf(nc, "%s", "HTTP/1.0 501 Not Implemented\r\n" 103 | "Content-Length: 0\r\n\r\n"); 104 | break; 105 | } 106 | } 107 | 108 | -------------------------------------------------------------------------------- /apps/api_server/unit_test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | PROG=$1 4 | PORT=${2:-8000} # If second param is given, this is load balancer port 5 | DB_FILE=/tmp/_$$.db 6 | URL=http://127.0.0.1:$PORT/api/v1 7 | 8 | cleanup() { 9 | rm -rf $DB_FILE 10 | kill -9 $PID >/dev/null 2>&1 11 | } 12 | 13 | #set -x 14 | trap cleanup EXIT 15 | 16 | cleanup 17 | $PROG -f $DB_FILE & 18 | PID=$! 19 | 20 | #sleep 1 21 | curl -s -X PUT -d 'value=123' $URL/foo 22 | curl -s -X PUT -d 'value=success' $URL/bar/baz 23 | 24 | # Fetch existing key 25 | RESULT=$(curl -s $URL/bar/baz) 26 | test "$RESULT" = "success" || exit 1 27 | 28 | # Delete it 29 | curl -s -X DELETE $URL/bar/baz 30 | 31 | # Make sure it's deleted - GET must result in 404 32 | RESULT=$(curl -s -i $URL/bar/baz | head -1 | tr -d '\r') 33 | test "$RESULT" = "HTTP/1.1 404 Not Found" || exit 1 34 | 35 | exit 0 36 | -------------------------------------------------------------------------------- /apps/api_server/web_root/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | RESTful API demo 6 | 7 | 26 | 27 | 28 | 32 | 33 | 34 |
35 |

API server

36 |
37 | 38 | 39 | -------------------------------------------------------------------------------- /apps/load_balancer/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM cesanta/fossa 2 | 3 | COPY load_balancer.c /fossa/ 4 | WORKDIR /fossa 5 | RUN mkdir /fossa/certs; \ 6 | sed -i 's:#include "../../fossa.h":#include "fossa.h":' load_balancer.c; \ 7 | cc load_balancer.c fossa.c -o load_balancer -W -Wall -pthread -DNS_ENABLE_SSL -lssl -lcrypto 8 | EXPOSE 8000 9 | VOLUME ["/fossa/certs"] 10 | ENTRYPOINT ["/fossa/load_balancer"] 11 | -------------------------------------------------------------------------------- /apps/load_balancer/Makefile: -------------------------------------------------------------------------------- 1 | # To build with SSL under windows, do: 2 | # wine make load_balancer.exe SSL=openssl # OpenSSL build 3 | # wine make load_balancer.exe SSL=krypton # Krypton build 4 | 5 | PROG = load_balancer 6 | SOURCES = $(PROG).c ../../fossa.c 7 | CFLAGS = -W -Wall -pthread $(CFLAGS_EXTRA) 8 | 9 | ifeq ($(SSL), openssl) 10 | OPENSSL_PATH = ./openssl-0.9.8 11 | CFLAGS_EXTRA += -DNS_ENABLE_SSL -I$(OPENSSL_PATH)/include 12 | CFLAGS_EXTRA += /link /libpath:$(OPENSSL_PATH)/lib ssleay32.lib libeay32.lib 13 | endif 14 | 15 | ifeq ($(SSL), krypton) 16 | KRYPTON_PATH = ../../../krypton 17 | CFLAGS_EXTRA += -DNS_ENABLE_SSL $(KRYPTON_PATH)/krypton.c -I$(KRYPTON_PATH) 18 | endif 19 | 20 | all: $(PROG) 21 | 22 | $(PROG): $(SOURCES) 23 | $(CC) $(SOURCES) -o $@ $(CFLAGS) 24 | 25 | $(PROG).exe: $(SOURCES) 26 | cl $(SOURCES) /I.. /MD /Fe$@ /DNS_ENABLE_THREADS advapi32.lib $(CFLAGS_EXTRA) 27 | 28 | test: $(PROG) 29 | $(MAKE) -C ../api_server 30 | sh unit_test.sh $$(pwd)/$(PROG) 31 | 32 | docker-build: 33 | docker build -t cesanta/load_balancer . 34 | 35 | docker-push: 36 | docker push cesanta/load_balancer 37 | 38 | clean: 39 | rm -rf *.gc* *.dSYM *.exe *.obj *.o a.out $(PROG) 40 | -------------------------------------------------------------------------------- /apps/load_balancer/README.md: -------------------------------------------------------------------------------- 1 | # Fossa-based HTTP load balancer 2 | 3 | ## Configuration 4 | 5 | Load balancer is configured with command-line flags. 6 | 7 | ### Global flags 8 | 9 | * `-p port` – TCP port to listen on. Default: 8000. 10 | * `-l log_file` – path to the log file. Default: none. 11 | * `-s ssl_cert` – path to SSL certificate. Default: none. 12 | 13 | ### Backend configuration 14 | 15 | Main flag is `-b uri_prefix host_port` – it adds a new backend for a given 16 | URI prefix. Example: `-b /stuff/ 127.0.0.1:8080` will route all requests that 17 | start with '/stuff/' to a backend at port 8080 on localhost. There is a special 18 | syntax for `uri_prefix` that allows you to change the URIs that get passed to 19 | backends: 20 | 21 | * `-b /stuff/=/ 127.0.0.1:8080` – for '/stuff/thing' backend will see '/thing'. 22 | * `-b /stuff/=/other/ 127.0.0.1:8080` – '/stuff/thing' => '/other/thing'. 23 | 24 | Also there are few per-backend flags that can be placed before `-b` and apply 25 | only to the next backend: 26 | 27 | * `-r` – instead of proxying requests load balancer will reply with 302 28 | redirect. 29 | * `-v vhost` – match not only URI prefix but 'Host:' header as well. 30 | 31 | ### Example 32 | 33 | ``` 34 | load_balancer -s path/to/cert.pem \ 35 | -v example.com -b /site/=/ 127.0.0.1:8080 \ 36 | -b /static/ 127.0.0.1:8081 \ 37 | -b /static/ 127.0.0.1:8082 38 | ``` 39 | 40 | In this example requests to 'example.com/site/' will be forwarded to the 41 | backend on port 8080 with '/site' prefix stripped off and requests to 42 | '/static/' on any virtual host will be balanced in round-robin fashion between 43 | backends on ports 8081 and 8082. 44 | 45 | -------------------------------------------------------------------------------- /apps/load_balancer/unit_test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | PROG=$1 4 | PORT=8002 5 | 6 | cleanup() { 7 | kill -9 $PID >/dev/null 2>&1 8 | } 9 | 10 | #set -x 11 | trap cleanup EXIT 12 | 13 | cleanup 14 | $PROG -p $PORT -b /api/ 127.0.0.1:8000 & 15 | PID=$! 16 | 17 | # Perform api_server unit test through the load balancer by passing 18 | # load balancer port to the unit test script 19 | (cd ../api_server && make && sh unit_test.sh ./api_server $PORT) 20 | 21 | exit $? 22 | -------------------------------------------------------------------------------- /examples/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2014 Cesanta Software 2 | # All rights reserved 3 | 4 | SUBDIRS = $(sort $(dir $(wildcard */))) 5 | X = $(SUBDIRS) 6 | 7 | .PHONY: $(SUBDIRS) 8 | 9 | all: $(SUBDIRS) 10 | 11 | $(SUBDIRS): 12 | @$(MAKE) -C $@ 13 | 14 | clean: 15 | for d in $(SUBDIRS) ; do $(MAKE) -C $$d clean ; done 16 | -------------------------------------------------------------------------------- /examples/arduino_restful_client/Makefile: -------------------------------------------------------------------------------- 1 | # This "makefile" is only intended to prevent errors during main makefile execution 2 | all: 3 | -------------------------------------------------------------------------------- /examples/arduino_restful_client/README.md: -------------------------------------------------------------------------------- 1 | # Arduino Restful Client 2 | 3 | This example demonstrates how to use [Fossa](https://www.cesanta.com/fossa) to send HTTP commands from Arduino. 4 | 5 | Example sends free memory size and current board uptime, but it can be modified to send any user-specific data. 6 | 7 | At the moment this example supports [Arduino Mega 2560](http://arduino.cc/en/Main/ArduinoBoardMega2560) board (and compatible) with either W5100-based 8 | network shield (like [Arduino Ethernet Shield](http://arduino.cc/en/Main/ArduinoEthernetShield)) or [CC3000](http://www.ti.com/product/cc3000)-based WIFI Shield. 9 | 10 | ## Build and run instructions: 11 | 12 | ###To run with Arduino Ethernet (W5100) shield: 13 | 1. Add (Sketch->Add file...) the following files to sketch: 14 | - /fossa/fossa.h 15 | - /fossa/fossa.c 16 | - /fossa/platforms/arduino_ethernet_W5100/avrsupport.h 17 | - /fossa/platforms/arduino_ethernet_W5100/avrsupport.cpp 18 | 3. Buils and start (in console) /Users/alex/Projects/fossa/examples/restful_server example 19 | 4. Make `board_ip` and `board_mac` variables suitable for your network and board 20 | 5. Change IP address in `s_target_address` variable to IP address of host running restful_server 21 | 6. Uncomment line `#include ` 22 | 7. Compile and flash sketch 23 | 8. restful_server will start to show current uptime and free memory size (with 5 seconds interval) 24 | 25 | ###To run with Adafruit WiFi (CC3000) shield: 26 | 1. Add (Sketch->Add files...) the following files to sketch: 27 | - /fossa/fossa.h 28 | - /fossa/fossa.c 29 | - /fossa/platforms/arduino_ethernet_W5100/avrsupport.h 30 | - /fossa/platforms/arduino_ethernet_W5100/avrsupport.cpp 31 | 2. Import Adafruit CC3000 library for fossa 32 | (select Sketch->Import Library...->Add library... and point 33 | /fossa/platforms/arduino_wifi_CC3000/adafruit_CC3000_lib_fossa folder) 34 | 3. Buils and start (in console) /Users/alex/Projects/fossa/examples/restful_server example 35 | 4. Make the following variables suitable for your network 36 | - `board_ip` 37 | - `subnet_mask` 38 | - `gateway` 39 | - `dns` 40 | - `wlan_ssid` 41 | - `wlan_pwd` 42 | - `wlan_security` 43 | 5. Change IP address in `s_target_address` variable to IP address of host running restful_server 44 | 6. Uncomment line `#include ` 45 | 8. Compile and flash sketch 46 | 9. restful_server will start to show current uptime and free memory size (with 5 seconds interval) 47 | -------------------------------------------------------------------------------- /examples/arduino_restful_client/arduino_restful_client.ino: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (c) 2015 Cesanta Software Limited 4 | * All rights reserved 5 | * 6 | * Build and run instructions: 7 | * To run with Arduino Ethernet (W5100) shield: 8 | * ----------------------------------------------------------- 9 | * 1. Add (Sketch->Add file...) the following files to sketch: 10 | * - /fossa/fossa.h 11 | * - /fossa/fossa.c 12 | * - /fossa/platforms/arduino_ethernet_W5100/avrsupport.h 13 | * - /fossa/platforms/arduino_ethernet_W5100/avrsupport.cpp 14 | * 2. Buils and run in console /Users/alex/Projects/fossa/examples/restful_server example 15 | * 3. Make board_ip and board_mac variables suitable for your network and board 16 | * 4. Uncomment line #include 17 | * 5. Change IP address in s_target_address variable to IP address of host running restful_server 18 | * 6. Compile & flash sketch 19 | * 7. restful_server server will start to show current uptime and free memory size (with 5 second interval) 20 | * 21 | * To run with Adafruit WiFi (CC3000) shield: 22 | * ----------------------------------------------------------- 23 | * 1. Add (Sketch->Add files...) the following files to sketch: 24 | * - /fossa/fossa.h 25 | * - /fossa/fossa.c 26 | * - /fossa/platforms/arduino_ethernet_W5100/avrsupport.h 27 | * - /fossa/platforms/arduino_ethernet_W5100/avrsupport.cpp 28 | * 2. Import Adafruit CC3000 library for fossa (select Sketch->Import Library...->Add library... and point 29 | * /fossa/platforms/arduino_wifi_CC3000/adafruit_CC3000_lib_fossa folder 30 | * 3. Buils and run in console /Users/alex/Projects/fossa/examples/restful_server example 31 | * 4. Make the following variables suitable for your network 32 | * - board_ip 33 | * - subnet_mask 34 | * - gateway 35 | * - dns 36 | * - wlan_ssid 37 | * - wlan_pwd 38 | * - wlan_security 39 | * 5. Uncomment line #include 40 | * 6. Compile & flash sketch 41 | * 7. restful_server server will start to show current uptime and free memory size (with 5 second interval) * 42 | * 43 | */ 44 | 45 | 46 | //#include 47 | //#include 48 | #include 49 | #include "fossa.h" 50 | 51 | // CHANGE THESE VARIABLES 52 | // NB: Devices with the same address must not end up on the same network. 53 | // Use MAC address provided by device manufacturer (e.g. on a sticker). 54 | // If there isn't one, use a random one from the locally administered range. 55 | // See http://en.wikipedia.org/wiki/MAC_address for details. 56 | static uint8_t board_mac[] = { 57 | 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED 58 | }; 59 | static uint8_t board_ip[] = {192, 168, 10, 177}; 60 | 61 | #ifdef WIFI_CC3000 62 | static uint8_t subnet_mask[] = {255, 255, 255, 0}; 63 | static uint8_t gateway[] = {192, 168, 10, 254}; 64 | static uint8_t dns_ip[] = {192, 168, 10, 254}; 65 | 66 | static const char *wlan_ssid = "mynetwork"; 67 | static const char *wlan_pwd = "mypassword"; 68 | static int wlan_security = WLAN_SEC_WPA2; 69 | #endif 70 | 71 | static const char *s_target_address = "192.168.10.3:8000"; 72 | 73 | ///////////////////////////////////////////// 74 | 75 | static const char *s_request = "/printcontent"; 76 | 77 | static uint32_t IP2U32(uint8_t* iparr) { 78 | return ((uint32_t)iparr[0] << 24) | ((uint32_t)iparr[1] << 16) | (iparr[2] << 8) | (iparr[3]); 79 | } 80 | 81 | static int get_data_to_send(char* buf, int buf_size) { 82 | // Adding data to send 83 | // It could be any sensor data, now just put uptime & free memory size here 84 | return snprintf(buf, buf_size, "Uptime: %lus Free memory: %db", 85 | millis()/1000, get_freememsize()); 86 | } 87 | static void rfc_ev_handler(struct ns_connection *nc, int ev, void *ev_data) { 88 | int connect_status; 89 | 90 | switch (ev) { 91 | case NS_CONNECT: 92 | connect_status = * (int *) ev_data; 93 | 94 | if (connect_status == 0) { 95 | char buf[100]; 96 | int len = get_data_to_send(buf, sizeof(buf)); 97 | ns_printf(nc, "POST %s HTTP/1.0\r\nHost: %s\r\nContent-Lenght: %d" 98 | "\r\n\r\n%s", s_request, s_target_address, len, buf); 99 | nc->flags |= NSF_SEND_AND_CLOSE; 100 | } else { 101 | nc->flags |= NSF_CLOSE_IMMEDIATELY; 102 | } 103 | break; 104 | default: 105 | break; 106 | } 107 | } 108 | 109 | static struct ns_mgr mgr; 110 | static struct ns_connection *nc; 111 | 112 | void setup() 113 | { 114 | Serial.begin(9600); 115 | Serial.println("Initialization..."); 116 | #if defined(ETHERNET_W5100) 117 | avr_netinit(board_mac, board_ip); 118 | #elif defined(WIFI_CC3000) 119 | if (avr_netinit(wlan_ssid, wlan_pwd, wlan_security, IP2U32(board_ip), 120 | IP2U32(subnet_mask), IP2U32(gateway), IP2U32(dns_ip)) != 0) { 121 | Serial.println("Initialization error, check network settings"); 122 | return; 123 | }; 124 | #endif 125 | 126 | ns_mgr_init(&mgr, NULL); 127 | Serial.println("Initialization done"); 128 | } 129 | 130 | void loop() { 131 | nc = ns_connect(&mgr, s_target_address, rfc_ev_handler); 132 | if (nc != NULL) { 133 | ns_set_protocol_http_websocket(nc); 134 | } 135 | 136 | uint32_t time_to_finish = millis() + 5000; 137 | while (millis() < time_to_finish) { 138 | ns_mgr_poll(&mgr, 1000); 139 | } 140 | } 141 | 142 | -------------------------------------------------------------------------------- /examples/arduino_restful_server/Makefile: -------------------------------------------------------------------------------- 1 | # This "makefile" is only intended to prevent errors during main makefile execution 2 | all: 3 | -------------------------------------------------------------------------------- /examples/arduino_restful_server/README.md: -------------------------------------------------------------------------------- 1 | # Arduino Restful Server 2 | 3 | This example demonstrates how to use [Fossa](https://www.cesanta.com/fossa) to control Arduino 4 | using HTTP requests. 5 | Example just blinks by LED when Fossa receives HTTP command, but it can be modified to execute any user-specific code. 6 | 7 | At the moment this example supports [Arduino Mega 2560](http://arduino.cc/en/Main/ArduinoBoardMega2560) board (and compatible) with either W5100-based 8 | network shield (like [Arduino Ethernet Shield](http://arduino.cc/en/Main/ArduinoEthernetShield)) or [CC3000](http://www.ti.com/product/cc3000)-based WIFI Shield. 9 | 10 | ## Build and run instructions: 11 | 12 | ###To run with Arduino Ethernet (W5100) shield: 13 | 1. Add (Sketch->Add file...) the following files to sketch: 14 | - /fossa/fossa.h 15 | - /fossa/fossa.c 16 | - /fossa/platforms/arduino_ethernet_W5100/avrsupport.h 17 | - /fossa/platforms/arduino_ethernet_W5100/avrsupport.cpp 18 | 2. Make `board_ip` and `board_mac` variables suitable for your network and board 19 | 3. Uncomment line `#include ` 20 | 4. Compile and flash sketch 21 | 5. Run `curl http://Add files...) the following files to sketch: 27 | - /fossa/fossa.h 28 | - /fossa/fossa.c 29 | - /fossa/platforms/arduino_ethernet_W5100/avrsupport.h 30 | - /fossa/platforms/arduino_ethernet_W5100/avrsupport.cpp 31 | 2. Import Adafruit CC3000 library for fossa 32 | (select Sketch->Import Library...->Add library... and point 33 | /fossa/platforms/arduino_wifi_CC3000/adafruit_CC3000_lib_fossa folder) 34 | 3. Make the following variables suitable for your network 35 | - `board_ip` 36 | - `subnet_mask` 37 | - `gateway` 38 | - `dns` 39 | - `wlan_ssid` 40 | - `wlan_pwd` 41 | - `wlan_security` 42 | 5. Uncomment line `#include ` 43 | 4. Compile and flash sketch 44 | 5. Run curl `http://Add file...) the following files to sketch: 9 | * - /fossa/fossa.h 10 | * - /fossa/fossa.c 11 | * - /fossa/platforms/arduino_ethernet_W5100/avrsupport.h 12 | * - /fossa/platforms/arduino_ethernet_W5100/avrsupport.cpp 13 | * 2. Make board_ip and board_mac variables suitable for your network and board 14 | * 3. Uncomment line #include 15 | * 4. Compile & flash sketch 16 | * 5. Run curl http://Add files...) the following files to sketch: 22 | * - /fossa/fossa.h 23 | * - /fossa/fossa.c 24 | * - /fossa/platforms/arduino_ethernet_W5100/avrsupport.h 25 | * - /fossa/platforms/arduino_ethernet_W5100/avrsupport.cpp 26 | * 2. Import Adafruit CC3000 library for fossa (select Sketch->Import Library...->Add library... and point 27 | * /fossa/platforms/arduino_wifi_CC3000/adafruit_CC3000_lib_fossa folder 28 | * 3. Make the following variables suitable for your network 29 | * - board_ip 30 | * - subnet_mask 31 | * - gateway 32 | * - dns 33 | * - wlan_ssid 34 | * - wlan_pwd 35 | * - wlan_security 36 | * 5. Uncomment line #include 37 | * 4. Compile & flash sketch 38 | * 5. Run curl http:// 44 | //#include 45 | #include 46 | #include "fossa.h" 47 | 48 | // CHANGE THESE VARIABLES 49 | // NB: Devices with the same address must not end up on the same network. 50 | // Use MAC address provided by device manufacturer (e.g. on a sticker). 51 | // If there isn't one, use a random one from the locally administered range. 52 | // See http://en.wikipedia.org/wiki/MAC_address for details. 53 | static uint8_t board_mac[] = { 54 | 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED 55 | }; 56 | 57 | static uint8_t board_ip[] = {192, 168, 10, 8}; 58 | 59 | #ifdef WIFI_CC3000 60 | static uint8_t subnet_mask[] = {255, 255, 255, 0}; 61 | static uint8_t gateway[] = {192, 168, 10, 254}; 62 | static uint8_t dns_ip[] = {192, 168, 10, 254}; 63 | 64 | static const char *wlan_ssid = "mynetwork"; 65 | static const char *wlan_pwd = "mypassword"; 66 | static int wlan_security = WLAN_SEC_WPA2; 67 | #endif 68 | 69 | /////////////////////////////////////////////// 70 | 71 | static const char *s_http_port = "60000"; 72 | 73 | static uint32_t IP2U32(uint8_t* iparr) { 74 | return ((uint32_t)iparr[0] << 24) | ((uint32_t)iparr[1] << 16) | (iparr[2] << 8) | (iparr[3]); 75 | } 76 | 77 | static void rfs_ev_handler(struct ns_connection *nc, int ev, void *ev_data) { 78 | struct http_message *hm = (struct http_message *) ev_data; 79 | char buf[100]; 80 | int clen; 81 | 82 | switch (ev) { 83 | case NS_HTTP_REQUEST: 84 | if (ns_vcmp(&hm->uri, "/blink") == 0) { 85 | blink(1, 500); 86 | } 87 | 88 | clen = snprintf(buf, sizeof(buf), 89 | "Free memory size: %d Uptime: %d", 90 | (int)get_freememsize(), (int)time(NULL)); 91 | 92 | ns_printf_http_chunk(nc, "HTTP/1.1 200 OK\r\n" 93 | "Content-Length: %d\r\n" 94 | "Transfer-Encoding: chunked\r\n\r\n" 95 | "%s", 96 | clen, buf); 97 | 98 | ns_send_http_chunk(nc, "", 0); 99 | break; 100 | case NS_SEND: 101 | nc->flags |= NSF_CLOSE_IMMEDIATELY; 102 | break; 103 | 104 | default: 105 | break; 106 | } 107 | } 108 | 109 | static struct ns_connection *nc; 110 | static struct ns_mgr mgr; 111 | 112 | void setup() { 113 | Serial.begin(9600); 114 | Serial.println("Initialization..."); 115 | #if defined(ETHERNET_W5100) 116 | avr_netinit(board_mac, board_ip); 117 | #elif defined(WIFI_CC3000) 118 | if (avr_netinit(wlan_ssid, wlan_pwd, wlan_security, IP2U32(board_ip), 119 | IP2U32(subnet_mask), IP2U32(gateway), IP2U32(dns_ip)) != 0) { 120 | Serial.println("Initialization error, check network settings"); 121 | return; 122 | }; 123 | #endif 124 | 125 | ns_mgr_init(&mgr, NULL); 126 | nc = ns_bind(&mgr, s_http_port, rfs_ev_handler); 127 | ns_set_protocol_http_websocket(nc); 128 | Serial.println("Initialization done"); 129 | } 130 | 131 | void loop() { 132 | ns_mgr_poll(&mgr, 1000); 133 | } 134 | -------------------------------------------------------------------------------- /examples/captive_dns_server/Makefile: -------------------------------------------------------------------------------- 1 | PROG = captive_dns_server 2 | MODULE_CFLAGS=-DNS_ENABLE_DNS_SERVER 3 | 4 | include ../rules.mk 5 | -------------------------------------------------------------------------------- /examples/captive_dns_server/captive_dns_server.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 Cesanta Software Limited 3 | * All rights reserved 4 | */ 5 | 6 | /* 7 | * Try it out with: 8 | * $ dig -t A www.google.com -4 @localhost -p 5533 9 | */ 10 | 11 | #include "../../fossa.h" 12 | 13 | #include 14 | 15 | static int s_exit_flag = 0; 16 | static in_addr_t s_our_ip_addr; 17 | static const char *s_listening_addr = "udp://:5533"; 18 | 19 | static void ev_handler(struct ns_connection *nc, int ev, void *ev_data) { 20 | struct ns_dns_message *msg; 21 | struct ns_dns_resource_record *rr; 22 | struct ns_dns_reply reply; 23 | int i; 24 | 25 | switch (ev) { 26 | case NS_DNS_MESSAGE: 27 | msg = (struct ns_dns_message *) ev_data; 28 | reply = ns_dns_create_reply(&nc->send_mbuf, msg); 29 | 30 | for (i = 0; i < msg->num_questions; i++) { 31 | rr = &msg->questions[i]; 32 | if (rr->rtype == NS_DNS_A_RECORD) { 33 | ns_dns_reply_record(&reply, rr, NULL, rr->rtype, 3600, 34 | &s_our_ip_addr, 4); 35 | } 36 | } 37 | 38 | /* 39 | * We don't set the error flag even if there were no answers 40 | * maching the NS_DNS_A_RECORD query type. 41 | * This indicates that we have (syntetic) answers for NS_DNS_A_RECORD. 42 | * See http://goo.gl/QWvufr for a distinction between NXDOMAIN and NODATA. 43 | */ 44 | 45 | ns_dns_send_reply(nc, &reply); 46 | break; 47 | } 48 | } 49 | 50 | int main(int argc, char *argv[]) { 51 | struct ns_mgr mgr; 52 | struct ns_connection *nc; 53 | int i; 54 | 55 | ns_mgr_init(&mgr, NULL); 56 | s_our_ip_addr = inet_addr("127.0.0.1"); 57 | 58 | /* Parse command line arguments */ 59 | for (i = 1; i < argc; i++) { 60 | if (strcmp(argv[i], "-D") == 0) { 61 | mgr.hexdump_file = argv[++i]; 62 | } else if (strcmp(argv[i], "-l") == 0 && i + 1 < argc) { 63 | s_listening_addr = argv[++i]; 64 | } else { 65 | s_our_ip_addr = inet_addr(argv[i]); 66 | } 67 | } 68 | 69 | fprintf(stderr, "Listening on '%s'\n", s_listening_addr); 70 | if ((nc = ns_bind(&mgr, s_listening_addr, ev_handler)) == NULL) { 71 | fprintf(stderr, "cannot bind to socket\n"); 72 | exit(1); 73 | } 74 | ns_set_protocol_dns(nc); 75 | 76 | while (s_exit_flag == 0) { 77 | ns_mgr_poll(&mgr, 1000); 78 | } 79 | ns_mgr_free(&mgr); 80 | 81 | return 0; 82 | } 83 | -------------------------------------------------------------------------------- /examples/coap_client/Makefile: -------------------------------------------------------------------------------- 1 | PROG = coap_client 2 | SOURCES = $(PROG).c ../../fossa.c 3 | CFLAGS = -W -Wall -I../.. $(CFLAGS_EXTRA) -DNS_ENABLE_COAP 4 | 5 | all: $(PROG) 6 | 7 | $(PROG): $(SOURCES) 8 | $(CC) $(SOURCES) -o $@ $(CFLAGS) 9 | 10 | $(PROG).exe: $(SOURCES) 11 | cl $(SOURCES) /I../.. /MD /Fe$@ 12 | 13 | clean: 14 | rm -rf *.gc* *.dSYM *.exe *.obj *.o a.out $(PROG) 15 | -------------------------------------------------------------------------------- /examples/coap_client/coap_client.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Cesanta Software Limited 3 | * All rights reserved 4 | * 5 | * This program sends CoAP CON-message to server (coap.me by default) 6 | * and waits for answer. 7 | */ 8 | 9 | #include "fossa.h" 10 | 11 | static int s_time_to_exit = 0; 12 | static char* s_default_address = "udp://coap.me:5683"; 13 | 14 | static void coap_handler(struct ns_connection *nc, int ev, void *p) { 15 | switch (ev) { 16 | case NS_CONNECT: { 17 | struct ns_coap_message cm; 18 | uint32_t res; 19 | 20 | memset(&cm, 0, sizeof(cm)); 21 | cm.msg_id = 1; 22 | cm.msg_type = NS_COAP_MSG_CON; 23 | printf("Sending CON...\n"); 24 | res = ns_coap_send_message(nc, &cm); 25 | if (res == 0) { 26 | printf("Sent CON with msg_id = %d\n", cm.msg_id); 27 | } else { 28 | printf("Error: %d\n", res); 29 | s_time_to_exit = 1; 30 | } 31 | break; 32 | } 33 | case NS_COAP_ACK: 34 | case NS_COAP_RST: { 35 | struct ns_coap_message *cm = (struct ns_coap_message *)p; 36 | printf("ACK/RST for message with msg_id = %d received\n", 37 | cm->msg_id); 38 | s_time_to_exit = 1; 39 | break; 40 | } 41 | } 42 | } 43 | 44 | int main(int argc, char* argv[]) { 45 | struct ns_mgr mgr; 46 | struct ns_connection *nc; 47 | char *address = s_default_address; 48 | 49 | if (argc > 1) { 50 | address = argv[1]; 51 | } 52 | 53 | printf("Using %s as CoAP server\n", address); 54 | 55 | ns_mgr_init(&mgr, 0); 56 | 57 | nc = ns_connect(&mgr, address, coap_handler); 58 | if (nc == NULL) { 59 | printf("Unable to connect to %s\n", address); 60 | return -1; 61 | } 62 | 63 | ns_set_protocol_coap(nc); 64 | 65 | while (!s_time_to_exit) { 66 | ns_mgr_poll(&mgr, 1); 67 | } 68 | 69 | ns_mgr_free(&mgr); 70 | 71 | return 0; 72 | } 73 | -------------------------------------------------------------------------------- /examples/coap_server/Makefile: -------------------------------------------------------------------------------- 1 | PROG = coap_server 2 | SOURCES = $(PROG).c ../../fossa.c 3 | CFLAGS = -W -Wall -I../.. $(CFLAGS_EXTRA) -DNS_ENABLE_COAP 4 | 5 | all: $(PROG) 6 | 7 | $(PROG): $(SOURCES) 8 | $(CC) $(SOURCES) -o $@ $(CFLAGS) 9 | 10 | $(PROG).exe: $(SOURCES) 11 | cl $(SOURCES) /I../.. /MD /Fe$@ 12 | 13 | clean: 14 | rm -rf *.gc* *.dSYM *.exe *.obj *.o a.out $(PROG) 15 | -------------------------------------------------------------------------------- /examples/coap_server/coap_server.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Cesanta Software Limited 3 | * All rights reserved 4 | * 5 | * This program listens on 5683 for CoAP messages, 6 | * sends ACK is nessesary and dump everything received. 7 | * It is possible to use ../coap_client to send message. 8 | */ 9 | 10 | #include "fossa.h" 11 | 12 | static char* s_default_address = "udp://:5683"; 13 | static int s_sig_received = 0; 14 | 15 | static void signal_handler(int sig_num) { 16 | signal(sig_num, signal_handler); 17 | s_sig_received = sig_num; 18 | } 19 | 20 | static void coap_handler(struct ns_connection *nc, int ev, void *p) { 21 | switch (ev) { 22 | case NS_COAP_CON: { 23 | uint32_t res; 24 | struct ns_coap_message *cm = (struct ns_coap_message *)p; 25 | printf("CON with msg_id = %d received\n", cm->msg_id); 26 | res = ns_coap_send_ack(nc, cm->msg_id); 27 | if (res == 0) { 28 | printf("Successfully sent ACK for message with msg_id = %d\n", 29 | cm->msg_id); 30 | } else { 31 | printf("Error: %d\n", res); 32 | } 33 | break; 34 | } 35 | case NS_COAP_NOC: 36 | case NS_COAP_ACK: 37 | case NS_COAP_RST: { 38 | struct ns_coap_message *cm = (struct ns_coap_message *)p; 39 | printf("ACK/RST/NOC with msg_id = %d received\n", 40 | cm->msg_id); 41 | break; 42 | } 43 | } 44 | } 45 | 46 | int main() { 47 | struct ns_mgr mgr; 48 | struct ns_connection *nc; 49 | 50 | signal(SIGTERM, signal_handler); 51 | signal(SIGINT, signal_handler); 52 | 53 | ns_mgr_init(&mgr, 0); 54 | 55 | nc = ns_bind(&mgr, s_default_address, coap_handler); 56 | if (nc == NULL) { 57 | printf("Unable to start listener at %s\n", s_default_address); 58 | return -1; 59 | } 60 | 61 | printf("Listening for CoAP messages at %s\n", s_default_address); 62 | 63 | ns_set_protocol_coap(nc); 64 | 65 | while (!s_sig_received) { 66 | ns_mgr_poll(&mgr, 1); 67 | } 68 | 69 | printf("Exiting on signal %d\n", s_sig_received); 70 | 71 | ns_mgr_free(&mgr); 72 | return 0; 73 | } 74 | -------------------------------------------------------------------------------- /examples/http_client/Makefile: -------------------------------------------------------------------------------- 1 | PROG = http_client 2 | SOURCES = $(PROG).c ../../fossa.c 3 | CFLAGS = -W -Wall -I../.. -DNS_ENABLE_SSL -lssl -lcrypto -pthread $(CFLAGS_EXTRA) 4 | 5 | all: $(PROG) 6 | 7 | $(PROG): $(SOURCES) 8 | $(CC) $(SOURCES) -o $@ $(CFLAGS) 9 | 10 | $(PROG).exe: $(SOURCES) 11 | cl $(SOURCES) /I../.. /MD /Fe$@ 12 | 13 | clean: 14 | rm -rf *.gc* *.dSYM *.exe *.obj *.o a.out $(PROG) 15 | -------------------------------------------------------------------------------- /examples/http_client/http_client.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 Cesanta Software Limited 3 | * All rights reserved 4 | * 5 | * This program fetches HTTP URLs. 6 | */ 7 | 8 | #include "fossa.h" 9 | 10 | static int s_exit_flag = 0; 11 | static int s_show_headers = 0; 12 | static const char *s_show_headers_opt = "--show-headers"; 13 | 14 | static void ev_handler(struct ns_connection *nc, int ev, void *ev_data) { 15 | struct http_message *hm = (struct http_message *) ev_data; 16 | 17 | switch (ev) { 18 | case NS_CONNECT: 19 | if (* (int *) ev_data != 0) { 20 | fprintf(stderr, "connect() failed: %s\n", strerror(* (int *) ev_data)); 21 | s_exit_flag = 1; 22 | } 23 | break; 24 | case NS_HTTP_REPLY: 25 | nc->flags |= NSF_CLOSE_IMMEDIATELY; 26 | if (s_show_headers) { 27 | fwrite(hm->message.p, 1, hm->message.len, stdout); 28 | } else { 29 | fwrite(hm->body.p, 1, hm->body.len, stdout); 30 | } 31 | putchar('\n'); 32 | s_exit_flag = 1; 33 | break; 34 | default: 35 | break; 36 | } 37 | } 38 | 39 | int main(int argc, char *argv[]) { 40 | struct ns_mgr mgr; 41 | int i; 42 | 43 | ns_mgr_init(&mgr, NULL); 44 | 45 | /* Process command line arguments */ 46 | for (i = 1; i < argc; i++) { 47 | if (strcmp(argv[i], s_show_headers_opt) == 0) { 48 | s_show_headers = 1; 49 | } else if (strcmp(argv[i], "--hexdump") == 0 && i + 1 < argc) { 50 | mgr.hexdump_file = argv[++i]; 51 | } else { 52 | break; 53 | } 54 | } 55 | 56 | if (i + 1 != argc) { 57 | fprintf(stderr, "Usage: %s [%s] [--hexdump ] \n", 58 | argv[0], s_show_headers_opt); 59 | exit(EXIT_FAILURE); 60 | } 61 | 62 | ns_connect_http(&mgr, ev_handler, argv[i], NULL, NULL); 63 | 64 | while (s_exit_flag == 0) { 65 | ns_mgr_poll(&mgr, 1000); 66 | } 67 | ns_mgr_free(&mgr); 68 | 69 | return 0; 70 | } 71 | -------------------------------------------------------------------------------- /examples/json_rpc_server/Makefile: -------------------------------------------------------------------------------- 1 | PROG = json_rpc_server 2 | SOURCES = $(PROG).c ../../fossa.c 3 | CFLAGS = -W -Wall -I../.. -pthread $(CFLAGS_EXTRA) 4 | 5 | all: $(PROG) 6 | 7 | $(PROG): $(SOURCES) 8 | $(CC) $(SOURCES) -o $@ $(CFLAGS) 9 | 10 | $(PROG).exe: $(SOURCES) 11 | cl $(SOURCES) /I../.. /MD /Fe$@ 12 | 13 | clean: 14 | rm -rf *.gc* *.dSYM *.exe *.obj *.o a.out $(PROG) 15 | -------------------------------------------------------------------------------- /examples/json_rpc_server/json_rpc_server.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 Cesanta Software Limited 3 | * All rights reserved 4 | * 5 | * To test this server, do 6 | * $ curl -d '{"id":1,method:"sum",params:[22,33]}' 127.0.0.1:8000 7 | */ 8 | 9 | #include "fossa.h" 10 | 11 | static const char *s_http_port = "8000"; 12 | 13 | static int rpc_sum(char *buf, int len, struct ns_rpc_request *req) { 14 | double sum = 0; 15 | int i; 16 | 17 | if (req->params[0].type != JSON_TYPE_ARRAY) { 18 | return ns_rpc_create_std_error(buf, len, req, 19 | JSON_RPC_INVALID_PARAMS_ERROR); 20 | } 21 | 22 | for (i = 0; i < req->params[0].num_desc; i++) { 23 | if (req->params[i + 1].type != JSON_TYPE_NUMBER) { 24 | return ns_rpc_create_std_error(buf, len, req, 25 | JSON_RPC_INVALID_PARAMS_ERROR); 26 | } 27 | sum += strtod(req->params[i + 1].ptr, NULL); 28 | } 29 | return ns_rpc_create_reply(buf, len, req, "f", sum); 30 | } 31 | 32 | static void ev_handler(struct ns_connection *nc, int ev, void *ev_data) { 33 | struct http_message *hm = (struct http_message *) ev_data; 34 | static const char *methods[] = { "sum", NULL }; 35 | static ns_rpc_handler_t handlers[] = { rpc_sum, NULL }; 36 | char buf[100]; 37 | 38 | switch (ev) { 39 | case NS_HTTP_REQUEST: 40 | ns_rpc_dispatch(hm->body.p, hm->body.len, buf, sizeof(buf), 41 | methods, handlers); 42 | ns_printf(nc, "HTTP/1.0 200 OK\r\nContent-Length: %d\r\n" 43 | "Content-Type: application/json\r\n\r\n%s", 44 | (int) strlen(buf), buf); 45 | nc->flags |= NSF_SEND_AND_CLOSE; 46 | break; 47 | default: 48 | break; 49 | } 50 | } 51 | 52 | int main(void) { 53 | struct ns_mgr mgr; 54 | struct ns_connection *nc; 55 | 56 | ns_mgr_init(&mgr, NULL); 57 | nc = ns_bind(&mgr, s_http_port, ev_handler); 58 | ns_set_protocol_http_websocket(nc); 59 | 60 | printf("Starting JSON-RPC server on port %s\n", s_http_port); 61 | for (;;) { 62 | ns_mgr_poll(&mgr, 1000); 63 | } 64 | ns_mgr_free(&mgr); 65 | 66 | return 0; 67 | } 68 | -------------------------------------------------------------------------------- /examples/mqtt_broker/Makefile: -------------------------------------------------------------------------------- 1 | PROG = mqtt_broker 2 | SOURCES = $(PROG).c ../../fossa.c 3 | CFLAGS = -W -Wall -I../.. -pthread -DNS_ENABLE_SSL -DNS_ENABLE_MQTT_BROKER -lssl -lcrypto $(CFLAGS_EXTRA) 4 | 5 | all: $(PROG) 6 | 7 | $(PROG): $(SOURCES) 8 | $(CC) $(SOURCES) -o $@ $(CFLAGS) 9 | 10 | $(PROG).exe: $(SOURCES) 11 | cl $(SOURCES) /I../.. /DNS_ENABLE_SSL /DNS_ENABLE_MQTT_BROKER /MD /Fe$@ 12 | 13 | clean: 14 | rm -rf *.gc* *.dSYM *.exe *.obj *.o a.out $(PROG) 15 | -------------------------------------------------------------------------------- /examples/mqtt_broker/mqtt_broker.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 Cesanta Software Limited 3 | * All rights reserved 4 | * This software is dual-licensed: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License version 2 as 6 | * published by the Free Software Foundation. For the terms of this 7 | * license, see . 8 | * 9 | * You are free to use this software under the terms of the GNU General 10 | * Public License, but WITHOUT ANY WARRANTY; without even the implied 11 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 12 | * See the GNU General Public License for more details. 13 | * 14 | * Alternatively, you can license this software under a commercial 15 | * license, as set out in . 16 | */ 17 | 18 | #include "../../fossa.h" 19 | 20 | int main(void) { 21 | struct ns_mgr mgr; 22 | const char *address = "0.0.0.0:1883"; 23 | struct ns_connection *nc; 24 | struct ns_mqtt_broker brk; 25 | 26 | ns_mgr_init(&mgr, NULL); 27 | ns_mqtt_broker_init(&brk, NULL); 28 | 29 | if ((nc = ns_bind(&mgr, address, ns_mqtt_broker)) == NULL) { 30 | fprintf(stderr, "ns_bind(%s) failed\n", address); 31 | exit(EXIT_FAILURE); 32 | } 33 | nc->user_data = &brk; 34 | 35 | /* 36 | * TODO: Add a HTTP status page that shows current sessions 37 | * and subscriptions 38 | */ 39 | 40 | for(;;) { 41 | ns_mgr_poll(&mgr, 1000); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /examples/mqtt_client/Makefile: -------------------------------------------------------------------------------- 1 | PROG = mqtt_client 2 | SOURCES = $(PROG).c ../../fossa.c 3 | CFLAGS = -W -Wall -I../.. -pthread -DNS_ENABLE_SSL -lssl -lcrypto $(CFLAGS_EXTRA) 4 | 5 | all: $(PROG) 6 | 7 | $(PROG): $(SOURCES) 8 | $(CC) $(SOURCES) -o $@ $(CFLAGS) 9 | 10 | $(PROG).exe: $(SOURCES) 11 | cl $(SOURCES) /I../.. /DNS_ENABLE_SSL /MD /Fe$@ 12 | 13 | clean: 14 | rm -rf *.gc* *.dSYM *.exe *.obj *.o a.out $(PROG) 15 | -------------------------------------------------------------------------------- /examples/mqtt_client/mqtt_client.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 Cesanta Software Limited 3 | * All rights reserved 4 | * This software is dual-licensed: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License version 2 as 6 | * published by the Free Software Foundation. For the terms of this 7 | * license, see . 8 | * 9 | * You are free to use this software under the terms of the GNU General 10 | * Public License, but WITHOUT ANY WARRANTY; without even the implied 11 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 12 | * See the GNU General Public License for more details. 13 | * 14 | * Alternatively, you can license this software under a commercial 15 | * license, as set out in . 16 | */ 17 | 18 | #include "fossa.h" 19 | 20 | struct ns_mqtt_topic_expression topic_expressions[] = { 21 | {"/stuff", 0} 22 | }; 23 | 24 | static void ev_handler(struct ns_connection *nc, int ev, void *p) { 25 | struct ns_mqtt_message *msg = (struct ns_mqtt_message *)p; 26 | (void) nc; 27 | 28 | #if 0 29 | if (ev != NS_POLL) 30 | printf("USER HANDLER GOT %d\n", ev); 31 | #endif 32 | 33 | switch (ev) { 34 | case NS_CONNECT: 35 | ns_set_protocol_mqtt(nc); 36 | ns_send_mqtt_handshake(nc, "dummy"); 37 | break; 38 | case NS_MQTT_CONNACK: 39 | if (msg->connack_ret_code != NS_MQTT_CONNACK_ACCEPTED) { 40 | printf("Got mqtt connection error: %d\n", msg->connack_ret_code); 41 | exit(1); 42 | } 43 | printf("Subscribing to '/stuff'\n"); 44 | ns_mqtt_subscribe(nc, topic_expressions, sizeof(topic_expressions)/sizeof(*topic_expressions), 42); 45 | break; 46 | case NS_MQTT_PUBACK: 47 | printf("Message publishing acknowledged (msg_id: %d)\n", msg->message_id); 48 | break; 49 | case NS_MQTT_SUBACK: 50 | printf("Subscription acknowledged, forwarding to '/test'\n"); 51 | break; 52 | case NS_MQTT_PUBLISH: 53 | { 54 | #if 0 55 | char hex[1024] = {0}; 56 | ns_hexdump(nc->recv_mbuf.buf, msg->payload.len, hex, sizeof(hex)); 57 | printf("Got incoming message %s:\n%s", msg->topic, hex); 58 | #else 59 | printf("Got incoming message %s: %.*s\n", msg->topic, (int)msg->payload.len, msg->payload.p); 60 | #endif 61 | 62 | printf("Forwarding to /test\n"); 63 | ns_mqtt_publish(nc, "/test", 65, NS_MQTT_QOS(0), msg->payload.p, msg->payload.len); 64 | } 65 | break; 66 | case NS_CLOSE: 67 | printf("Connection closed\n"); 68 | exit(1); 69 | } 70 | } 71 | 72 | int main(void) { 73 | struct ns_mgr mgr; 74 | const char *address = "localhost:1883"; 75 | 76 | ns_mgr_init(&mgr, NULL); 77 | 78 | if (ns_connect(&mgr, address, ev_handler) == NULL) { 79 | fprintf(stderr, "ns_connect(%s) failed\n", address); 80 | exit(EXIT_FAILURE); 81 | } 82 | 83 | for(;;) { 84 | ns_mgr_poll(&mgr, 1000); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /examples/multithreaded_restful_server/Makefile: -------------------------------------------------------------------------------- 1 | PROG = multithreaded_restful_server 2 | SOURCES = $(PROG).c ../../fossa.c 3 | APP_FLAGS = -DNS_ENABLE_THREADS $(CFLAGS_EXTRA) 4 | 5 | ifeq ($(OS), Windows_NT) 6 | APP_FLAGS += advapi32.lib 7 | endif 8 | 9 | all: $(PROG) 10 | 11 | $(PROG): $(SOURCES) 12 | $(CC) $(SOURCES) -o $@ -W -Wall -I../.. -pthread $(APP_FLAGS) 13 | 14 | $(PROG).exe: $(SOURCES) 15 | cl $(SOURCES) /I../.. /MD /Fe$@ $(APP_FLAGS) 16 | 17 | clean: 18 | rm -rf *.gc* *.dSYM *.exe *.obj *.o a.out $(PROG) 19 | -------------------------------------------------------------------------------- /examples/multithreaded_restful_server/multithreaded_restful_server.c: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Cesanta Software Limited 2 | // All rights reserved 3 | 4 | // This example shows how to handle long, blocking requests by 5 | // handing off computation to different threads. Here, each 6 | // request spawns a new thread. In a production scenario, a thread 7 | // pools can be used for efficiency, if required. 8 | // Long computation is simulated by sleeping for a random interval. 9 | 10 | #include "fossa.h" 11 | 12 | static const char *s_http_port = "8000"; 13 | 14 | static void ev_handler(struct ns_connection *c, int ev, void *p) { 15 | if (ev == NS_HTTP_REQUEST) { 16 | struct http_message *hm = (struct http_message *) p; 17 | char reply[100]; 18 | 19 | /* Simulate long calculation */ 20 | sleep(3); 21 | 22 | /* Send the reply */ 23 | snprintf(reply, sizeof(reply), "{ \"uri\": \"%.*s\" }\n", 24 | (int) hm->uri.len, hm->uri.p); 25 | ns_printf(c, "HTTP/1.1 200 OK\r\n" 26 | "Content-Type: application/json\r\n" 27 | "Content-Length: %d\r\n" 28 | "\r\n" 29 | "%s", 30 | (int) strlen(reply), reply); 31 | } 32 | } 33 | 34 | int main(void) { 35 | struct ns_mgr mgr; 36 | struct ns_connection *nc; 37 | 38 | ns_mgr_init(&mgr, NULL); 39 | nc = ns_bind(&mgr, s_http_port, ev_handler); 40 | ns_set_protocol_http_websocket(nc); 41 | 42 | /* For each new connection, execute ev_handler in a separate thread */ 43 | ns_enable_multithreading(nc); 44 | 45 | printf("Starting multi-threaded server on port %s\n", s_http_port); 46 | for (;;) { 47 | ns_mgr_poll(&mgr, 3000); 48 | } 49 | ns_mgr_free(&mgr); 50 | 51 | return 0; 52 | } 53 | -------------------------------------------------------------------------------- /examples/netcat/Makefile: -------------------------------------------------------------------------------- 1 | PROG = nc 2 | SOURCES = $(PROG).c ../../fossa.c 3 | CFLAGS = -W -Wall -I../.. -pthread -DNS_ENABLE_SSL -DNS_ENABLE_THREADS -lssl -lcrypto $(CFLAGS_EXTRA) 4 | 5 | all: $(PROG) 6 | 7 | $(PROG): $(SOURCES) 8 | $(CC) $(SOURCES) -o $@ $(CFLAGS) 9 | 10 | $(PROG).exe: $(SOURCES) 11 | cl $(SOURCES) /I../.. /DNS_ENABLE_SSL /MD /Fe$@ 12 | 13 | clean: 14 | rm -rf *.gc* *.dSYM *.exe *.obj *.o a.out $(PROG) 15 | -------------------------------------------------------------------------------- /examples/netcat/nc.c: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2014 Cesanta Software Limited 2 | // All rights reserved 3 | // 4 | // This software is dual-licensed: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License version 2 as 6 | // published by the Free Software Foundation. For the terms of this 7 | // license, see . 8 | // 9 | // You are free to use this software under the terms of the GNU General 10 | // Public License, but WITHOUT ANY WARRANTY; without even the implied 11 | // warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 12 | // See the GNU General Public License for more details. 13 | // 14 | // Alternatively, you can license this software under a commercial 15 | // license, as set out in . 16 | // 17 | // $Date: 2014-09-28 05:04:41 UTC $ 18 | 19 | // This file implements "netcat" utility with SSL and traffic hexdump. 20 | 21 | #include "fossa.h" 22 | 23 | static sig_atomic_t s_received_signal = 0; 24 | 25 | static void signal_handler(int sig_num) { 26 | signal(sig_num, signal_handler); 27 | s_received_signal = sig_num; 28 | } 29 | 30 | static void show_usage_and_exit(const char *prog_name) { 31 | fprintf(stderr, "%s\n", "Copyright (c) 2014 CESANTA SOFTWARE"); 32 | fprintf(stderr, "%s\n", "Usage:"); 33 | fprintf(stderr, " %s\n [-d debug_file] [-l] [tcp|ssl]://[ip:]port[:cert][:ca_cert]", 34 | prog_name); 35 | fprintf(stderr, "%s\n", "Examples:"); 36 | fprintf(stderr, " %s\n -d hexdump.txt ssl://google.com:443", prog_name); 37 | fprintf(stderr, " %s\n -l ssl://443:ssl_cert.pem", prog_name); 38 | fprintf(stderr, " %s\n -l tcp://8080", prog_name); 39 | exit(EXIT_FAILURE); 40 | } 41 | 42 | static void on_stdin_read(struct ns_connection *nc, int ev, void *p) { 43 | int ch = * (int *) p; 44 | 45 | (void) ev; 46 | 47 | if (ch < 0) { 48 | // EOF is received from stdin. Schedule the connection to close 49 | nc->flags |= NSF_SEND_AND_CLOSE; 50 | if (nc->send_mbuf.len <= 0) { 51 | nc->flags |= NSF_CLOSE_IMMEDIATELY; 52 | } 53 | } else { 54 | // A character is received from stdin. Send it to the connection. 55 | unsigned char c = (unsigned char) ch; 56 | ns_send(nc, &c, 1); 57 | } 58 | } 59 | 60 | static void *stdio_thread_func(void *param) { 61 | struct ns_mgr *mgr = (struct ns_mgr *) param; 62 | int ch; 63 | 64 | // Read stdin until EOF character by character, sending them to the mgr 65 | while ((ch = getchar()) != EOF) { 66 | ns_broadcast(mgr, on_stdin_read, &ch, sizeof(ch)); 67 | } 68 | s_received_signal = 1; 69 | 70 | return NULL; 71 | } 72 | 73 | static void ev_handler(struct ns_connection *nc, int ev, void *p) { 74 | (void) p; 75 | 76 | switch (ev) { 77 | case NS_ACCEPT: 78 | case NS_CONNECT: 79 | ns_start_thread(stdio_thread_func, nc->mgr); 80 | break; 81 | 82 | case NS_CLOSE: 83 | s_received_signal = 1; 84 | break; 85 | 86 | case NS_RECV: 87 | fwrite(nc->recv_mbuf.buf, 1, nc->recv_mbuf.len, stdout); 88 | mbuf_remove(&nc->recv_mbuf, nc->recv_mbuf.len); 89 | break; 90 | 91 | default: 92 | break; 93 | } 94 | } 95 | 96 | int main(int argc, char *argv[]) { 97 | struct ns_mgr mgr; 98 | int i, is_listening = 0; 99 | const char *address = NULL; 100 | 101 | ns_mgr_init(&mgr, NULL); 102 | 103 | // Parse command line options 104 | for (i = 1; i < argc && argv[i][0] == '-'; i++) { 105 | if (strcmp(argv[i], "-l") == 0) { 106 | is_listening = 1; 107 | } else if (strcmp(argv[i], "-d") == 0 && i + 1 < argc) { 108 | mgr.hexdump_file = argv[++i]; 109 | } else { 110 | show_usage_and_exit(argv[0]); 111 | } 112 | } 113 | 114 | if (i + 1 == argc) { 115 | address = argv[i]; 116 | } else { 117 | show_usage_and_exit(argv[0]); 118 | } 119 | 120 | signal(SIGTERM, signal_handler); 121 | signal(SIGINT, signal_handler); 122 | signal(SIGPIPE, SIG_IGN); 123 | 124 | if (is_listening) { 125 | if (ns_bind(&mgr, address, ev_handler) == NULL) { 126 | fprintf(stderr, "ns_bind(%s) failed\n", address); 127 | exit(EXIT_FAILURE); 128 | } 129 | } else if (ns_connect(&mgr, address, ev_handler) == NULL) { 130 | fprintf(stderr, "ns_connect(%s) failed\n", address); 131 | exit(EXIT_FAILURE); 132 | } 133 | 134 | while (s_received_signal == 0) { 135 | ns_mgr_poll(&mgr, 1000); 136 | } 137 | ns_mgr_free(&mgr); 138 | 139 | return EXIT_SUCCESS; 140 | } 141 | -------------------------------------------------------------------------------- /examples/publish_subscribe/Makefile: -------------------------------------------------------------------------------- 1 | PROG = publish_subscribe 2 | SOURCES = $(PROG).c ../../fossa.c 3 | CFLAGS = -W -Wall -I../.. -DNS_ENABLE_THREADS -pthread $(CFLAGS_EXTRA) 4 | 5 | all: $(PROG) 6 | 7 | $(PROG): $(SOURCES) 8 | $(CC) $(SOURCES) -o $@ $(CFLAGS) 9 | 10 | $(PROG).exe: $(SOURCES) 11 | cl $(SOURCES) /I../.. /MD /Fe$@ 12 | 13 | clean: 14 | rm -rf *.gc* *.dSYM *.exe *.obj *.o a.out $(PROG) 15 | -------------------------------------------------------------------------------- /examples/publish_subscribe/publish_subscribe.c: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2014 Cesanta Software Limited 2 | // All rights reserved 3 | // 4 | // This software is dual-licensed: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License version 2 as 6 | // published by the Free Software Foundation. For the terms of this 7 | // license, see . 8 | // 9 | // You are free to use this software under the terms of the GNU General 10 | // Public License, but WITHOUT ANY WARRANTY; without even the implied 11 | // warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 12 | // See the GNU General Public License for more details. 13 | // 14 | // Alternatively, you can license this software under a commercial 15 | // license, as set out in . 16 | // 17 | // $Date: 2014-09-28 05:04:41 UTC $ 18 | 19 | #include "fossa.h" 20 | 21 | static void *stdin_thread(void *param) { 22 | int ch, sock = * (int *) param; 23 | while ((ch = getchar()) != EOF) { 24 | unsigned char c = (unsigned char) ch; 25 | send(sock, &c, 1, 0); // Forward all types characters to the socketpair 26 | } 27 | return NULL; 28 | } 29 | 30 | static void server_handler(struct ns_connection *nc, int ev, void *p) { 31 | (void) p; 32 | if (ev == NS_RECV) { 33 | // Push received message to all ncections 34 | struct mbuf *io = &nc->recv_mbuf; 35 | struct ns_connection *c; 36 | 37 | for (c = ns_next(nc->mgr, NULL); c != NULL; c = ns_next(nc->mgr, c)) { 38 | ns_send(c, io->buf, io->len); 39 | } 40 | mbuf_remove(io, io->len); 41 | } 42 | } 43 | 44 | static void client_handler(struct ns_connection *conn, int ev, void *p) { 45 | struct mbuf *io = &conn->recv_mbuf; 46 | (void) p; 47 | 48 | if (ev == NS_CONNECT) { 49 | if (conn->flags & NSF_CLOSE_IMMEDIATELY) { 50 | printf("%s\n", "Error connecting to server!"); 51 | exit(EXIT_FAILURE); 52 | } 53 | printf("%s\n", "Connected to server. Type a message and press enter."); 54 | } else if (ev == NS_RECV) { 55 | if (conn->flags & NSF_USER_1) { 56 | // Received data from the stdin, forward it to the server 57 | struct ns_connection *c = (struct ns_connection *) conn->user_data; 58 | ns_send(c, io->buf, io->len); 59 | mbuf_remove(io, io->len); 60 | } else { 61 | // Received data from server connection, print it 62 | fwrite(io->buf, io->len, 1, stdout); 63 | mbuf_remove(io, io->len); 64 | } 65 | } else if (ev == NS_CLOSE) { 66 | // Connection has closed, most probably cause server has stopped 67 | exit(EXIT_SUCCESS); 68 | } 69 | } 70 | 71 | int main(int argc, char *argv[]) { 72 | struct ns_mgr mgr; 73 | 74 | if (argc != 3) { 75 | fprintf(stderr, "Usage: %s \n", argv[0]); 76 | exit(EXIT_FAILURE); 77 | } else if (strcmp(argv[2], "client") == 0) { 78 | int fds[2]; 79 | struct ns_connection *ioconn, *server_conn; 80 | 81 | ns_mgr_init(&mgr, NULL); 82 | 83 | // Connect to the pubsub server 84 | server_conn = ns_connect(&mgr, argv[1], client_handler); 85 | if (server_conn == NULL) { 86 | fprintf(stderr, "Cannot connect to port %s\n", argv[1]); 87 | exit(EXIT_FAILURE); 88 | } 89 | 90 | // Create a socketpair and give one end to the thread that reads stdin 91 | ns_socketpair(fds, SOCK_STREAM); 92 | ns_start_thread(stdin_thread, &fds[1]); 93 | 94 | // The other end of a pair goes inside the server 95 | ioconn = ns_add_sock(&mgr, fds[0], client_handler); 96 | ioconn->flags |= NSF_USER_1; // Mark this so we know this is a stdin 97 | ioconn->user_data = server_conn; 98 | 99 | } else { 100 | // Server code path 101 | ns_mgr_init(&mgr, NULL); 102 | ns_bind(&mgr, argv[1], server_handler); 103 | printf("Starting pubsub server on port %s\n", argv[1]); 104 | } 105 | 106 | for (;;) { 107 | ns_mgr_poll(&mgr, 1000); 108 | } 109 | ns_mgr_free(&mgr); 110 | 111 | return EXIT_SUCCESS; 112 | } 113 | -------------------------------------------------------------------------------- /examples/raspberry_pi_mjpeg_led/Makefile: -------------------------------------------------------------------------------- 1 | NS=../../fossa.c 2 | FLAGS = ../../fossa.c -I../.. 3 | CFLAGS=-W -Wall -DNS_ENABLE_THREADS -pthread $(CFLAGS_EXTRA) 4 | PROGS = device_side cloud_side 5 | 6 | all: $(PROGS) 7 | 8 | device_side: Makefile device_side.c $(NS) 9 | $(CC) device_side.c $(FLAGS) -o $@ $(CFLAGS) 10 | 11 | cloud_side: Makefile cloud_side.c $(NS) 12 | $(CC) cloud_side.c $(FLAGS) -o $@ $(CFLAGS) 13 | 14 | device_side.exe: Makefile device_side.c $(NS) 15 | cl device_side.c $(FLAGS) /MD /Fe$@ 16 | 17 | clean: 18 | rm -rf *.gc* *.dSYM *.exe *.obj *.o a.out $(PROGS) 19 | -------------------------------------------------------------------------------- /examples/raspberry_pi_mjpeg_led/README.adoc: -------------------------------------------------------------------------------- 1 | = Raspberry Pi camera/LED demo 2 | 3 | == Overview 4 | 5 | The link:/[demo] consists of web app providing access to a webcam and a LED attached to a RaspberryPi. 6 | The device is assumed to have a limited bandwidth towards the server hosting the web app. 7 | 8 | == Objective 9 | 10 | The demo shows how to use websockets to communicate bidirectionally with an embedded device using standard protocols. 11 | 12 | It also shows that it's possible to use Smart.c to develop also the cloud endpoint and expose WebSocket and RESTful APIs 13 | easy to integreate with modern web stacks. 14 | 15 | == How it works 16 | 17 | image::docs/arch.png[] 18 | 19 | There are two components, once with runs on the device (`device_side`) and one that runs on a stronger machine 20 | and with more bandwidth (`cloud_side`). 21 | 22 | The device app connects to the cloud app via websocket and sends a new jpeg frame as fast as the underlying `raspistill` camera 23 | grabbing application can handle. The device automatically attempts reconnecting. 24 | 25 | The cloud side serves the webapp static pages and serves an MPJEG image on `/mpjg`. 26 | The MPJEG image handler blocks all the clients until a JPEG frame arrives via websocket 27 | and then every client will recieve a copy of the frame. 28 | 29 | The web app can turn on and off the LED via a RESTful api accessible via the `/api` handler. 30 | 31 | == Installation 32 | 33 | === Server side 34 | 35 | ---- 36 | git clone https://github.com/cesanta/fossa 37 | cd fossa/examples/web_demo 38 | make cloud_side && ./cloud_side 0.0.0.0:8080 39 | ---- 40 | 41 | === Raspberry Pi 42 | 43 | The instructions provided here are tailored for the Raspbian distribution. 44 | 45 | ==== Dependencies 46 | 47 | jpegoptim:: 48 | apt-get install jpegoptim 49 | 50 | camera:: 51 | run raspi-config and enable camera 52 | 53 | ==== LED 54 | 55 | In order to access the led on your link:http://www.qdh.org.uk/wordpress/?page_id=15[HotPi] 56 | board you need to export the gpio pins: 57 | 58 | ---- 59 | for i in 22 23 24; do 60 | echo $i >/sys/class/gpio/export 61 | echo out >/sys/class/gpio/gpio$i/direction 62 | chgrp pi /sys/class/gpio/gpio$i/value 63 | done 64 | ---- 65 | 66 | ==== Build and run 67 | 68 | ---- 69 | git clone https://github.com/cesanta/fossa 70 | cd fossa/examples/web_demo 71 | make device_side && ./device_side yourserver:8080 72 | ---- 73 | -------------------------------------------------------------------------------- /examples/raspberry_pi_mjpeg_led/docs/arch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cesanta/fossa/03b7e568abafcca31a4361df849e01b5fca7e202/examples/raspberry_pi_mjpeg_led/docs/arch.png -------------------------------------------------------------------------------- /examples/raspberry_pi_mjpeg_led/web_root/docs/arch.png: -------------------------------------------------------------------------------- 1 | ../../docs/arch.png -------------------------------------------------------------------------------- /examples/raspberry_pi_mjpeg_led/web_root/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | Smart.c mjpg example 13 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 |
28 | 29 |
30 | 31 | 48 | 49 | 86 |
87 |
88 | 89 | 90 | 107 | 108 | 109 | -------------------------------------------------------------------------------- /examples/restful_client/Makefile: -------------------------------------------------------------------------------- 1 | PROG = restful_client 2 | SOURCES = $(PROG).c ../../fossa.c 3 | CFLAGS = -W -Wall -I../.. -pthread $(CFLAGS_EXTRA) 4 | 5 | all: $(PROG) 6 | 7 | $(PROG): $(SOURCES) 8 | $(CC) $(SOURCES) -o $@ $(CFLAGS) 9 | 10 | $(PROG).exe: $(SOURCES) 11 | cl $(SOURCES) /I../.. /MD /Fe$@ 12 | 13 | clean: 14 | rm -rf *.gc* *.dSYM *.exe *.obj *.o a.out $(PROG) 15 | -------------------------------------------------------------------------------- /examples/restful_client/restful_client.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 Cesanta Software Limited 3 | * All rights reserved 4 | */ 5 | 6 | #include "fossa.h" 7 | 8 | /* RESTful server host and request URI */ 9 | static const char *s_target_address = "ajax.googleapis.com:80"; 10 | static const char *s_request = "/ajax/services/search/web?v=1.0&q=cesanta"; 11 | 12 | static int s_exit_flag = 0; 13 | 14 | static void ev_handler(struct ns_connection *nc, int ev, void *ev_data) { 15 | struct http_message *hm = (struct http_message *) ev_data; 16 | int connect_status; 17 | 18 | switch (ev) { 19 | case NS_CONNECT: 20 | connect_status = * (int *) ev_data; 21 | if (connect_status == 0) { 22 | printf("Connected to %s, sending request...\n", s_target_address); 23 | ns_printf(nc, "GET %s HTTP/1.0\r\nHost: %s\r\n\r\n", 24 | s_request, s_target_address); 25 | } else { 26 | printf("Error connecting to %s: %s\n", 27 | s_target_address, strerror(connect_status)); 28 | s_exit_flag = 1; 29 | } 30 | break; 31 | case NS_HTTP_REPLY: 32 | printf("Got reply:\n%.*s\n", (int) hm->body.len, hm->body.p); 33 | nc->flags |= NSF_SEND_AND_CLOSE; 34 | s_exit_flag = 1; 35 | break; 36 | default: 37 | break; 38 | } 39 | } 40 | 41 | int main(void) { 42 | struct ns_mgr mgr; 43 | struct ns_connection *nc; 44 | 45 | ns_mgr_init(&mgr, NULL); 46 | nc = ns_connect(&mgr, s_target_address, ev_handler); 47 | ns_set_protocol_http_websocket(nc); 48 | 49 | printf("Starting RESTful client against %s\n", s_target_address); 50 | while (s_exit_flag == 0) { 51 | ns_mgr_poll(&mgr, 1000); 52 | } 53 | ns_mgr_free(&mgr); 54 | 55 | return 0; 56 | } 57 | -------------------------------------------------------------------------------- /examples/restful_server/Makefile: -------------------------------------------------------------------------------- 1 | PROG = restful_server 2 | SOURCES = $(PROG).c ../../fossa.c 3 | CFLAGS = -W -Wall -I../.. $(CFLAGS_EXTRA) 4 | 5 | ifeq ($(SSL), openssl) 6 | CFLAGS += -DNS_ENABLE_SSL -lssl -lcrypto -lcrypto 7 | else ifeq ($(SSL), krypton) 8 | CFLAGS += -DNS_ENABLE_SSL ../../../krypton/krypton.c 9 | endif 10 | 11 | all: $(PROG) 12 | 13 | $(PROG): $(SOURCES) 14 | $(CC) $(SOURCES) -o $@ $(CFLAGS) 15 | 16 | $(PROG).exe: $(SOURCES) 17 | cl $(SOURCES) /I../.. /MD /DNS_ENABLE_THREADS /Fe$@ advapi32.lib 18 | 19 | clean: 20 | rm -rf *.gc* *.dSYM *.exe *.obj *.o a.out $(PROG) 21 | -------------------------------------------------------------------------------- /examples/restful_server/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | RESTful API demo 6 | 7 | 26 | 27 | 28 | 45 | 46 | 47 |
48 |

RESTful API demo.

49 | 50 |

51 | This page demonstrates how Fossa could be used to implement 52 | RESTful APIs. Start typing numbers into the text fields below. 53 | Browser sends two numbers to /api/v1/sum URI. 54 | Web server calclulates the sum and returns the result. 55 |

56 | 57 |
58 | 59 |
60 | 61 |
62 |   63 |
64 | 65 |
66 | 67 | 68 | -------------------------------------------------------------------------------- /examples/restful_server/restful_server.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 Cesanta Software Limited 3 | * All rights reserved 4 | */ 5 | 6 | #include "fossa.h" 7 | 8 | static const char *s_http_port = "8000"; 9 | static struct ns_serve_http_opts s_http_server_opts; 10 | 11 | static void handle_sum_call(struct ns_connection *nc, struct http_message *hm) { 12 | char n1[100], n2[100]; 13 | double result; 14 | 15 | /* Get form variables */ 16 | ns_get_http_var(&hm->body, "n1", n1, sizeof(n1)); 17 | ns_get_http_var(&hm->body, "n2", n2, sizeof(n2)); 18 | 19 | /* Send headers */ 20 | ns_printf(nc, "%s", "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n"); 21 | 22 | /* Compute the result and send it back as a JSON object */ 23 | result = strtod(n1, NULL) + strtod(n2, NULL); 24 | ns_printf_http_chunk(nc, "{ \"result\": %lf }", result); 25 | ns_send_http_chunk(nc, "", 0); /* Send empty chunk, the end of response */ 26 | } 27 | 28 | static void ev_handler(struct ns_connection *nc, int ev, void *ev_data) { 29 | struct http_message *hm = (struct http_message *) ev_data; 30 | 31 | switch (ev) { 32 | case NS_HTTP_REQUEST: 33 | if (ns_vcmp(&hm->uri, "/api/v1/sum") == 0) { 34 | handle_sum_call(nc, hm); /* Handle RESTful call */ 35 | } else if (ns_vcmp(&hm->uri, "/printcontent") == 0) { 36 | char buf[100] = {0}; 37 | memcpy(buf, hm->body.p, 38 | sizeof(buf) - 1 < hm->body.len? sizeof(buf) - 1 : hm->body.len); 39 | printf("%s\n", buf); 40 | } else { 41 | ns_serve_http(nc, hm, s_http_server_opts); /* Serve static content */ 42 | } 43 | break; 44 | default: 45 | break; 46 | } 47 | } 48 | 49 | int main(int argc, char *argv[]) { 50 | struct ns_mgr mgr; 51 | struct ns_connection *nc; 52 | int i; 53 | char *cp; 54 | 55 | ns_mgr_init(&mgr, NULL); 56 | 57 | /* Process command line options to customize HTTP server */ 58 | for (i = 1; i < argc; i++) { 59 | if (strcmp(argv[i], "-D") == 0 && i + 1 < argc) { 60 | mgr.hexdump_file = argv[++i]; 61 | } else if (strcmp(argv[i], "-d") == 0 && i + 1 < argc) { 62 | s_http_server_opts.document_root = argv[++i]; 63 | } else if (strcmp(argv[i], "-p") == 0 && i + 1 < argc) { 64 | s_http_port = argv[++i]; 65 | } else if (strcmp(argv[i], "-a") == 0 && i + 1 < argc) { 66 | s_http_server_opts.auth_domain = argv[++i]; 67 | } else if (strcmp(argv[i], "-P") == 0 && i + 1 < argc) { 68 | s_http_server_opts.global_auth_file = argv[++i]; 69 | } else if (strcmp(argv[i], "-p") == 0 && i + 1 < argc) { 70 | s_http_server_opts.per_directory_auth_file = argv[++i]; 71 | } else if (strcmp(argv[i], "-r") == 0 && i + 1 < argc) { 72 | s_http_server_opts.url_rewrites = argv[++i]; 73 | #ifndef NS_DISABLE_CGI 74 | } else if (strcmp(argv[i], "-i") == 0 && i + 1 < argc) { 75 | s_http_server_opts.cgi_interpreter = argv[++i]; 76 | #endif 77 | #ifdef NS_ENABLE_SSL 78 | } else if (strcmp(argv[i], "-s") == 0 && i + 1 < argc) { 79 | const char *ssl_cert = argv[++i]; 80 | const char *err_str = ns_set_ssl(nc, ssl_cert, NULL); 81 | if (err_str != NULL) { 82 | fprintf(stderr, "Error loading SSL cert: %s\n", err_str); 83 | exit(1); 84 | } 85 | #endif 86 | } 87 | } 88 | 89 | /* Set HTTP server options */ 90 | nc = ns_bind(&mgr, s_http_port, ev_handler); 91 | if (nc == NULL) { 92 | fprintf(stderr, "Error starting server on port %s\n", s_http_port); 93 | exit(1); 94 | } 95 | 96 | ns_set_protocol_http_websocket(nc); 97 | s_http_server_opts.document_root = "."; 98 | s_http_server_opts.enable_directory_listing = "yes"; 99 | 100 | /* Use current binary directory as document root */ 101 | if (argc > 0 && ((cp = strrchr(argv[0], '/')) != NULL || 102 | (cp = strrchr(argv[0], '/')) != NULL)) { 103 | *cp = '\0'; 104 | s_http_server_opts.document_root = argv[0]; 105 | } 106 | 107 | printf("Starting RESTful server on port %s\n", s_http_port); 108 | for (;;) { 109 | ns_mgr_poll(&mgr, 1000); 110 | } 111 | ns_mgr_free(&mgr); 112 | 113 | return 0; 114 | } 115 | -------------------------------------------------------------------------------- /examples/restful_server_s3/Makefile: -------------------------------------------------------------------------------- 1 | PROG = restful_server_s3 2 | SOURCES = $(PROG).c ../../fossa.c 3 | CFLAGS = -W -Wall -I../.. $(CFLAGS_EXTRA) 4 | 5 | ifeq ($(SSL), openssl) 6 | CFLAGS += -DNS_ENABLE_SSL -lssl -lcrypto -lcrypto 7 | else ifeq ($(SSL), krypton) 8 | CFLAGS += -DNS_ENABLE_SSL ../../../krypton/krypton.c 9 | endif 10 | 11 | all: $(PROG) 12 | 13 | $(PROG): $(SOURCES) 14 | $(CC) $(SOURCES) -o $@ $(CFLAGS) 15 | 16 | $(PROG).exe: $(SOURCES) 17 | cl $(SOURCES) /I../.. /MD /DNS_ENABLE_THREADS /Fe$@ advapi32.lib 18 | 19 | clean: 20 | rm -rf *.gc* *.dSYM *.exe *.obj *.o a.out $(PROG) 21 | -------------------------------------------------------------------------------- /examples/restful_server_s3/README.md: -------------------------------------------------------------------------------- 1 | RESTful server with Amazon S3 upload example 2 | ============================================ 3 | 4 | This example demonstrates how Fossa could be used to implement a RESTful 5 | service that uses another RESTful service to handle it's own API call. 6 | This example takes form data and uploads it as a file to Amazon S3. 7 | 8 | ## Prerequisites 9 | 10 | - Amazon S3 account security credentials: Access Key ID and Secret Access 11 | Key ID. Get them from the Amazon IAM console. 12 | - Amazon S3 bucket. 13 | 14 | ## Building and running the example 15 | 16 | $ git clone https://github.com/cesanta/fossa.git 17 | $ cd fossa/examples/restful_server_s3 18 | $ make 19 | $ ./restful_server_s3 -a ACCESS_KEY_ID -s SECRET_ACCESS_KEY_ID 20 | Starting RESTful server on port 8000 21 | 22 | Then, open a browser on `http://localhost:8000` 23 | 24 | Note: If you're getting a *Temporary Redirect* error, look what is the 25 | Endpoint value is. It's likely that you have something like 26 | `BUCKET_NAME.S3_ZONE.amazonaws.com`. 27 | Change the *Host* field to `S3_ZONE.amazonaws.com and retry`. 28 | 29 | ## Screenshot 30 | 31 | ![](https://docs.cesanta.com/images/fossa_s3_example.png) 32 | -------------------------------------------------------------------------------- /examples/restful_server_s3/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | RESTful API demo 6 | 7 | 30 | 31 | 32 | 54 | 55 | 56 |
57 |

RESTful server with Amazon S3 integration demo.

58 | 59 |

60 | This page demonstrates how Fossa could be used to implement 61 | a RESTful service that uses another RESTful service to handle 62 | it's own API call. This example takes form data and uploads it as a file 63 | to Amazon S3. 64 | Open S3 console and create a bucket for testing. Fill out correct 65 | bucket name in the fields below. 66 |

67 | 68 |

If you're getting a "Temporary Redirect" error, look what is the 69 | Endpoint value is. It's likely that you have something like 70 | BUCKET_NAME.S3_ZONE.amazonaws.com. Change 71 | the Host field to S3_ZONE.amazonaws.com and retry. 72 |

73 | 74 |
75 |
76 | 78 |
79 | 81 |
82 | 84 |
85 | 87 |
88 | 89 | 90 |
91 |
 
92 |
93 |
94 | 95 |
96 | 97 | 98 | -------------------------------------------------------------------------------- /examples/rules.mk: -------------------------------------------------------------------------------- 1 | SOURCES = $(PROG).c ../../fossa.c 2 | CFLAGS = -W -Wall -I../.. -pthread -DNS_ENABLE_SSL -DNS_ENABLE_IPV6 -DNS_ENABLE_THREADS -lssl -lcrypto $(CFLAGS_EXTRA) $(MODULE_CFLAGS) 3 | 4 | all: $(PROG) 5 | 6 | $(PROG): $(SOURCES) 7 | $(CC) $(SOURCES) -o $@ $(CFLAGS) 8 | 9 | $(PROG).exe: $(SOURCES) 10 | cl $(SOURCES) /I../.. /DNS_ENABLE_SSL /MD /Fe$@ 11 | 12 | clean: 13 | rm -rf *.gc* *.dSYM *.exe *.obj *.o a.out $(PROG) 14 | -------------------------------------------------------------------------------- /examples/settings_panel_for_a_device/Makefile: -------------------------------------------------------------------------------- 1 | PROG = settings_panel 2 | SOURCES = $(PROG).c ../../fossa.c 3 | CFLAGS = -W -Wall -I../.. -DNS_ENABLE_SSL -lssl -lcrypto $(CFLAGS_EXTRA) 4 | 5 | all: $(PROG) 6 | 7 | $(PROG): $(SOURCES) 8 | $(CC) $(SOURCES) -o $@ $(CFLAGS) 9 | 10 | clean: 11 | rm -rf *.gc* *.dSYM *.exe *.obj *.o a.out $(PROG) 12 | -------------------------------------------------------------------------------- /examples/settings_panel_for_a_device/settings_panel.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Cesanta Software Limited 3 | * All rights reserved 4 | */ 5 | 6 | #include "fossa.h" 7 | 8 | struct device_settings { 9 | char setting1[100]; 10 | char setting2[100]; 11 | }; 12 | 13 | static const char *s_http_port = "8000"; 14 | static struct ns_serve_http_opts s_http_server_opts; 15 | static struct device_settings s_settings = { "value1", "value2" }; 16 | 17 | static void handle_save(struct ns_connection *nc, struct http_message *hm) { 18 | /* Get form variables and store settings values */ 19 | ns_get_http_var(&hm->body, "setting1", s_settings.setting1, 20 | sizeof(s_settings.setting1)); 21 | ns_get_http_var(&hm->body, "setting2", s_settings.setting2, 22 | sizeof(s_settings.setting2)); 23 | 24 | /* Send response */ 25 | ns_printf(nc, "HTTP/1.1 200 OK\r\nContent-Length: %lu\r\n\r\n%.*s", 26 | (unsigned long) hm->body.len, (int) hm->body.len, hm->body.p); 27 | } 28 | 29 | static void handle_ssi_call(struct ns_connection *nc, const char *param) { 30 | if (strcmp(param, "setting1") == 0) { 31 | ns_printf_html_escape(nc, "%s", s_settings.setting1); 32 | } else if (strcmp(param, "setting2") == 0) { 33 | ns_printf_html_escape(nc, "%s", s_settings.setting2); 34 | } 35 | } 36 | 37 | static void ev_handler(struct ns_connection *nc, int ev, void *ev_data) { 38 | struct http_message *hm = (struct http_message *) ev_data; 39 | 40 | switch (ev) { 41 | case NS_HTTP_REQUEST: 42 | if (ns_vcmp(&hm->uri, "/save") == 0) { 43 | handle_save(nc, hm); /* Handle RESTful call */ 44 | } else { 45 | ns_serve_http(nc, hm, s_http_server_opts); /* Serve static content */ 46 | } 47 | break; 48 | case NS_SSI_CALL: 49 | handle_ssi_call(nc, ev_data); 50 | break; 51 | default: 52 | break; 53 | } 54 | } 55 | 56 | int main(int argc, char *argv[]) { 57 | struct ns_mgr mgr; 58 | struct ns_connection *nc; 59 | char *p, path[512]; 60 | 61 | ns_mgr_init(&mgr, NULL); 62 | nc = ns_bind(&mgr, s_http_port, ev_handler); 63 | ns_set_protocol_http_websocket(nc); 64 | s_http_server_opts.document_root = "./web_root"; 65 | s_http_server_opts.auth_domain = "example.com"; 66 | //mgr.hexdump_file = "/dev/stdout"; 67 | 68 | /* If our current directory */ 69 | if (argc > 0 && (p = strrchr(argv[0], '/'))) { 70 | snprintf(path, sizeof(path), "%.*s/web_root", (int)(p - argv[0]), argv[0]); 71 | s_http_server_opts.document_root = path; 72 | } 73 | 74 | printf("Starting device configurator on port %s\n", s_http_port); 75 | for (;;) { 76 | ns_mgr_poll(&mgr, 1000); 77 | } 78 | ns_mgr_free(&mgr); 79 | 80 | return 0; 81 | } 82 | -------------------------------------------------------------------------------- /examples/settings_panel_for_a_device/web_root/fossa.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cesanta/fossa/03b7e568abafcca31a4361df849e01b5fca7e202/examples/settings_panel_for_a_device/web_root/fossa.jpg -------------------------------------------------------------------------------- /examples/settings_panel_for_a_device/web_root/index.shtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | RESTful API demo 6 | 7 | 31 | 32 | 33 | 57 | 58 | 59 |
60 | 61 |

Device Configurator demo.

62 | 63 |

64 | This page demonstrates how Fossa could be used to implement 65 | device settings page.

66 | 67 |

How to show device parameters on the page

68 |

This page has embedded 69 | <!--#call parameter_name --> blocks. For each such 70 | block, fossa triggers NS_SSI_CALL event, passing 71 | parameter_name string as an event parameter. A callback 72 | then can print some content, which will replace the 73 | <!--#call parameter_name --> block. 74 | Take a look at handle_ssi_call() to see how that is done. 75 |

76 | 77 |

How to save updated values

78 |

When Save button is clicked, this page makes Ajax call and passes 79 | values to the backend in a POST request. Backend extracts values from 80 | the POST request and updates the configuration. Take a look at 81 | handle_save() to see how that is done.

82 | 83 | 84 |

You can change values, click Save button, refresh this page - make sure 85 | settings values stay intact between refreshes.

86 | 87 |
88 |
89 | Device settings 90 | 92 | 94 |
95 | 96 |
97 | 98 |
99 |
 
100 |
101 | 102 |
103 | 104 | 105 | -------------------------------------------------------------------------------- /examples/simplest_web_server/Makefile: -------------------------------------------------------------------------------- 1 | PROG = simplest_web_server 2 | SOURCES = $(PROG).c ../../fossa.c 3 | CFLAGS = -W -Wall -I../.. $(CFLAGS_EXTRA) 4 | 5 | all: $(PROG) 6 | 7 | $(PROG): $(SOURCES) 8 | $(CC) $(SOURCES) -o $@ $(CFLAGS) 9 | 10 | $(PROG).exe: $(SOURCES) 11 | cl $(SOURCES) /I../.. /MD /Fe$@ 12 | 13 | clean: 14 | rm -rf *.gc* *.dSYM *.exe *.obj *.o a.out $(PROG) 15 | -------------------------------------------------------------------------------- /examples/simplest_web_server/simplest_web_server.c: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Cesanta Software Limited 2 | // All rights reserved 3 | 4 | #include "fossa.h" 5 | 6 | static const char *s_http_port = "8000"; 7 | static struct ns_serve_http_opts s_http_server_opts; 8 | 9 | static void ev_handler(struct ns_connection *nc, int ev, void *p) { 10 | if (ev == NS_HTTP_REQUEST) { 11 | ns_serve_http(nc, p, s_http_server_opts); 12 | } 13 | } 14 | 15 | int main(void) { 16 | struct ns_mgr mgr; 17 | struct ns_connection *nc; 18 | 19 | ns_mgr_init(&mgr, NULL); 20 | nc = ns_bind(&mgr, s_http_port, ev_handler); 21 | 22 | // Set up HTTP server parameters 23 | ns_set_protocol_http_websocket(nc); 24 | s_http_server_opts.document_root = "."; // Serve current directory 25 | s_http_server_opts.enable_directory_listing = "yes"; 26 | 27 | printf("Starting web server on port %s\n", s_http_port); 28 | for (;;) { 29 | ns_mgr_poll(&mgr, 1000); 30 | } 31 | ns_mgr_free(&mgr); 32 | 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /examples/tcp_echo_server/Makefile: -------------------------------------------------------------------------------- 1 | PROG = echo_server 2 | SOURCES = $(PROG).c ../../fossa.c 3 | CFLAGS = -W -Wall -I../.. -pthread $(CFLAGS_EXTRA) 4 | 5 | all: $(PROG) 6 | 7 | $(PROG): $(SOURCES) 8 | $(CC) $(SOURCES) -o $@ $(CFLAGS) 9 | 10 | $(PROG).exe: $(SOURCES) 11 | cl $(SOURCES) /I../.. /MD /Fe$@ 12 | 13 | clean: 14 | rm -rf *.gc* *.dSYM *.exe *.obj *.o a.out $(PROG) 15 | -------------------------------------------------------------------------------- /examples/tcp_echo_server/echo_server.c: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2014 Cesanta Software Limited 2 | // All rights reserved 3 | // 4 | // This software is dual-licensed: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License version 2 as 6 | // published by the Free Software Foundation. For the terms of this 7 | // license, see . 8 | // 9 | // You are free to use this software under the terms of the GNU General 10 | // Public License, but WITHOUT ANY WARRANTY; without even the implied 11 | // warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 12 | // See the GNU General Public License for more details. 13 | // 14 | // Alternatively, you can license this software under a commercial 15 | // license, as set out in . 16 | // 17 | // $Date: 2014-09-28 05:04:41 UTC $ 18 | 19 | #include "fossa.h" 20 | 21 | static void ev_handler(struct ns_connection *nc, int ev, void *p) { 22 | struct mbuf *io = &nc->recv_mbuf; 23 | (void) p; 24 | 25 | switch (ev) { 26 | case NS_RECV: 27 | ns_send(nc, io->buf, io->len); // Echo message back 28 | mbuf_remove(io, io->len); // Discard message from recv buffer 29 | break; 30 | default: 31 | break; 32 | } 33 | } 34 | 35 | int main(void) { 36 | struct ns_mgr mgr; 37 | const char *port1 = "1234", *port2 = "127.0.0.1:17000"; 38 | 39 | ns_mgr_init(&mgr, NULL); 40 | ns_bind(&mgr, port1, ev_handler); 41 | ns_bind(&mgr, port2, ev_handler); 42 | 43 | printf("Starting echo mgr on ports %s, %s\n", port1, port2); 44 | for (;;) { 45 | ns_mgr_poll(&mgr, 1000); 46 | } 47 | ns_mgr_free(&mgr); 48 | 49 | return 0; 50 | } 51 | -------------------------------------------------------------------------------- /examples/websocket_chat/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2014 Cesanta Software 2 | # All rights reserved 3 | 4 | PROG = websocket_chat 5 | CFLAGS = -W -Wall -I../.. -pthread -g -O0 $(CFLAGS_EXTRA) 6 | SOURCES = $(PROG).c ../../fossa.c 7 | 8 | $(PROG): $(SOURCES) 9 | $(CC) -o $(PROG) $(SOURCES) $(CFLAGS) 10 | 11 | clean: 12 | rm -rf $(PROG) *.exe *.dSYM *.obj *.exp .*o *.lib 13 | -------------------------------------------------------------------------------- /examples/websocket_chat/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | WebSocket Test 6 | 7 | 29 | 30 | 61 | 62 | 63 |
64 |

Websocket PubSub Demonstration

65 | 66 |

67 | This page demonstrates how Fossa could be used to implement 68 | 69 | publish–subscribe pattern. Open this page in several browser 70 | windows. Each window initiates persistent 71 | WebSocket 72 | connection with the server, making each browser window a websocket client. 73 | Send messages, and see messages sent by other clients. 74 |

75 | 76 |
77 |
78 | 79 |

80 | 81 | 82 |

83 |
84 | 85 | 86 | -------------------------------------------------------------------------------- /examples/websocket_chat/websocket_chat.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 Cesanta Software Limited 3 | * All rights reserved 4 | */ 5 | 6 | #include "fossa.h" 7 | 8 | static sig_atomic_t s_signal_received = 0; 9 | static const char *s_http_port = "8000"; 10 | static struct ns_serve_http_opts s_http_server_opts; 11 | 12 | static void signal_handler(int sig_num) { 13 | signal(sig_num, signal_handler); // Reinstantiate signal handler 14 | s_signal_received = sig_num; 15 | } 16 | 17 | static int is_websocket(const struct ns_connection *nc) { 18 | return nc->flags & NSF_IS_WEBSOCKET; 19 | } 20 | 21 | static void broadcast(struct ns_connection *nc, const char *msg, size_t len) { 22 | struct ns_connection *c; 23 | char buf[500]; 24 | 25 | snprintf(buf, sizeof(buf), "%p %.*s", nc, (int) len, msg); 26 | for (c = ns_next(nc->mgr, NULL); c != NULL; c = ns_next(nc->mgr, c)) { 27 | ns_send_websocket_frame(c, WEBSOCKET_OP_TEXT, buf, strlen(buf)); 28 | } 29 | } 30 | 31 | static void ev_handler(struct ns_connection *nc, int ev, void *ev_data) { 32 | struct http_message *hm = (struct http_message *) ev_data; 33 | struct websocket_message *wm = (struct websocket_message *) ev_data; 34 | 35 | switch (ev) { 36 | case NS_HTTP_REQUEST: 37 | /* Usual HTTP request - serve static files */ 38 | ns_serve_http(nc, hm, s_http_server_opts); 39 | nc->flags |= NSF_SEND_AND_CLOSE; 40 | break; 41 | case NS_WEBSOCKET_HANDSHAKE_DONE: 42 | /* New websocket connection. Tell everybody. */ 43 | broadcast(nc, "joined", 6); 44 | break; 45 | case NS_WEBSOCKET_FRAME: 46 | /* New websocket message. Tell everybody. */ 47 | broadcast(nc, (char *) wm->data, wm->size); 48 | break; 49 | case NS_CLOSE: 50 | /* Disconnect. Tell everybody. */ 51 | if (is_websocket(nc)) { 52 | broadcast(nc, "left", 4); 53 | } 54 | break; 55 | default: 56 | break; 57 | } 58 | } 59 | 60 | int main(void) { 61 | struct ns_mgr mgr; 62 | struct ns_connection *nc; 63 | 64 | signal(SIGTERM, signal_handler); 65 | signal(SIGINT, signal_handler); 66 | 67 | ns_mgr_init(&mgr, NULL); 68 | 69 | nc = ns_bind(&mgr, s_http_port, ev_handler); 70 | s_http_server_opts.document_root = "."; 71 | ns_set_protocol_http_websocket(nc); 72 | 73 | printf("Started on port %s\n", s_http_port); 74 | while (s_signal_received == 0) { 75 | ns_mgr_poll(&mgr, 200); 76 | } 77 | ns_mgr_free(&mgr); 78 | 79 | return 0; 80 | } 81 | -------------------------------------------------------------------------------- /platforms/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | @make -C arduino_ethernet_W5100/ 3 | @make -C arduino_wifi_CC3000/ 4 | -------------------------------------------------------------------------------- /platforms/arduino_common/avrdebug.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Cesanta Software Limited 3 | * All rights reserved 4 | */ 5 | #include 6 | 7 | void blink(int times, int ms) { 8 | static int inited = 0; 9 | int i; 10 | 11 | if (!inited) { 12 | DDRB |= 0x80; 13 | inited = 1; 14 | } 15 | 16 | for (i = 0; i < times; i++) { 17 | PORTB |= 0x80; 18 | delay(ms); 19 | PORTB &= 0x7F; 20 | delay(ms); 21 | } 22 | } 23 | 24 | extern unsigned int __heap_start; 25 | extern void *__brkval; 26 | 27 | struct __freelist { 28 | size_t sz; 29 | struct __freelist *nx; 30 | }; 31 | 32 | extern struct __freelist *__flp; 33 | 34 | int get_freelistsize() { 35 | struct __freelist *current; 36 | int total = 0; 37 | for (current = __flp; current; current = current->nx) { 38 | total += 2; 39 | total += (int) current->sz; 40 | } 41 | return total; 42 | } 43 | 44 | int get_freememsize() { 45 | int free_memory; 46 | if ((int) __brkval == 0) { 47 | free_memory = ((int) &free_memory) - ((int) &__heap_start); 48 | } else { 49 | free_memory = ((int) &free_memory) - ((int) __brkval); 50 | free_memory += get_freelistsize(); 51 | } 52 | return free_memory; 53 | } 54 | -------------------------------------------------------------------------------- /platforms/arduino_common/avrdebug.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Cesanta Software Limited 3 | * All rights reserved 4 | */ 5 | 6 | #ifndef AVRDEBUG_HEADER_INCLUDED 7 | #define AVRDEBUG_HEADER_INCLUDED 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | /* Blinks ($times) times with ($ms) delay */ 13 | void blink(int times, int ms); 14 | 15 | /* Returns free memory size */ 16 | int get_freememsize(); 17 | 18 | #if defined(AVR_ENABLE_DEBUG) 19 | 20 | #define DUMPINIT() Serial.begin(9600) 21 | #define DUMPSTR(msg) Serial.println(msg) 22 | #define DUMPDEC(num) Serial.println(num, DEC) 23 | #define DUMPFREEMEM() \ 24 | Serial.print("Free mem: "); \ 25 | Serial.println(get_freememsize()) 26 | 27 | #define DUMPFUNCNAME() Serial.println(__func__) 28 | 29 | #define BLINK(t, m) blink(t, m); 30 | 31 | #else 32 | 33 | #define DUMPINIT() 34 | #define DUMPFUNCNAME() 35 | #define DUMPFREEMEM() 36 | #define BLINK(t, m) 37 | #define DUMPSTR(msg) 38 | #define DUMPDEC(num) 39 | 40 | #endif 41 | 42 | #ifdef __cplusplus 43 | } 44 | #endif 45 | 46 | #endif /* NS_AVRDEBUG_HEADER_INCLUDED */ 47 | -------------------------------------------------------------------------------- /platforms/arduino_common/avrlibc_compat.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Cesanta Software Limited 3 | * All rights reserved 4 | */ 5 | 6 | #include 7 | #include 8 | 9 | long long int to64(const char* str) { 10 | long long int res = 0; 11 | char negative = 0; 12 | 13 | while (isspace(*str)) str++; 14 | 15 | if (*str == '+') { 16 | str++; 17 | } else if (*str == '-') { 18 | negative = 1; 19 | str++; 20 | } 21 | 22 | while (*str >= '0' && *str <= '9') { 23 | res = res * 10 + (*str - '0'); 24 | str++; 25 | } 26 | 27 | return negative ? -res : res; 28 | } 29 | 30 | char* strerror(int errnum) { 31 | /* TODO(alashkin): show real error message */ 32 | const char frmstr[] = "Error: %d"; 33 | static char retbuf[sizeof(frmstr) + 11]; 34 | 35 | snprintf(retbuf, sizeof(retbuf), frmstr, errnum); 36 | return retbuf; 37 | } 38 | 39 | /* 40 | * Returns the number of seconds since the Arduino board 41 | * began running the current program. 42 | * So, this function 43 | * 1. doesn't support anything but NULL as a parameter 44 | * 2. suitable only to detect timeouts etc. 45 | * If time(NULL) is logged, result would be something 46 | * like "1970-01-01..." etc) 47 | */ 48 | 49 | time_t time(time_t* timer) { 50 | return millis() / 1000; 51 | } 52 | -------------------------------------------------------------------------------- /platforms/arduino_common/avrlibc_compat.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Cesanta Software Limited 3 | * All rights reserved 4 | */ 5 | 6 | #ifndef AVRLIBC_COMPAT_HEADER_INCLUDED 7 | #define AVRLIBC_COMPAT_HEADER_INCLUDED 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | /* 14 | * Some of this stuff breaks 15 | * Fossa o Arduino 16 | * TODO(alashkin): remove these defines when 17 | * some kind of AVR-build-test will be ready 18 | */ 19 | #define NS_DISABLE_HTTP_DIGEST_AUTH 20 | #define NS_DISABLE_MQTT 21 | #define NS_DISABLE_MD5 22 | #define NS_DISABLE_JSON_RPC 23 | #define NS_DISABLE_SOCKETPAIR 24 | #define NS_DISABLE_SSI 25 | #define NS_DISABLE_POPEN 26 | #define NS_DISABLE_DIRECTORY_LISTING 27 | #define NS_DISABLE_DAV 28 | #define NS_DISABLE_DNS 29 | #define NS_DISABLE_RESOLVER 30 | #define NS_DISABLE_CGI 31 | 32 | #ifdef __cplusplus 33 | extern "C" { 34 | #endif 35 | 36 | /* fossa requires to64, so define it' instead of strtol & co */ 37 | long long int to64(const char* str); 38 | 39 | char* strerror(int errnum); 40 | 41 | /* Time declaration & functions */ 42 | typedef unsigned long time_t; 43 | 44 | #ifndef TIMEVAL 45 | struct timeval { 46 | uint32_t tv_sec; 47 | uint32_t tv_usec; 48 | }; 49 | #define TIMEVAL 50 | #endif 51 | 52 | time_t time(time_t* timer); 53 | 54 | /* TODO(alashkin): add (at least) in-flash "files" operations */ 55 | 56 | #define AVR_NOFS 57 | #define AVR_LIBC 58 | 59 | #ifdef __cplusplus 60 | } 61 | #endif 62 | 63 | #endif 64 | -------------------------------------------------------------------------------- /platforms/arduino_ethernet_W5100/Makefile: -------------------------------------------------------------------------------- 1 | AVRCOMMON = ./../arduino_common/ 2 | SOURCES = $(AVRCOMMON)/avrdebug.cpp $(AVRCOMMON)/avrlibc_compat.cpp src/W5100_sockets.cpp 3 | HEADERS = $(SOURCES:.cpp=.h) 4 | 5 | all: avrsupport.h avrsupport.cpp 6 | 7 | avrsupport.h: $(HEADERS) 8 | @cat $(HEADERS) > avrsupport.h 9 | 10 | avrsupport.cpp: $(SOURCES) 11 | @echo "#include \"avrsupport.h\"" > avrsupport.cpp 12 | @cat $(SOURCES) >> avrsupport.cpp 13 | -------------------------------------------------------------------------------- /platforms/arduino_ethernet_W5100/src/W5100_sockets.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Cesanta Software Limited 3 | * All rights reserved 4 | * 5 | * Partially BSD-compatible sockets for Wiznet W5100. 6 | * 7 | * Note: this implementation is intended for Fossa network library only. 8 | * It supports only non-blocking mode and contains some 9 | * simplifications. 10 | */ 11 | 12 | #ifndef W5100_SOCKETS_HEADER_INCLUDED 13 | #define W5100_SOCKETS_HEADER_INCLUDED 14 | 15 | #define ETHERNET_W5100 16 | 17 | #ifdef __cplusplus 18 | extern "C" { 19 | #endif 20 | 21 | typedef void* sock_t; 22 | 23 | #define INVALID_SOCKET NULL 24 | 25 | #define SOCKET_ERROR -1 26 | #define INADDR_ANY 0 27 | #define AF_INET 2 28 | 29 | #define SOCK_STREAM 0 30 | #define SOCK_DGRAM 1 31 | 32 | #define SOMAXCONN 0 /* use hardware-specific maxconn */ 33 | 34 | #define SOL_SOCKET 1 35 | #define SO_ERROR 1 36 | #define SO_REUSEADDR 2 37 | 38 | #define FD_CLOEXEC 1 39 | 40 | #define F_GETFL 1 41 | #define F_SETFL 2 42 | #define F_SETFD 3 43 | 44 | #define O_NONBLOCK 1 45 | 46 | /* errors */ 47 | #define ENOENT 2 48 | #define EINTR 4 49 | #define EINPROGRESS 115 50 | #define EAGAIN 11 51 | #define EWOULDBLOCK EAGAIN 52 | /* TODO(alashkin): change to darwin values */ 53 | #define ENOTCONN 10057 54 | #define EMSGSIZE 10040 55 | #define EINVAL 10022 56 | 57 | #define BUFSIZ 128 58 | 59 | typedef int16_t socklen_t; 60 | typedef uint8_t sa_family_t; 61 | typedef uint16_t in_port_t; 62 | typedef uint8_t ushort_t; 63 | typedef uint32_t ulong_t; 64 | 65 | typedef uint32_t in_addr_t; 66 | 67 | struct in_addr { 68 | in_addr_t s_addr; 69 | }; 70 | 71 | struct sockaddr_in { 72 | sa_family_t sin_family; 73 | in_port_t sin_port; 74 | struct in_addr sin_addr; 75 | }; 76 | 77 | struct sockaddr { 78 | union { 79 | sa_family_t sa_family; 80 | struct sockaddr_in sin; 81 | }; 82 | }; 83 | 84 | struct hostent { 85 | /* 86 | * 1. only one ip address is supported 87 | * 2. fossa uses only one field, so, gethostbyname fills only it 88 | */ 89 | char* h_addr_list[1][sizeof(uint32_t)]; 90 | }; 91 | 92 | #define FD_SETSIZE 4 /* W5100 has four sockets only */ 93 | 94 | typedef struct _fd_set { 95 | uint8_t fd_count; 96 | sock_t fd_array[FD_SETSIZE]; 97 | } fd_set; 98 | 99 | /* 100 | * Usually, FD_XXX and xtoy are macroses, 101 | * here use funtions 102 | * coz size warnings with functions are 103 | * more clear in avr-gcc 104 | */ 105 | void FD_ZERO(fd_set* s); 106 | int FD_ISSET(sock_t fd, fd_set* set); 107 | void FD_SET(sock_t fd, fd_set* set); 108 | 109 | uint16_t htons(uint16_t hostshort); 110 | uint32_t htonl(uint32_t hostlong); 111 | uint16_t ntohs(uint16_t netshort); 112 | uint32_t ntohl(uint32_t netlong); 113 | 114 | sock_t socket(int af, int type, int protocol); 115 | int closesocket(sock_t s); 116 | /* fossa uses BSD-style, so define close() */ 117 | #define close(x) closesocket(x) 118 | 119 | int sendto(sock_t s, const void* buf, size_t len, int flags, 120 | const struct sockaddr* addr, socklen_t addr_len); 121 | int recvfrom(sock_t s, char* buf, int len, int flags, struct sockaddr* from, 122 | int* fromlen); 123 | int bind(sock_t s, const struct sockaddr* name, int namelen); 124 | int getsockname(sock_t s, struct sockaddr* name, int* namelen); 125 | struct hostent* gethostbyname(const char* name); 126 | char* inet_ntoa(struct in_addr in); 127 | const char* inet_ntop(int af, const void* src, char* dst, socklen_t size); 128 | int listen(sock_t s, int backlog); 129 | sock_t accept(sock_t s, struct sockaddr* addr, int* addrlen); 130 | int recv(sock_t s, char* buf, int len, int flags); 131 | int send(sock_t s, const char* buf, int len, int flags); 132 | int connect(sock_t s, const struct sockaddr* name, int namelen); 133 | int getpeername(sock_t s, struct sockaddr* name, int* namelen); 134 | int select(int nfds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, 135 | const struct timeval* timeout); 136 | int getsockopt(sock_t s, int level, int optname, char* optval, int* optlen); 137 | int fcntl(sock_t s, int cmd, uint32_t arg); 138 | int setsockopt(sock_t s, int level, int optname, void* optval, int optlen); 139 | 140 | int ns_avr_get_dns_name(char* name, size_t namelen); 141 | int avr_netinit(uint8_t* mac, uint8_t* ip); 142 | 143 | #ifdef __cplusplus 144 | } 145 | #endif 146 | 147 | #endif /* W5100_SOCKETS_HEADER_INCLUDED */ 148 | -------------------------------------------------------------------------------- /platforms/arduino_wifi_CC3000/Makefile: -------------------------------------------------------------------------------- 1 | AVRCOMMON = ./../arduino_common/ 2 | SOURCES = $(AVRCOMMON)/avrdebug.cpp $(AVRCOMMON)/avrlibc_compat.cpp src/CC3000_utils.cpp 3 | HEADERS = $(SOURCES:.cpp=.h) 4 | 5 | all: avrsupport.h avrsupport.cpp 6 | 7 | avrsupport.h: $(HEADERS) 8 | @cat $(HEADERS) > avrsupport.h 9 | 10 | avrsupport.cpp: $(SOURCES) 11 | @echo "#include \"avrsupport.h\"" > avrsupport.cpp 12 | @cat $(SOURCES) >> avrsupport.cpp 13 | -------------------------------------------------------------------------------- /platforms/arduino_wifi_CC3000/adafruit_CC3000_lib_fossa/Adafruit_CC3000_Server.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************/ 2 | /*! 3 | @file Adafruit_CC3000_Server.h 4 | @author Tony DiCola (tony@tonydicola.com) 5 | @license BSD (see license.txt) 6 | 7 | Adafruit CC3000 TCP server implementation based on the same interface as 8 | the Arduino Ethernet library server class. 9 | 10 | See http://arduino.cc/en/Reference/Ethernet for documentation on the 11 | Arduino Ethernet library and its server interface. 12 | 13 | The only difference between this implementation and the Ethernet library 14 | is that a special client reference facade is returned by the available() 15 | function, instead of a copy of a client like in the Ethernet library. This 16 | is necessary to ensure the buffers that client instances contain aren't 17 | copied and get out of sync. 18 | 19 | */ 20 | /**************************************************************************/ 21 | 22 | #ifndef ADAFRUIT_CC3000_SERVER_H 23 | #define ADAFRUIT_CC3000_SERVER_H 24 | 25 | #include "Adafruit_CC3000.h" 26 | 27 | #include "Client.h" 28 | #include "Server.h" 29 | 30 | // Assume 4 sockets available, 1 of which is used for listening, so at most 3 31 | // clients can be connected at once. 32 | #define MAX_SERVER_CLIENTS 3 33 | 34 | // Facade that wraps a reference to a client instance into something that looks 35 | // and acts like a client instance value. This is done to mimic the semantics 36 | // of the Ethernet library, without running into problems allowing client 37 | // buffers 38 | // to be copied and get out of sync. 39 | class Adafruit_CC3000_ClientRef : public Client { 40 | public: 41 | Adafruit_CC3000_ClientRef(Adafruit_CC3000_Client *client); 42 | // Return true if the referenced client is connected. This is provided for 43 | // compatibility with Ethernet library code. 44 | operator bool(); 45 | // Below are all the public methods of the client class: 46 | int connect(IPAddress ip, uint16_t port); 47 | int connect(const char *host, uint16_t port); 48 | 49 | uint8_t connected(void); 50 | size_t write(uint8_t c); 51 | 52 | size_t fastrprint(const char *str); 53 | size_t fastrprintln(const char *str); 54 | size_t fastrprint(char *str); 55 | size_t fastrprintln(char *str); 56 | size_t fastrprint(const __FlashStringHelper *ifsh); 57 | size_t fastrprintln(const __FlashStringHelper *ifsh); 58 | 59 | size_t write(const void *buf, uint16_t len, uint32_t flags = 0); 60 | int read(void *buf, uint16_t len, uint32_t flags = 0); 61 | int read(void); 62 | int32_t close(void); 63 | int available(void); 64 | 65 | int read(uint8_t *buf, size_t size); 66 | size_t write(const uint8_t *buf, size_t size); 67 | int peek(); 68 | void flush(); 69 | void stop(); 70 | 71 | private: 72 | // Hide the fact that users are really dealing with a pointer to a client 73 | // instance. Note: this class does not own the contents of the client 74 | // pointer and should NEVER attempt to free/delete this pointer. 75 | Adafruit_CC3000_Client *_client; 76 | }; 77 | 78 | class Adafruit_CC3000_Server : public Server { 79 | public: 80 | // Construct a TCP server to listen on the specified port. 81 | Adafruit_CC3000_Server(uint16_t port); 82 | // Return the index of a client instance with data available to read. 83 | // This is useful if you need to keep track of your own client state, you can 84 | // index into an array of client state based on the available index returned 85 | // from this function. Optional boolean parameter returns by reference true 86 | // if the available client is connecting for the first time. 87 | int8_t availableIndex(bool *newClient = NULL); 88 | // Get a client instance from a given index. 89 | Adafruit_CC3000_ClientRef getClientRef(int8_t clientIndex); 90 | // Return a reference to a client instance which has data available to read. 91 | Adafruit_CC3000_ClientRef available(); 92 | // Initialize the server and start listening for connections. 93 | virtual void begin(); 94 | // Write data to all connected clients. Buffer is a pointer to an array 95 | // of bytes, and size specifies how many bytes to write from the buffer. 96 | // Return the sum of bytes written to all clients. 97 | virtual size_t write(const uint8_t *buffer, size_t size); 98 | // Write a byte value to all connected clients. 99 | // Return the sum of bytes written to all clients. 100 | virtual size_t write(uint8_t value); 101 | // Make the overloads of write from the Print base class available. 102 | using Print::write; 103 | 104 | private: 105 | // Store the clients in a simple array. 106 | Adafruit_CC3000_Client _clients[MAX_SERVER_CLIENTS]; 107 | // The port this server will listen for connections on. 108 | uint16_t _port; 109 | // The id of the listening socket. 110 | uint32_t _listenSocket; 111 | 112 | // Accept new connections and update the connected clients. 113 | bool acceptNewConnections(); 114 | }; 115 | 116 | #endif 117 | -------------------------------------------------------------------------------- /platforms/arduino_wifi_CC3000/adafruit_CC3000_lib_fossa/README.md: -------------------------------------------------------------------------------- 1 | # Adafruit CC3000 Library 2 | 3 | This is a library for the Adafruit CC3000 WiFi Breakouts etc 4 | 5 | Designed specifically to work with the Adafruit CC3000 Breakout 6 | ----> https://www.adafruit.com/products/1469 7 | 8 | These modules use SPI to communicate, 6 pins are required to interface 9 | 10 | Adafruit invests time and resources providing this open source code, 11 | please support Adafruit and open-source hardware by purchasing 12 | products from Adafruit! 13 | 14 | Check out the links above for our tutorials and wiring diagrams 15 | 16 | Arduino library Written by Limor Fried & Kevin Townsend for Adafruit Industries. 17 | CC3000 host core written by TI 18 | 19 | To download. click the DOWNLOADS button in the top right corner, rename the uncompressed folder Adafruit_CC3000 20 | Check that the Adafruit_CC3000 folder contains Adafruit_CC3000.cpp and Adafruit_CC3000.h 21 | 22 | Place the Adafruit_CC3000 library folder your *arduinosketchfolder*/libraries/ folder. 23 | You may need to create the libraries subfolder if its your first library. Restart the IDE. 24 | 25 | NOTE: the 'SendTweet' example currently DOES NOT WORK due to Twitter API changes. The code is being kept for posterity in case a workaround can be developed. 26 | 27 | -------------------------------------------------------------------------------- /platforms/arduino_wifi_CC3000/adafruit_CC3000_lib_fossa/ccspi.h: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * spi.h - CC3000 Host Driver Implementation. 4 | * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ 5 | * 6 | * Adapted for use with the Arduino/AVR by KTOWN (Kevin Townsend) 7 | * & Limor Fried for Adafruit Industries 8 | * This library works with the Adafruit CC3000 breakout 9 | * ----> https://www.adafruit.com/products/1469 10 | * Adafruit invests time and resources providing this open source code, 11 | * please support Adafruit and open-source hardware by purchasing 12 | * products from Adafruit! 13 | * 14 | * Redistribution and use in source and binary forms, with or without 15 | * modification, are permitted provided that the following conditions 16 | * are met: 17 | * 18 | * Redistributions of source code must retain the above copyright 19 | * notice, this list of conditions and the following disclaimer. 20 | * 21 | * Redistributions in binary form must reproduce the above copyright 22 | * notice, this list of conditions and the following disclaimer in the 23 | * documentation and/or other materials provided with the 24 | * distribution. 25 | * 26 | * Neither the name of Texas Instruments Incorporated nor the names of 27 | * its contributors may be used to endorse or promote products derived 28 | * from this software without specific prior written permission. 29 | * 30 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 31 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 32 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 33 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 34 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 35 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 36 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 37 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 38 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 39 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 40 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 41 | * 42 | *****************************************************************************/ 43 | 44 | #ifndef __SPI_H__ 45 | #define __SPI_H__ 46 | 47 | // Adafruit CC3k Host Driver Difference 48 | // Include necessary Arduino headers. 49 | // Noted 12-12-2014 by tdicola 50 | #if ARDUINO >= 100 51 | #include "Arduino.h" 52 | #else 53 | #include "WProgram.h" 54 | #endif 55 | 56 | #include 57 | #include 58 | #include 59 | #include 60 | 61 | #include "utility/wlan.h" 62 | 63 | typedef void (*gcSpiHandleRx)(void *p); 64 | typedef void (*gcSpiHandleTx)(void); 65 | 66 | extern unsigned char wlan_tx_buffer[]; 67 | 68 | //***************************************************************************** 69 | // 70 | // Prototypes for the APIs. 71 | // 72 | //***************************************************************************** 73 | extern void SpiOpen(gcSpiHandleRx pfRxHandler); 74 | extern void SpiClose(void); 75 | extern long SpiWrite(unsigned char *pUserBuffer, unsigned short usLength); 76 | extern void SpiResumeSpi(void); 77 | extern void SpiCleanGPIOISR(void); 78 | extern int init_spi(void); 79 | extern long TXBufferIsEmpty(void); 80 | extern long RXBufferIsEmpty(void); 81 | extern void CC3000_UsynchCallback(long lEventType, char *data, 82 | unsigned char length); 83 | extern void WriteWlanPin(unsigned char val); 84 | extern long ReadWlanInterruptPin(void); 85 | extern void WlanInterruptEnable(); 86 | extern void WlanInterruptDisable(); 87 | extern char *sendDriverPatch(unsigned long *Length); 88 | extern char *sendBootLoaderPatch(unsigned long *Length); 89 | extern char *sendWLFWPatch(unsigned long *Length); 90 | extern void SPI_IRQ(void); 91 | 92 | #endif 93 | -------------------------------------------------------------------------------- /platforms/arduino_wifi_CC3000/adafruit_CC3000_lib_fossa/library.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Adafruit-CC3000", 3 | "keywords": "wifi, wi-fi, http, web, server, json, rest, spi", 4 | "description": "Library code for Adafruit's CC3000 Wi-Fi/WiFi breakouts", 5 | "repository": 6 | { 7 | "type": "git", 8 | "url": "https://github.com/adafruit/Adafruit_CC3000_Library.git" 9 | }, 10 | "frameworks": "arduino", 11 | "platforms": "atmelavr" 12 | } 13 | -------------------------------------------------------------------------------- /platforms/arduino_wifi_CC3000/adafruit_CC3000_lib_fossa/library.properties: -------------------------------------------------------------------------------- 1 | name=Adafruit CC3000 Library (for fossa) 2 | version=1.0.0 3 | author=Adafruit 4 | maintainer=Adafruit 5 | sentence=Library code for Adafruit's CC3000 WiFi breakouts. 6 | paragraph=The CC3000 allows an Arduino to connect to a WiFi network and access the internet. See more at: https://learn.adafruit.com/adafruit-cc3000-wifi/ 7 | category=Communication 8 | url=https://github.com/adafruit/Adafruit_CC3000_Library 9 | architectures=* 10 | -------------------------------------------------------------------------------- /platforms/arduino_wifi_CC3000/adafruit_CC3000_lib_fossa/license.txt: -------------------------------------------------------------------------------- 1 | ===== 2 | 3 | Copyright (c) 2013-2014 4 | Limor Fried, Kevin Townsend for Adafruit Industries & Tony DiCola (tony@tonydicola.com) 5 | 6 | Adafruit invests time and resources providing this open source code, 7 | please support Adafruit and open-source hardware by purchasing 8 | products from Adafruit! 9 | 10 | All rights reserved. 11 | 12 | ===== 13 | 14 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 15 | 16 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 17 | 18 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /platforms/arduino_wifi_CC3000/adafruit_CC3000_lib_fossa/utility/data_types.h: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * data_types.h - CC3000 Host Driver Implementation. 4 | * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ 5 | * 6 | * Adapted for use with the Arduino/AVR by KTOWN (Kevin Townsend) 7 | * & Limor Fried for Adafruit Industries 8 | * This library works with the Adafruit CC3000 breakout 9 | * ----> https://www.adafruit.com/products/1469 10 | * Adafruit invests time and resources providing this open source code, 11 | * please support Adafruit and open-source hardware by purchasing 12 | * products from Adafruit! 13 | * 14 | * Redistribution and use in source and binary forms, with or without 15 | * modification, are permitted provided that the following conditions 16 | * are met: 17 | * 18 | * Redistributions of source code must retain the above copyright 19 | * notice, this list of conditions and the following disclaimer. 20 | * 21 | * Redistributions in binary form must reproduce the above copyright 22 | * notice, this list of conditions and the following disclaimer in the 23 | * documentation and/or other materials provided with the 24 | * distribution. 25 | * 26 | * Neither the name of Texas Instruments Incorporated nor the names of 27 | * its contributors may be used to endorse or promote products derived 28 | * from this software without specific prior written permission. 29 | * 30 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 31 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 32 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 33 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 34 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 35 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 36 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 37 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 38 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 39 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 40 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 41 | * 42 | *****************************************************************************/ 43 | #ifndef __DATA_TYPES__ 44 | #define __DATA_TYPES__ 45 | 46 | //***************************************************************************** 47 | // 48 | // If building with a C++ compiler, make all of the definitions in this header 49 | // have a C binding. 50 | // 51 | //***************************************************************************** 52 | #ifdef __cplusplus 53 | extern "C" { 54 | #endif 55 | 56 | #ifndef NULL 57 | #define NULL (0) 58 | #endif 59 | 60 | #ifndef FALSE 61 | #define FALSE (0) 62 | #endif 63 | 64 | #ifndef TRUE 65 | #define TRUE (!FALSE) 66 | #endif 67 | 68 | #ifndef OK 69 | #define OK (0) 70 | #endif 71 | 72 | #ifndef _INT8 73 | #define _INT8 74 | typedef signed char INT8; 75 | #endif 76 | 77 | #ifndef _UINT8 78 | #define _UINT8 79 | typedef unsigned char UINT8; 80 | #endif 81 | 82 | #ifndef _INT16 83 | #define _INT16 84 | typedef signed short INT16; 85 | #endif 86 | 87 | #ifndef _UINT16 88 | #define _UINT16 89 | typedef unsigned short UINT16; 90 | #endif 91 | 92 | #ifndef _BOOLEAN 93 | #define _BOOLEAN 94 | typedef unsigned char BOOLEAN; 95 | #endif 96 | 97 | #ifndef _INT32 98 | #define _INT32 99 | typedef signed long INT32; 100 | #endif 101 | 102 | #ifndef _UINT32 103 | #define _UINT32 104 | typedef unsigned long UINT32; 105 | #endif 106 | 107 | typedef int INT; 108 | typedef char CHAR; 109 | 110 | #ifdef __cplusplus 111 | } 112 | #endif /* __cplusplus */ 113 | 114 | #endif /* __DATA_TYPE__ */ 115 | -------------------------------------------------------------------------------- /platforms/arduino_wifi_CC3000/adafruit_CC3000_lib_fossa/utility/debug.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************/ 2 | /*! 3 | @file Adafruit_CC3000.cpp 4 | @author KTOWN (Kevin Townsend Adafruit Industries) 5 | @license BSD (see license.txt) 6 | 7 | This is a library for the Adafruit CC3000 WiFi breakout board 8 | This library works with the Adafruit CC3000 breakout 9 | ----> https://www.adafruit.com/products/1469 10 | 11 | Check out the links above for our tutorials and wiring diagrams 12 | These chips use SPI to communicate. 13 | 14 | Adafruit invests time and resources providing this open source code, 15 | please support Adafruit and open-source hardware by purchasing 16 | products from Adafruit! 17 | 18 | @section HISTORY 19 | 20 | v1.0 - Initial release 21 | */ 22 | /**************************************************************************/ 23 | 24 | #include "debug.h" 25 | 26 | /**************************************************************************/ 27 | /*! 28 | @brief This function will display the number of bytes currently free 29 | in RAM ... useful for debugging! 30 | */ 31 | /**************************************************************************/ 32 | 33 | #if defined(__arm__) && defined(__SAM3X8E__) // Arduino Due 34 | // should use uinstd.h to define sbrk but on Arduino Due this causes a conflict 35 | extern "C" char* sbrk(int incr); 36 | int getFreeRam(void) { 37 | char top; 38 | return &top - reinterpret_cast(sbrk(0)); 39 | } 40 | #else // AVR 41 | int getFreeRam(void) { 42 | extern int __bss_end; 43 | extern int* __brkval; 44 | int free_memory; 45 | if ((int) __brkval == 0) { 46 | free_memory = ((int) &free_memory) - ((int) &__bss_end); 47 | } else { 48 | free_memory = ((int) &free_memory) - ((int) __brkval); 49 | } 50 | 51 | return free_memory; 52 | } 53 | #endif 54 | 55 | void displayFreeRam(void) { 56 | if (CC3KPrinter == 0) { 57 | return; 58 | } 59 | CC3KPrinter->print(F("Free RAM: ")); 60 | CC3KPrinter->print(getFreeRam()); 61 | CC3KPrinter->println(F(" bytes")); 62 | } 63 | 64 | void uart_putchar(char c) { 65 | if (CC3KPrinter != 0) { 66 | CC3KPrinter->write(c); 67 | } 68 | } 69 | 70 | void printDec(uint8_t h) { 71 | uart_putchar((h / 100) + '0'); 72 | h %= 100; 73 | uart_putchar((h / 10) + '0'); 74 | h %= 10; 75 | uart_putchar(h + '0'); 76 | } 77 | 78 | void printHex(uint8_t h) { 79 | uint8_t d = h >> 4; 80 | if (d >= 10) { 81 | uart_putchar(d - 10 + 'A'); 82 | } else { 83 | uart_putchar(d + '0'); 84 | } 85 | h &= 0xF; 86 | if (h >= 10) { 87 | uart_putchar(h - 10 + 'A'); 88 | } else { 89 | uart_putchar(h + '0'); 90 | } 91 | } 92 | 93 | void printHex16(uint16_t h) { 94 | uart_putchar('0'); 95 | uart_putchar('x'); 96 | DEBUGPRINT_HEX(h >> 8); 97 | DEBUGPRINT_HEX(h); 98 | } 99 | 100 | void printDec16(uint16_t h) { 101 | uart_putchar((h / 10000) + '0'); 102 | h %= 10000; 103 | uart_putchar((h / 1000) + '0'); 104 | h %= 1000; 105 | uart_putchar((h / 100) + '0'); 106 | h %= 100; 107 | uart_putchar((h / 10) + '0'); 108 | h %= 10; 109 | uart_putchar(h + '0'); 110 | } 111 | 112 | void DEBUGPRINT(const prog_char* fstr) { 113 | char c; 114 | if (!fstr) return; 115 | while ((c = pgm_read_byte(fstr++))) uart_putchar(c); 116 | } 117 | -------------------------------------------------------------------------------- /platforms/arduino_wifi_CC3000/adafruit_CC3000_lib_fossa/utility/debug.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************/ 2 | /*! 3 | @file Adafruit_CC3000.cpp 4 | @author KTOWN (Kevin Townsend for Adafruit Industries) 5 | @license BSD (see license.txt) 6 | 7 | This is a library for the Adafruit CC3000 WiFi breakout board 8 | This library works with the Adafruit CC3000 breakout 9 | ----> https://www.adafruit.com/products/1469 10 | 11 | Check out the links above for our tutorials and wiring diagrams 12 | These chips use SPI to communicate. 13 | 14 | Adafruit invests time and resources providing this open source code, 15 | please support Adafruit and open-source hardware by purchasing 16 | products from Adafruit! 17 | 18 | @section HISTORY 19 | 20 | v1.0 - Initial release 21 | */ 22 | /**************************************************************************/ 23 | 24 | #include 25 | 26 | #define GCC_VERSION \ 27 | (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) 28 | #if (GCC_VERSION >= 40702) || !defined(prog_char) 29 | typedef char PROGMEM prog_char; 30 | #endif 31 | 32 | #ifndef _CC3000_DEBUG 33 | #define _CC3000_DEBUG 34 | 35 | #define DEBUG_MODE (0) 36 | 37 | int getFreeRam(void); 38 | void displayFreeRam(void); 39 | void uart_putchar(char c); 40 | void printHex(uint8_t h); 41 | void printHex16(uint16_t h); 42 | void DEBUGPRINT(const prog_char* fstr); 43 | void printDec(uint8_t h); 44 | void printDec16(uint16_t h); 45 | 46 | #ifndef FLASHIFY 47 | #define FLASHIFY(s) \ 48 | ({ \ 49 | static const char c[] __attribute__((progmem)) = s; \ 50 | c; \ 51 | }) 52 | #endif 53 | 54 | #define PRINT_F(__s) DEBUGPRINT(FLASHIFY(__s)) 55 | 56 | #if (DEBUG_MODE != 0) 57 | #define DEBUGPRINT_F(__s) DEBUGPRINT(FLASHIFY(__s)) 58 | #define DEBUGPRINT_DEC(x) printDec(x) 59 | #define DEBUGPRINT_DEC16(x) printDec16(x) 60 | #define DEBUGPRINT_HEX(x) printHex(x) 61 | #define DEBUGPRINT_HEX16(x) printHex16(x) 62 | #else 63 | #define DEBUGPRINT_F(__s) /* do nothing! */ 64 | #define DEBUGPRINT_DEC(x) 65 | #define DEBUGPRINT_DEC16(x) 66 | #define DEBUGPRINT_HEX(x) 67 | #define DEBUGPRINT_HEX16(x) 68 | #endif 69 | 70 | extern Print* CC3KPrinter; 71 | 72 | #endif 73 | -------------------------------------------------------------------------------- /platforms/arduino_wifi_CC3000/adafruit_CC3000_lib_fossa/utility/error_codes.h: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * error_codes.h - CC3000 Host Driver Implementation. 4 | * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ 5 | * 6 | * Adapted for use with the Arduino/AVR by KTOWN (Kevin Townsend) 7 | * & Limor Fried for Adafruit Industries 8 | * This library works with the Adafruit CC3000 breakout 9 | * ----> https://www.adafruit.com/products/1469 10 | * Adafruit invests time and resources providing this open source code, 11 | * please support Adafruit and open-source hardware by purchasing 12 | * products from Adafruit! 13 | * 14 | * Redistribution and use in source and binary forms, with or without 15 | * modification, are permitted provided that the following conditions 16 | * are met: 17 | * 18 | * Redistributions of source code must retain the above copyright 19 | * notice, this list of conditions and the following disclaimer. 20 | * 21 | * Redistributions in binary form must reproduce the above copyright 22 | * notice, this list of conditions and the following disclaimer in the 23 | * documentation and/or other materials provided with the 24 | * distribution. 25 | * 26 | * Neither the name of Texas Instruments Incorporated nor the names of 27 | * its contributors may be used to endorse or promote products derived 28 | * from this software without specific prior written permission. 29 | * 30 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 31 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 32 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 33 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 34 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 35 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 36 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 37 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 38 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 39 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 40 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 41 | * 42 | *****************************************************************************/ 43 | #ifndef __ERROR_CODES__ 44 | #define __ERROR_CODES__ 45 | 46 | //***************************************************************************** 47 | // 48 | // If building with a C++ compiler, make all of the definitions in this header 49 | // have a C binding. 50 | // 51 | //***************************************************************************** 52 | #ifdef __cplusplus 53 | extern "C" { 54 | #endif 55 | 56 | // 57 | // Error numbers 58 | // 59 | #define ERROR_WIFI_ALREADY_DISCONNECTED -129 60 | #define NOT_ENOUGH_SOCKETS -128 61 | #define SOCKET_ALREADY_EXISTS -127 62 | #define NOT_SUPPORTED -126 63 | #define TCP_OPEN_FAILED -124 64 | #define BAD_SOCKET_DATA -123 65 | #define SOCKET_NOT_FOUND -122 66 | #define SOCKET_TIMED_OUT -121 67 | #define BAD_IP_HEADER -120 68 | #define NEED_TO_LISTEN -119 69 | #define RECV_TIMED_OUT -118 70 | #define NEED_TO_SEND -114 71 | #define UNABLE_TO_SEND -113 72 | #define DHCP_ERROR -100 73 | #define DHCP_LEASE_EXPIRED -99 74 | #define ARP_REQUEST_FAILED -95 75 | #define DHCP_LEASE_RENEWING -92 76 | #define IGMP_ERROR -91 77 | #define INVALID_VALUE -85 78 | #define DNS_ID_ERROR -75 79 | #define DNS_OPCODE_ERROR -74 80 | #define DNS_RCODE_ERROR -73 81 | #define DNS_COUNT_ERROR -72 82 | #define DNS_TYPE_ERROR -71 83 | #define DNS_CLASS_ERROR -70 84 | #define DNS_NOT_FOUND -69 85 | #define SOCKET_BUFFER_TOO_SMALL -68 86 | #define REASSEMBLY_ERROR -64 87 | #define REASSEMBLY_TIMED_OUT -63 88 | #define BAD_REASSEMBLY_DATA -62 89 | #define UNABLE_TO_TCP_SEND -60 90 | #define ERROR_WIFI_NOT_CONNECTED -59 91 | #define SEND_FAILED_ARP_IN_PROCESS -58 92 | #define RECV_FAILED_SOCKET_INACTIVE -57 93 | 94 | // 95 | // Return the same error code to all socket 96 | // calls which fail due to socket's inactivity 97 | // 98 | #define ERROR_SOCKET_INACTIVE RECV_FAILED_SOCKET_INACTIVE 99 | 100 | // 101 | // TCP function error codes 102 | // 103 | #define TCP_ERROR -1 104 | #define TCP_TOO_LONG -2 105 | #define TCP_BAD_HEADER -3 106 | #define TCP_BAD_CSUM -4 107 | #define TCP_BAD_FCS -5 108 | #define TCP_NO_CONNECT -6 109 | 110 | // 111 | // UDP function error codes 112 | // 113 | #define UDP_ERROR -1 114 | #define UDP_TOO_LONG -2 115 | #define UDP_BAD_CSUM -4 116 | #define UDP_BAD_FCS -5 117 | 118 | // 119 | // Raw error codes 120 | // 121 | #define RAW_ERROR -1 122 | #define RAW_TOO_LONG -2 123 | 124 | // 125 | // SimpleLink error codes 126 | // 127 | #define SL_INVALID_INTERFACE -1 128 | #define SL_NO_MORE_DATA_TO_READ -2 129 | #define SL_OUT_OF_RESOURCES (-150) 130 | #define SL_NOT_ENOUGH_SPACE (-151) 131 | #define SL_INCORRECT_IF (-152) 132 | #define SL_NOTHING_TO_SEND (-153) 133 | #define SL_WILL_SEND_LATER \ 134 | (100) // This is not an error - just an indication that we can't send data 135 | // now 136 | #define SL_TX_ALLOC_FAILED (-161) 137 | 138 | #define SL_INVALID_COMMAND_ARGUMENTS (-170) 139 | 140 | #ifdef __cplusplus 141 | } 142 | #endif /* __cplusplus */ 143 | 144 | #endif /* __ERROR_CODES__ */ 145 | -------------------------------------------------------------------------------- /platforms/arduino_wifi_CC3000/adafruit_CC3000_lib_fossa/utility/host_driver_version.h: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * host_driver_version.h - CC3000 Host Driver Implementation. 4 | * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ 5 | * 6 | * Adapted for use with the Arduino/AVR by KTOWN (Kevin Townsend) 7 | * & Limor Fried for Adafruit Industries 8 | * This library works with the Adafruit CC3000 breakout 9 | * ----> https://www.adafruit.com/products/1469 10 | * Adafruit invests time and resources providing this open source code, 11 | * please support Adafruit and open-source hardware by purchasing 12 | * products from Adafruit! 13 | * 14 | * Redistribution and use in source and binary forms, with or without 15 | * modification, are permitted provided that the following conditions 16 | * are met: 17 | * 18 | * Redistributions of source code must retain the above copyright 19 | * notice, this list of conditions and the following disclaimer. 20 | * 21 | * Redistributions in binary form must reproduce the above copyright 22 | * notice, this list of conditions and the following disclaimer in the 23 | * documentation and/or other materials provided with the 24 | * distribution. 25 | * 26 | * Neither the name of Texas Instruments Incorporated nor the names of 27 | * its contributors may be used to endorse or promote products derived 28 | * from this software without specific prior written permission. 29 | * 30 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 31 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 32 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 33 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 34 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 35 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 36 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 37 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 38 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 39 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 40 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 41 | * 42 | *****************************************************************************/ 43 | #ifndef __HOST_DRIVER_VERSION_H__ 44 | #define __HOST_DRIVER_VERSION_H__ 45 | 46 | #define DRIVER_VERSION_NUMBER 16 47 | 48 | #endif // __VERSION_H__ 49 | -------------------------------------------------------------------------------- /platforms/arduino_wifi_CC3000/adafruit_CC3000_lib_fossa/utility/security.h: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * security.h - CC3000 Host Driver Implementation. 4 | * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ 5 | * 6 | * Adapted for use with the Arduino/AVR by KTOWN (Kevin Townsend) 7 | * & Limor Fried for Adafruit Industries 8 | * This library works with the Adafruit CC3000 breakout 9 | * ----> https://www.adafruit.com/products/1469 10 | * Adafruit invests time and resources providing this open source code, 11 | * please support Adafruit and open-source hardware by purchasing 12 | * products from Adafruit! 13 | * 14 | * Redistribution and use in source and binary forms, with or without 15 | * modification, are permitted provided that the following conditions 16 | * are met: 17 | * 18 | * Redistributions of source code must retain the above copyright 19 | * notice, this list of conditions and the following disclaimer. 20 | * 21 | * Redistributions in binary form must reproduce the above copyright 22 | * notice, this list of conditions and the following disclaimer in the 23 | * documentation and/or other materials provided with the 24 | * distribution. 25 | * 26 | * Neither the name of Texas Instruments Incorporated nor the names of 27 | * its contributors may be used to endorse or promote products derived 28 | * from this software without specific prior written permission. 29 | * 30 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 31 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 32 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 33 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 34 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 35 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 36 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 37 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 38 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 39 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 40 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 41 | * 42 | *****************************************************************************/ 43 | #ifndef __SECURITY__ 44 | #define __SECURITY__ 45 | 46 | #include "nvmem.h" 47 | 48 | //***************************************************************************** 49 | // 50 | // If building with a C++ compiler, make all of the definitions in this header 51 | // have a C binding. 52 | // 53 | //***************************************************************************** 54 | #ifdef __cplusplus 55 | extern "C" { 56 | #endif 57 | 58 | #define AES128_KEY_SIZE 16 59 | 60 | #ifndef CC3000_UNENCRYPTED_SMART_CONFIG 61 | 62 | //***************************************************************************** 63 | // 64 | //! aes_encrypt 65 | //! 66 | //! @param[in] key AES128 key of size 16 bytes 67 | //! @param[in\out] state 16 bytes of plain text and cipher text 68 | //! 69 | //! @return none 70 | //! 71 | //! @brief AES128 encryption: 72 | //! Given AES128 key and 16 bytes plain text, cipher text of 16 bytes 73 | //! is computed. The AES implementation is in mode ECB (Electronic 74 | //! Code Book). 75 | //! 76 | //! 77 | //***************************************************************************** 78 | extern void aes_encrypt(UINT8 *state, UINT8 *key); 79 | 80 | //***************************************************************************** 81 | // 82 | //! aes_decrypt 83 | //! 84 | //! @param[in] key AES128 key of size 16 bytes 85 | //! @param[in\out] state 16 bytes of cipher text and plain text 86 | //! 87 | //! @return none 88 | //! 89 | //! @brief AES128 decryption: 90 | //! Given AES128 key and 16 bytes cipher text, plain text of 16 bytes 91 | //! is computed The AES implementation is in mode ECB 92 | //! (Electronic Code Book). 93 | //! 94 | //! 95 | //***************************************************************************** 96 | extern void aes_decrypt(UINT8 *state, UINT8 *key); 97 | 98 | //***************************************************************************** 99 | // 100 | //! aes_read_key 101 | //! 102 | //! @param[out] key AES128 key of size 16 bytes 103 | //! 104 | //! @return on success 0, error otherwise. 105 | //! 106 | //! @brief Reads AES128 key from EEPROM 107 | //! Reads the AES128 key from fileID #12 in EEPROM 108 | //! returns an error if the key does not exist. 109 | //! 110 | //! 111 | //***************************************************************************** 112 | extern INT32 aes_read_key(UINT8 *key); 113 | 114 | //***************************************************************************** 115 | // 116 | //! aes_write_key 117 | //! 118 | //! @param[out] key AES128 key of size 16 bytes 119 | //! 120 | //! @return on success 0, error otherwise. 121 | //! 122 | //! @brief writes AES128 key from EEPROM 123 | //! Writes the AES128 key to fileID #12 in EEPROM 124 | //! 125 | //! 126 | //***************************************************************************** 127 | extern INT32 aes_write_key(UINT8 *key); 128 | 129 | #endif // CC3000_UNENCRYPTED_SMART_CONFIG 130 | 131 | #ifdef __cplusplus 132 | } 133 | #endif // __cplusplus 134 | 135 | #endif 136 | -------------------------------------------------------------------------------- /platforms/arduino_wifi_CC3000/avrsupport.cpp: -------------------------------------------------------------------------------- 1 | #include "avrsupport.h" 2 | /* 3 | * Copyright (c) 2015 Cesanta Software Limited 4 | * All rights reserved 5 | */ 6 | #include 7 | 8 | void blink(int times, int ms) { 9 | static int inited = 0; 10 | int i; 11 | 12 | if (!inited) { 13 | DDRB |= 0x80; 14 | inited = 1; 15 | } 16 | 17 | for (i = 0; i < times; i++) { 18 | PORTB |= 0x80; 19 | delay(ms); 20 | PORTB &= 0x7F; 21 | delay(ms); 22 | } 23 | } 24 | 25 | extern unsigned int __heap_start; 26 | extern void* __brkval; 27 | 28 | struct __freelist { 29 | size_t sz; 30 | struct __freelist* nx; 31 | }; 32 | 33 | extern struct __freelist* __flp; 34 | 35 | int get_freelistsize() { 36 | struct __freelist* current; 37 | int total = 0; 38 | for (current = __flp; current; current = current->nx) { 39 | total += 2; 40 | total += (int) current->sz; 41 | } 42 | return total; 43 | } 44 | 45 | int get_freememsize() { 46 | int free_memory; 47 | if ((int) __brkval == 0) { 48 | free_memory = ((int) &free_memory) - ((int) &__heap_start); 49 | } else { 50 | free_memory = ((int) &free_memory) - ((int) __brkval); 51 | free_memory += get_freelistsize(); 52 | } 53 | return free_memory; 54 | } 55 | /* 56 | * Copyright (c) 2015 Cesanta Software Limited 57 | * All rights reserved 58 | */ 59 | 60 | #include 61 | #include 62 | 63 | long long int to64(const char* str) { 64 | long long int res = 0; 65 | char negative = 0; 66 | 67 | while (isspace(*str)) str++; 68 | 69 | if (*str == '+') { 70 | str++; 71 | } else if (*str == '-') { 72 | negative = 1; 73 | str++; 74 | } 75 | 76 | while (*str >= '0' && *str <= '9') { 77 | res = res * 10 + (*str - '0'); 78 | str++; 79 | } 80 | 81 | return negative ? -res : res; 82 | } 83 | 84 | char* strerror(int errnum) { 85 | /* TODO(alashkin): show real error message */ 86 | const char frmstr[] = "Error: %d"; 87 | static char retbuf[sizeof(frmstr) + 11]; 88 | 89 | snprintf(retbuf, sizeof(retbuf), frmstr, errnum); 90 | return retbuf; 91 | } 92 | 93 | /* 94 | * Returns the number of seconds since the Arduino board 95 | * began running the current program. 96 | * So, this function 97 | * 1. doesn't support anything but NULL as a parameter 98 | * 2. suitable only to detect timeouts etc. 99 | * If time(NULL) is logged, result would be something 100 | * like "1970-01-01..." etc) 101 | */ 102 | 103 | time_t time(time_t* timer) { 104 | return millis() / 1000; 105 | } 106 | /* 107 | * Copyright (c) 2015 Cesanta Software Limited 108 | * All rights reserved 109 | */ 110 | 111 | #include 112 | #include 113 | #include 114 | 115 | #include 116 | #include 117 | 118 | #define ADAFRUIT_CC3000_IRQ 3 119 | #define ADAFRUIT_CC3000_VBAT 5 120 | #define ADAFRUIT_CC3000_CS 10 121 | #define DHCP_TIMEOUT 30 122 | 123 | static unsigned long aucDHCP = 14400; 124 | static unsigned long aucARP = 3600; 125 | static unsigned long aucKeepalive = 30; 126 | static unsigned long aucInactivity = 0; 127 | 128 | Adafruit_CC3000 cc3000(ADAFRUIT_CC3000_CS, ADAFRUIT_CC3000_IRQ, 129 | ADAFRUIT_CC3000_VBAT, SPI_CLOCK_DIVIDER); 130 | 131 | int check_dhcp() { 132 | time_t finish_time = millis() + DHCP_TIMEOUT * 1000; 133 | while (!cc3000.checkDHCP() && millis() < finish_time) { 134 | delay(100); 135 | yield(); 136 | } 137 | 138 | return cc3000.checkDHCP(); 139 | } 140 | 141 | int avr_netinit(const char* wlan_ssid, const char* wlan_pwd, int wlan_security, 142 | uint32_t ip, uint32_t subnet_mask, uint32_t gateway, 143 | uint32_t dns) { 144 | init_sockets_buffer(); 145 | 146 | if (!cc3000.begin()) { 147 | return -1; 148 | } 149 | 150 | if (!cc3000.connectToAP(wlan_ssid, wlan_pwd, wlan_security)) { 151 | return -1; 152 | } 153 | 154 | if (!check_dhcp()) { 155 | return -1; 156 | } 157 | 158 | uint32_t current_ip = 0, current_subnet_mask = 0, current_gw = 0, 159 | currend_dhcp = 0, current_dns = 0; 160 | 161 | if (!cc3000.getIPAddress(¤t_ip, ¤t_subnet_mask, ¤t_gw, 162 | ¤d_dhcp, ¤t_dns)) { 163 | return -1; 164 | } 165 | 166 | if (current_ip != ip || current_subnet_mask != subnet_mask || 167 | current_gw != gateway || current_dns != dns) { 168 | if (!cc3000.setStaticIPAddress(ip, subnet_mask, gateway, dns)) { 169 | return -1; 170 | } 171 | 172 | /* Waiting while new address is really assigned */ 173 | if (!check_dhcp()) { 174 | return -1; 175 | } 176 | } 177 | 178 | if (netapp_timeout_values(&aucDHCP, &aucARP, &aucKeepalive, &aucInactivity) != 179 | 0) { 180 | return -1; 181 | } 182 | 183 | /* TODO(alashkin): power fix */ 184 | delay(5000); 185 | 186 | return 0; 187 | } 188 | -------------------------------------------------------------------------------- /platforms/arduino_wifi_CC3000/avrsupport.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Cesanta Software Limited 3 | * All rights reserved 4 | */ 5 | 6 | #ifndef AVRDEBUG_HEADER_INCLUDED 7 | #define AVRDEBUG_HEADER_INCLUDED 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | /* Blinks ($times) times with ($ms) delay */ 13 | void blink(int times, int ms); 14 | 15 | /* Returns free memory size */ 16 | int get_freememsize(); 17 | 18 | #if defined(AVR_ENABLE_DEBUG) 19 | 20 | #define DUMPINIT() Serial.begin(9600) 21 | #define DUMPSTR(msg) Serial.println(msg) 22 | #define DUMPDEC(num) Serial.println(num, DEC) 23 | #define DUMPFREEMEM() \ 24 | Serial.print("Free mem: "); \ 25 | Serial.println(get_freememsize()) 26 | 27 | #define DUMPFUNCNAME() Serial.println(__func__) 28 | 29 | #define BLINK(t, m) blink(t, m); 30 | 31 | #else 32 | 33 | #define DUMPINIT() 34 | #define DUMPFUNCNAME() 35 | #define DUMPFREEMEM() 36 | #define BLINK(t, m) 37 | #define DUMPSTR(msg) 38 | #define DUMPDEC(num) 39 | 40 | #endif 41 | 42 | #ifdef __cplusplus 43 | } 44 | #endif 45 | 46 | #endif /* NS_AVRDEBUG_HEADER_INCLUDED */ 47 | /* 48 | * Copyright (c) 2015 Cesanta Software Limited 49 | * All rights reserved 50 | */ 51 | 52 | #ifndef AVRLIBC_COMPAT_HEADER_INCLUDED 53 | #define AVRLIBC_COMPAT_HEADER_INCLUDED 54 | 55 | #include 56 | #include 57 | #include 58 | 59 | /* 60 | * Some of this stuff breaks 61 | * Fossa o Arduino 62 | * TODO(alashkin): remove these defines when 63 | * some kind of AVR-build-test will be ready 64 | */ 65 | #define NS_DISABLE_HTTP_DIGEST_AUTH 66 | #define NS_DISABLE_MQTT 67 | #define NS_DISABLE_MD5 68 | #define NS_DISABLE_JSON_RPC 69 | #define NS_DISABLE_SOCKETPAIR 70 | #define NS_DISABLE_SSI 71 | #define NS_DISABLE_POPEN 72 | #define NS_DISABLE_DIRECTORY_LISTING 73 | #define NS_DISABLE_DAV 74 | #define NS_DISABLE_DNS 75 | #define NS_DISABLE_RESOLVER 76 | #define NS_DISABLE_CGI 77 | 78 | #ifdef __cplusplus 79 | extern "C" { 80 | #endif 81 | 82 | /* fossa requires to64, so define it' instead of strtol & co */ 83 | long long int to64(const char* str); 84 | 85 | char* strerror(int errnum); 86 | 87 | /* Time declaration & functions */ 88 | typedef unsigned long time_t; 89 | 90 | #ifndef TIMEVAL 91 | struct timeval { 92 | uint32_t tv_sec; 93 | uint32_t tv_usec; 94 | }; 95 | #define TIMEVAL 96 | #endif 97 | 98 | time_t time(time_t* timer); 99 | 100 | /* TODO(alashkin): add (at least) in-flash "files" operations */ 101 | 102 | #define AVR_NOFS 103 | #define AVR_LIBC 104 | 105 | #ifdef __cplusplus 106 | } 107 | #endif 108 | 109 | #endif 110 | 111 | /* 112 | * Copyright (c) 2015 Cesanta Software Limited 113 | * All rights reserved 114 | */ 115 | 116 | #ifndef CC3000UTILS_HEADER_INCLUDED 117 | #define CC3000UTILS_HEADER_INCLUDED 118 | 119 | #define WIFI_CC3000 120 | 121 | #ifdef __cplusplus 122 | extern "C" { 123 | #endif 124 | 125 | int avr_netinit(const char* wlan_ssid, const char* wlan_pwd, int wlan_security, 126 | uint32_t ip, uint32_t subnet_mask, uint32_t gateway, 127 | uint32_t dns); 128 | 129 | #include 130 | #include 131 | 132 | #define close(x) closesocket(x) 133 | 134 | #ifdef __cplusplus 135 | } 136 | #endif 137 | 138 | #endif 139 | -------------------------------------------------------------------------------- /platforms/arduino_wifi_CC3000/src/CC3000_utils.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Cesanta Software Limited 3 | * All rights reserved 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | #define ADAFRUIT_CC3000_IRQ 3 14 | #define ADAFRUIT_CC3000_VBAT 5 15 | #define ADAFRUIT_CC3000_CS 10 16 | #define DHCP_TIMEOUT 30 17 | 18 | static unsigned long aucDHCP = 14400; 19 | static unsigned long aucARP = 3600; 20 | static unsigned long aucKeepalive = 30; 21 | static unsigned long aucInactivity = 0; 22 | 23 | Adafruit_CC3000 cc3000(ADAFRUIT_CC3000_CS, ADAFRUIT_CC3000_IRQ, 24 | ADAFRUIT_CC3000_VBAT, SPI_CLOCK_DIVIDER); 25 | 26 | int check_dhcp() { 27 | time_t finish_time = millis() + DHCP_TIMEOUT * 1000; 28 | while (!cc3000.checkDHCP() && millis() < finish_time) { 29 | delay(100); 30 | yield(); 31 | } 32 | 33 | return cc3000.checkDHCP(); 34 | } 35 | 36 | int avr_netinit(const char* wlan_ssid, const char* wlan_pwd, int wlan_security, 37 | uint32_t ip, uint32_t subnet_mask, uint32_t gateway, 38 | uint32_t dns) { 39 | init_sockets_buffer(); 40 | 41 | if (!cc3000.begin()) { 42 | return -1; 43 | } 44 | 45 | if (!cc3000.connectToAP(wlan_ssid, wlan_pwd, wlan_security)) { 46 | return -1; 47 | } 48 | 49 | if (!check_dhcp()) { 50 | return -1; 51 | } 52 | 53 | uint32_t current_ip = 0, current_subnet_mask = 0, current_gw = 0, 54 | currend_dhcp = 0, current_dns = 0; 55 | 56 | if (!cc3000.getIPAddress(¤t_ip, ¤t_subnet_mask, ¤t_gw, 57 | ¤d_dhcp, ¤t_dns)) { 58 | return -1; 59 | } 60 | 61 | if (current_ip != ip || current_subnet_mask != subnet_mask || 62 | current_gw != gateway || current_dns != dns) { 63 | if (!cc3000.setStaticIPAddress(ip, subnet_mask, gateway, dns)) { 64 | return -1; 65 | } 66 | 67 | /* Waiting while new address is really assigned */ 68 | if (!check_dhcp()) { 69 | return -1; 70 | } 71 | } 72 | 73 | if (netapp_timeout_values(&aucDHCP, &aucARP, &aucKeepalive, &aucInactivity) != 74 | 0) { 75 | return -1; 76 | } 77 | 78 | /* TODO(alashkin): power fix */ 79 | delay(5000); 80 | 81 | return 0; 82 | } 83 | -------------------------------------------------------------------------------- /platforms/arduino_wifi_CC3000/src/CC3000_utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Cesanta Software Limited 3 | * All rights reserved 4 | */ 5 | #ifndef CC3000UTILS_HEADER_INCLUDED 6 | #define CC3000UTILS_HEADER_INCLUDED 7 | 8 | #define WIFI_CC3000 9 | 10 | #ifdef __cplusplus 11 | extern "C" { 12 | #endif 13 | 14 | int avr_netinit(const char* wlan_ssid, const char* wlan_pwd, int wlan_security, 15 | uint32_t ip, uint32_t subnet_mask, uint32_t gateway, 16 | uint32_t dns); 17 | 18 | #include 19 | #include 20 | 21 | #define close(x) closesocket(x) 22 | 23 | #ifdef __cplusplus 24 | } 25 | #endif 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /src/CPPLINT.cfg: -------------------------------------------------------------------------------- 1 | exclude_files=sha1\.c 2 | -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | include modules.mk 2 | 3 | all: ../fossa.c ../fossa.h 4 | 5 | ../fossa.h: Makefile modules.mk $(HEADERS) 6 | @echo "AMALGAMATING\tfossa.h" 7 | @echo "#ifdef __AVR__\n#include \"avrsupport.h\"\n#endif" > $@ 8 | @cat $(HEADERS) | sed '/^#include "/d' >>$@ 9 | 10 | ../fossa.c: Makefile internal.h modules.mk $(SOURCES) 11 | @echo "AMALGAMATING\tfossa.c" 12 | @(echo '#include "fossa.h"'; ../../tools/amalgam --srcdir src internal.h $(SOURCES)) >$@ 13 | -------------------------------------------------------------------------------- /src/common.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 Cesanta Software Limited 3 | * All rights reserved 4 | * This software is dual-licensed: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License version 2 as 6 | * published by the Free Software Foundation. For the terms of this 7 | * license, see . 8 | * 9 | * You are free to use this software under the terms of the GNU General 10 | * Public License, but WITHOUT ANY WARRANTY; without even the implied 11 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 12 | * See the GNU General Public License for more details. 13 | * 14 | * Alternatively, you can license this software under a commercial 15 | * license, as set out in . 16 | */ 17 | 18 | #define NS_FOSSA_VERSION "2.0.0" 19 | -------------------------------------------------------------------------------- /src/dns-server.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 Cesanta Software Limited 3 | * All rights reserved 4 | */ 5 | 6 | #ifdef NS_ENABLE_DNS_SERVER 7 | 8 | #include "internal.h" 9 | 10 | struct ns_dns_reply ns_dns_create_reply(struct mbuf *io, 11 | struct ns_dns_message *msg) { 12 | struct ns_dns_reply rep; 13 | rep.msg = msg; 14 | rep.io = io; 15 | rep.start = io->len; 16 | 17 | /* reply + recursion allowed */ 18 | msg->flags |= 0x8080; 19 | ns_dns_copy_body(io, msg); 20 | 21 | msg->num_answers = 0; 22 | return rep; 23 | } 24 | 25 | int ns_dns_send_reply(struct ns_connection *nc, struct ns_dns_reply *r) { 26 | size_t sent = r->io->len - r->start; 27 | ns_dns_insert_header(r->io, r->start, r->msg); 28 | if (!(nc->flags & NSF_UDP)) { 29 | uint16_t len = htons(sent); 30 | mbuf_insert(r->io, r->start, &len, 2); 31 | } 32 | 33 | if (&nc->send_mbuf != r->io || nc->flags & NSF_UDP) { 34 | sent = ns_send(nc, r->io->buf + r->start, r->io->len - r->start); 35 | r->io->len = r->start; 36 | } 37 | return sent; 38 | } 39 | 40 | int ns_dns_reply_record(struct ns_dns_reply *reply, 41 | struct ns_dns_resource_record *question, 42 | const char *name, int rtype, int ttl, const void *rdata, 43 | size_t rdata_len) { 44 | struct ns_dns_message *msg = (struct ns_dns_message *) reply->msg; 45 | char rname[512]; 46 | struct ns_dns_resource_record *ans = &msg->answers[msg->num_answers]; 47 | if (msg->num_answers >= NS_MAX_DNS_ANSWERS) { 48 | return -1; /* LCOV_EXCL_LINE */ 49 | } 50 | 51 | if (name == NULL) { 52 | name = rname; 53 | rname[511] = 0; 54 | ns_dns_uncompress_name(msg, &question->name, rname, sizeof(rname) - 1); 55 | } 56 | 57 | *ans = *question; 58 | ans->kind = NS_DNS_ANSWER; 59 | ans->rtype = rtype; 60 | ans->ttl = ttl; 61 | 62 | if (ns_dns_encode_record(reply->io, ans, name, strlen(name), rdata, 63 | rdata_len) == -1) { 64 | return -1; /* LCOV_EXCL_LINE */ 65 | }; 66 | 67 | msg->num_answers++; 68 | return 0; 69 | } 70 | 71 | #endif /* NS_ENABLE_DNS_SERVER */ 72 | -------------------------------------------------------------------------------- /src/dns-server.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 Cesanta Software Limited 3 | * All rights reserved 4 | */ 5 | 6 | /* 7 | * === DNS server 8 | * 9 | * Disabled by default; enable with `-DNS_ENABLE_DNS_SERVER`. 10 | */ 11 | 12 | #ifndef NS_DNS_SERVER_HEADER_DEFINED 13 | #define NS_DNS_SERVER_HEADER_DEFINED 14 | 15 | #ifdef NS_ENABLE_DNS_SERVER 16 | 17 | #include "dns.h" 18 | 19 | #ifdef __cplusplus 20 | extern "C" { 21 | #endif /* __cplusplus */ 22 | 23 | #define NS_DNS_SERVER_DEFAULT_TTL 3600 24 | 25 | struct ns_dns_reply { 26 | struct ns_dns_message *msg; 27 | struct mbuf *io; 28 | size_t start; 29 | }; 30 | 31 | /* 32 | * Create a DNS reply. 33 | * 34 | * The reply will be based on an existing query message `msg`. 35 | * The query body will be appended to the output buffer. 36 | * "reply + recursion allowed" will be added to the message flags and 37 | * message's num_answers will be set to 0. 38 | * 39 | * Answer records can be appended with `ns_dns_send_reply` or by lower 40 | * level function defined in the DNS API. 41 | * 42 | * In order to send the reply use `ns_dns_send_reply`. 43 | * It's possible to use a connection's send buffer as reply buffers, 44 | * and it will work for both UDP and TCP connections. 45 | * 46 | * Example: 47 | * 48 | * [source,c] 49 | * ----- 50 | * reply = ns_dns_create_reply(&nc->send_mbuf, msg); 51 | * for (i = 0; i < msg->num_questions; i++) { 52 | * rr = &msg->questions[i]; 53 | * if (rr->rtype == NS_DNS_A_RECORD) { 54 | * ns_dns_reply_record(&reply, rr, 3600, &dummy_ip_addr, 4); 55 | * } 56 | * } 57 | * ns_dns_send_reply(nc, &reply); 58 | * ----- 59 | */ 60 | struct ns_dns_reply ns_dns_create_reply(struct mbuf *, struct ns_dns_message *); 61 | 62 | /* 63 | * Append a DNS reply record to the IO buffer and to the DNS message. 64 | * 65 | * The message num_answers field will be incremented. It's caller's duty 66 | * to ensure num_answers is propertly initialized. 67 | * 68 | * Returns -1 on error. 69 | */ 70 | int ns_dns_reply_record(struct ns_dns_reply *, struct ns_dns_resource_record *, 71 | const char *, int, int, const void *, size_t); 72 | 73 | /* 74 | * Send a DNS reply through a connection. 75 | * 76 | * The DNS data is stored in an IO buffer pointed by reply structure in `r`. 77 | * This function mutates the content of that buffer in order to ensure that 78 | * the DNS header reflects size and flags of the mssage, that might have been 79 | * updated either with `ns_dns_reply_record` or by direct manipulation of 80 | * `r->message`. 81 | * 82 | * Once sent, the IO buffer will be trimmed unless the reply IO buffer 83 | * is the connection's send buffer and the connection is not in UDP mode. 84 | */ 85 | int ns_dns_send_reply(struct ns_connection *, struct ns_dns_reply *); 86 | 87 | #ifdef __cplusplus 88 | } 89 | #endif /* __cplusplus */ 90 | 91 | #endif /* NS_ENABLE_DNS_SERVER */ 92 | #endif /* NS_HTTP_HEADER_DEFINED */ 93 | -------------------------------------------------------------------------------- /src/dns.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 Cesanta Software Limited 3 | * All rights reserved 4 | */ 5 | 6 | /* 7 | * === DNS 8 | */ 9 | 10 | #ifndef NS_DNS_HEADER_DEFINED 11 | #define NS_DNS_HEADER_DEFINED 12 | 13 | #include "net.h" 14 | 15 | #ifdef __cplusplus 16 | extern "C" { 17 | #endif /* __cplusplus */ 18 | 19 | #define NS_DNS_A_RECORD 0x01 /* Lookup IP address */ 20 | #define NS_DNS_CNAME_RECORD 0x05 /* Lookup CNAME */ 21 | #define NS_DNS_AAAA_RECORD 0x1c /* Lookup IPv6 address */ 22 | #define NS_DNS_MX_RECORD 0x0f /* Lookup mail server for domain */ 23 | 24 | #define NS_MAX_DNS_QUESTIONS 32 25 | #define NS_MAX_DNS_ANSWERS 32 26 | 27 | #define NS_DNS_MESSAGE 100 /* High-level DNS message event */ 28 | 29 | enum ns_dns_resource_record_kind { 30 | NS_DNS_INVALID_RECORD = 0, 31 | NS_DNS_QUESTION, 32 | NS_DNS_ANSWER 33 | }; 34 | 35 | /* DNS resource record. */ 36 | struct ns_dns_resource_record { 37 | struct ns_str name; /* buffer with compressed name */ 38 | int rtype; 39 | int rclass; 40 | int ttl; 41 | enum ns_dns_resource_record_kind kind; 42 | struct ns_str rdata; /* protocol data (can be a compressed name) */ 43 | }; 44 | 45 | /* DNS message (request and response). */ 46 | struct ns_dns_message { 47 | struct ns_str pkt; /* packet body */ 48 | uint16_t flags; 49 | uint16_t transaction_id; 50 | int num_questions; 51 | int num_answers; 52 | struct ns_dns_resource_record questions[NS_MAX_DNS_QUESTIONS]; 53 | struct ns_dns_resource_record answers[NS_MAX_DNS_ANSWERS]; 54 | }; 55 | 56 | struct ns_dns_resource_record *ns_dns_next_record( 57 | struct ns_dns_message *, int, struct ns_dns_resource_record *); 58 | 59 | /* 60 | * Parse the record data from a DNS resource record. 61 | * 62 | * - A: struct in_addr *ina 63 | * - AAAA: struct in6_addr *ina 64 | * - CNAME: char buffer 65 | * 66 | * Returns -1 on error. 67 | * 68 | * TODO(mkm): MX 69 | */ 70 | int ns_dns_parse_record_data(struct ns_dns_message *, 71 | struct ns_dns_resource_record *, void *, size_t); 72 | 73 | /* 74 | * Send a DNS query to the remote end. 75 | */ 76 | void ns_send_dns_query(struct ns_connection *, const char *, int); 77 | 78 | /* 79 | * Insert a DNS header to an IO buffer. 80 | * 81 | * Return number of bytes inserted. 82 | */ 83 | int ns_dns_insert_header(struct mbuf *, size_t, struct ns_dns_message *); 84 | 85 | /* 86 | * Append already encoded body from an existing message. 87 | * 88 | * This is useful when generating a DNS reply message which includes 89 | * all question records. 90 | * 91 | * Return number of appened bytes. 92 | */ 93 | int ns_dns_copy_body(struct mbuf *, struct ns_dns_message *); 94 | 95 | /* 96 | * Encode and append a DNS resource record to an IO buffer. 97 | * 98 | * The record metadata is taken from the `rr` parameter, while the name and data 99 | * are taken from the parameters, encoded in the appropriate format depending on 100 | * record type, and stored in the IO buffer. The encoded values might contain 101 | * offsets within the IO buffer. It's thus important that the IO buffer doesn't 102 | * get trimmed while a sequence of records are encoded while preparing a DNS 103 | *reply. 104 | * 105 | * This function doesn't update the `name` and `rdata` pointers in the `rr` 106 | *struct 107 | * because they might be invalidated as soon as the IO buffer grows again. 108 | * 109 | * Return the number of bytes appened or -1 in case of error. 110 | */ 111 | int ns_dns_encode_record(struct mbuf *, struct ns_dns_resource_record *, 112 | const char *, size_t, const void *, size_t); 113 | 114 | /* Low-level: parses a DNS response. */ 115 | int ns_parse_dns(const char *, int, struct ns_dns_message *); 116 | 117 | /* 118 | * Uncompress a DNS compressed name. 119 | * 120 | * The containing dns message is required because the compressed encoding 121 | * and reference suffixes present elsewhere in the packet. 122 | * 123 | * If name is less than `dst_len` characters long, the remainder 124 | * of `dst` is terminated with `\0' characters. Otherwise, `dst` is not 125 | *terminated. 126 | * 127 | * If `dst_len` is 0 `dst` can be NULL. 128 | * Return the uncompressed name length. 129 | */ 130 | size_t ns_dns_uncompress_name(struct ns_dns_message *, struct ns_str *, char *, 131 | int); 132 | 133 | /* 134 | * Attach built-in DNS event handler to the given listening connection. 135 | * 136 | * DNS event handler parses incoming UDP packets, treating them as DNS 137 | * requests. If incoming packet gets successfully parsed by the DNS event 138 | * handler, a user event handler will receive `NS_DNS_REQUEST` event, with 139 | * `ev_data` pointing to the parsed `struct ns_dns_message`. 140 | * 141 | * See 142 | * https://github.com/cesanta/fossa/tree/master/examples/captive_dns_server[captive_dns_server] 143 | * example on how to handle DNS request and send DNS reply. 144 | */ 145 | void ns_set_protocol_dns(struct ns_connection *); 146 | 147 | #ifdef __cplusplus 148 | } 149 | #endif /* __cplusplus */ 150 | #endif /* NS_HTTP_HEADER_DEFINED */ 151 | -------------------------------------------------------------------------------- /src/internal.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 Cesanta Software Limited 3 | * All rights reserved 4 | */ 5 | 6 | #ifndef NS_INTERNAL_HEADER_INCLUDED 7 | #define NS_INTERNAL_HEADER_INCLUDED 8 | 9 | #ifndef NS_MALLOC 10 | #define NS_MALLOC malloc 11 | #endif 12 | 13 | #ifndef NS_CALLOC 14 | #define NS_CALLOC calloc 15 | #endif 16 | 17 | #ifndef NS_REALLOC 18 | #define NS_REALLOC realloc 19 | #endif 20 | 21 | #ifndef NS_FREE 22 | #define NS_FREE free 23 | #endif 24 | 25 | #ifndef MBUF_REALLOC 26 | #define MBUF_REALLOC NS_REALLOC 27 | #endif 28 | 29 | #ifndef MBUF_FREE 30 | #define MBUF_FREE NS_FREE 31 | #endif 32 | 33 | #define NS_SET_PTRPTR(_ptr, _v) \ 34 | do { \ 35 | if (_ptr) *(_ptr) = _v; \ 36 | } while (0) 37 | 38 | #ifndef NS_INTERNAL 39 | #define NS_INTERNAL static 40 | #endif 41 | 42 | #if !defined(NS_MGR_EV_MGR) && defined(__linux__) 43 | #define NS_MGR_EV_MGR 1 /* epoll() */ 44 | #endif 45 | #if !defined(NS_MGR_EV_MGR) 46 | #define NS_MGR_EV_MGR 0 /* select() */ 47 | #endif 48 | 49 | #ifdef PICOTCP 50 | #define NO_LIBC 51 | #define NS_DISABLE_FILESYSTEM 52 | #define NS_DISABLE_POPEN 53 | #define NS_DISABLE_CGI 54 | #define NS_DISABLE_DIRECTORY_LISTING 55 | #define NS_DISABLE_SOCKETPAIR 56 | #define NS_DISABLE_PFS 57 | #endif 58 | 59 | #include "../fossa.h" 60 | 61 | /* internals that need to be accessible in unit tests */ 62 | NS_INTERNAL struct ns_connection *ns_finish_connect(struct ns_connection *nc, 63 | int proto, 64 | union socket_address *sa, 65 | struct ns_add_sock_opts); 66 | 67 | NS_INTERNAL int ns_parse_address(const char *str, union socket_address *sa, 68 | int *proto, char *host, size_t host_len); 69 | NS_INTERNAL void ns_call(struct ns_connection *, int ev, void *ev_data); 70 | NS_INTERNAL void ns_forward(struct ns_connection *, struct ns_connection *); 71 | NS_INTERNAL void ns_add_conn(struct ns_mgr *mgr, struct ns_connection *c); 72 | NS_INTERNAL void ns_remove_conn(struct ns_connection *c); 73 | 74 | #ifndef NS_DISABLE_FILESYSTEM 75 | NS_INTERNAL int find_index_file(char *, size_t, const char *, ns_stat_t *); 76 | #endif 77 | 78 | #ifdef _WIN32 79 | void to_wchar(const char *path, wchar_t *wbuf, size_t wbuf_len); 80 | #endif 81 | 82 | /* 83 | * Reassemble the content of the buffer (buf, blen) which should be 84 | * in the HTTP chunked encoding, by collapsing data chunks to the 85 | * beginning of the buffer. 86 | * 87 | * If chunks get reassembled, modify hm->body to point to the reassembled 88 | * body and fire NS_HTTP_CHUNK event. If handler sets NSF_DELETE_CHUNK 89 | * in nc->flags, delete reassembled body from the mbuf. 90 | * 91 | * Return reassembled body size. 92 | */ 93 | NS_INTERNAL size_t ns_handle_chunked(struct ns_connection *nc, 94 | struct http_message *hm, char *buf, 95 | size_t blen); 96 | 97 | /* Forward declarations for testing. */ 98 | extern void *(*test_malloc)(size_t); 99 | extern void *(*test_calloc)(size_t, size_t); 100 | 101 | #endif /* NS_INTERNAL_HEADER_INCLUDED */ 102 | -------------------------------------------------------------------------------- /src/json-rpc.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2014 Cesanta Software Limited */ 2 | /* All rights reserved */ 3 | 4 | #ifndef NS_DISABLE_JSON_RPC 5 | 6 | #include "internal.h" 7 | 8 | int ns_rpc_create_reply(char *buf, int len, const struct ns_rpc_request *req, 9 | const char *result_fmt, ...) { 10 | static const struct json_token null_tok = {"null", 4, 0, JSON_TYPE_NULL}; 11 | const struct json_token *id = req->id == NULL ? &null_tok : req->id; 12 | va_list ap; 13 | int n = 0; 14 | 15 | n += json_emit(buf + n, len - n, "{s:s,s:", "jsonrpc", "2.0", "id"); 16 | if (id->type == JSON_TYPE_STRING) { 17 | n += json_emit_quoted_str(buf + n, len - n, id->ptr, id->len); 18 | } else { 19 | n += json_emit_unquoted_str(buf + n, len - n, id->ptr, id->len); 20 | } 21 | n += json_emit(buf + n, len - n, ",s:", "result"); 22 | 23 | va_start(ap, result_fmt); 24 | n += json_emit_va(buf + n, len - n, result_fmt, ap); 25 | va_end(ap); 26 | 27 | n += json_emit(buf + n, len - n, "}"); 28 | 29 | return n; 30 | } 31 | 32 | int ns_rpc_create_request(char *buf, int len, const char *method, 33 | const char *id, const char *params_fmt, ...) { 34 | va_list ap; 35 | int n = 0; 36 | 37 | n += json_emit(buf + n, len - n, "{s:s,s:s,s:s,s:", "jsonrpc", "2.0", "id", 38 | id, "method", method, "params"); 39 | va_start(ap, params_fmt); 40 | n += json_emit_va(buf + n, len - n, params_fmt, ap); 41 | va_end(ap); 42 | 43 | n += json_emit(buf + n, len - n, "}"); 44 | 45 | return n; 46 | } 47 | 48 | int ns_rpc_create_error(char *buf, int len, struct ns_rpc_request *req, 49 | int code, const char *message, const char *fmt, ...) { 50 | va_list ap; 51 | int n = 0; 52 | 53 | n += json_emit(buf + n, len - n, "{s:s,s:V,s:{s:i,s:s,s:", "jsonrpc", "2.0", 54 | "id", req->id == NULL ? "null" : req->id->ptr, 55 | req->id == NULL ? 4 : req->id->len, "error", "code", code, 56 | "message", message, "data"); 57 | va_start(ap, fmt); 58 | n += json_emit_va(buf + n, len - n, fmt, ap); 59 | va_end(ap); 60 | 61 | n += json_emit(buf + n, len - n, "}}"); 62 | 63 | return n; 64 | } 65 | 66 | int ns_rpc_create_std_error(char *buf, int len, struct ns_rpc_request *req, 67 | int code) { 68 | const char *message = NULL; 69 | 70 | switch (code) { 71 | case JSON_RPC_PARSE_ERROR: 72 | message = "parse error"; 73 | break; 74 | case JSON_RPC_INVALID_REQUEST_ERROR: 75 | message = "invalid request"; 76 | break; 77 | case JSON_RPC_METHOD_NOT_FOUND_ERROR: 78 | message = "method not found"; 79 | break; 80 | case JSON_RPC_INVALID_PARAMS_ERROR: 81 | message = "invalid parameters"; 82 | break; 83 | case JSON_RPC_SERVER_ERROR: 84 | message = "server error"; 85 | break; 86 | default: 87 | message = "unspecified error"; 88 | break; 89 | } 90 | 91 | return ns_rpc_create_error(buf, len, req, code, message, "N"); 92 | } 93 | 94 | int ns_rpc_dispatch(const char *buf, int len, char *dst, int dst_len, 95 | const char **methods, ns_rpc_handler_t *handlers) { 96 | struct json_token tokens[200]; 97 | struct ns_rpc_request req; 98 | int i, n; 99 | 100 | memset(&req, 0, sizeof(req)); 101 | n = parse_json(buf, len, tokens, sizeof(tokens) / sizeof(tokens[0])); 102 | if (n <= 0) { 103 | int err_code = (n == JSON_STRING_INVALID) ? JSON_RPC_PARSE_ERROR 104 | : JSON_RPC_SERVER_ERROR; 105 | return ns_rpc_create_std_error(dst, dst_len, &req, err_code); 106 | } 107 | 108 | req.message = tokens; 109 | req.id = find_json_token(tokens, "id"); 110 | req.method = find_json_token(tokens, "method"); 111 | req.params = find_json_token(tokens, "params"); 112 | 113 | if (req.id == NULL || req.method == NULL) { 114 | return ns_rpc_create_std_error(dst, dst_len, &req, 115 | JSON_RPC_INVALID_REQUEST_ERROR); 116 | } 117 | 118 | for (i = 0; methods[i] != NULL; i++) { 119 | int mlen = strlen(methods[i]); 120 | if (mlen == req.method->len && 121 | memcmp(methods[i], req.method->ptr, mlen) == 0) 122 | break; 123 | } 124 | 125 | if (methods[i] == NULL) { 126 | return ns_rpc_create_std_error(dst, dst_len, &req, 127 | JSON_RPC_METHOD_NOT_FOUND_ERROR); 128 | } 129 | 130 | return handlers[i](dst, dst_len, &req); 131 | } 132 | 133 | int ns_rpc_parse_reply(const char *buf, int len, struct json_token *toks, 134 | int max_toks, struct ns_rpc_reply *rep, 135 | struct ns_rpc_error *er) { 136 | int n = parse_json(buf, len, toks, max_toks); 137 | 138 | memset(rep, 0, sizeof(*rep)); 139 | memset(er, 0, sizeof(*er)); 140 | 141 | if (n > 0) { 142 | if ((rep->result = find_json_token(toks, "result")) != NULL) { 143 | rep->message = toks; 144 | rep->id = find_json_token(toks, "id"); 145 | } else { 146 | er->message = toks; 147 | er->id = find_json_token(toks, "id"); 148 | er->error_code = find_json_token(toks, "error.code"); 149 | er->error_message = find_json_token(toks, "error.message"); 150 | er->error_data = find_json_token(toks, "error.data"); 151 | } 152 | } 153 | return n; 154 | } 155 | 156 | #endif /* NS_DISABLE_JSON_RPC */ 157 | -------------------------------------------------------------------------------- /src/json-rpc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 Cesanta Software Limited 3 | * All rights reserved 4 | */ 5 | 6 | /* 7 | * === JSON-RPC 8 | */ 9 | 10 | #ifndef NS_JSON_RPC_HEADER_DEFINED 11 | #define NS_JSON_RPC_HEADER_DEFINED 12 | 13 | #ifdef __cplusplus 14 | extern "C" { 15 | #endif /* __cplusplus */ 16 | 17 | /* JSON-RPC request */ 18 | struct ns_rpc_request { 19 | struct json_token *message; /* Whole RPC message */ 20 | struct json_token *id; /* Message ID */ 21 | struct json_token *method; /* Method name */ 22 | struct json_token *params; /* Method params */ 23 | }; 24 | 25 | /* JSON-RPC response */ 26 | struct ns_rpc_reply { 27 | struct json_token *message; /* Whole RPC message */ 28 | struct json_token *id; /* Message ID */ 29 | struct json_token *result; /* Remote call result */ 30 | }; 31 | 32 | /* JSON-RPC error */ 33 | struct ns_rpc_error { 34 | struct json_token *message; /* Whole RPC message */ 35 | struct json_token *id; /* Message ID */ 36 | struct json_token *error_code; /* error.code */ 37 | struct json_token *error_message; /* error.message */ 38 | struct json_token *error_data; /* error.data, can be NULL */ 39 | }; 40 | 41 | /* 42 | * Parse JSON-RPC reply contained in `buf`, `len` into JSON tokens array 43 | * `toks`, `max_toks`. If buffer contains valid reply, `reply` structure is 44 | * populated. The result of RPC call is located in `reply.result`. On error, 45 | * `error` structure is populated. Returns: the result of calling 46 | * `parse_json(buf, len, toks, max_toks)`: 47 | * 48 | * On success, an offset inside `json_string` is returned 49 | * where parsing has finished. On failure, a negative number is 50 | * returned, one of: 51 | * 52 | * - #define JSON_STRING_INVALID -1 53 | * - #define JSON_STRING_INCOMPLETE -2 54 | * - #define JSON_TOKEN_ARRAY_TOO_SMALL -3 55 | */ 56 | int ns_rpc_parse_reply(const char *buf, int len, struct json_token *toks, 57 | int max_toks, struct ns_rpc_reply *, 58 | struct ns_rpc_error *); 59 | 60 | /* 61 | * Create JSON-RPC request in a given buffer. 62 | * 63 | * Return length of the request, which 64 | * can be larger then `len` that indicates an overflow. 65 | * `params_fmt` format string should conform to `json_emit()` API, 66 | * see https://github.com/cesanta/frozen 67 | */ 68 | int ns_rpc_create_request(char *buf, int len, const char *method, 69 | const char *id, const char *params_fmt, ...); 70 | 71 | /* 72 | * Create JSON-RPC reply in a given buffer. 73 | * 74 | * Return length of the reply, which 75 | * can be larger then `len` that indicates an overflow. 76 | * `result_fmt` format string should conform to `json_emit()` API, 77 | * see https://github.com/cesanta/frozen 78 | */ 79 | int ns_rpc_create_reply(char *buf, int len, const struct ns_rpc_request *req, 80 | const char *result_fmt, ...); 81 | 82 | /* 83 | * Create JSON-RPC error reply in a given buffer. 84 | * 85 | * Return length of the error, which 86 | * can be larger then `len` that indicates an overflow. 87 | * `fmt` format string should conform to `json_emit()` API, 88 | * see https://github.com/cesanta/frozen 89 | */ 90 | int ns_rpc_create_error(char *buf, int len, struct ns_rpc_request *req, 91 | int code, const char *message, const char *fmt, ...); 92 | 93 | /* JSON-RPC standard error codes */ 94 | #define JSON_RPC_PARSE_ERROR (-32700) 95 | #define JSON_RPC_INVALID_REQUEST_ERROR (-32600) 96 | #define JSON_RPC_METHOD_NOT_FOUND_ERROR (-32601) 97 | #define JSON_RPC_INVALID_PARAMS_ERROR (-32602) 98 | #define JSON_RPC_INTERNAL_ERROR (-32603) 99 | #define JSON_RPC_SERVER_ERROR (-32000) 100 | 101 | /* 102 | * Create JSON-RPC error in a given buffer. 103 | * 104 | * Return length of the error, which 105 | * can be larger then `len` that indicates an overflow. See 106 | * JSON_RPC_*_ERROR definitions for standard error values: 107 | * 108 | * - #define JSON_RPC_PARSE_ERROR (-32700) 109 | * - #define JSON_RPC_INVALID_REQUEST_ERROR (-32600) 110 | * - #define JSON_RPC_METHOD_NOT_FOUND_ERROR (-32601) 111 | * - #define JSON_RPC_INVALID_PARAMS_ERROR (-32602) 112 | * - #define JSON_RPC_INTERNAL_ERROR (-32603) 113 | * - #define JSON_RPC_SERVER_ERROR (-32000) 114 | */ 115 | int ns_rpc_create_std_error(char *, int, struct ns_rpc_request *, int code); 116 | 117 | typedef int (*ns_rpc_handler_t)(char *buf, int len, struct ns_rpc_request *); 118 | 119 | /* 120 | * Dispatches a JSON-RPC request. 121 | * 122 | * Parses JSON-RPC request contained in `buf`, `len`. 123 | * Then, dispatches the request to the correct handler method. 124 | * Valid method names should be specified in NULL 125 | * terminated array `methods`, and corresponding handlers in `handlers`. 126 | * Result is put in `dst`, `dst_len`. Return: length of the result, which 127 | * can be larger then `dst_len` that indicates an overflow. 128 | * Overflown bytes are not written to the buffer. 129 | * If method is not found, an error is automatically generated. 130 | */ 131 | int ns_rpc_dispatch(const char *buf, int, char *dst, int dst_len, 132 | const char **methods, ns_rpc_handler_t *handlers); 133 | 134 | #ifdef __cplusplus 135 | } 136 | #endif /* __cplusplus */ 137 | #endif /* NS_JSON_RPC_HEADER_DEFINED */ 138 | -------------------------------------------------------------------------------- /src/modules.mk: -------------------------------------------------------------------------------- 1 | COMMON = ../../common 2 | FROZEN = ../deps/frozen 3 | 4 | HEADERS = common.h \ 5 | $(COMMON)/osdep.h \ 6 | $(COMMON)/mbuf.h \ 7 | $(COMMON)/sha1.h \ 8 | $(COMMON)/md5.h \ 9 | $(COMMON)/base64.h \ 10 | $(COMMON)/str_util.h \ 11 | $(FROZEN)/frozen.h \ 12 | net.h \ 13 | util.h \ 14 | http.h \ 15 | json-rpc.h \ 16 | mqtt.h \ 17 | mqtt-broker.h \ 18 | dns.h \ 19 | dns-server.h \ 20 | resolv.h \ 21 | coap.h 22 | 23 | SOURCES = $(COMMON)/mbuf.c \ 24 | $(COMMON)/sha1.c \ 25 | $(COMMON)/md5.c \ 26 | $(COMMON)/base64.c \ 27 | $(COMMON)/str_util.c \ 28 | $(COMMON)/dirent.c \ 29 | $(FROZEN)/frozen.c \ 30 | net.c \ 31 | multithreading.c \ 32 | http.c \ 33 | util.c \ 34 | json-rpc.c \ 35 | mqtt.c \ 36 | mqtt-broker.c \ 37 | dns.c \ 38 | dns-server.c \ 39 | resolv.c \ 40 | coap.c 41 | -------------------------------------------------------------------------------- /src/mqtt-broker.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 Cesanta Software Limited 3 | * All rights reserved 4 | * This software is dual-licensed: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License version 2 as 6 | * published by the Free Software Foundation. For the terms of this 7 | * license, see . 8 | * 9 | * You are free to use this software under the terms of the GNU General 10 | * Public License, but WITHOUT ANY WARRANTY; without even the implied 11 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 12 | * See the GNU General Public License for more details. 13 | * 14 | * Alternatively, you can license this software under a commercial 15 | * license, as set out in . 16 | */ 17 | 18 | /* 19 | * === MQTT Broker 20 | */ 21 | 22 | #ifndef NS_MQTT_BROKER_HEADER_INCLUDED 23 | #define NS_MQTT_BROKER_HEADER_INCLUDED 24 | 25 | #ifdef NS_ENABLE_MQTT_BROKER 26 | 27 | #include "mqtt.h" 28 | 29 | #ifdef __cplusplus 30 | extern "C" { 31 | #endif /* __cplusplus */ 32 | 33 | #define NS_MQTT_MAX_SESSION_SUBSCRIPTIONS 512; 34 | 35 | struct ns_mqtt_broker; 36 | 37 | /* MQTT session (Broker side). */ 38 | struct ns_mqtt_session { 39 | struct ns_mqtt_broker *brk; /* Broker */ 40 | struct ns_mqtt_session *next, *prev; /* ns_mqtt_broker::sessions linkage */ 41 | struct ns_connection *nc; /* Connection with the client */ 42 | size_t num_subscriptions; /* Size of `subscriptions` array */ 43 | struct ns_mqtt_topic_expression *subscriptions; 44 | void *user_data; /* User data */ 45 | }; 46 | 47 | /* MQTT broker. */ 48 | struct ns_mqtt_broker { 49 | struct ns_mqtt_session *sessions; /* Session list */ 50 | void *user_data; /* User data */ 51 | }; 52 | 53 | /* Initialize a MQTT broker. */ 54 | void ns_mqtt_broker_init(struct ns_mqtt_broker *, void *); 55 | 56 | /* 57 | * Process a MQTT broker message. 58 | * 59 | * Listening connection expects a pointer to an initialized `ns_mqtt_broker` 60 | * structure in the `user_data` field. 61 | * 62 | * Basic usage: 63 | * 64 | * [source,c] 65 | * ----- 66 | * ns_mqtt_broker_init(&brk, NULL); 67 | * 68 | * if ((nc = ns_bind(&mgr, address, ns_mqtt_broker)) == NULL) { 69 | * // fail; 70 | * } 71 | * nc->user_data = &brk; 72 | * ----- 73 | * 74 | * New incoming connections will receive a `ns_mqtt_session` structure 75 | * in the connection `user_data`. The original `user_data` will be stored 76 | * in the `user_data` field of the session structure. This allows the user 77 | * handler to store user data before `ns_mqtt_broker` creates the session. 78 | * 79 | * Since only the NS_ACCEPT message is processed by the listening socket, 80 | * for most events the `user_data` will thus point to a `ns_mqtt_session`. 81 | */ 82 | void ns_mqtt_broker(struct ns_connection *, int, void *); 83 | 84 | /* 85 | * Iterate over all mqtt sessions connections. Example: 86 | * 87 | * struct ns_mqtt_session *s; 88 | * for (s = ns_mqtt_next(brk, NULL); s != NULL; s = ns_mqtt_next(brk, s)) { 89 | * // Do something 90 | * } 91 | */ 92 | struct ns_mqtt_session *ns_mqtt_next(struct ns_mqtt_broker *, 93 | struct ns_mqtt_session *); 94 | 95 | #ifdef __cplusplus 96 | } 97 | #endif /* __cplusplus */ 98 | 99 | #endif /* NS_ENABLE_MQTT_BROKER */ 100 | #endif /* NS_MQTT_HEADER_INCLUDED */ 101 | -------------------------------------------------------------------------------- /src/multithreading.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 Cesanta Software Limited 3 | * All rights reserved 4 | */ 5 | 6 | #include "internal.h" 7 | 8 | #ifdef NS_ENABLE_THREADS 9 | 10 | static void multithreaded_ev_handler(struct ns_connection *c, int ev, void *p); 11 | 12 | /* 13 | * This thread function executes user event handler. 14 | * It runs an event manager that has only one connection, until that 15 | * connection is alive. 16 | */ 17 | static void *per_connection_thread_function(void *param) { 18 | struct ns_connection *c = (struct ns_connection *) param; 19 | struct ns_mgr m; 20 | 21 | ns_mgr_init(&m, NULL); 22 | ns_add_conn(&m, c); 23 | while (m.active_connections != NULL) { 24 | ns_mgr_poll(&m, 1000); 25 | } 26 | ns_mgr_free(&m); 27 | 28 | return param; 29 | } 30 | 31 | static void link_conns(struct ns_connection *c1, struct ns_connection *c2) { 32 | c1->priv_2 = c2; 33 | c2->priv_2 = c1; 34 | } 35 | 36 | static void unlink_conns(struct ns_connection *c) { 37 | struct ns_connection *peer = (struct ns_connection *) c->priv_2; 38 | if (peer != NULL) { 39 | peer->flags |= NSF_SEND_AND_CLOSE; 40 | peer->priv_2 = NULL; 41 | } 42 | c->priv_2 = NULL; 43 | } 44 | 45 | static void forwarder_ev_handler(struct ns_connection *c, int ev, void *p) { 46 | (void) p; 47 | if (ev == NS_RECV && c->priv_2) { 48 | ns_forward(c, c->priv_2); 49 | } else if (ev == NS_CLOSE) { 50 | unlink_conns(c); 51 | } 52 | } 53 | 54 | static void spawn_handling_thread(struct ns_connection *nc) { 55 | struct ns_mgr dummy = {}; 56 | sock_t sp[2]; 57 | struct ns_connection *c[2]; 58 | 59 | /* 60 | * Create a socket pair, and wrap each socket into the connection with 61 | * dummy event manager. 62 | * c[0] stays in this thread, c[1] goes to another thread. 63 | */ 64 | ns_socketpair(sp, SOCK_STREAM); 65 | c[0] = ns_add_sock(&dummy, sp[0], forwarder_ev_handler); 66 | c[1] = ns_add_sock(&dummy, sp[1], nc->listener->priv_1); 67 | 68 | /* Interlink client connection with c[0] */ 69 | link_conns(c[0], nc); 70 | 71 | /* 72 | * Switch c[0] manager from the dummy one to the real one. c[1] manager 73 | * will be set in another thread, allocated on stack of that thread. 74 | */ 75 | ns_add_conn(nc->mgr, c[0]); 76 | 77 | /* 78 | * Dress c[1] as nc. 79 | * TODO(lsm): code in accept_conn() looks similar. Refactor. 80 | */ 81 | c[1]->listener = nc->listener; 82 | c[1]->proto_handler = nc->proto_handler; 83 | c[1]->proto_data = nc->proto_data; 84 | c[1]->user_data = nc->user_data; 85 | 86 | ns_start_thread(per_connection_thread_function, c[1]); 87 | } 88 | 89 | static void multithreaded_ev_handler(struct ns_connection *c, int ev, void *p) { 90 | (void) p; 91 | if (ev == NS_ACCEPT) { 92 | spawn_handling_thread(c); 93 | c->handler = forwarder_ev_handler; 94 | } 95 | } 96 | 97 | void ns_enable_multithreading(struct ns_connection *nc) { 98 | /* Wrap user event handler into our multithreaded_ev_handler */ 99 | nc->priv_1 = nc->handler; 100 | nc->handler = multithreaded_ev_handler; 101 | } 102 | #endif 103 | -------------------------------------------------------------------------------- /src/resolv.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 Cesanta Software Limited 3 | * All rights reserved 4 | */ 5 | 6 | /* 7 | * === Asynchronouns DNS resolver 8 | */ 9 | 10 | #ifndef NS_RESOLV_HEADER_DEFINED 11 | #define NS_RESOLV_HEADER_DEFINED 12 | 13 | #include "dns.h" 14 | 15 | #ifdef __cplusplus 16 | extern "C" { 17 | #endif /* __cplusplus */ 18 | 19 | typedef void (*ns_resolve_callback_t)(struct ns_dns_message *, void *); 20 | 21 | /* Options for `ns_resolve_async_opt`. */ 22 | struct ns_resolve_async_opts { 23 | const char *nameserver_url; 24 | int max_retries; /* defaults to 2 if zero */ 25 | int timeout; /* in seconds; defaults to 5 if zero */ 26 | int accept_literal; /* pseudo-resolve literal ipv4 and ipv6 addrs */ 27 | int only_literal; /* only resolves literal addrs; sync cb invocation */ 28 | }; 29 | 30 | /* See `ns_resolve_async_opt()` */ 31 | int ns_resolve_async(struct ns_mgr *, const char *, int, ns_resolve_callback_t, 32 | void *data); 33 | 34 | /* 35 | * Resolved a DNS name asynchronously. 36 | * 37 | * Upon successful resolution, the user callback will be invoked 38 | * with the full DNS response message and a pointer to the user's 39 | * context `data`. 40 | * 41 | * In case of timeout while performing the resolution the callback 42 | * will receive a NULL `msg`. 43 | * 44 | * The DNS answers can be extracted with `ns_next_record` and 45 | * `ns_dns_parse_record_data`: 46 | * 47 | * [source,c] 48 | * ---- 49 | * struct in_addr ina; 50 | * struct ns_dns_resource_record *rr = ns_next_record(msg, NS_DNS_A_RECORD, 51 | * NULL); 52 | * ns_dns_parse_record_data(msg, rr, &ina, sizeof(ina)); 53 | * ---- 54 | */ 55 | int ns_resolve_async_opt(struct ns_mgr *, const char *, int, 56 | ns_resolve_callback_t, void *data, 57 | struct ns_resolve_async_opts opts); 58 | 59 | /* 60 | * Resolve a name from `/etc/hosts`. 61 | * 62 | * Returns 0 on success, -1 on failure. 63 | */ 64 | int ns_resolve_from_hosts_file(const char *host, union socket_address *usa); 65 | 66 | #ifdef __cplusplus 67 | } 68 | #endif /* __cplusplus */ 69 | #endif /* NS_RESOLV_HEADER_DEFINED */ 70 | -------------------------------------------------------------------------------- /test/Makefile: -------------------------------------------------------------------------------- 1 | SOURCES=unit_test.c test_util.c ../fossa.c 2 | CFLAGS = -W -Wall -I../.. -pthread -DNS_ENABLE_COAP -DNS_ENABLE_IPV6 -DNS_ENABLE_THREADS -DNS_ENABLE_MQTT_BROKER -DNS_ENABLE_DNS_SERVER \ 3 | -DNS_INTERNAL="" -DNS_MODULE_LINES -include unit_test.h -DNS_MALLOC=test_malloc -DNS_CALLOC=test_calloc -lssl $(CFLAGS_EXTRA) 4 | 5 | all: test 6 | 7 | unit_test: $(SOURCES) ../fossa.h 8 | @$(CC) $(SOURCES) -o $@ $(CFLAGS) 9 | 10 | test: unit_test 11 | @MallocLogFile=/dev/null ./unit_test $(TEST_FILTER) 12 | -------------------------------------------------------------------------------- /test/ca.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEpAIBAAKCAQEAv3/TSSi5hZDwMKG43eqe+GzR1lRMXVYt9I1Mr987v1DT99xR 3 | Dcpfo/3aj6B/V/G67oPz+zbVZN/ZPvvA1Z82T7ixcBFsGIXgEWzxUm1UCUf51ftl 4 | MlOaf24cdyegi0y8hRdkWLoC7w0vuMfrgR6cmpbI2LSDSMaXXX2qDoofQsFUYaJN 5 | Nn3uqRK0ixs/jzbzbAT9q2BWYwySUX4VEgADpmi0FyANDjEhmdktxQW9l6IGGzF8 6 | M9mA053hIgZwo+9qf9X3nfNUTWMvisMQtxm0mRYgvD53Oix08VLs6bodNTVOLQoc 7 | H0uH3CTs+H3Z0CkcZaAJe/kwCLFhls9ee3M0nQIDAQABAoIBAQCsADPWUi3QOg6C 8 | n79cE5AVsigHSlAMxYshTIjErs0LWZ4J0mk66bpdoXTd7Fp0szojYYGS8f1ZTXXj 9 | jFv3g7lUgZ9d+UgN/rDy9dcLIgeJDozoFZUfTthF/LC0lXMtqw7ou8n1p51a+Y0T 10 | ev2cS9J9R1G+0uPYSgdKgcRsqsLJQS4fu5CAk9d0aeTTl009uxcn9yfTUjwOaR5J 11 | PuNmunAEvhE/DGSkt5oNXo7t8Q2L3mYSM0MwKdDFqoQdZAV6TMTv22Mjb6SxOOnJ 12 | r5gNK2BmM6oNPWvzY0PoI0LcLgFNDWIMqIq4mg73MdzszakaNRDlOYtLAuKbTF3Q 13 | SDq8OkZBAoGBAOn6B5jBxSa+5GcIIeGqtiRhDMExyblt3Gk2gaw6UIZpvVDXPWWm 14 | r0tkGJrYecmqesN7DGmmdkyx8KONF+yzYLxSsIEGNesvVYe6PXTDZYYI57As4Z4W 15 | DFlCDt2FaKuMXxyOlUCiXg94z8IJBJ2ldCmmG34gBSvuFe6V5x4XE3crAoGBANGG 16 | P7AWw6uygfjog6B2dFT6n+9UhpyJlqwfPi5eD9V5JXtWlH6xWi3dRfuYAIafg95I 17 | W8/OZGHrj44gNCgYjvZHud+H3NPJPZ7lftoay5KeShBAa/pCd67OMxp1SvvONYcp 18 | 7TSwm5s+hOJvQOpw2wg0cXnfrxGKpGLOFaRddp9XAoGAFdeXefUs2G8dl1i1AQIU 19 | utSsgiSJtlvBJblG5bMT7VhVqgRN4P1sg9c2TM5EoETf7PvBruMxS/uYgUwcnaYp 20 | M6tser7/rZLfoyoJrqrHAXo3VsT50u4v/O0jwh5AJTOXdW0CFeSSb1NR4cVBvw3B 21 | CFpPWrjWgsFZHsqzpqV01b0CgYEAkDft4pDowmgumlvBLlQaotuX9q6hsWHrOjKP 22 | JG9OSswGhq0DrWj5/5PNNe5cfk2SARChUZpo8hWoTFXSUL8GuHKKeFgWIhjkt1iU 23 | RiAne5ZEuIb/S9UweDwqZM3TfRtlMNIlGh1uHh+cbBfUAQsJWM5wRUk4QcTCfdgI 24 | gYhrvCUCgYBB6u8Q49RjrTBxWK8bcZOjVhYNrd3xrCunFVMt2QAXGGrRaXpqUMnp 25 | xNUmGe9vGux+s0TRguZcLEX3vX+wFyBfFKwZY9hSU7PFY/da8echpu37JasKvAov 26 | 5+5XWI5RgF+SFVk+Q7St2BlSJa/vBAH8vtrX9Dt/hN/VSo2mAPAyMQ== 27 | -----END RSA PRIVATE KEY----- 28 | -----BEGIN CERTIFICATE----- 29 | MIIDjjCCAnagAwIBAgIJAIOEuwkahzkOMA0GCSqGSIb3DQEBBQUAMDgxCzAJBgNV 30 | BAMTAm5zMQswCQYDVQQKEwJuczELMAkGA1UEBhMCSUUxDzANBgNVBAcTBkR1Ymxp 31 | bjAeFw0xNDA4MzAxOTA3NDNaFw0yNDA4MjcxOTA3NDNaMDgxCzAJBgNVBAMTAm5z 32 | MQswCQYDVQQKEwJuczELMAkGA1UEBhMCSUUxDzANBgNVBAcTBkR1YmxpbjCCASIw 33 | DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL9/00kouYWQ8DChuN3qnvhs0dZU 34 | TF1WLfSNTK/fO79Q0/fcUQ3KX6P92o+gf1fxuu6D8/s21WTf2T77wNWfNk+4sXAR 35 | bBiF4BFs8VJtVAlH+dX7ZTJTmn9uHHcnoItMvIUXZFi6Au8NL7jH64EenJqWyNi0 36 | g0jGl119qg6KH0LBVGGiTTZ97qkStIsbP48282wE/atgVmMMklF+FRIAA6ZotBcg 37 | DQ4xIZnZLcUFvZeiBhsxfDPZgNOd4SIGcKPvan/V953zVE1jL4rDELcZtJkWILw+ 38 | dzosdPFS7Om6HTU1Ti0KHB9Lh9wk7Ph92dApHGWgCXv5MAixYZbPXntzNJ0CAwEA 39 | AaOBmjCBlzAdBgNVHQ4EFgQUsz/nOHpjMkV8pk9dFpy41batoTcwaAYDVR0jBGEw 40 | X4AUsz/nOHpjMkV8pk9dFpy41batoTehPKQ6MDgxCzAJBgNVBAMTAm5zMQswCQYD 41 | VQQKEwJuczELMAkGA1UEBhMCSUUxDzANBgNVBAcTBkR1YmxpboIJAIOEuwkahzkO 42 | MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAEDOtAl7bgAXgcL3HRlV 43 | H71tkUaok589PIqsTE4d8s8tFBZ92CyWD8ZPU46HbbyJXMFoFxiN7PvCzOBlgoZM 44 | r80HJWZc9tSlqK0NIbIyk1aeM06+F8qB+8/vw/spIkdYzDv3avwyOrc6fFnEzbwz 45 | 5BFFrF2G9JajRKAP5snAV9iM8I2TD4l+w75MXXl7/DBEohdMBsTeDrrXj4q4sgoB 46 | L/yLeCoK6inkMTU5DwcGbiqvNnZA+9T654qlAlKjPMObGGPphK5/QKcOnV7Qtdju 47 | DHzDsDimdVbz9G1cxXs/AI/35GD7IDTdNTtmBhkf4/tsQ7Ua80xpIowb1fFUHmo1 48 | UAo= 49 | -----END CERTIFICATE----- 50 | -------------------------------------------------------------------------------- /test/client.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEpAIBAAKCAQEAwV5xaK7ez2/TX7vSgJ0a3YbZj2l1VQ2rMzqO1Id01xlWbF/U 3 | rebwhAdVtWcT9R6RaBTPDGaILkV38u77M2BxIHX4MSnR6WezoA2bGMgvt3+tq2N6 4 | q+xkj57vwBEqedBjscVtFkoWtsX8pKwtNlMB1NvTa8p5+BNsvpvzaDX+51+FotId 5 | wvieQfQYgFg36HpOtOyyIV31rZ/5+qtoce8gU6wApHxmovTnQPoduNM6fOUJCHDd 6 | Lz90EeBREtoTVgoWcKvQoCEwJQSBmeDZgkA8Q1OYmbYoS12tIyi8rTkseRj5BvPH 7 | iXfNmHFKliAjvlsml5qI44I9DoagPubTf6qR5wIDAQABAoIBACZ6VZTgH0Ql22jU 8 | ZhnjqUHloIsyEAABvUxvXZaa8bwPtavREfAc4UVUdFCpl0YSdBrC8URlbrnOZwT3 9 | WxMpILm139JgoP2R/iNeMbunsh8QkA1nuTRW0NfnZ4vPnqUou33XbFKgIY7zLMfT 10 | 3xdNQzMJHzP20Xh03RG81J2rCPMfLScTRo2XxcSxmhhS/p2WLk6pnmMHiNgYGGwX 11 | gcdK5lIVjMMNxgcltC30x90v0o0GDRM8/+wua+/vfn8rr3iudv9IHzL8xIzpi6NY 12 | CXJ8Kxd6Jtgsr3Boj5i6Mqi3Q/Trxt+rIA4bKAFXxwcp4+GmRIJtQFFiTWXpLCPC 13 | tLT4CHECgYEA7iCbrGjWHJ4QsUWUGrGlw1/sQ0SIv9BdZm8RydHzpRVtQOi+YOuU 14 | i6raVaXWzUBKgKcs/htVjAMTiePs/yhlU/MGXivz6uTX/nrD7ISJImmK2K50hgUe 15 | +UBnFKmBMVaNxD9RFWPJkfmNXfW7nBkqSa9CxlBcYPuOcPtZDqRl+gkCgYEAz+HX 16 | 8wh3SHKb1cAI+o4caclpUTpGa9/zW4k+7gOh72WCKaqxTNvBvNyZGdXc9t5ToDSf 17 | xxsDXWG10lcHBIGLj4QBEoSWp9I43lid5swY3mCo7CjTl+1l03IfDNaC6CYQFp5p 18 | ZnKlsQUwR38t/uiyZpnnicCAZjqIfJbeQ5jD6G8CgYB8ufmwQa08ihJmN/KOVNRl 19 | VF31EfWquqHhYHXpxx2eL23tXLszGtHQoioASIANPAqJ/oaTho+1aXsXc5oUP/1r 20 | DlUciFsXgswb0APFY9pMewmt2xrPg+koVvJnIS25QQO6cguvb3gKDLNeLrMY3RmI 21 | RNNt+nOYnMqMJSsNf1CmuQKBgQCiCZxWaCbyZcNqncFh7BvhqYlaM15o/6ulkhln 22 | VZWIEUugRtjk2/bry9fa94TBORNeMSbKABhjVaJwTj2+GWw7dd2QHaGBNq/1QIX0 23 | POq1jAqf6kLkjbttUes6CosHgYPQ3bGylXLpxO2ZDV1A8Qj+SMDd8xsilEWHN+IQ 24 | NqeeKQKBgQDe4c7VVG+WvRRKshTh8+tjzc9nXKE2AWgwnw729SMFZO/WqX2FPp2C 25 | 7C99XJTVBsCBy8VzuyaojeTKkag0YL3v6UTZYUeyu0YTHGQ33WVPaqdCAo840nmG 26 | ttwHVqshB9c67HHiYOOFt1VmT3xW6x6yympUyRqR0L+BZ1wOS3h2vQ== 27 | -----END RSA PRIVATE KEY----- 28 | -----BEGIN CERTIFICATE----- 29 | MIIC6DCCAdACBRQJQlZlMA0GCSqGSIb3DQEBBQUAMDgxCzAJBgNVBAMTAm5zMQsw 30 | CQYDVQQKEwJuczELMAkGA1UEBhMCSUUxDzANBgNVBAcTBkR1YmxpbjAeFw0xNDA4 31 | MzAxOTA3NDRaFw0yNDA4MjcxOTA3NDRaMDgxCzAJBgNVBAMTAm5zMQswCQYDVQQK 32 | EwJuczELMAkGA1UEBhMCSUUxDzANBgNVBAcTBkdhbHdheTCCASIwDQYJKoZIhvcN 33 | AQEBBQADggEPADCCAQoCggEBAMFecWiu3s9v01+70oCdGt2G2Y9pdVUNqzM6jtSH 34 | dNcZVmxf1K3m8IQHVbVnE/UekWgUzwxmiC5Fd/Lu+zNgcSB1+DEp0elns6ANmxjI 35 | L7d/ratjeqvsZI+e78ARKnnQY7HFbRZKFrbF/KSsLTZTAdTb02vKefgTbL6b82g1 36 | /udfhaLSHcL4nkH0GIBYN+h6TrTssiFd9a2f+fqraHHvIFOsAKR8ZqL050D6HbjT 37 | OnzlCQhw3S8/dBHgURLaE1YKFnCr0KAhMCUEgZng2YJAPENTmJm2KEtdrSMovK05 38 | LHkY+Qbzx4l3zZhxSpYgI75bJpeaiOOCPQ6GoD7m03+qkecCAwEAATANBgkqhkiG 39 | 9w0BAQUFAAOCAQEAJ+wZ/IgAF5LIu0yOfJlaFRJLunKHZENigiVjYvkTdM7NI3O2 40 | 1AZGY4O8H5Fs3YT5ZY3vas/n6IwWTk3o/JSPXojMFo82XkbI1k2cm3oLtwgEGN3p 41 | s5yFsjZE3H7fQJ9wHIzESBPHFY6dwwgMsNENuAM2zkwFpbAkisKhjK+EyUCXauok 42 | 7zJY6RVPMaNojsje4iE/SBtSOnK/9WDBAgpCznHrSChJmKs4FsU7ZTO+Dg+0vQln 43 | l8/yBcEGAFe0GA2D9NvZKH5IoNmitvtU9zdNDK4dzC3Q+C28IjW5jE8peDFtdGs1 44 | P0u4kRxmb4UH1DchgoWlZjL2lSFScJ7L4xY2aQ== 45 | -----END CERTIFICATE----- 46 | -------------------------------------------------------------------------------- /test/data/auth/a.txt: -------------------------------------------------------------------------------- 1 | hi 2 | -------------------------------------------------------------------------------- /test/data/auth/passwords.txt: -------------------------------------------------------------------------------- 1 | joe:foo.com:77bbd68c7bc5cd7b6bb33a19e2fc7007 2 | -------------------------------------------------------------------------------- /test/data/cgi/index.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | 3 | use Cwd; 4 | use CGI; 5 | 6 | use vars '%in'; 7 | CGI::ReadParse(); 8 | 9 | print "Content-Type: text/html\r\nStatus: 201 Created\r\n\r\n"; 10 | 11 | print "
\n";
12 | foreach my $key (sort keys %ENV) {
13 | 	print "$key=$ENV{$key}\n";
14 | }
15 | 
16 | print "\n";
17 | 
18 | foreach my $key (sort keys %in) {
19 | 	print "$key=$in{$key}\n";
20 | }
21 | 
22 | print "\n";
23 | 
24 | print 'CURRENT_DIR=' . getcwd() . "\n";
25 | print "
\n"; 26 | 27 | my $stuff = < 29 | function set_val() { 30 | } 31 | 32 |
33 | 34 | 35 | 36 |
37 | 38 |
39 | 40 | 41 |
42 | EOP 43 | 44 | print $stuff; 45 | -------------------------------------------------------------------------------- /test/data/dav/a.txt: -------------------------------------------------------------------------------- 1 | hi 2 | -------------------------------------------------------------------------------- /test/data/dav/hidden_file.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cesanta/fossa/03b7e568abafcca31a4361df849e01b5fca7e202/test/data/dav/hidden_file.txt -------------------------------------------------------------------------------- /test/data/dir_no_index/some_file: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cesanta/fossa/03b7e568abafcca31a4361df849e01b5fca7e202/test/data/dir_no_index/some_file -------------------------------------------------------------------------------- /test/data/dir_with_index/index.html: -------------------------------------------------------------------------------- 1 | foo -------------------------------------------------------------------------------- /test/data/dummy.xml: -------------------------------------------------------------------------------- 1 | :-) 2 | -------------------------------------------------------------------------------- /test/data/multipart.txt: -------------------------------------------------------------------------------- 1 | ------WebKitFormBoundaryh3pBS3C5nni6XxR4 2 | Content-Disposition: form-data; name="file1"; filename="keyword.c" 3 | Content-Type: application/octet-stream 4 | 5 | file1 data 6 | 7 | ------WebKitFormBoundaryh3pBS3C5nni6XxR4 8 | Content-Disposition: form-data; name="file2"; filename="stdarg.c" 9 | Content-Type: application/octet-stream 10 | 11 | file2 data 12 | 13 | ------WebKitFormBoundaryh3pBS3C5nni6XxR4-- 14 | -------------------------------------------------------------------------------- /test/data/range.txt: -------------------------------------------------------------------------------- 1 | Faith of consciousness is freedom 2 | Faith of feeling is weakness 3 | Faith of body is stupidity. 4 | Love of consciousness evokes the same in response 5 | Love of feeling evokes the opposite 6 | Love of body depends only on type and polarity. 7 | Hope of consciousness is strength 8 | Hope of feelings is slavery 9 | Hope of body is disease. 10 | -------------------------------------------------------------------------------- /test/data/rewrites/foo.com/index.html: -------------------------------------------------------------------------------- 1 | foo_root 2 | -------------------------------------------------------------------------------- /test/data/rewrites/msg.txt: -------------------------------------------------------------------------------- 1 | works 2 | -------------------------------------------------------------------------------- /test/data/ssi/f1.txt: -------------------------------------------------------------------------------- 1 | a 2 | -------------------------------------------------------------------------------- /test/data/ssi/index.shtml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /test/data/ssi/nested.shtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /test/server.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEpAIBAAKCAQEA1mONQ0hAXOL9lb15Pz4fqXXNHREsF3a7/NoMJdQDclx0+a32 3 | MhuHcO6R7Fhsc0mZMuzbmAFLMmIIgXPMKQBZLoA12yCBlZPyKFoWUhFrLa3gUjO6 4 | CZlBKqkUVEACpVrQ41ihapeeUHa0uryt3tXwMn2/853yzi1uciGYi4ULTy3yTE/n 5 | qRIVJLiBDSC9WNFLg26f/W4YRW7tANOk2b/W/Ws9B/n7vNDgHG7Lpd38YTpFhhXT 6 | n3xlt/VcczkQhW79Moh6/lY6sLg6H15EjHKHeTn8t9BRm+qYi/CvC258YF/Qz/qK 7 | agSsLT/3FrQ6+aQgg/Eyao0IWAql49PQNxuwPQIDAQABAoIBAQC5y3S1BnyhAyb5 8 | Ckd1g4U0+x5TPnqTqxanvuAgOGj0RyQo7ZYbPrhWKqrTxJ3YG8Rk2dhFF3nvo/3z 9 | EkOwlNi07++8g6NJ2flW9xu469eSsslg8+saPnK3Yeh4SzD/1ICLRlg9ZECTQwzF 10 | eJbGM2oCl/AuVIgEHmNFDdCBuT9f0b7j3/Z3aK3lKzqzBYQgZ5fd8UxT+Kn4oAuS 11 | cLr3lQT1s6xZOAYn7O2GvXEC+yMMbvm0a97MdwSpQez1WcE9YxtCgAWwn5EmSXlh 12 | 296iLtbaM1wgYOykJUOUoSgijf8pUfotk4Zj/y1KPHXePgAlyGCtE1zasiYb5K+5 13 | LuajD++BAoGBAPpKWLNzQBwQLiFaJgt6bLOxlEUR+EnjdFePDPJtyCCCiKJiKO5c 14 | Z5s/FT1JDQawouhjQwYqT48hbGBPjWRHkSkzB7+cg6FVSKkQRYX2TsSFvN+KCu32 15 | oSgDV9cFo68v1csoZIQ41TtHC82db4OTv9MPUe3Glujnep1TOTwspAM1AoGBANtH 16 | i+HWKOxOm7f/R2VX1ys9UjkAK+msac512XWSLAzBs7NFnB7iJ7m3Bh3ydb1ZiTgW 17 | l6bIdoT8TLPYNIXJ6uohhxPU5h3v81PHqIuJMBtmHCQjq3nxeH9mOsfjOFvS1cQa 18 | At45F9pK/5sQpOkkaBGSv8jXUFIKBEDBErourVHpAoGAK0gSAK4sZu3xXDkfnRqF 19 | k6lgr3UFD5nys3V8UqvjUKPiBtqco2N9Ux5ciOWKCB8hfLg1jephKaoo+JqpI68w 20 | jgRSEbN6G7sIvpueuiS2yEssNyfC7hWZFrdFSFykSpYmDWSlxSuizAZkJyFTeFhj 21 | cpcSnuCZlhr5XB1ZJ2u8zQUCgYEAke5QgpCDFZjO+ynR+vj1gppBwRuDHfUXSUaW 22 | 3S7VT/wNOq6F0uvRYkASuxVkFAqlToWCkYVxktlRtpKZibwyMXT0r1cNejj5Z/VF 23 | Du/S6zkOW2K9uN7hwW9oiSSHmlx61RI2fGvkmus0pp7yERKgi6ltJx1cH+z4nZug 24 | efWcdRkCgYBy+XdmsxgNZOunlSC6VZiD0Ve/VFrCtKPWUivKDAZZPKl0T/1tbTwb 25 | I/N4zTF82jx88rDz+6jN5nOy9qbSR5TeCy6WlBesTvXm49awr5jSK3WkcLgmO+JI 26 | Zr2ozCBhUG6RvVsUPp2kXEsmwZMV/e9faFAlIXeJhKum6hZmfOgodg== 27 | -----END RSA PRIVATE KEY----- 28 | -----BEGIN CERTIFICATE----- 29 | MIIC6DCCAdACBRQJQlZkMA0GCSqGSIb3DQEBBQUAMDgxCzAJBgNVBAMTAm5zMQsw 30 | CQYDVQQKEwJuczELMAkGA1UEBhMCSUUxDzANBgNVBAcTBkR1YmxpbjAeFw0xNDA4 31 | MzAxOTA3NDNaFw0yNDA4MjcxOTA3NDNaMDgxCzAJBgNVBAMTAm5zMQswCQYDVQQK 32 | EwJuczELMAkGA1UEBhMCSUUxDzANBgNVBAcTBkdhbHdheTCCASIwDQYJKoZIhvcN 33 | AQEBBQADggEPADCCAQoCggEBANZjjUNIQFzi/ZW9eT8+H6l1zR0RLBd2u/zaDCXU 34 | A3JcdPmt9jIbh3DukexYbHNJmTLs25gBSzJiCIFzzCkAWS6ANdsggZWT8ihaFlIR 35 | ay2t4FIzugmZQSqpFFRAAqVa0ONYoWqXnlB2tLq8rd7V8DJ9v/Od8s4tbnIhmIuF 36 | C08t8kxP56kSFSS4gQ0gvVjRS4Nun/1uGEVu7QDTpNm/1v1rPQf5+7zQ4Bxuy6Xd 37 | /GE6RYYV0598Zbf1XHM5EIVu/TKIev5WOrC4Oh9eRIxyh3k5/LfQUZvqmIvwrwtu 38 | fGBf0M/6imoErC0/9xa0OvmkIIPxMmqNCFgKpePT0DcbsD0CAwEAATANBgkqhkiG 39 | 9w0BAQUFAAOCAQEAoVXK97WA24tp3JyPBJKr28gFSUtOBNDPdY8atWaqw7PwUIIM 40 | qhs3BTag96tgSoaISRwRphz2LM1Cl+QlItYXySAnxPKrUsA0S6DlxnA6Hq3s2wTR 41 | 6yIT7oDUDKcWkVQcQmuNGdfxCvZXkCih9lnQn++xHcuVn9mZmjXW2xk42ljDTZCp 42 | CM29betpcmuho6sFXsBhY7WjQWg7UpRZat0bOwleS4fsePebMKrnr/6cq4bVw59U 43 | XvhSFBlLoGMYteJ82fOYH6pUO1hiPr6ww5d819LPcJEcRpcxCdQZqIq680Kp7+GY 44 | 0wkyOYr0gkNwWVP7IUZ0FExaQ/s54g71Kd0OgA== 45 | -----END CERTIFICATE----- 46 | -------------------------------------------------------------------------------- /test/test_util.c: -------------------------------------------------------------------------------- 1 | #include "test_util.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #ifndef _WIN32 8 | #include 9 | #else 10 | #include 11 | #endif 12 | 13 | int num_tests = 0; 14 | 15 | static char *_escape(const char *s, size_t n) { 16 | size_t i, j; 17 | char *res = (char *) malloc(n * 4 + 1); 18 | for (i = j = 0; s[i] != '\0' && i < n; i++) { 19 | if (!iscntrl((int) s[i])) { 20 | res[j++] = s[i]; 21 | } else { 22 | j += sprintf(res + j, "\\x%02x", s[i]); 23 | } 24 | } 25 | res[j] = '\0'; 26 | return res; 27 | } 28 | 29 | void _strfail(const char *a, const char *e, int len) { 30 | char *ae, *ee; 31 | if (len < 0) { 32 | len = strlen(a); 33 | if (strlen(e) > (size_t) len) len = strlen(e); 34 | } 35 | ae = _escape(a, len); 36 | ee = _escape(e, len); 37 | printf("Expected: %s\nActual : %s\n", ee, ae); 38 | free(ae); 39 | free(ee); 40 | } 41 | 42 | double _now() { 43 | double now; 44 | #ifndef _WIN32 45 | struct timeval tv; 46 | if (gettimeofday(&tv, NULL /* tz */) != 0) return 0; 47 | now = (double) tv.tv_sec + (((double) tv.tv_usec) / 1000000.0); 48 | #else 49 | now = GetTickCount() / 1000.0; 50 | #endif 51 | return now; 52 | } 53 | 54 | int _assert_streq(const char *actual, const char *expected) { 55 | if (strcmp(actual, expected) != 0) { 56 | _strfail(actual, expected, -1); 57 | return 0; 58 | } 59 | return 1; 60 | } 61 | 62 | int _assert_streq_nz(const char *actual, const char *expected) { 63 | size_t n = strlen(expected); 64 | if (strncmp(actual, expected, n) != 0) { 65 | _strfail(actual, expected, n); 66 | return 0; 67 | } 68 | return 1; 69 | } 70 | -------------------------------------------------------------------------------- /test/test_util.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Cesanta Software Limited 3 | * All rights reserved 4 | * This software is dual-licensed: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License version 2 as 6 | * published by the Free Software Foundation. For the terms of this 7 | * license, see . 8 | * 9 | * You are free to use this software under the terms of the GNU General 10 | * Public License, but WITHOUT ANY WARRANTY; without even the implied 11 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 12 | * See the GNU General Public License for more details. 13 | * 14 | * Alternatively, you can license this software under a commercial 15 | * license, as set out in . 16 | */ 17 | 18 | #ifndef NS_TEST_UTIL_HEADER_INCLUDED 19 | #define NS_TEST_UTIL_HEADER_INCLUDED 20 | 21 | #include 22 | #include 23 | 24 | extern int num_tests; 25 | 26 | #ifdef NS_TEST_ABORT_ON_FAIL 27 | #define NS_TEST_ABORT abort() 28 | #else 29 | #define NS_TEST_ABORT 30 | #endif 31 | 32 | int _assert_streq(const char *actual, const char *expected); 33 | int _assert_streq_nz(const char *actual, const char *expected); 34 | void _strfail(const char *a, const char *e, int len); 35 | double _now(); 36 | 37 | #define FAIL(str, line) \ 38 | do { \ 39 | printf("%s:%d:1 [%s] (in %s)\n", __FILE__, line, str, __func__); \ 40 | NS_TEST_ABORT; \ 41 | return str; \ 42 | } while (0) 43 | 44 | #define ASSERT(expr) \ 45 | do { \ 46 | num_tests++; \ 47 | if (!(expr)) FAIL(#expr, __LINE__); \ 48 | } while (0) 49 | 50 | #define RUN_TEST(test) \ 51 | do { \ 52 | const char *msg = NULL; \ 53 | if (strstr(#test, filter)) { \ 54 | double elapsed = _now(); \ 55 | msg = test(); \ 56 | elapsed = _now() - elapsed; \ 57 | printf(" [%.3f] %s\n", elapsed, #test); \ 58 | *total_elapsed += elapsed; \ 59 | } \ 60 | if (msg) return msg; \ 61 | } while (0) 62 | 63 | /* VC6 doesn't know how to cast an unsigned 64-bit int to double */ 64 | #if (defined(_MSC_VER) && _MSC_VER <= 1200) 65 | #define AS_DOUBLE(d) (double)(int64_t)(d) 66 | #else 67 | #define AS_DOUBLE(d) (double)(d) 68 | #endif 69 | 70 | /* 71 | * Numeric equality assertion. Compariosn is made in native types but for 72 | * printing both are convetrted to double. 73 | */ 74 | #define ASSERT_EQ(actual, expected) \ 75 | do { \ 76 | num_tests++; \ 77 | if (!(actual == expected)) { \ 78 | printf("%f != %f\n", AS_DOUBLE(actual), AS_DOUBLE(expected)); \ 79 | FAIL(#actual " == " #expected, __LINE__); \ 80 | } \ 81 | } while (0) 82 | 83 | /* Assert that actual == expected, where both are NUL-terminated. */ 84 | #define ASSERT_STREQ(actual, expected) \ 85 | do { \ 86 | num_tests++; \ 87 | if (!_assert_streq(actual, expected)) { \ 88 | FAIL("ASSERT_STREQ(" #actual ", " #expected ")", __LINE__); \ 89 | } \ 90 | } while (0) 91 | 92 | /* Same as STREQ, but only expected is NUL-terminated. */ 93 | #define ASSERT_STREQ_NZ(actual, expected) \ 94 | do { \ 95 | num_tests++; \ 96 | if (!_assert_streq_nz(actual, expected)) { \ 97 | FAIL("ASSERT_STREQ_NZ(" #actual ", " #expected ")", __LINE__); \ 98 | } \ 99 | } while (0) 100 | 101 | #endif /* NS_TEST_UTIL_HEADER_INCLUDED */ 102 | -------------------------------------------------------------------------------- /test/unit_test.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 Cesanta Software Limited 3 | * All rights reserved 4 | * This software is dual-licensed: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License version 2 as 6 | * published by the Free Software Foundation. For the terms of this 7 | * license, see . 8 | * 9 | * You are free to use this software under the terms of the GNU General 10 | * Public License, but WITHOUT ANY WARRANTY; without even the implied 11 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 12 | * See the GNU General Public License for more details. 13 | * 14 | * Alternatively, you can license this software under a commercial 15 | * license, as set out in . 16 | */ 17 | 18 | #ifndef NS_UNIT_TEST_HEADER_INCLUDED 19 | #define NS_UNIT_TEST_HEADER_INCLUDED 20 | 21 | #include "osdep.h" 22 | 23 | extern void * (*test_malloc)(size_t); 24 | extern void * (*test_calloc)(size_t, size_t); 25 | 26 | #endif 27 | --------------------------------------------------------------------------------