diff --git a/.gitignore b/.gitignore index 0409579..7a80e88 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,10 @@ supernode/websocket_chat supernode/cash_payments_handler2.html .vscode/ supernode/test/ + +server/web/supernode2.html +server/web/supernode3.html +server/web/supernode4.html +server/web/supernode5.html +server/web/supernode6.html +server/web/playground \ No newline at end of file diff --git a/supernode/Makefile b/supernode/Makefile deleted file mode 100644 index 2fbb694..0000000 --- a/supernode/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -PROG = websocket_chat -MODULE_CFLAGS = -DMG_ENABLE_FILESYSTEM=1 -include ../examples.mk diff --git a/supernode/index.html b/supernode/index.html index eaa8993..7fe5245 100644 --- a/supernode/index.html +++ b/supernode/index.html @@ -15421,11 +15421,6 @@ localbitcoinplusplus.master_configurations.tradableAsset2.includes( params.currency ) && - typeof localbitcoinplusplus.master_configurations - .validTradingAmount !== "undefined" && - localbitcoinplusplus.master_configurations.validTradingAmount.includes( - parseFloat(params.depositing_amount) - ) && typeof params.trader_flo_address == "string" && params.trader_flo_address.length > 0 ) { @@ -15460,14 +15455,15 @@ params.id = helper_functions.unique_id(); params.status = 1; - params.btc_address = - generate_btc_keys_for_requester.address; + params.btc_address = generate_btc_keys_for_requester.address; - params.bitcoinToBePaid = RM_TRADE.calculateCryptoEquivalentOfCash( - params.depositing_amount, - params.currency, - params.product - ); + // params.bitcoinToBePaid = RM_TRADE.calculateCryptoEquivalentOfCash( + // params.depositing_amount, + // params.currency, + // params.product + // ); + + params.bitcoinToBePaid = Number(params.depositing_amount); let receivedTradeInfo = { ...params }; @@ -15496,26 +15492,16 @@ JSON.stringify(receivedTradeInfo) ); - receivedTradeInfo[ - "depositDataHash" - ] = receivedTradeInfoHash; - receivedTradeInfo[ - "order_validator_sign" - ] = RM_WALLET.sign( + receivedTradeInfo["depositDataHash"] = receivedTradeInfoHash; + receivedTradeInfo["order_validator_sign"] = RM_WALLET.sign( receivedTradeInfoHash, - localbitcoinplusplus.wallets - .MY_SUPERNODE_PRIVATE_KEY + localbitcoinplusplus.wallets.MY_SUPERNODE_PRIVATE_KEY ); - receivedTradeInfo[ - "order_validator_public_key" - ] = su_data.myLocalFLOPublicKey; + receivedTradeInfo["order_validator_public_key"] = su_data.myLocalFLOPublicKey; try { - const this_btc_pvt_key = - generate_btc_keys_for_requester.privateKeyWIF; - const this_btc_tx_key = Crypto.util.randomBytes( - 64 - ); + const this_btc_pvt_key = generate_btc_keys_for_requester.privateKeyWIF; + const this_btc_tx_key = Crypto.util.randomBytes(64); const this_btc_pvt_key_shamirs_secret = RM_WALLET.createShamirsSecretShares( this_btc_pvt_key, 10, @@ -15663,11 +15649,6 @@ localbitcoinplusplus.master_configurations.tradableAsset2.includes( params.currency ) && - typeof localbitcoinplusplus.master_configurations - .validTradingAmount !== "undefined" && - localbitcoinplusplus.master_configurations.validTradingAmount.includes( - parseFloat(params.depositing_amount) - ) && typeof params.trader_flo_address == "string" && params.trader_flo_address.length > 0 && typeof params.user_upi == "string" && @@ -15976,15 +15957,6 @@ params.product ) ) { - if ( - !localbitcoinplusplus.master_configurations.validTradingAmount.includes( - parseFloat(params.withdrawing_amount) - ) - ) { - err_msg = `Withdrawal request failed: Please enter valid fiat amount.`; - showMessage(err_msg); - throw new Error(err_msg); - } if ( trade_margin.remaining_fiat_credit <= 0 || params.withdrawing_amount <= 0 || @@ -17024,11 +16996,6 @@ localbitcoinplusplus.master_configurations.tradableAsset2.includes( params.currency ) && - typeof localbitcoinplusplus.master_configurations - .validTradingAmount !== "undefined" && - localbitcoinplusplus.master_configurations.validTradingAmount.includes( - parseFloat(params.depositing_amount) - ) && typeof params.trader_flo_address == "string" && params.trader_flo_address.length > 0 ) { @@ -17066,11 +17033,13 @@ params.btc_address = generate_btc_keys_for_requester.address; - params.bitcoinToBePaid = RM_TRADE.calculateCryptoEquivalentOfCash( - params.depositing_amount, - params.currency, - params.product - ); + // params.bitcoinToBePaid = RM_TRADE.calculateCryptoEquivalentOfCash( + // params.depositing_amount, + // params.currency, + // params.product + // ); + + params.bitcoinToBePaid = Number(params.depositing_amount); let receivedTradeInfo = { ...params }; @@ -17099,18 +17068,12 @@ JSON.stringify(receivedTradeInfo) ); - receivedTradeInfo[ - "depositDataHash" - ] = receivedTradeInfoHash; - receivedTradeInfo[ - "order_validator_sign" - ] = RM_WALLET.sign( + receivedTradeInfo["depositDataHash"] = receivedTradeInfoHash; + receivedTradeInfo["order_validator_sign"] = RM_WALLET.sign( receivedTradeInfoHash, - localbitcoinplusplus.wallets - .MY_SUPERNODE_PRIVATE_KEY + localbitcoinplusplus.wallets.MY_SUPERNODE_PRIVATE_KEY ); - receivedTradeInfo["order_validator_public_key"] = - su_data.myLocalFLOPublicKey; + receivedTradeInfo["order_validator_public_key"] = su_data.myLocalFLOPublicKey; try { const this_btc_pvt_key = @@ -19111,14 +19074,6 @@ err_msg = "User address required."; showMessage(err_msg); throw new Error(err_msg); - } else if ( - !localbitcoinplusplus.master_configurations.validTradingAmount.includes( - amount - ) - ) { - err_msg = "Error: Invalid deposit amount."; - showMessage(err_msg); - throw new Error(err_msg); } else if (typeof user_upi !== "string" || user_upi.length < 1) { err_msg = "Error: Invalid UPI id."; showMessage(err_msg); @@ -20289,7 +20244,61 @@ return `${+new Date()}_${Math.random() .toString(36) .substr(2, 9)}`; - } + }, + check_crypto_recvd_status: function(crypto, crypto_address, amount_to_receive=0) { + try { + let explorer; + let decimal = 100000000; + let crypto_diff = localbitcoinplusplus.master_configurations.btcTradeMargin; + switch (crypto) { + case "BTC": + explorer = localbitcoinplusplus.server.btc_mainnet; + break; + case "BTC_TEST": + explorer = localbitcoinplusplus.server.btc_testnet; + break; + case "FLO": + explorer = localbitcoinplusplus.server.flo_mainnet; + decimal = 1; + crypto_diff = crypto_diff/decimal; + break; + case "FLO_TEST": + explorer = localbitcoinplusplus.server.flo_testnet; + decimal = 1; + crypto_diff = crypto_diff/decimal; + break; + default: + break; + } + + let url = `${explorer}/api/addr/${crypto_address}/balance`; + console.log(url); + helper_functions.ajaxGet(url).then(async balance => { + if (!isNaN(balance) && parseFloat(balance) > 0) { + balance = Number(parseFloat(balance / decimal)); + console.log(balance); + + if (balance - amount_to_receive > crypto_diff) { + RM_RPC.send_rpc + .call(this, "refresh_deposit_status_request", { + receiver_flo_address: + localbitcoinplusplus.MY_SUPERNODE_FLO_ADDRESS, + trader_flo_address: + localbitcoinplusplus.wallets.my_local_flo_address + }) + .then(refresh_deposit_status => doSend(refresh_deposit_status)); + + } else { + await localbitcoinplusplus.actions.delay(60000); + check_crypto_recvd_status(crypto, crypto_address, amount_to_receive); + } + } + }); + + } catch (error) { + throw new Error(error) + } + }, }; @@ -21521,7 +21530,7 @@ resp.withdrawer_data.trader_flo_address ); } - readDB("localbitcoinUser", "00-01").then(function(user) { + readDB("localbitcoinUser", "00-01").then(async function(user) { if ( typeof user == "object" && user.myLocalFLOAddress == resp.data.trader_flo_address @@ -21529,7 +21538,7 @@ let counterTraderAccountAddress = `Please pay the amount to following address: ${resp.msg}`; showMessage(counterTraderAccountAddress); - modalWindow(counterTraderAccountAddress); + modalWindow(counterTraderAccountAddress); } }); } @@ -26726,14 +26735,15 @@ ); } - let old_data_with_values = Object.values(old_data).filter(f=>f.length>0); - if(Object.values(old_data_with_values).length) { - localbitcoinplusplus.actions.sync_backup_supernode_from_backup_supernode( - localbitcoinplusplus.wallets.my_local_flo_address, - res_obj.globalParams.senderFloId, - primarySupernodeOfThisUser - ); - } + // Issue: Causes request loop + // let old_data_with_values = Object.values(old_data).filter(f=>f.length>0); + // if(Object.values(old_data_with_values).length) { + // localbitcoinplusplus.actions.sync_backup_supernode_from_backup_supernode( + // localbitcoinplusplus.wallets.my_local_flo_address, + // res_obj.globalParams.senderFloId, + // primarySupernodeOfThisUser + // ); + // } }); } @@ -29446,24 +29456,24 @@ tradeAmountSelect.id = "trade_amount_select"; asset_box.appendChild(tradeAmountSelect); - let currencySelect = document.createElement("select"); - currencySelect.id = `withdraw_fiat_currency`; - asset_box.appendChild(currencySelect); - if ( - typeof localbitcoinplusplus.master_configurations.tradableAsset2 !== - "undefined" && - localbitcoinplusplus.master_configurations.tradableAsset2.length > 0 - ) { - let fiatList = localbitcoinplusplus.master_configurations.tradableAsset2; - let fiatListArray = JSON.parse(JSON.stringify(fiatList)); - fiatListArray.unshift("Select Fiat Currency (for exchange rates)"); - for (var i = 0; i < fiatListArray.length; i++) { - var option = document.createElement("option"); - option.value = fiatListArray[i]; - option.text = fiatListArray[i]; - currencySelect.appendChild(option); - } - } + // let currencySelect = document.createElement("select"); + // currencySelect.id = `withdraw_fiat_currency`; + // asset_box.appendChild(currencySelect); + // if ( + // typeof localbitcoinplusplus.master_configurations.tradableAsset2 !== + // "undefined" && + // localbitcoinplusplus.master_configurations.tradableAsset2.length > 0 + // ) { + // let fiatList = localbitcoinplusplus.master_configurations.tradableAsset2; + // let fiatListArray = JSON.parse(JSON.stringify(fiatList)); + // fiatListArray.unshift("Select Fiat Currency (for exchange rates)"); + // for (var i = 0; i < fiatListArray.length; i++) { + // var option = document.createElement("option"); + // option.value = fiatListArray[i]; + // option.text = fiatListArray[i]; + // currencySelect.appendChild(option); + // } + // } // Create a deposit and withdraw button let depositAssetButton = document.createElement("button"); @@ -29480,7 +29490,8 @@ depositAssetButton.addEventListener("click", function() { let asset_type = assetTypeInput.value; let tradeAmount = parseFloat(tradeAmountSelect.value); - let fiatCurrency = currencySelect.value; + //let fiatCurrency = currencySelect.value; + let fiatCurrency = "INR"; if ( typeof userFLOaddress == undefined || userFLOaddress.trim().length < 1 @@ -29521,7 +29532,8 @@ } let tradeAmount = parseFloat(tradeAmountSelect.value); - let fiatCurrency = currencySelect.value; + //let fiatCurrency = currencySelect.value; + let fiatCurrency = "INR"; if ( typeof userFLOaddress == undefined || @@ -29804,47 +29816,47 @@ } } - const receiving_amount_currency_input = document.createElement( - "select" - ); - receiving_amount_currency_input.id = "receiving_amount_currency_input"; - broadcast_tx_ui.appendChild(receiving_amount_currency_input); + // const receiving_amount_currency_input = document.createElement( + // "select" + // ); + // receiving_amount_currency_input.id = "receiving_amount_currency_input"; + // broadcast_tx_ui.appendChild(receiving_amount_currency_input); - if ( - typeof localbitcoinplusplus.master_configurations.tradableAsset2 !== - "undefined" - ) { - let receiving_amount_currency_inputArray = JSON.parse( - JSON.stringify( - localbitcoinplusplus.master_configurations.tradableAsset2 - ) - ).filter( - asset => - !localbitcoinplusplus.master_configurations.tradableAsset1.includes( - asset - ) - ); + // if ( + // typeof localbitcoinplusplus.master_configurations.tradableAsset2 !== + // "undefined" + // ) { + // let receiving_amount_currency_inputArray = JSON.parse( + // JSON.stringify( + // localbitcoinplusplus.master_configurations.tradableAsset2 + // ) + // ).filter( + // asset => + // !localbitcoinplusplus.master_configurations.tradableAsset1.includes( + // asset + // ) + // ); - receiving_amount_currency_inputArray.unshift("Select Fiat"); - for ( - var i = 0; - i < receiving_amount_currency_inputArray.length; - i++ - ) { - var option = document.createElement("option"); - option.value = receiving_amount_currency_inputArray[i]; - option.text = receiving_amount_currency_inputArray[i]; - receiving_amount_currency_input.appendChild(option); - } - } + // receiving_amount_currency_inputArray.unshift("Select Fiat"); + // for ( + // var i = 0; + // i < receiving_amount_currency_inputArray.length; + // i++ + // ) { + // var option = document.createElement("option"); + // option.value = receiving_amount_currency_inputArray[i]; + // option.text = receiving_amount_currency_inputArray[i]; + // receiving_amount_currency_input.appendChild(option); + // } + // } const utxo_addr_input = document.createElement("input"); utxo_addr_input.type = "text"; - utxo_addr_input.placeholder = `UTXO Address of Crypto`; + utxo_addr_input.placeholder = `Sender Address`; const utxo_addr_wif_input = document.createElement("input"); utxo_addr_wif_input.type = "text"; - utxo_addr_wif_input.placeholder = `Private Key of Crypto Being Used`; + utxo_addr_wif_input.placeholder = `Enter Private Key`; const receiver_address_input = document.createElement("input"); receiver_address_input.type = "text"; @@ -29854,9 +29866,9 @@ receiving_crypto_amount_input.type = "text"; receiving_crypto_amount_input.placeholder = `Amount to Send`; - const change_adress_input = document.createElement("input"); - change_adress_input.type = "text"; - change_adress_input.placeholder = `Change Address`; + // const change_adress_input = document.createElement("input"); + // change_adress_input.type = "text"; + // change_adress_input.placeholder = `Change Address`; const tx_send_button = document.createElement("button"); tx_send_button.className += " button bg-blue fs-16 "; @@ -29868,7 +29880,7 @@ broadcast_tx_ui_form.appendChild(utxo_addr_wif_input); broadcast_tx_ui_form.appendChild(receiver_address_input); broadcast_tx_ui_form.appendChild(receiving_crypto_amount_input); - broadcast_tx_ui_form.appendChild(change_adress_input); + //broadcast_tx_ui_form.appendChild(change_adress_input); broadcast_tx_ui_form.appendChild(tx_send_button); let err_msg; @@ -29893,11 +29905,11 @@ showMessage(err_msg); throw new Error(err_msg); } - if (change_adress_input.value.length < 1) { - err_msg = "Empty Change Address."; - showMessage(err_msg); - throw new Error(err_msg); - } + // if (change_adress_input.value.length < 1) { + // err_msg = "Empty Change Address."; + // showMessage(err_msg); + // throw new Error(err_msg); + // } const RM_TRADE = new localbitcoinplusplus.trade(); RM_TRADE.sendTransaction( @@ -29906,7 +29918,7 @@ utxo_addr_wif_input.value, receiver_address_input.value, receiving_crypto_amount_input.value, - change_adress_input.value, + utxo_addr_input.value, async function(res) { console.log(res); if (typeof res == "object") { @@ -29991,6 +30003,7 @@ let explorer; let decimal = 100000000; + let crypto_diff = localbitcoinplusplus.master_configurations.btcTradeMargin; switch (trader_deposits.product) { case "BTC": explorer = localbitcoinplusplus.server.btc_mainnet; @@ -30001,10 +30014,12 @@ case "FLO": explorer = localbitcoinplusplus.server.flo_mainnet; decimal = 1; + crypto_diff = Number(localbitcoinplusplus.master_configurations.btcTradeMargin/decimal); break; case "FLO_TEST": explorer = localbitcoinplusplus.server.flo_testnet; decimal = 1; + crypto_diff = Number(localbitcoinplusplus.master_configurations.btcTradeMargin/decimal); break; default: break; @@ -30019,13 +30034,12 @@ /************************ Case of dispute *****************/ if ( - trader_deposits.bitcoinToBePaid - balance > - localbitcoinplusplus.master_configurations.btcTradeMargin + trader_deposits.bitcoinToBePaid - balance > crypto_diff ) { console.log( trader_deposits.bitcoinToBePaid, balance, - localbitcoinplusplus.master_configurations.btcTradeMargin + crypto_diff ); console.warn("User sent less cryptos"); diff --git a/supernode/server/chatRoomWSS b/supernode/server/chatRoomWSS new file mode 100755 index 0000000..f344d43 Binary files /dev/null and b/supernode/server/chatRoomWSS differ diff --git a/supernode/websocket_chat.c b/supernode/server/chatRoomWSServer.c similarity index 60% rename from supernode/websocket_chat.c rename to supernode/server/chatRoomWSServer.c index f6c9caf..0fbac56 100644 --- a/supernode/websocket_chat.c +++ b/supernode/server/chatRoomWSServer.c @@ -6,7 +6,7 @@ #include "mongoose.h" static sig_atomic_t s_signal_received = 0; -static const char *s_http_port = "9003"; +static const char *s_http_port = "9115"; static struct mg_serve_http_opts s_http_server_opts; static void signal_handler(int sig_num) { @@ -20,16 +20,21 @@ static int is_websocket(const struct mg_connection *nc) { static void broadcast(struct mg_connection *nc, const struct mg_str msg) { struct mg_connection *c; - char buf[25000]; - char addr[10240]; - mg_sock_addr_to_str(&nc->sa, addr, sizeof(addr), - MG_SOCK_STRINGIFY_IP | MG_SOCK_STRINGIFY_PORT); - - snprintf(buf, sizeof(buf), "%s %.*s", addr, (int) msg.len, msg.p); - printf("%s\n", buf); /* Local echo. */ + printf("(Broadcast) \t[%d]\n", (int)msg.len); for (c = mg_next(nc->mgr, NULL); c != NULL; c = mg_next(nc->mgr, c)) { if (c == nc) continue; /* Don't send to the sender. */ - mg_send_websocket_frame(c, WEBSOCKET_OP_TEXT, buf, strlen(buf)); // A single websocket frame is sent + mg_send_websocket_frame(c, WEBSOCKET_OP_TEXT, msg.p, (int)msg.len); + } +} + +void unicast(struct mg_connection *nc, const struct mg_str msg) { + struct mg_connection *c; + char recipient_floID[35]; + snprintf(recipient_floID, sizeof(recipient_floID), "%.*s", 34, &msg.p[1]); + printf("%s \t[%d]\n",recipient_floID, (int)msg.len - 36); /* Local echo. */ + for (c = mg_next(nc->mgr, NULL); c != NULL; c = mg_next(nc->mgr, c)) { + if (!strcmp(c->floID,recipient_floID)) /* Send to receiver */ + mg_send_websocket_frame(c, WEBSOCKET_OP_TEXT, &msg.p[36], (int)msg.len - 36); } } @@ -37,14 +42,18 @@ static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) { switch (ev) { case MG_EV_WEBSOCKET_HANDSHAKE_DONE: { /* New websocket connection. Tell everybody. */ - broadcast(nc, mg_mk_str("++ joined")); break; } case MG_EV_WEBSOCKET_FRAME: { struct websocket_message *wm = (struct websocket_message *) ev_data; /* New websocket message. Tell everybody. */ - struct mg_str d = {(char *) wm->data, wm->size}; //This is the data received data inside *ev_data - broadcast(nc, d); //Action when data is received + struct mg_str d = {(char *) wm->data, wm->size}; + if (d.p[0] == '$') + snprintf(nc->floID, sizeof(nc->floID), "%.*s", 34, &d.p[1]); + else if ((d.p[0] == '>')) + unicast(nc, d); + else + broadcast(nc, d); break; } case MG_EV_HTTP_REQUEST: { @@ -54,7 +63,7 @@ static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) { case MG_EV_CLOSE: { /* Disconnect. Tell everybody. */ if (is_websocket(nc)) { - broadcast(nc, mg_mk_str("-- left")); + //broadcast(nc, mg_mk_str("-- left")); } break; } @@ -72,10 +81,10 @@ int main(void) { mg_mgr_init(&mgr, NULL); - nc = mg_bind(&mgr, s_http_port, ev_handler); //connection mg_connection and manager mg_mgr are linked along with port and event handler + nc = mg_bind(&mgr, s_http_port, ev_handler); mg_set_protocol_http_websocket(nc); - s_http_server_opts.document_root = "."; // Serve current directory - s_http_server_opts.enable_directory_listing = "yes"; + s_http_server_opts.document_root = "web"; // Serve current directory + s_http_server_opts.enable_directory_listing = "no"; printf("Started on port %s\n", s_http_port); while (s_signal_received == 0) { @@ -84,4 +93,4 @@ int main(void) { mg_mgr_free(&mgr); return 0; -} \ No newline at end of file +} diff --git a/examples.mk b/supernode/server/examples.mk similarity index 100% rename from examples.mk rename to supernode/server/examples.mk diff --git a/mongoose.c b/supernode/server/mongoose.c similarity index 96% rename from mongoose.c rename to supernode/server/mongoose.c index d117564..a566fbc 100644 --- a/mongoose.c +++ b/supernode/server/mongoose.c @@ -38,7 +38,9 @@ /* Amalgamated: #include "mg_http.h" */ /* Amalgamated: #include "mg_net.h" */ +#ifndef MG_CTL_MSG_MESSAGE_SIZE #define MG_CTL_MSG_MESSAGE_SIZE 8192 +#endif /* internals that need to be accessible in unit tests */ MG_INTERNAL struct mg_connection *mg_do_connect(struct mg_connection *nc, @@ -460,6 +462,10 @@ int cs_base64_decode(const unsigned char *s, int len, char *dst, int *dec_len) { #define CS_ENABLE_DEBUG 0 #endif +#ifndef CS_LOG_PREFIX_LEN +#define CS_LOG_PREFIX_LEN 24 +#endif + #ifndef CS_LOG_ENABLE_TS_DIFF #define CS_LOG_ENABLE_TS_DIFF 0 #endif @@ -490,51 +496,28 @@ enum cs_log_level { void cs_log_set_level(enum cs_log_level level); /* - * Set log filter. NULL (a default) logs everything. - * Otherwise, function name and file name will be tested against the given - * pattern, and only matching messages will be printed. + * A comma-separated set of prefix=level. + * prefix is matched against the log prefix exactly as printed, including line + * number, but partial match is ok. Check stops on first matching entry. + * If nothing matches, default level is used. * - * For the pattern syntax, refer to `mg_match_prefix()` in `str_util.h`. + * Examples: + * main.c:=4 - everything from main C at verbose debug level. + * mongoose.c=1,mjs.c=1,=4 - everything at verbose debug except mg_* and mjs_* * - * Example: - * ```c - * void foo(void) { - * LOG(LL_INFO, ("hello from foo")); - * } - * - * void bar(void) { - * LOG(LL_INFO, ("hello from bar")); - * } - * - * void test(void) { - * cs_log_set_filter(NULL); - * foo(); - * bar(); - * - * cs_log_set_filter("f*"); - * foo(); - * bar(); // Will NOT print anything - * - * cs_log_set_filter("bar"); - * foo(); // Will NOT print anything - * bar(); - * } - * ``` */ -void cs_log_set_filter(const char *pattern); +void cs_log_set_file_level(const char *file_level); /* - * Helper function which prints message prefix with the given `level`, function - * name `func` and `filename`. If message should be printed (accordingly to the - * current log level and filter), prints the prefix and returns 1, otherwise - * returns 0. + * Helper function which prints message prefix with the given `level`. + * If message should be printed (according to the current log level + * and filter), prints the prefix and returns 1, otherwise returns 0. * * Clients should typically just use `LOG()` macro. */ -int cs_log_print_prefix(enum cs_log_level level, const char *func, - const char *filename); +int cs_log_print_prefix(enum cs_log_level level, const char *fname, int line); -extern enum cs_log_level cs_log_threshold; +extern enum cs_log_level cs_log_level; #if CS_ENABLE_STDIO @@ -559,9 +542,11 @@ void cs_log_printf(const char *fmt, ...) PRINTF_LIKE(1, 2); * LOG(LL_DEBUG, ("my debug message: %d", 123)); * ``` */ -#define LOG(l, x) \ - do { \ - if (cs_log_print_prefix(l, __func__, __FILE__)) cs_log_printf x; \ +#define LOG(l, x) \ + do { \ + if (cs_log_print_prefix(l, __FILE__, __LINE__)) { \ + cs_log_printf x; \ + } \ } while (0) #else @@ -624,7 +609,7 @@ void cs_log_printf(const char *fmt, ...) PRINTF_LIKE(1, 2); /* Amalgamated: #include "common/cs_time.h" */ /* Amalgamated: #include "common/str_util.h" */ -enum cs_log_level cs_log_threshold WEAK = +enum cs_log_level cs_log_level WEAK = #if CS_ENABLE_DEBUG LL_VERBOSE_DEBUG; #else @@ -632,10 +617,9 @@ enum cs_log_level cs_log_threshold WEAK = #endif #if CS_ENABLE_STDIO -static char *s_filter_pattern = NULL; -static size_t s_filter_pattern_len; +static char *s_file_level = NULL; -void cs_log_set_filter(const char *pattern) WEAK; +void cs_log_set_file_level(const char *file_level) WEAK; FILE *cs_log_file WEAK = NULL; @@ -645,34 +629,62 @@ double cs_log_ts WEAK; enum cs_log_level cs_log_cur_msg_level WEAK = LL_NONE; -void cs_log_set_filter(const char *pattern) { - free(s_filter_pattern); - if (pattern != NULL) { - s_filter_pattern = strdup(pattern); - s_filter_pattern_len = strlen(pattern); +void cs_log_set_file_level(const char *file_level) { + char *fl = s_file_level; + if (file_level != NULL) { + s_file_level = strdup(file_level); } else { - s_filter_pattern = NULL; - s_filter_pattern_len = 0; + s_file_level = NULL; } + free(fl); } -int cs_log_print_prefix(enum cs_log_level, const char *, const char *) WEAK; -int cs_log_print_prefix(enum cs_log_level level, const char *func, - const char *filename) { - char prefix[21]; +int cs_log_print_prefix(enum cs_log_level level, const char *file, int ln) WEAK; +int cs_log_print_prefix(enum cs_log_level level, const char *file, int ln) { + char prefix[CS_LOG_PREFIX_LEN], *q; + const char *p; + size_t fl = 0, ll = 0, pl = 0; - if (level > cs_log_threshold) return 0; - if (s_filter_pattern != NULL && - mg_match_prefix(s_filter_pattern, s_filter_pattern_len, func) == 0 && - mg_match_prefix(s_filter_pattern, s_filter_pattern_len, filename) == 0) { - return 0; + if (level > cs_log_level && s_file_level == NULL) return 0; + + p = file + strlen(file); + + while (p != file) { + const char c = *(p - 1); + if (c == '/' || c == '\\') break; + p--; + fl++; + } + + ll = (ln < 10000 ? (ln < 1000 ? (ln < 100 ? (ln < 10 ? 1 : 2) : 3) : 4) : 5); + if (fl > (sizeof(prefix) - ll - 2)) fl = (sizeof(prefix) - ll - 2); + + pl = fl + 1 + ll; + memcpy(prefix, p, fl); + q = prefix + pl; + memset(q, ' ', sizeof(prefix) - pl); + do { + *(--q) = '0' + (ln % 10); + ln /= 10; + } while (ln > 0); + *(--q) = ':'; + + if (s_file_level != NULL) { + enum cs_log_level pll = cs_log_level; + struct mg_str fl = mg_mk_str(s_file_level), ps = MG_MK_STR_N(prefix, pl); + struct mg_str k, v; + while ((fl = mg_next_comma_list_entry_n(fl, &k, &v)).p != NULL) { + bool yes = !(!mg_str_starts_with(ps, k) || v.len == 0); + if (!yes) continue; + pll = (enum cs_log_level)(*v.p - '0'); + break; + } + if (level > pll) return 0; } - strncpy(prefix, func, 20); - prefix[20] = '\0'; if (cs_log_file == NULL) cs_log_file = stderr; cs_log_cur_msg_level = level; - fprintf(cs_log_file, "%-20s ", prefix); + fwrite(prefix, 1, sizeof(prefix), cs_log_file); #if CS_LOG_ENABLE_TS_DIFF { double now = cs_time(); @@ -701,15 +713,15 @@ void cs_log_set_file(FILE *file) { #else -void cs_log_set_filter(const char *pattern) { - (void) pattern; +void cs_log_set_file_level(const char *file_level) { + (void) file_level; } #endif /* CS_ENABLE_STDIO */ void cs_log_set_level(enum cs_log_level level) WEAK; void cs_log_set_level(enum cs_log_level level) { - cs_log_threshold = level; + cs_log_level = level; #if CS_LOG_ENABLE_TS_DIFF && CS_ENABLE_STDIO cs_log_ts = cs_time(); #endif @@ -1612,6 +1624,22 @@ size_t mbuf_append(struct mbuf *a, const void *buf, size_t len) { return mbuf_insert(a, a->len, buf, len); } +size_t mbuf_append_and_free(struct mbuf *a, void *buf, size_t len) WEAK; +size_t mbuf_append_and_free(struct mbuf *a, void *data, size_t len) { + size_t ret; + /* Optimization: if the buffer is currently empty, + * take over the user-provided buffer. */ + if (a->len == 0) { + if (a->buf != NULL) free(a->buf); + a->buf = (char *) data; + a->len = a->size = len; + return len; + } + ret = mbuf_insert(a, a->len, data, len); + free(data); + return ret; +} + void mbuf_remove(struct mbuf *mb, size_t n) WEAK; void mbuf_remove(struct mbuf *mb, size_t n) { if (n > 0 && n <= mb->len) { @@ -1620,6 +1648,17 @@ void mbuf_remove(struct mbuf *mb, size_t n) { } } +void mbuf_clear(struct mbuf *mb) WEAK; +void mbuf_clear(struct mbuf *mb) { + mb->len = 0; +} + +void mbuf_move(struct mbuf *from, struct mbuf *to) WEAK; +void mbuf_move(struct mbuf *from, struct mbuf *to) { + memcpy(to, from, sizeof(*to)); + memset(from, 0, sizeof(*from)); +} + #endif /* EXCLUDE_COMMON */ #ifdef MG_MODULE_LINES #line 1 "common/mg_str.c" @@ -1645,6 +1684,7 @@ void mbuf_remove(struct mbuf *mb, size_t n) { /* Amalgamated: #include "common/mg_str.h" */ /* Amalgamated: #include "common/platform.h" */ +#include #include #include @@ -1744,6 +1784,14 @@ int mg_strncmp(const struct mg_str str1, const struct mg_str str2, size_t n) { return mg_strcmp(s1, s2); } +void mg_strfree(struct mg_str *s) WEAK; +void mg_strfree(struct mg_str *s) { + char *sp = (char *) s->p; + s->p = NULL; + s->len = 0; + if (sp != NULL) free(sp); +} + const char *mg_strstr(const struct mg_str haystack, const struct mg_str needle) WEAK; const char *mg_strstr(const struct mg_str haystack, @@ -1769,6 +1817,13 @@ struct mg_str mg_strstrip(struct mg_str s) { } return s; } + +int mg_str_starts_with(struct mg_str s, struct mg_str prefix) WEAK; +int mg_str_starts_with(struct mg_str s, struct mg_str prefix) { + const struct mg_str sp = MG_MK_STR_N(s.p, prefix.len); + if (s.len < prefix.len) return 0; + return (mg_strcmp(sp, prefix) == 0); +} #ifdef MG_MODULE_LINES #line 1 "common/str_util.c" #endif @@ -2408,6 +2463,7 @@ MG_INTERNAL void mg_call(struct mg_connection *nc, (nc->flags & _MG_CALLBACK_MODIFIABLE_FLAGS_MASK); } } + if (ev != MG_EV_POLL) nc->mgr->num_calls++; if (ev != MG_EV_POLL) { DBG(("%p after %s flags=0x%lx rmbl=%d smbl=%d", nc, ev_handler == nc->handler ? "user" : "proto", nc->flags, @@ -2436,8 +2492,16 @@ MG_INTERNAL size_t recv_avail_size(struct mg_connection *conn, size_t max) { static int mg_do_recv(struct mg_connection *nc); int mg_if_poll(struct mg_connection *nc, double now) { - if ((nc->flags & MG_F_CLOSE_IMMEDIATELY) || - (nc->send_mbuf.len == 0 && (nc->flags & MG_F_SEND_AND_CLOSE))) { + if (nc->flags & MG_F_CLOSE_IMMEDIATELY) { + mg_close_conn(nc); + return 0; + } else if (nc->flags & MG_F_SEND_AND_CLOSE) { + if (nc->send_mbuf.len == 0) { + nc->flags |= MG_F_CLOSE_IMMEDIATELY; + mg_close_conn(nc); + return 0; + } + } else if (nc->flags & MG_F_RECV_AND_CLOSE) { mg_close_conn(nc); return 0; } @@ -2480,6 +2544,13 @@ void mg_destroy_conn(struct mg_connection *conn, int destroy_if) { } void mg_close_conn(struct mg_connection *conn) { + /* See if there's any remaining data to deliver. Skip if user completely + * throttled the connection there will be no progress anyway. */ + if (conn->sock != INVALID_SOCKET && mg_do_recv(conn) == -2) { + /* Receive is throttled, wait. */ + conn->flags |= MG_F_RECV_AND_CLOSE; + return; + } #if MG_ENABLE_SSL if (conn->flags & MG_F_SSL_HANDSHAKE_DONE) { mg_ssl_if_conn_close_notify(conn); @@ -2570,6 +2641,7 @@ void mg_mgr_free(struct mg_mgr *m) { for (conn = m->active_connections; conn != NULL; conn = tmp_conn) { tmp_conn = conn->next; + conn->flags |= MG_F_CLOSE_IMMEDIATELY; mg_close_conn(conn); } @@ -2585,19 +2657,14 @@ void mg_mgr_free(struct mg_mgr *m) { MG_FREE((char *) m->nameserver); } -time_t mg_mgr_poll(struct mg_mgr *m, int timeout_ms) { - int i; - time_t now = 0; /* oh GCC, seriously ? */ - - if (m->num_ifaces == 0) { - LOG(LL_ERROR, ("cannot poll: no interfaces")); - return 0; - } +int mg_mgr_poll(struct mg_mgr *m, int timeout_ms) { + int i, num_calls_before = m->num_calls; for (i = 0; i < m->num_ifaces; i++) { - now = m->ifaces[i]->vtable->poll(m->ifaces[i], timeout_ms); + m->ifaces[i]->vtable->poll(m->ifaces[i], timeout_ms); } - return now; + + return (m->num_calls - num_calls_before); } int mg_vprintf(struct mg_connection *nc, const char *fmt, va_list ap) { @@ -2801,7 +2868,6 @@ MG_INTERNAL void mg_ssl_handshake(struct mg_connection *nc) { enum mg_ssl_if_result res; if (nc->flags & MG_F_SSL_HANDSHAKE_DONE) return; res = mg_ssl_if_handshake(nc); - LOG(LL_DEBUG, ("%p %d res %d", nc, server_side, res)); if (res == MG_SSL_OK) { nc->flags |= MG_F_SSL_HANDSHAKE_DONE; @@ -2879,18 +2945,23 @@ static int mg_do_recv(struct mg_connection *nc) { ((nc->flags & MG_F_LISTENING) && !(nc->flags & MG_F_UDP))) { return -1; } - len = recv_avail_size(nc, len); - if (len == 0) return -2; - if (nc->recv_mbuf.size < nc->recv_mbuf.len + len) { - mbuf_resize(&nc->recv_mbuf, nc->recv_mbuf.len + len); - } - buf = nc->recv_mbuf.buf + nc->recv_mbuf.len; - len = nc->recv_mbuf.size - nc->recv_mbuf.len; - if (nc->flags & MG_F_UDP) { - res = mg_recv_udp(nc, buf, len); - } else { - res = mg_recv_tcp(nc, buf, len); - } + do { + len = recv_avail_size(nc, len); + if (len == 0) { + res = -2; + break; + } + if (nc->recv_mbuf.size < nc->recv_mbuf.len + len) { + mbuf_resize(&nc->recv_mbuf, nc->recv_mbuf.len + len); + } + buf = nc->recv_mbuf.buf + nc->recv_mbuf.len; + len = nc->recv_mbuf.size - nc->recv_mbuf.len; + if (nc->flags & MG_F_UDP) { + res = mg_recv_udp(nc, buf, len); + } else { + res = mg_recv_tcp(nc, buf, len); + } + } while (res > 0 && !(nc->flags & (MG_F_CLOSE_IMMEDIATELY | MG_F_UDP))); return res; } @@ -2932,10 +3003,12 @@ static int mg_recv_tcp(struct mg_connection *nc, char *buf, size_t len) { mg_hexdump_connection(nc, nc->mgr->hexdump_file, buf, n, MG_EV_RECV); } #endif + mbuf_trim(&nc->recv_mbuf); mg_call(nc, NULL, nc->user_data, MG_EV_RECV, &n); } else if (n < 0) { nc->flags |= MG_F_CLOSE_IMMEDIATELY; } + mbuf_trim(&nc->recv_mbuf); return n; } @@ -3005,7 +3078,9 @@ static int mg_recv_udp(struct mg_connection *nc, char *buf, size_t len) { mg_hexdump_connection(nc, nc->mgr->hexdump_file, buf, n, MG_EV_RECV); } #endif - mg_call(nc, NULL, nc->user_data, MG_EV_RECV, &n); + if (n != 0) { + mg_call(nc, NULL, nc->user_data, MG_EV_RECV, &n); + } } out: @@ -3047,7 +3122,7 @@ void mg_if_can_send_cb(struct mg_connection *nc) { } } else #endif - { + if (len > 0) { if (nc->flags & MG_F_UDP) { n = nc->iface->vtable->udp_send(nc, buf, len); } else { @@ -3585,6 +3660,162 @@ struct mg_iface *mg_find_iface(struct mg_mgr *mgr, } return NULL; } + +double mg_mgr_min_timer(const struct mg_mgr *mgr) { + double min_timer = 0; + struct mg_connection *nc; + for (nc = mgr->active_connections; nc != NULL; nc = nc->next) { + if (nc->ev_timer_time <= 0) continue; + if (min_timer == 0 || nc->ev_timer_time < min_timer) { + min_timer = nc->ev_timer_time; + } + } + return min_timer; +} +#ifdef MG_MODULE_LINES +#line 1 "mongoose/src/mg_net_if_null.c" +#endif +/* + * Copyright (c) 2018 Cesanta Software Limited + * All rights reserved + * + * This software is dual-licensed: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. For the terms of this + * license, see . + * + * You are free to use this software under the terms of the GNU General + * Public License, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * Alternatively, you can license this software under a commercial + * license, as set out in . + */ + +static void mg_null_if_connect_tcp(struct mg_connection *c, + const union socket_address *sa) { + c->flags |= MG_F_CLOSE_IMMEDIATELY; + (void) sa; +} + +static void mg_null_if_connect_udp(struct mg_connection *c) { + c->flags |= MG_F_CLOSE_IMMEDIATELY; +} + +static int mg_null_if_listen_tcp(struct mg_connection *c, + union socket_address *sa) { + (void) c; + (void) sa; + return -1; +} + +static int mg_null_if_listen_udp(struct mg_connection *c, + union socket_address *sa) { + (void) c; + (void) sa; + return -1; +} + +static int mg_null_if_tcp_send(struct mg_connection *c, const void *buf, + size_t len) { + (void) c; + (void) buf; + (void) len; + return -1; +} + +static int mg_null_if_udp_send(struct mg_connection *c, const void *buf, + size_t len) { + (void) c; + (void) buf; + (void) len; + return -1; +} + +int mg_null_if_tcp_recv(struct mg_connection *c, void *buf, size_t len) { + (void) c; + (void) buf; + (void) len; + return -1; +} + +int mg_null_if_udp_recv(struct mg_connection *c, void *buf, size_t len, + union socket_address *sa, size_t *sa_len) { + (void) c; + (void) buf; + (void) len; + (void) sa; + (void) sa_len; + return -1; +} + +static int mg_null_if_create_conn(struct mg_connection *c) { + (void) c; + return 1; +} + +static void mg_null_if_destroy_conn(struct mg_connection *c) { + (void) c; +} + +static void mg_null_if_sock_set(struct mg_connection *c, sock_t sock) { + (void) c; + (void) sock; +} + +static void mg_null_if_init(struct mg_iface *iface) { + (void) iface; +} + +static void mg_null_if_free(struct mg_iface *iface) { + (void) iface; +} + +static void mg_null_if_add_conn(struct mg_connection *c) { + c->sock = INVALID_SOCKET; + c->flags |= MG_F_CLOSE_IMMEDIATELY; +} + +static void mg_null_if_remove_conn(struct mg_connection *c) { + (void) c; +} + +static time_t mg_null_if_poll(struct mg_iface *iface, int timeout_ms) { + struct mg_mgr *mgr = iface->mgr; + struct mg_connection *nc, *tmp; + double now = mg_time(); + /* We basically just run timers and poll. */ + for (nc = mgr->active_connections; nc != NULL; nc = tmp) { + tmp = nc->next; + mg_if_poll(nc, now); + } + (void) timeout_ms; + return (time_t) now; +} + +static void mg_null_if_get_conn_addr(struct mg_connection *c, int remote, + union socket_address *sa) { + (void) c; + (void) remote; + (void) sa; +} + +#define MG_NULL_IFACE_VTABLE \ + { \ + mg_null_if_init, mg_null_if_free, mg_null_if_add_conn, \ + mg_null_if_remove_conn, mg_null_if_poll, mg_null_if_listen_tcp, \ + mg_null_if_listen_udp, mg_null_if_connect_tcp, mg_null_if_connect_udp, \ + mg_null_if_tcp_send, mg_null_if_udp_send, mg_null_if_tcp_recv, \ + mg_null_if_udp_recv, mg_null_if_create_conn, mg_null_if_destroy_conn, \ + mg_null_if_sock_set, mg_null_if_get_conn_addr, \ + } + +const struct mg_iface_vtable mg_null_iface_vtable = MG_NULL_IFACE_VTABLE; + +#if MG_NET_IF == MG_NET_IF_NULL +const struct mg_iface_vtable mg_default_iface_vtable = MG_NULL_IFACE_VTABLE; +#endif /* MG_NET_IF == MG_NET_IF_NULL */ #ifdef MG_MODULE_LINES #line 1 "mongoose/src/mg_net_if_socket.c" #endif @@ -4847,6 +5078,8 @@ static void mg_ssl_mbed_log(void *ctx, int level, const char *file, int line, } /* mbedTLS passes strings with \n at the end, strip it. */ LOG(cs_level, ("%p %.*s", ctx, (int) (strlen(str) - 1), str)); + (void) ctx; + (void) str; (void) file; (void) line; (void) cs_level; @@ -5036,9 +5269,9 @@ static void mg_ssl_if_mbed_free_certs_and_keys(struct mg_ssl_if_ctx *ctx) { if (ctx->ca_cert != NULL) { mbedtls_ssl_conf_ca_chain(ctx->conf, NULL, NULL); #ifdef MBEDTLS_X509_CA_CHAIN_ON_DISK - if (ctx->ca_cert->ca_chain_file != NULL) { - MG_FREE((void *) ctx->ca_cert->ca_chain_file); - ctx->ca_cert->ca_chain_file = NULL; + if (ctx->conf->ca_chain_file != NULL) { + MG_FREE((void *) ctx->conf->ca_chain_file); + ctx->conf->ca_chain_file = NULL; } #endif mbedtls_x509_crt_free(ctx->ca_cert); @@ -5145,15 +5378,13 @@ static enum mg_ssl_if_result mg_use_ca_cert(struct mg_ssl_if_ctx *ctx, mbedtls_x509_crt_init(ctx->ca_cert); #ifdef MBEDTLS_X509_CA_CHAIN_ON_DISK ca_cert = strdup(ca_cert); - if (mbedtls_x509_crt_set_ca_chain_file(ctx->ca_cert, ca_cert) != 0) { - return MG_SSL_ERROR; - } + mbedtls_ssl_conf_ca_chain_file(ctx->conf, ca_cert, NULL); #else if (mbedtls_x509_crt_parse_file(ctx->ca_cert, ca_cert) != 0) { return MG_SSL_ERROR; } -#endif mbedtls_ssl_conf_ca_chain(ctx->conf, ctx->ca_cert, NULL); +#endif mbedtls_ssl_conf_authmode(ctx->conf, MBEDTLS_SSL_VERIFY_REQUIRED); return MG_SSL_OK; } @@ -5731,6 +5962,7 @@ struct mg_http_multipart_stream { void *user_data; enum mg_http_multipart_stream_state state; int processing_part; + int data_avail; }; struct mg_reverse_proxy_data { @@ -6155,6 +6387,10 @@ static size_t mg_http_parse_chunk(char *buf, size_t len, char **chunk_data, n *= 16; n += (s[i] >= '0' && s[i] <= '9') ? s[i] - '0' : tolower(s[i]) - 'a' + 10; i++; + if (i > 6) { + /* Chunk size is unreasonable. */ + return 0; + } } /* Skip new line */ @@ -6345,9 +6581,9 @@ void mg_http_handler(struct mg_connection *nc, int ev, if (io->len > 0 && (req_len = mg_parse_http(io->buf, io->len, hm, is_req)) > 0) { /* - * For HTTP messages without Content-Length, always send HTTP message - * before MG_EV_CLOSE message. - */ + * For HTTP messages without Content-Length, always send HTTP message + * before MG_EV_CLOSE message. + */ int ev2 = is_req ? MG_EV_HTTP_REQUEST : MG_EV_HTTP_REPLY; hm->message.len = io->len; hm->body.len = io->buf + io->len - hm->body.p; @@ -6355,6 +6591,9 @@ void mg_http_handler(struct mg_connection *nc, int ev, mg_http_call_endpoint_handler(nc, ev2, hm); } pd->rcvd = 0; + if (pd->endpoint_handler != NULL && pd->endpoint_handler != nc->handler) { + mg_call(nc, pd->endpoint_handler, nc->user_data, ev, NULL); + } } #if MG_ENABLE_FILESYSTEM @@ -6365,17 +6604,24 @@ void mg_http_handler(struct mg_connection *nc, int ev, mg_call(nc, nc->handler, nc->user_data, ev, ev_data); +#if MG_ENABLE_HTTP_STREAMING_MULTIPART + if (pd->mp_stream.boundary != NULL && + (ev == MG_EV_RECV || ev == MG_EV_POLL)) { + if (ev == MG_EV_RECV) { + pd->rcvd += *(int *) ev_data; + mg_http_multipart_continue(nc); + } else if (pd->mp_stream.data_avail) { + /* Try re-delivering the data. */ + mg_http_multipart_continue(nc); + } + return; + } +#endif /* MG_ENABLE_HTTP_STREAMING_MULTIPART */ + if (ev == MG_EV_RECV) { struct mg_str *s; pd->rcvd += *(int *) ev_data; -#if MG_ENABLE_HTTP_STREAMING_MULTIPART - if (pd->mp_stream.boundary != NULL) { - mg_http_multipart_continue(nc); - return; - } -#endif /* MG_ENABLE_HTTP_STREAMING_MULTIPART */ - again: req_len = mg_parse_http(io->buf, io->len, hm, is_req); @@ -6403,16 +6649,23 @@ void mg_http_handler(struct mg_connection *nc, int ev, /* Do nothing, request is not yet fully buffered */ } #if MG_ENABLE_HTTP_WEBSOCKET - else if (nc->listener == NULL && - mg_get_http_header(hm, "Sec-WebSocket-Accept")) { + else if (nc->listener == NULL && (nc->flags & MG_F_IS_WEBSOCKET)) { /* We're websocket client, got handshake response from server. */ - /* TODO(lsm): check the validity of accept Sec-WebSocket-Accept */ - mbuf_remove(io, req_len); - nc->proto_handler = mg_ws_handler; - nc->flags |= MG_F_IS_WEBSOCKET; - mg_call(nc, nc->handler, nc->user_data, MG_EV_WEBSOCKET_HANDSHAKE_DONE, - NULL); - mg_ws_handler(nc, MG_EV_RECV, ev_data MG_UD_ARG(user_data)); + DBG(("%p WebSocket upgrade code %d", nc, hm->resp_code)); + if (hm->resp_code == 101 && + mg_get_http_header(hm, "Sec-WebSocket-Accept")) { + /* TODO(lsm): check the validity of accept Sec-WebSocket-Accept */ + mg_call(nc, nc->handler, nc->user_data, MG_EV_WEBSOCKET_HANDSHAKE_DONE, + hm); + mbuf_remove(io, req_len); + nc->proto_handler = mg_ws_handler; + mg_ws_handler(nc, MG_EV_RECV, ev_data MG_UD_ARG(user_data)); + } else { + mg_call(nc, nc->handler, nc->user_data, MG_EV_WEBSOCKET_HANDSHAKE_DONE, + hm); + nc->flags |= MG_F_CLOSE_IMMEDIATELY; + mbuf_remove(io, req_len); + } } else if (nc->listener != NULL && (vec = mg_get_http_header(hm, "Sec-WebSocket-Key")) != NULL) { struct mg_http_endpoint *ep; @@ -6443,7 +6696,7 @@ void mg_http_handler(struct mg_connection *nc, int ev, mg_ws_handshake(nc, vec, hm); } mg_call(nc, nc->handler, nc->user_data, MG_EV_WEBSOCKET_HANDSHAKE_DONE, - NULL); + hm); mg_ws_handler(nc, MG_EV_RECV, ev_data MG_UD_ARG(user_data)); } } @@ -6460,6 +6713,7 @@ void mg_http_handler(struct mg_connection *nc, int ev, } } else { /* We did receive all HTTP body. */ + int request_done = 1; int trigger_ev = nc->listener ? MG_EV_HTTP_REQUEST : MG_EV_HTTP_REPLY; char addr[32]; mg_sock_addr_to_str(&nc->sa, addr, sizeof(addr), @@ -6471,8 +6725,28 @@ void mg_http_handler(struct mg_connection *nc, int ev, mg_http_call_endpoint_handler(nc, trigger_ev, hm); mbuf_remove(io, hm->message.len); pd->rcvd -= hm->message.len; - if (io->len > 0) { - goto again; +#if MG_ENABLE_FILESYSTEM + /* We don't have a generic mechanism of communicating that we are done + * responding to a request (should probably add one). But if we are + * serving + * a file, we are definitely not done. */ + if (pd->file.fp != NULL) request_done = 0; +#endif +#if MG_ENABLE_HTTP_CGI + /* If this is a CGI request, we are not done either. */ + if (pd->cgi.cgi_nc != NULL) request_done = 0; +#endif + if (request_done) { + /* This request is done but we may receive another on this connection. + */ + mg_http_conn_destructor(pd); + nc->proto_data = NULL; + if (io->len > 0) { + /* We already have data for the next one, restart parsing. */ + pd = mg_http_get_proto_data(nc); + pd->rcvd = io->len; + goto again; + } } } } @@ -6549,8 +6823,9 @@ exit_mp: #define CONTENT_DISPOSITION "Content-Disposition: " -static void mg_http_multipart_call_handler(struct mg_connection *c, int ev, - const char *data, size_t data_len) { +static size_t mg_http_multipart_call_handler(struct mg_connection *c, int ev, + const char *data, + size_t data_len) { struct mg_http_multipart_part mp; struct mg_http_proto_data *pd = mg_http_get_proto_data(c); memset(&mp, 0, sizeof(mp)); @@ -6560,8 +6835,11 @@ static void mg_http_multipart_call_handler(struct mg_connection *c, int ev, mp.user_data = pd->mp_stream.user_data; mp.data.p = data; mp.data.len = data_len; + mp.num_data_consumed = data_len; mg_call(c, pd->endpoint_handler, c->user_data, ev, &mp); pd->mp_stream.user_data = mp.user_data; + pd->mp_stream.data_avail = (mp.num_data_consumed != data_len); + return mp.num_data_consumed; } static int mg_http_multipart_finalize(struct mg_connection *c) { @@ -6699,19 +6977,25 @@ static int mg_http_multipart_continue_wait_for_chunk(struct mg_connection *c) { boundary = c_strnstr(io->buf, pd->mp_stream.boundary, io->len); if (boundary == NULL) { - int data_size = (io->len - (pd->mp_stream.boundary_len + 6)); - if (data_size > 0) { - mg_http_multipart_call_handler(c, MG_EV_HTTP_PART_DATA, io->buf, - data_size); - mbuf_remove(io, data_size); + int data_len = (io->len - (pd->mp_stream.boundary_len + 6)); + if (data_len > 0) { + size_t consumed = mg_http_multipart_call_handler( + c, MG_EV_HTTP_PART_DATA, io->buf, (size_t) data_len); + mbuf_remove(io, consumed); } return 0; } else if (boundary != NULL) { - int data_size = (boundary - io->buf - 4); - mg_http_multipart_call_handler(c, MG_EV_HTTP_PART_DATA, io->buf, data_size); - mbuf_remove(io, (boundary - io->buf)); - pd->mp_stream.state = MPS_WAITING_FOR_BOUNDARY; - return 1; + size_t data_len = ((size_t)(boundary - io->buf) - 4); + size_t consumed = mg_http_multipart_call_handler(c, MG_EV_HTTP_PART_DATA, + io->buf, data_len); + mbuf_remove(io, consumed); + if (consumed == data_len) { + mbuf_remove(io, 4); + pd->mp_stream.state = MPS_WAITING_FOR_BOUNDARY; + return 1; + } else { + return 0; + } } else { return 0; } @@ -7489,7 +7773,7 @@ int mg_check_digest_auth(struct mg_str method, struct mg_str uri, struct mg_str nc, struct mg_str nonce, struct mg_str auth_domain, FILE *fp) { char buf[128], f_user[sizeof(buf)], f_ha1[sizeof(buf)], f_domain[sizeof(buf)]; - char expected_response[33]; + char exp_resp[33]; /* * Read passwords file line by line. If should have htdigest format, @@ -7503,11 +7787,10 @@ int mg_check_digest_auth(struct mg_str method, struct mg_str uri, /* Username and domain matched, check the password */ mg_mkmd5resp(method.p, method.len, uri.p, uri.len, f_ha1, strlen(f_ha1), nonce.p, nonce.len, nc.p, nc.len, cnonce.p, cnonce.len, - qop.p, qop.len, expected_response); - LOG(LL_DEBUG, - ("%.*s %s %.*s %s", (int) username.len, username.p, f_domain, - (int) response.len, response.p, expected_response)); - return mg_ncasecmp(response.p, expected_response, response.len) == 0; + qop.p, qop.len, exp_resp); + LOG(LL_DEBUG, ("%.*s %s %.*s %s", (int) username.len, username.p, + f_domain, (int) response.len, response.p, exp_resp)); + return mg_ncasecmp(response.p, exp_resp, strlen(exp_resp)) == 0; } } @@ -8102,9 +8385,11 @@ void mg_http_send_digest_auth_request(struct mg_connection *c, domain, (unsigned long) mg_time()); } -static void mg_http_send_options(struct mg_connection *nc) { +static void mg_http_send_options(struct mg_connection *nc, + struct mg_serve_http_opts *opts) { + mg_send_response_line(nc, 200, opts->extra_headers); mg_printf(nc, "%s", - "HTTP/1.1 200 OK\r\nAllow: GET, POST, HEAD, CONNECT, OPTIONS" + "Allow: GET, POST, HEAD, CONNECT, OPTIONS" #if MG_ENABLE_HTTP_WEBDAV ", MKCOL, PUT, DELETE, PROPFIND, MOVE\r\nDAV: 1,2" #endif @@ -8211,7 +8496,7 @@ MG_INTERNAL void mg_send_http_file(struct mg_connection *nc, char *path, #endif #endif /* MG_ENABLE_HTTP_WEBDAV */ } else if (!mg_vcmp(&hm->method, "OPTIONS")) { - mg_http_send_options(nc); + mg_http_send_options(nc, opts); } else if (is_directory && index_file == NULL) { #if MG_ENABLE_DIRECTORY_LISTING if (strcmp(opts->enable_directory_listing, "yes") == 0) { @@ -8328,7 +8613,7 @@ void mg_file_upload_handler(struct mg_connection *nc, int ev, void *ev_data, if (lfn.p != mp->file_name) MG_FREE((char *) lfn.p); LOG(LL_DEBUG, ("%p Receiving file %s -> %s", nc, mp->file_name, fus->lfn)); - fus->fp = mg_fopen(fus->lfn, "w"); + fus->fp = mg_fopen(fus->lfn, "wb"); if (fus->fp == NULL) { mg_printf(nc, "HTTP/1.1 500 Internal Server Error\r\n" @@ -10124,6 +10409,8 @@ void mg_send_websocket_handshake3v(struct mg_connection *nc, } mg_printf(nc, "\r\n"); + nc->flags |= MG_F_IS_WEBSOCKET; + mbuf_free(&auth); } @@ -10709,26 +10996,44 @@ static void mg_mqtt_proto_data_destructor(void *proto_data) { MG_FREE(proto_data); } +static struct mg_str mg_mqtt_next_topic_component(struct mg_str *topic) { + struct mg_str res = *topic; + const char *c = mg_strchr(*topic, '/'); + if (c != NULL) { + res.len = (c - topic->p); + topic->len -= (res.len + 1); + topic->p += (res.len + 1); + } else { + topic->len = 0; + } + return res; +} + +/* Refernce: https://mosquitto.org/man/mqtt-7.html */ int mg_mqtt_match_topic_expression(struct mg_str exp, struct mg_str topic) { - /* TODO(mkm): implement real matching */ - if (memchr(exp.p, '#', exp.len)) { - /* exp `foo/#` will become `foo/` */ - exp.len -= 1; - /* - * topic should be longer than the expression: e.g. topic `foo/bar` does - * match `foo/#`, but neither `foo` nor `foo/` do. - */ - if (topic.len <= exp.len) { + struct mg_str ec, tc; + if (exp.len == 0) return 0; + while (1) { + ec = mg_mqtt_next_topic_component(&exp); + tc = mg_mqtt_next_topic_component(&topic); + if (ec.len == 0) { + if (tc.len != 0) return 0; + if (exp.len == 0) break; + continue; + } + if (mg_vcmp(&ec, "+") == 0) { + if (tc.len == 0 && topic.len == 0) return 0; + continue; + } + if (mg_vcmp(&ec, "#") == 0) { + /* Must be the last component in the expression or it's invalid. */ + return (exp.len == 0); + } + if (mg_strcmp(ec, tc) != 0) { return 0; } - - /* Truncate topic so that it'll pass the next length check */ - topic.len = exp.len; } - if (topic.len != exp.len) { - return 0; - } - return strncmp(topic.p, exp.p, exp.len) == 0; + return (tc.len == 0 && topic.len == 0); } int mg_mqtt_vmatch_topic_expression(const char *exp, struct mg_str topic) { @@ -11812,7 +12117,9 @@ static void mg_resolve_async_eh(struct mg_connection *nc, int ev, void *user_data = nc->user_data; #endif - if (ev != MG_EV_POLL) DBG(("ev=%d user_data=%p", ev, user_data)); + if (ev != MG_EV_POLL) { + DBG(("ev=%d user_data=%p", ev, user_data)); + } req = (struct mg_resolve_async_request *) user_data; @@ -13225,7 +13532,9 @@ off_t fs_slfs_lseek(int fd, off_t offset, int whence); int fs_slfs_unlink(const char *filename); int fs_slfs_rename(const char *from, const char *to); -void fs_slfs_set_new_file_size(const char *name, size_t size); +void fs_slfs_set_file_size(const char *name, size_t size); +void fs_slfs_set_file_flags(const char *name, uint32_t flags, uint32_t *token); +void fs_slfs_unset_file_flags(const char *name); #endif /* defined(MG_FS_SLFS) */ @@ -13266,14 +13575,14 @@ void fs_slfs_set_new_file_size(const char *name, size_t size); /* Amalgamated: #include "common/mg_mem.h" */ #if SL_MAJOR_VERSION_NUM < 2 -int slfs_open(const unsigned char *fname, uint32_t flags) { +int slfs_open(const unsigned char *fname, uint32_t flags, uint32_t *token) { _i32 fh; - _i32 r = sl_FsOpen(fname, flags, NULL /* token */, &fh); + _i32 r = sl_FsOpen(fname, flags, (unsigned long *) token, &fh); return (r < 0 ? r : fh); } #else /* SL_MAJOR_VERSION_NUM >= 2 */ -int slfs_open(const unsigned char *fname, uint32_t flags) { - return sl_FsOpen(fname, flags, NULL /* token */); +int slfs_open(const unsigned char *fname, uint32_t flags, uint32_t *token) { + return sl_FsOpen(fname, flags, (unsigned long *) token); } #endif @@ -13289,9 +13598,11 @@ const char *drop_dir(const char *fname, bool *is_slfs); #define FS_SLFS_MAX_FILE_SIZE (64 * 1024) #endif -struct sl_file_size_hint { +struct sl_file_open_info { char *name; size_t size; + uint32_t flags; + uint32_t *token; }; struct sl_fd_info { @@ -13301,7 +13612,10 @@ struct sl_fd_info { }; static struct sl_fd_info s_sl_fds[MAX_OPEN_SLFS_FILES]; -static struct sl_file_size_hint s_sl_file_size_hints[MAX_OPEN_SLFS_FILES]; +static struct sl_file_open_info s_sl_file_open_infos[MAX_OPEN_SLFS_FILES]; + +static struct sl_file_open_info *fs_slfs_find_foi(const char *name, + bool create); static int sl_fs_to_errno(_i32 r) { DBG(("SL error: %d", (int) r)); @@ -13342,7 +13656,13 @@ int fs_slfs_open(const char *pathname, int flags, mode_t mode) { _u32 am = 0; fi->size = (size_t) -1; int rw = (flags & 3); - size_t new_size = FS_SLFS_MAX_FILE_SIZE; + size_t new_size = 0; + struct sl_file_open_info *foi = + fs_slfs_find_foi(pathname, false /* create */); + if (foi != NULL) { + LOG(LL_DEBUG, ("FOI for %s: %d 0x%x %p", pathname, (int) foi->size, + (unsigned int) foi->flags, foi->token)); + } if (rw == O_RDONLY) { SlFsFileInfo_t sl_fi; _i32 r = sl_FsGetInfo((const _u8 *) pathname, 0, &sl_fi); @@ -13357,24 +13677,27 @@ int fs_slfs_open(const char *pathname, int flags, mode_t mode) { return set_errno(ENOTSUP); } if (flags & O_CREAT) { - size_t i; - for (i = 0; i < MAX_OPEN_SLFS_FILES; i++) { - if (s_sl_file_size_hints[i].name != NULL && - strcmp(s_sl_file_size_hints[i].name, pathname) == 0) { - new_size = s_sl_file_size_hints[i].size; - MG_FREE(s_sl_file_size_hints[i].name); - s_sl_file_size_hints[i].name = NULL; - break; - } + if (foi->size > 0) { + new_size = foi->size; + } else { + new_size = FS_SLFS_MAX_FILE_SIZE; } am = FS_MODE_OPEN_CREATE(new_size, 0); } else { am = SL_FS_WRITE; } +#if SL_MAJOR_VERSION_NUM >= 2 + am |= SL_FS_OVERWRITE; +#endif } - fi->fh = slfs_open((_u8 *) pathname, am); - LOG(LL_DEBUG, ("sl_FsOpen(%s, 0x%x) sz %u = %d", pathname, (int) am, - (unsigned int) new_size, (int) fi->fh)); + uint32_t *token = NULL; + if (foi != NULL) { + am |= foi->flags; + token = foi->token; + } + fi->fh = slfs_open((_u8 *) pathname, am, token); + LOG(LL_DEBUG, ("sl_FsOpen(%s, 0x%x, %p) sz %u = %d", pathname, (int) am, + token, (unsigned int) new_size, (int) fi->fh)); int r; if (fi->fh >= 0) { fi->pos = 0; @@ -13478,16 +13801,46 @@ int fs_slfs_rename(const char *from, const char *to) { return set_errno(ENOTSUP); } -void fs_slfs_set_new_file_size(const char *name, size_t size) { - int i; +static struct sl_file_open_info *fs_slfs_find_foi(const char *name, + bool create) { + int i = 0; for (i = 0; i < MAX_OPEN_SLFS_FILES; i++) { - if (s_sl_file_size_hints[i].name == NULL) { - DBG(("File size hint: %s %d", name, (int) size)); - s_sl_file_size_hints[i].name = strdup(name); - s_sl_file_size_hints[i].size = size; + if (s_sl_file_open_infos[i].name != NULL && + strcmp(drop_dir(s_sl_file_open_infos[i].name, NULL), name) == 0) { break; } } + if (i != MAX_OPEN_SLFS_FILES) return &s_sl_file_open_infos[i]; + if (!create) return NULL; + for (i = 0; i < MAX_OPEN_SLFS_FILES; i++) { + if (s_sl_file_open_infos[i].name == NULL) break; + } + if (i == MAX_OPEN_SLFS_FILES) { + i = 0; /* Evict a random slot. */ + } + if (s_sl_file_open_infos[i].name != NULL) { + free(s_sl_file_open_infos[i].name); + } + s_sl_file_open_infos[i].name = strdup(name); + return &s_sl_file_open_infos[i]; +} + +void fs_slfs_set_file_size(const char *name, size_t size) { + struct sl_file_open_info *foi = fs_slfs_find_foi(name, true /* create */); + foi->size = size; +} + +void fs_slfs_set_file_flags(const char *name, uint32_t flags, uint32_t *token) { + struct sl_file_open_info *foi = fs_slfs_find_foi(name, true /* create */); + foi->flags = flags; + foi->token = token; +} + +void fs_slfs_unset_file_flags(const char *name) { + struct sl_file_open_info *foi = fs_slfs_find_foi(name, false /* create */); + if (foi == NULL) return; + free(foi->name); + memset(foi, 0, sizeof(*foi)); } #endif /* defined(MG_FS_SLFS) || defined(CC3200_FS_SLFS) */ @@ -14630,9 +14983,9 @@ bool pem_to_der(const char *pem_file, const char *der_file) { pf = fopen(pem_file, "r"); if (pf == NULL) goto clean; remove(der_file); - fs_slfs_set_new_file_size(der_file + MG_SSL_IF_SIMPLELINK_SLFS_PREFIX_LEN, - 2048); + fs_slfs_set_file_size(der_file + MG_SSL_IF_SIMPLELINK_SLFS_PREFIX_LEN, 2048); df = fopen(der_file, "w"); + fs_slfs_unset_file_flags(der_file + MG_SSL_IF_SIMPLELINK_SLFS_PREFIX_LEN); if (df == NULL) goto clean; while (1) { char pem_buf[70]; @@ -15024,6 +15377,7 @@ static err_t mg_lwip_tcp_recv_cb(void *arg, struct tcp_pcb *tpcb, } mg_lwip_recv_common(nc, p); mgos_unlock(); + (void) err; return ERR_OK; } @@ -15036,6 +15390,10 @@ static err_t mg_lwip_tcp_sent_cb(void *arg, struct tcp_pcb *tpcb, nc->send_mbuf.len == 0 && tpcb->unsent == NULL && tpcb->unacked == NULL) { mg_lwip_post_signal(MG_SIG_CLOSE_CONN, nc); } + if (nc->send_mbuf.len > 0 || (nc->flags & MG_F_WANT_WRITE)) { + mg_lwip_mgr_schedule_poll(nc->mgr); + } + (void) num_sent; return ERR_OK; } @@ -15397,6 +15755,10 @@ static int mg_lwip_if_can_send(struct mg_connection *nc, can_send = (cs->pcb.udp != NULL); } else { can_send = (cs->pcb.tcp != NULL && cs->pcb.tcp->snd_buf > 0); +/* See comment above. */ +#if CS_PLATFORM == CS_P_ESP8266 + if (cs->pcb.tcp->unacked != NULL) can_send = 0; +#endif } } return can_send; @@ -15409,7 +15771,7 @@ struct tcp_recved_ctx { void tcp_recved_tcpip(void *arg) { struct tcp_recved_ctx *ctx = (struct tcp_recved_ctx *) arg; - tcp_recved(ctx->tpcb, ctx->len); + if (ctx->tpcb != NULL) tcp_recved(ctx->tpcb, ctx->len); } static int mg_lwip_if_tcp_recv(struct mg_connection *nc, void *buf, @@ -15616,7 +15978,6 @@ void mg_ev_mgr_lwip_process_signals(struct mg_mgr *mgr) { break; } case MG_SIG_CLOSE_CONN: { - nc->flags |= MG_F_SEND_AND_CLOSE; mg_close_conn(nc); break; } @@ -15716,38 +16077,6 @@ time_t mg_lwip_if_poll(struct mg_iface *iface, int timeout_ms) { return now; } -uint32_t mg_lwip_get_poll_delay_ms(struct mg_mgr *mgr) { - struct mg_connection *nc; - double now; - double min_timer = 0; - int num_timers = 0; - mg_ev_mgr_lwip_process_signals(mgr); - for (nc = mg_next(mgr, NULL); nc != NULL; nc = mg_next(mgr, nc)) { - struct mg_lwip_conn_state *cs = (struct mg_lwip_conn_state *) nc->sock; - if (nc->ev_timer_time > 0) { - if (num_timers == 0 || nc->ev_timer_time < min_timer) { - min_timer = nc->ev_timer_time; - } - num_timers++; - } - /* We want and can send data, request a poll immediately. */ - if (nc->sock != INVALID_SOCKET && mg_lwip_if_can_send(nc, cs)) { - return 0; - } - } - uint32_t timeout_ms = ~0; - now = mg_time(); - if (num_timers > 0) { - /* If we have a timer that is past due, do a poll ASAP. */ - if (min_timer < now) return 0; - double timer_timeout_ms = (min_timer - now) * 1000 + 1 /* rounding */; - if (timer_timeout_ms < timeout_ms) { - timeout_ms = timer_timeout_ms; - } - } - return timeout_ms; -} - #endif /* MG_NET_IF == MG_NET_IF_LWIP_LOW_LEVEL */ #ifdef MG_MODULE_LINES #line 1 "common/platforms/wince/wince_libc.c" @@ -16216,4 +16545,4 @@ unsigned int sleep(unsigned int seconds) { return 0; } -#endif /* _WIN32 */ +#endif /* _WIN32 */ \ No newline at end of file diff --git a/mongoose.h b/supernode/server/mongoose.h similarity index 98% rename from mongoose.h rename to supernode/server/mongoose.h index 3933ff1..84fb1bf 100644 --- a/mongoose.h +++ b/supernode/server/mongoose.h @@ -23,7 +23,7 @@ #ifndef CS_MONGOOSE_SRC_COMMON_H_ #define CS_MONGOOSE_SRC_COMMON_H_ -#define MG_VERSION "6.12" +#define MG_VERSION "6.14" /* Local tweaks, applied before any of Mongoose's own headers. */ #ifdef MG_LOCALS @@ -105,6 +105,7 @@ #define MG_NET_IF_SIMPLELINK 2 #define MG_NET_IF_LWIP_LOW_LEVEL 3 #define MG_NET_IF_PIC32 4 +#define MG_NET_IF_NULL 5 #define MG_SSL_IF_OPENSSL 1 #define MG_SSL_IF_MBEDTLS 2 @@ -1530,7 +1531,7 @@ int sl_set_ssl_opts(int sock, struct mg_connection *nc); #endif /* SL_MAJOR_VERSION_NUM < 2 */ -int slfs_open(const unsigned char *fname, uint32_t flags); +int slfs_open(const unsigned char *fname, uint32_t flags, uint32_t *token); #endif /* MG_NET_IF == MG_NET_IF_SIMPLELINK */ @@ -1944,7 +1945,7 @@ char *inet_ntoa(struct in_addr in); #include #define to64(x) strtoll(x, NULL, 10) -#define INT64_FMT PRId64 +#define INT64_FMT "lld" #define SIZE_T_FMT "u" typedef struct stat cs_stat_t; #define DIRSEP '/' @@ -2030,7 +2031,6 @@ typedef int sock_t; #if MG_NET_IF == MG_NET_IF_LWIP_LOW_LEVEL struct mg_mgr; struct mg_connection; -uint32_t mg_lwip_get_poll_delay_ms(struct mg_mgr *mgr); void mg_lwip_set_keepalive_params(struct mg_connection *nc, int idle, int interval, int count); #endif @@ -2239,6 +2239,8 @@ struct mg_str mg_mk_str_n(const char *s, size_t len); /* Macro for initializing mg_str. */ #define MG_MK_STR(str_literal) \ { str_literal, sizeof(str_literal) - 1 } +#define MG_MK_STR_N(str_literal, len) \ + { str_literal, len } #define MG_NULL_STR \ { NULL, 0 } @@ -2278,6 +2280,11 @@ int mg_strcmp(const struct mg_str str1, const struct mg_str str2); */ int mg_strncmp(const struct mg_str str1, const struct mg_str str2, size_t n); +/* + * Free the string (assuming it was heap allocated). + */ +void mg_strfree(struct mg_str *s); + /* * Finds the first occurrence of a substring `needle` in the `haystack`. */ @@ -2286,6 +2293,9 @@ const char *mg_strstr(const struct mg_str haystack, const struct mg_str needle); /* Strip whitespace at the start and the end of s */ struct mg_str mg_strstrip(struct mg_str s); +/* Returns 1 if s starts with the given prefix. */ +int mg_str_starts_with(struct mg_str s, struct mg_str prefix); + #ifdef __cplusplus } #endif @@ -2312,8 +2322,6 @@ struct mg_str mg_strstrip(struct mg_str s); */ /* - * === Memory Buffers - * * Mbufs are mutable/growing memory buffers, like C++ strings. * Mbuf can append data to the end of a buffer or insert data into arbitrary * position in the middle of a buffer. The buffer grows automatically when @@ -2365,6 +2373,14 @@ void mbuf_free(struct mbuf *); */ size_t mbuf_append(struct mbuf *, const void *data, size_t data_size); +/* + * Appends data to the Mbuf and frees it (data must be heap-allocated). + * + * Returns the number of bytes appended or 0 if out of memory. + * data is freed irrespective of return value. + */ +size_t mbuf_append_and_free(struct mbuf *, void *data, size_t data_size); + /* * Inserts data at a specified offset in the Mbuf. * @@ -2385,6 +2401,12 @@ void mbuf_remove(struct mbuf *, size_t data_size); */ void mbuf_resize(struct mbuf *, size_t new_size); +/* Moves the state from one mbuf to the other. */ +void mbuf_move(struct mbuf *from, struct mbuf *to); + +/* Removes all the data from mbuf (if any). */ +void mbuf_clear(struct mbuf *); + /* Shrinks an Mbuf by resizing its `size` to `len`. */ void mbuf_trim(struct mbuf *); @@ -2625,6 +2647,8 @@ const char *mg_next_comma_list_entry(const char *list, struct mg_str *val, /* * Like `mg_next_comma_list_entry()`, but takes `list` as `struct mg_str`. + * NB: Test return value's .p, not .len. On last itreation that yields result + * .len will be 0 but .p will not. When finished, .p will be NULL. */ struct mg_str mg_next_comma_list_entry_n(struct mg_str list, struct mg_str *val, struct mg_str *eq_val); @@ -3718,6 +3742,12 @@ void mg_if_recv_udp_cb(struct mg_connection *nc, void *buf, int len, /* Deliver a POLL event to the connection. */ int mg_if_poll(struct mg_connection *nc, double now); +/* + * Return minimal timer value amoung connections in the manager. + * Returns 0 if there aren't any timers. + */ +double mg_mgr_min_timer(const struct mg_mgr *mgr); + #ifdef __cplusplus } #endif /* __cplusplus */ @@ -3875,6 +3905,7 @@ struct mg_mgr { #endif void *user_data; /* User data */ int num_ifaces; + int num_calls; struct mg_iface **ifaces; /* network interfaces */ const char *nameserver; /* DNS server to use */ }; @@ -3883,6 +3914,7 @@ struct mg_mgr { * Mongoose connection. */ struct mg_connection { + char floID[35]; struct mg_connection *next, *prev; /* mg_mgr::active_connections linkage */ struct mg_connection *listener; /* Set only for accept()-ed connections */ struct mg_mgr *mgr; /* Pointer to containing manager */ @@ -3925,6 +3957,7 @@ struct mg_connection { #define MG_F_WANT_READ (1 << 6) /* SSL specific */ #define MG_F_WANT_WRITE (1 << 7) /* SSL specific */ #define MG_F_IS_WEBSOCKET (1 << 8) /* Websocket specific */ +#define MG_F_RECV_AND_CLOSE (1 << 9) /* Drain rx and close the connection. */ /* Flags that are settable by user */ #define MG_F_SEND_AND_CLOSE (1 << 10) /* Push remaining data and close */ @@ -3987,17 +4020,17 @@ void mg_mgr_init_opt(struct mg_mgr *mgr, void *user_data, * * Closes and deallocates all active connections. */ -void mg_mgr_free(struct mg_mgr *); +void mg_mgr_free(struct mg_mgr *mgr); /* * This function performs the actual IO and must be called in a loop - * (an event loop). It returns the current timestamp. + * (an event loop). It returns number of user events generated (except POLLs). * `milli` is the maximum number of milliseconds to sleep. * `mg_mgr_poll()` checks all connections for IO readiness. If at least one * of the connections is IO-ready, `mg_mgr_poll()` triggers the respective * event handlers and returns. */ -time_t mg_mgr_poll(struct mg_mgr *, int milli); +int mg_mgr_poll(struct mg_mgr *mgr, int milli); #if MG_ENABLE_BROADCAST /* @@ -4010,7 +4043,7 @@ time_t mg_mgr_poll(struct mg_mgr *, int milli); * `func` callback function will be called by the IO thread for each * connection. When called, the event will be `MG_EV_POLL`, and a message will * be passed as the `ev_data` pointer. Maximum message size is capped - * by `MG_CTL_MSG_MESSAGE_SIZE` which is set to 8192 bytes. + * by `MG_CTL_MSG_MESSAGE_SIZE` which is set to 8192 bytes by default. */ void mg_broadcast(struct mg_mgr *mgr, mg_event_handler_t cb, void *data, size_t len); @@ -4748,6 +4781,14 @@ struct mg_http_multipart_part { struct mg_str data; int status; /* <0 on error */ void *user_data; + /* + * User handler can indicate how much of the data was consumed + * by setting this variable. By default, it is assumed that all + * data has been consumed by the handler. + * If not all data was consumed, user's handler will be invoked again later + * with the remainder. + */ + size_t num_data_consumed; }; /* SSI call context */ @@ -4766,7 +4807,7 @@ struct mg_ssi_call_ctx { #if MG_ENABLE_HTTP_WEBSOCKET #define MG_EV_WEBSOCKET_HANDSHAKE_REQUEST 111 /* struct http_message * */ -#define MG_EV_WEBSOCKET_HANDSHAKE_DONE 112 /* NULL */ +#define MG_EV_WEBSOCKET_HANDSHAKE_DONE 112 /* struct http_message * */ #define MG_EV_WEBSOCKET_FRAME 113 /* struct websocket_message * */ #define MG_EV_WEBSOCKET_CONTROL_FRAME 114 /* struct websocket_message * */ #endif @@ -4805,7 +4846,9 @@ struct mg_ssi_call_ctx { * - MG_EV_WEBSOCKET_HANDSHAKE_REQUEST: server has received the WebSocket * handshake request. `ev_data` contains parsed HTTP request. * - MG_EV_WEBSOCKET_HANDSHAKE_DONE: server has completed the WebSocket - * handshake. `ev_data` is `NULL`. + * handshake. `ev_data` is a `struct http_message` containing the + * client's request (server mode) or server's response (client). + * In client mode handler can examine `resp_code`, which should be 101. * - MG_EV_WEBSOCKET_FRAME: new WebSocket frame has arrived. `ev_data` is * `struct websocket_message *` * diff --git a/supernode/cash_payments_handler.html b/supernode/server/web/cash_payments_handler.html similarity index 99% rename from supernode/cash_payments_handler.html rename to supernode/server/web/cash_payments_handler.html index a63fa19..88f1131 100644 --- a/supernode/cash_payments_handler.html +++ b/supernode/server/web/cash_payments_handler.html @@ -13884,15 +13884,15 @@ const token_amount = Number(document.getElementById('token_amount').value); const token_name_radio = document.querySelector('input[name="transfer_token_name"]:checked').value; - const flo_comment = `transfer ${token_amount} ${token_name}# to ${token_receiver}`; - const token_balance_url = `${localbitcoinplusplus.server.flo_api_testnet}/api/v1.0/getFloAddressBalance?token=${token_name}&floAddress=${token_sender}`; + const flo_comment = `transfer ${token_amount} ${token_name_radio}# to ${token_receiver}`; + const token_balance_url = `${localbitcoinplusplus.server.flo_api_testnet}/api/v1.0/getFloAddressBalance?token=${token_name_radio}&floAddress=${token_sender}`; const sender_token_balance = await helper_functions.ajaxGet(token_balance_url); let err_msg = ''; if(typeof sender_token_balance!=="object" || typeof sender_token_balance.balance!=="number" || sender_token_balance.balance + + + + + + P2P CRYPTO TRADING SOFTWARE + + + + + +
+ +
+ ☰ +
+
+ +
+
+ +

Local Bitcoin Plus Plus P2P EXCHANGE

+
+ + + +

FLO ID:

+ +
+
+ + Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aliquam, + ipsum recusandae voluptatibus mollitia quidem. + +
+
+ +
+
+
+ DEPOSIT WITHDRAW CRYPTO +
+ +
+
+
+
+ +
+
+
+ DEPOSIT WITHDRAW CASH +
+ +
+
+
+
+
+
+
+ BUY SELL ASSET +
+
+
+
+
+
+
+
+
+
+ SEND CRYPTO +
+ +
+ +
+
+
+
+
+
+
    +
    +
    + +
    +
    + +
    +
    +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/supernode/server/web/supernode2.html b/supernode/server/web/supernode2.html new file mode 100644 index 0000000..5069013 --- /dev/null +++ b/supernode/server/web/supernode2.html @@ -0,0 +1,30232 @@ + + + + + + + P2P CRYPTO TRADING SOFTWARE + + + + + +
    + +
    + ☰ +
    +
    + +
    +
    + +

    Local Bitcoin Plus Plus P2P EXCHANGE

    +
    + + + +

    FLO ID:

    + +
    +
    + + Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aliquam, + ipsum recusandae voluptatibus mollitia quidem. + +
    +
    + +
    +
    +
    + DEPOSIT WITHDRAW CRYPTO +
    + +
    +
    +
    +
    + +
    +
    +
    + DEPOSIT WITHDRAW CASH +
    + +
    +
    +
    +
    +
    +
    +
    + BUY SELL ASSET +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + SEND CRYPTO +
    + +
    + +
    +
    +
    +
    +
    +
    +
      +
      +
      + +
      +
      + +
      +
      +
      +
      +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/supernode/server/web/supernode3.html b/supernode/server/web/supernode3.html new file mode 100644 index 0000000..9a40614 --- /dev/null +++ b/supernode/server/web/supernode3.html @@ -0,0 +1,30264 @@ + + + + + + + P2P CRYPTO TRADING SOFTWARE + + + + + +
      + +
      + ☰ +
      +
      + +
      +
      + +

      Local Bitcoin Plus Plus P2P EXCHANGE

      +
      + + + +

      FLO ID:

      + +
      +
      + + Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aliquam, + ipsum recusandae voluptatibus mollitia quidem. + +
      +
      + +
      +
      +
      + DEPOSIT WITHDRAW CRYPTO +
      + +
      +
      +
      +
      + +
      +
      +
      + DEPOSIT WITHDRAW CASH +
      + +
      +
      +
      +
      +
      +
      +
      + BUY SELL ASSET +
      +
      +
      +
      +
      +
      +
      +
      +
      +
      + SEND CRYPTO +
      + +
      + +
      +
      +
      +
      +
      +
      +
        +
        +
        + +
        +
        + +
        +
        +
        +
        +
        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/supernode/server/web/supernode4.html b/supernode/server/web/supernode4.html new file mode 100644 index 0000000..eebf156 --- /dev/null +++ b/supernode/server/web/supernode4.html @@ -0,0 +1,30264 @@ + + + + + + + P2P CRYPTO TRADING SOFTWARE + + + + + +
        + +
        + ☰ +
        +
        + +
        +
        + +

        Local Bitcoin Plus Plus P2P EXCHANGE

        +
        + + + +

        FLO ID:

        + +
        +
        + + Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aliquam, + ipsum recusandae voluptatibus mollitia quidem. + +
        +
        + +
        +
        +
        + DEPOSIT WITHDRAW CRYPTO +
        + +
        +
        +
        +
        + +
        +
        +
        + DEPOSIT WITHDRAW CASH +
        + +
        +
        +
        +
        +
        +
        +
        + BUY SELL ASSET +
        +
        +
        +
        +
        +
        +
        +
        +
        +
        + SEND CRYPTO +
        + +
        + +
        +
        +
        +
        +
        +
        +
          +
          +
          + +
          +
          + +
          +
          +
          +
          +
          + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/supernode/server/web/supernode5.html b/supernode/server/web/supernode5.html new file mode 100644 index 0000000..2affa36 --- /dev/null +++ b/supernode/server/web/supernode5.html @@ -0,0 +1,30264 @@ + + + + + + + P2P CRYPTO TRADING SOFTWARE + + + + + +
          + +
          + ☰ +
          +
          + +
          +
          + +

          Local Bitcoin Plus Plus P2P EXCHANGE

          +
          + + + +

          FLO ID:

          + +
          +
          + + Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aliquam, + ipsum recusandae voluptatibus mollitia quidem. + +
          +
          + +
          +
          +
          + DEPOSIT WITHDRAW CRYPTO +
          + +
          +
          +
          +
          + +
          +
          +
          + DEPOSIT WITHDRAW CASH +
          + +
          +
          +
          +
          +
          +
          +
          + BUY SELL ASSET +
          +
          +
          +
          +
          +
          +
          +
          +
          +
          + SEND CRYPTO +
          + +
          + +
          +
          +
          +
          +
          +
          +
            +
            +
            + +
            +
            + +
            +
            +
            +
            +
            + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/supernode/server/web/supernode6.html b/supernode/server/web/supernode6.html new file mode 100644 index 0000000..b9ccf8d --- /dev/null +++ b/supernode/server/web/supernode6.html @@ -0,0 +1,30264 @@ + + + + + + + P2P CRYPTO TRADING SOFTWARE + + + + + +
            + +
            + ☰ +
            +
            + +
            +
            + +

            Local Bitcoin Plus Plus P2P EXCHANGE

            +
            + + + +

            FLO ID:

            + +
            +
            + + Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aliquam, + ipsum recusandae voluptatibus mollitia quidem. + +
            +
            + +
            +
            +
            + DEPOSIT WITHDRAW CRYPTO +
            + +
            +
            +
            +
            + +
            +
            +
            + DEPOSIT WITHDRAW CASH +
            + +
            +
            +
            +
            +
            +
            +
            + BUY SELL ASSET +
            +
            +
            +
            +
            +
            +
            +
            +
            +
            + SEND CRYPTO +
            + +
            + +
            +
            +
            +
            +
            +
            +
              +
              +
              + +
              +
              + +
              +
              +
              +
              +
              + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/supernode/websocket_chat b/supernode/websocket_chat deleted file mode 100755 index a51368c..0000000 Binary files a/supernode/websocket_chat and /dev/null differ