Samba Client SPNEGO login failed: An invalid combination of parameters was specified - samba

I am trying to write a samba client program by making use of libsmbclient.so file. I hosted samba server on machine x and trying to access from a machine y. Even-though both are in the same work groups and I am able to successfully access from the command line smbclient tool, when I try to access from the program, I keep on getting the below error. Not able to figure out the problem, any help will be of great use. Tried searching with below error but not getting results related to SMB Client.
SPNEGO login failed: An invalid combination of parameters was specified.
Full error log is
Initilizing SMB Context... 0xf2bb20
Using netbios name SUMAN
Using workgroup WORKGROUP.
Initilizing SMB Context is successfull: 0xf2bb20.
Opening directory... smb://192.168.140.128/smbshare
parsed path: fname='smb://192.168.140.128/smbshare' server='192.168.140.128' share='smbshare' path='' options=''
SMBC_check_options(): server='192.168.140.128' share='smbshare' path='' options=''
Server: 192.168.140.128
Share: smbshare
Workgroup: WORKGROUP
Username: smbuser
Password: password
SMBC_server: server_n=[192.168.140.128] server=[192.168.140.128]
-> server_n=[192.168.140.128] server=[192.168.140.128]
Connecting to 192.168.140.128 at port 445
Socket options:
SO_KEEPALIVE = 0
SO_REUSEADDR = 0
SO_BROADCAST = 0
TCP_NODELAY = 1
TCP_KEEPCNT = 9
TCP_KEEPIDLE = 7200
TCP_KEEPINTVL = 75
IPTOS_LOWDELAY = 0
IPTOS_THROUGHPUT = 0
SO_REUSEPORT = 0
SO_SNDBUF = 87040
SO_RCVBUF = 372480
SO_SNDLOWAT = 1
SO_RCVLOWAT = 1
SO_SNDTIMEO = 0
SO_RCVTIMEO = 0
TCP_QUICKACK = 1
TCP_DEFER_ACCEPT = 0
Doing spnego session setup (blob length=74)
got OID=1.3.6.1.4.1.311.2.2.10
got principal=not_defined_in_RFC4178#please_ignore
GENSEC backend 'gssapi_spnego' registered
GENSEC backend 'gssapi_krb5' registered
GENSEC backend 'gssapi_krb5_sasl' registered
GENSEC backend 'spnego' registered
GENSEC backend 'schannel' registered
GENSEC backend 'naclrpc_as_system' registered
GENSEC backend 'sasl-EXTERNAL' registered
GENSEC backend 'ntlmssp' registered
GENSEC backend 'ntlmssp_resume_ccache' registered
GENSEC backend 'http_basic' registered
GENSEC backend 'http_ntlm' registered
GENSEC backend 'krb5' registered
GENSEC backend 'fake_gssapi_krb5' registered
SPNEGO login failed: An invalid combination of parameters was specified.
Doing spnego session setup (blob length=74)
got OID=1.3.6.1.4.1.311.2.2.10
got principal=not_defined_in_RFC4178#please_ignore
SPNEGO login failed: An invalid combination of parameters was specified.
Couldn't open SMB directory smb://192.168.140.128/smbshare: Workgroup not found
Freeing up the context.
Performing aggressive shutdown.
Context 0xf2bb20 successfully freed
Freeing parametrics:
Example program is:
#include <iostream>
using namespace std;
#include <libsmbclient.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_BUFFER_LENGTH 1024
#define SMB_WORKGROUP "WORKGROUP"
#define SMB_USERNAME "smbuser"
#define SMB_PASSWORD "password"
#define SMB_PATH "smb://192.168.140.128/smbshare"
typedef struct _SmbClientStruct
{
SMBCCTX *smbContext;
char workgroup[MAX_BUFFER_LENGTH];
char username[MAX_BUFFER_LENGTH];
char password[MAX_BUFFER_LENGTH];
int error;
} SmbClientStruct;
void
smbclient_auth_func (SMBCCTX *ctx, const char *server, const char *share, char *wrkg, int wrkglen, char *user, int userlen, char *pass, int passlen)
{
/* Given context, server and share, return workgroup, username and password.
* String lengths are the max allowable lengths. */
SmbClientStruct *state;
printf("Server: %s\n", server);
printf("Share: %s\n", share);
if (ctx == NULL || (state = (SmbClientStruct *)smbc_getOptionUserData(ctx)) == NULL) {
printf("Not able to get user data. \n");
return;
}
strncpy(wrkg, state->workgroup, (size_t)wrkglen);
strncpy(user, state->username, (size_t)userlen);
strncpy(pass, state->password, (size_t)passlen);
printf("Workgroup: %s\n", wrkg);
printf("Username: %s\n", user);
printf("Password: %s\n", pass);
}
static const char *
type_to_string (unsigned int type)
{
switch (type) {
case SMBC_WORKGROUP : return "workgroup";
case SMBC_SERVER : return "server";
case SMBC_FILE_SHARE : return "file share";
case SMBC_PRINTER_SHARE : return "printer share";
case SMBC_COMMS_SHARE : return "communication share";
case SMBC_IPC_SHARE : return "IPC share";
case SMBC_DIR : return "directory";
case SMBC_FILE : return "file";
case SMBC_LINK : return "link";
}
return "unknown";
}
int main(int argc,char *argv[])
{
SmbClientStruct stSmbClient;
memset(&stSmbClient, 0x0, sizeof(stSmbClient));
stSmbClient.smbContext = smbc_new_context();
strncpy(stSmbClient.workgroup, SMB_WORKGROUP, MAX_BUFFER_LENGTH);
strncpy(stSmbClient.username, SMB_USERNAME, MAX_BUFFER_LENGTH);
strncpy(stSmbClient.password, SMB_PASSWORD, MAX_BUFFER_LENGTH);
smbc_setDebug(stSmbClient.smbContext, atoi(argv[1]));
smbc_setOptionUserData(stSmbClient.smbContext, (void *)&stSmbClient);
smbc_setFunctionAuthDataWithContext(stSmbClient.smbContext, smbclient_auth_func);
smbc_setOptionUseNTHash(stSmbClient.smbContext, 1);
//smbc_setOptionUseKerberos(stSmbClient.smbContext, 1);
//smbc_setOptionFallbackAfterKerberos(stSmbClient.smbContext, 1);
/* Must also save a pointer to the state object inside the context, to
* find the state from the context in the auth function: */
/* Force full, modern timenames when getting xattrs: */
//smbc_setOptionFullTimeNames(stSmbClient.smbContext, 1);
/* Tell the compatibility layer to use this context */
smbc_set_context(stSmbClient.smbContext);
//Init the SMB Context
SMBCCTX *ctx;
printf("\nInitilizing SMB Context... %p\n", stSmbClient.smbContext);
if ((ctx = smbc_init_context(stSmbClient.smbContext)) != NULL) {
stSmbClient.smbContext = ctx;
printf("Initilizing SMB Context is successfull: %p.\n", stSmbClient.smbContext);
} else {
switch (stSmbClient.error = errno) {
case EBADF: printf("Couldn't init SMB context: null context given\n"); break;
case ENOMEM: printf("Couldn't init SMB context: insufficient memory\n"); break;
case ENOENT: printf("Couldn't init SMB context: cannot load smb.conf\n"); break;
default: printf("Couldn't init SMB context: unknown error (%d) (0x%X) \n", errno, errno); break;
}
return -1;
}
//Open the directory
SMBCFILE *dir;
smbc_opendir_fn smbc_opendir;
const char *path = SMB_PATH;
errno = 0;
printf("\nOpening directory... %s\n", path);
if ((smbc_opendir = smbc_getFunctionOpendir(stSmbClient.smbContext)) == NULL) {
printf("Not able to get open directory function.\n");
goto ERROR;
}
if ((dir = smbc_opendir(stSmbClient.smbContext, path)) != NULL) {
printf("Able to open the directory\n");
} else {
switch (stSmbClient.error = errno) {
case EACCES: printf("Couldn't open SMB directory %s: Permission denied\n", path); break;
case EINVAL: printf("Couldn't open SMB directory %s: Invalid URL\n", path); break;
case ENOENT: printf("Couldn't open SMB directory %s: Path does not exist\n", path); break;
case ENOMEM: printf("Couldn't open SMB directory %s: Insufficient memory\n", path); break;
case ENOTDIR: printf("Couldn't open SMB directory %s: Not a directory\n", path); break;
case EPERM: printf("Couldn't open SMB directory %s: Workgroup not found\n", path); break;
case ENODEV: printf("Couldn't open SMB directory %s: Workgroup or server not found\n", path); break;
default: printf("Couldn't open SMB directory %s: unknown error (%d) (0x%X)\n", path, errno, errno); break;
}
goto ERROR;
}
//Read directory
printf("\nReading directory...\n");
struct smbc_dirent *dirent;
smbc_readdir_fn smbc_readdir;
if ((smbc_readdir = smbc_getFunctionReaddir(stSmbClient.smbContext)) == NULL) {
printf("Not able to get read directory function.\n");
goto ERROR;
}
errno = 0;
if ((dirent = smbc_readdir(stSmbClient.smbContext, dir)) == NULL) {
switch (stSmbClient.error = errno) {
//case 0: RETURN_FALSE;
case EBADF: printf("Couldn't read " SMB_PATH ": Not a directory resource\n"); break;
case EINVAL: printf("Couldn't read " SMB_PATH ": State resource not initialized\n"); break;
default: printf("Couldn't read " SMB_PATH ": unknown error (%d)\n", errno); break;
}
goto ERROR;
}
printf("type: %s\n", type_to_string(dirent->smbc_type));
printf("comment: %s, commentlen: %d\n", dirent->comment, dirent->commentlen);
printf("name: %s, namelen: %d \n", dirent->name, dirent->namelen);
//Close directory
printf("\n Closing directory...");
smbc_closedir_fn smbc_closedir;
if ((smbc_closedir = smbc_getFunctionClosedir(stSmbClient.smbContext)) == NULL) {
printf("Not ale to get close directory function\n");
goto ERROR;
}
if (smbc_closedir(stSmbClient.smbContext, dir) == 0) {
printf("Able to close directory successfull.\n");
} else {
switch (stSmbClient.error = errno) {
case EBADF: printf("Couldn't close " SMB_PATH ": Not a directory resource\n"); break;
default: printf("Couldn't close " SMB_PATH ": unknown error (%d)\n", errno); break;
}
goto ERROR;
}
ERROR:
printf("Freeing up the context.\n");
//At the end, destroy the context
smbc_free_context(stSmbClient.smbContext, 1);
return -0;
}

This particular below line was causing the issue, after I commented out, it started working.
smbc_setOptionUseNTHash(stSmbClient.smbContext, 1);

Related

ESP32 board_POST_Error_[E][WiFiClient.cpp:258] connect(): socket error on fd 56, errno: 113, "Software caused connection abort"

I need to send HTTP POST request using ESP32 module, to my REST API server which coded using python. But when running following code, an error comes. Running on Windows 10 OS. WiFi is connecting with the module. here I need to send "A" to the REST API server.
Code - Running on VSCode PlatformIO IDE.
#include <Arduino.h>
#include <WiFi.h>
#include <HTTPClient.h>
#include <Arduino_JSON.h>
const char *ssid = "***need to fill***";
const char *password = "***need to fill***";
const char *serverName = "***need to fill***";
String sensorReadings;
String httpGETRequest(const char *serverName);
void setup()
{
Serial.begin(115200);
WiFi.begin(ssid, password);
Serial.print("Connecting to WiFi ..");
while (WiFi.status() != WL_CONNECTED)
{
Serial.print('.');
delay(1000);
}
Serial.println(WiFi.localIP());
}
void loop()
{
//Check WiFi connection status
if (WiFi.status() == WL_CONNECTED)
{
sensorReadings = httpGETRequest(serverName);
Serial.println(sensorReadings);
JSONVar myObject = JSON.parse(sensorReadings);
// JSON.typeof(jsonVar) can be used to get the type of the var
if (JSON.typeof(myObject) == "undefined")
{
Serial.println("Parsing input failed!");
return;
}
Serial.print("JSON object = ");
Serial.println(myObject);
// myObject.keys() can be used to get an array of all the keys in the object
JSONVar keys = myObject.keys();
for (int i = 0; i < keys.length(); i++)
{
JSONVar value = myObject[keys[i]];
Serial.print(keys[i]);
Serial.print(" = ");
Serial.println(value);
}
}
else
{
Serial.println("WiFi Disconnected");
}
delay(2000);
}
String httpGETRequest(const char *serverName)
{
WiFiClient client;
HTTPClient http;
// Your Domain name with URL path or IP address with path
http.begin(client, serverName);
http.addHeader("Content-Type", "application/json");
// Reading one byte from serial buffer
uint8_t buffer;
Serial.readBytes(&buffer, 1);
// Dummy data to check
// this is the hex value for
// 'A' = 0x41
buffer = 0x41;
// creating payload buff
char buff[100];
sprintf(buff, "{\"Serial_Data\": \"%c\"}", buffer);
// Send HTTP POST request
int httpResponseCode = http.POST(buff);
String payload = "{}";
if (httpResponseCode > 0)
{
Serial.print("HTTP Response code: ");
Serial.println(httpResponseCode);
payload = http.getString();
}
else
{
Serial.print("Error code: ");
Serial.println(httpResponseCode);
}
// Free resources
http.end();
return payload;
}
Error comes as below,
[E][WiFiClient.cpp:258] connect(): socket error on fd 54, errno: 113, "Software caused
connection abort"
Error code: -1
{}
JSON object = {}
Though this is very late I have an answer that could help any that will run into this problem. Follow the steps.
Make sure you are running your service on a WiFi IP that your PC and the ESP-32 are connected to. In my case, my Pc is connected to the WiFi with the IP 192.168.43.178 and I am using FastAPI, so I have the following line of code in my run.py
import unicorn
if __name__ == "__main__":
uvicorn.run("app.main:app", host="192.168.43.178", port=8080, reload=True)
Increase the delay. When the dataset is huge, the ESP-32 needs more time to send it, therefore it is necessary to increase the delay to suit your needs of the data sending.

esp32 arduino ide Web Socket stream json no errors but no values

Thank you for considering this problem.
I'm streaming a small json from a Web socket and can see the stringified json arrive to the client because it prints to the serial monitor, but then it deserializes to a 1 or 0 instead of my key:value pairs. I just want it to parse the json so that the rest of my program can use the values. I get no errors. Tried both Dynamic and Static json docs. Tried triple the memory requirement.
Arduino:
#include <WiFi.h>
#define ARDUINOJSON_ENABLE_ARDUINO_STREAM 1
#include <ArduinoJson.h>
#include <StreamUtils.h>
const char* ssid = "ssid";
const char* password = "pw";
const char* host = "10.0.0.250";
void setup()
{
Serial.begin(115200);
delay(10);
// We start by connecting to a WiFi network
int loopCount = 0;
StaticJsonDocument<384> doc;
DeserializationError error;
void loop()
{
//delay(5000);
++loopCount;
if (loopCount > 1) return;
Serial.print("connecting to ");
Serial.println(host);
// Use WiFiClient class to create TCP connections
WiFiClient client;
const int httpPort = 1337;
if (!client.connect(host, httpPort)) {
Serial.println("connection failed");
return;
}
// This will send the request to the server
client.print(String("GET ") + "HTTP/1.1\r\n" +
"Host: " + host + "\r\n" +
"Connection: close\r\n\r\n");
unsigned long timeout = millis();
while (client.available() == 0) {
if (millis() - timeout > 5000) {
Serial.println(">>> Client Timeout !");
client.stop();
return;
}
}
// Read all the lines of the reply from server and print them to Serial
while (client.available() > 0) {
ReadLoggingStream loggingClient(client, Serial);
error = deserializeJson(doc, loggingClient);
}
Serial.println("");
if (error) {
Serial.print(F("deserializeJson() failed: "));
Serial.println(error.f_str());
return;
}
//this doesn't work
int id = doc["id"]; // Should be 5 but I get 0 for every value
Serial.print("id: "); Serial.println(id);
}
/*Serial monitor:
14:21:25.905 ->
07:16:36.574 -> WiFi connected
07:16:36.574 -> IP address:
07:16:36.574 -> 10.0.0.113
07:16:36.574 -> connecting to 10.0.0.250
07:16:36.849 -> "{\"id\":5,\"nom\":\"whynot\",\"delayStart\":200,\"rampePWM\":11,\"pulseWelding\":200,\"speedBalayage\":0.4,\"speedWelding\":0.5,\"speedWire\":1.1,\"balayage\":0.8,\"pulseWire\":5,\"retractWire\":7}"
07:16:36.849 -> id: 0
*/
The tcp-socket is in my node express setup. The file projet.json is only the json seen above ^^ no white space.
var net = require('net');
var serverN = net.createServer(function(socket) {
fs.readFile("./data/projet.json", 'utf-8', (err, data) => {
if (err) {
throw err;
}
socket.write(JSON.stringify(data));
socket.pipe(socket);
});
});
serverN.listen(1337, '10.0.0.250');
I can only show you how i use it to get the right values. i use a DynamicJsonDocument in my solution:
DynamicJsonDocument root(2048);
DeserializationError err = deserializeJson(root, http.getString());
String TravelTimes = root["travelTime"];
Otherwise you can also try to output the values directly via the jsonobject
JsonObject object = doc.to<JsonObject>();
const char* id = object["id"];
The code parses the JSON string but then calls JsonDocument::to<T>() to obtain a JsonObject. This method clears the document - from https://arduinojson.org/v6/api/jsondocument/to/
Clears the JsonDocument and converts it to the specified type.
JsonDocument::as<T>() should be used instead:
JsonObject object = doc.as<JsonObject>();
From https://arduinojson.org/v6/api/jsondocument/as/
Casts JsonDocument to the specified type.
Unlike JsonDocument::to(), this function doesn’t change the content of the JsonDocument.
You can also use serializeJsonPretty() to display the JsonObject on the serial output. Instead of:
JsonObject object = doc.to<JsonObject>();
Serial.println(object);
this can be done with:
serializeJsonPretty(doc, Serial);
Thanks to bblanchon of ArduinoJson - The node socket was stringifying the json twice. I changed the socket to socket.write(data) instead of socket.write(JSON.stringify(data)) and it works.
See full explanation here
https://github.com/bblanchon/ArduinoJson/issues/1507
Thanks again!

How to fix no matching function for call in Arduino IDE?

This is my first time using Arduino IDE, and after replacing the jsonBuffer with jsonDOcument, as jsonBuffer was an older version, instructed by the jsonarduino website, and i have received the error message, "no matching function for call to 'ArduinoJson6171_91::BasicJsonDocument<ArduinoJson6171_91::DefaultAllocator>::BasicJsonDocument()'"
What should I do?
This is my code:
#include <FS.h>
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <RCSwitch.h>
#include <WiFiUdp.h>
#include <WiFiManager.h>
#include <ArduinoJson.h>
#include
#ifndef CALLBACKFUNCTION_H //this is the beginning of the callbackfunction script
#define CALLBACKFUNCTION_H
#include <Arduino.h>
typedef void (*CallbackFunction) ();
#endif //this is the end of the callbackfunction script
#ifndef SWITCH_H //this is the beginning of the switch script
#define SWITCH_H
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <WiFiUDP.h>
#include "CallbackFunction.h"
class Switch {
private:
ESP8266WebServer *server = NULL;
WiFiUDP UDP;
String serial;
String persistent_uuid;
String device_name;
unsigned int localPort;
CallbackFunction onCallback;
CallbackFunction offCallback;
void startWebServer();
void handleEventservice();
void handleUpnpControl();
void handleRoot();
void handleSetupXml();
public:
Switch();
Switch(String alexaInvokeName, unsigned int port, CallbackFunction onCallback, CallbackFunction offCallback);
~Switch();
String getAlexaInvokeName();
void serverLoop();
void respondToSearch(IPAddress& senderIP, unsigned int senderPort);
};
#endif //this is the end of the switch script
#include "switch.h"
#include "UpnpBroadcastResponder.h"
#include "CallbackFunction.h"
UpnpBroadcastResponder upnpBroadcastResponder;
Switch *alexa_switch1 = NULL;
Switch *alexa_switch2 = NULL;
Switch *alexa_switch3 = NULL;
Switch *alexa_switch4 = NULL;
Switch *alexa_switch5 = NULL;
// Callback prototypes
void alexa_switch1On();
void alexa_switch1Off();
void alexa_switch2On();
void alexa_switch2Off();
void alexa_switch3On();
void alexa_switch3Off();
void alexa_switch4On();
void alexa_switch4Off();
void alexa_switch5On();
void alexa_switch5Off();
// Set Relay Pins
int relayOne = 12;
int relayTwo = 13;
int relayThree = 14;
int relayFour = 16;
// Names each relay/outlet/device is known by -- these are set during config
char alexa_name1[100] = "1";
char alexa_name2[100] = "2";
char alexa_name3[100] = "3";
char alexa_name4[100] = "4";
char alexa_name5[100] = "5";
const char* AP_Name = "EchoBase1";
char saved_ssid[100] = "";
char saved_psk[100] = "";
// Flag for saving config data
bool shouldSaveConfig = false;
bool forceConfigPortal = false;
WiFiManager wifiManager;
// RF Tooling - https://codebender.cc/sketch:80290#RCSwitch%20-%20Transmit%20(Etekcity%20Power%20Outlets).ino
RCSwitch RFSwitch = RCSwitch();
int RF_PULSE_LENGTH = 179; // Pulse length to use for RF transmitter
int RF_TX_PIN = 0; // Digital pin connected to RF transmitter
int RF_BIT_LENGTH = 24;
// RF Signals (varies per remote controlled plugin set)
unsigned long rc_codes[5][2] = {
// ON //OFF
{5313843, 5313852}, /* Outlet 1 /
{5313987, 5313996}, / Outlet 2 /
{5314307, 5314316}, / Outlet 3 /
{335107, 335116}, / Outlet 4 /
{341251, 341260}, / Outlet 5 */
};
// Callback notifying us of the need to save config
void saveConfigCallback () {
Serial.println("Should save config");
shouldSaveConfig = true;
}
void setup()
{
Serial.begin(115200);
// -- WifiManager handling
// 5-second delay in case you wish to observe boot-up
for(int i=0; i < 5; i++) {
Serial.print(".");
delay(1000);
}
Serial.println("Booting");
// Clean FS, for testing... consider enabling if jumper is in flash mode, etc.
// SPIFFS.format();
// Set the flash/boot pin for input so we can read if the jumper is present
pinMode(0, INPUT);
// If the jumper is in "flash" mode (i.e., pin 0 is grounded), we will be enabling the config portal
forceConfigPortal = (digitalRead(0) == 0);
if(forceConfigPortal) {
Serial.println("Jumper set for flash - will trigger config portal");
} else {
Serial.println("Jumper set for boot - will attempt autoconnect, else config portal");
}
// Read configuration from FS json
Serial.println("Mounting ESP8266 integrated filesystem...");
if (SPIFFS.begin()) {
Serial.println("Mounted file system");
if (SPIFFS.exists("/config.json")) {
Serial.println("Found existing config; reading file");
File configFile = SPIFFS.open("/config.json", "r");
if (configFile) {
Serial.println("Opened config file for reading");
size_t size = configFile.size();
Serial.print("File size (bytes) = ");
Serial.println(size);
// Allocate a buffer to store contents of the file.
std::unique_ptr<char[]> buf(new char[size]);
configFile.readBytes(buf.get(), size);
DynamicJsonDocument jsonDocument;
JsonObject& json = jsonDocument.parseObject(buf.get());
Serial.println("Parsed JSON content:");
json.printTo(Serial);
Serial.println();
if (json.success()) {
strcpy(alexa_name1, json["alexa_name1"]);
strcpy(alexa_name2, json["alexa_name2"]);
strcpy(alexa_name3, json["alexa_name3"]);
strcpy(alexa_name4, json["alexa_name4"]);
strcpy(alexa_name5, json["alexa_name5"]);
Serial.println("Parsed Alexa relay name #1: " + String(alexa_name1));
Serial.println("Parsed Alexa relay name #2: " + String(alexa_name2));
Serial.println("Parsed Alexa relay name CharlesJGantt#3: " + String(alexa_name3));
Serial.println("Parsed Alexa relay name CharlesJGantt#4: " + String(alexa_name4));
Serial.println("Parsed Alexa relay name CharlesJGantt#5: " + String(alexa_name5));
} else {
Serial.println("** ERROR ** Failed to load/parse JSON config");
}
} else {
Serial.println("No JSON file found in filesystem");
}
}
} else {
Serial.println("** ERROR ** Failed to mount ESP8266's integrated filesyste,m");
}
// The extra parameters to be configured (can be either global or just in the setup)
// After connecting, parameter.getValue() will get you the configured value
// id/name placeholder/prompt default length
WiFiManagerParameter custom_alexa_name1("alexa_name1", "Device #1 name", alexa_name1, 100);
WiFiManagerParameter custom_alexa_name2("alexa_name2", "Device #2 name", alexa_name2, 100);
WiFiManagerParameter custom_alexa_name3("alexa_name3", "Device CharlesJGantt#3 name", alexa_name3, 100);
WiFiManagerParameter custom_alexa_name4("alexa_name4", "Device CharlesJGantt#4 name", alexa_name4, 100);
WiFiManagerParameter custom_alexa_name5("alexa_name5", "Device CharlesJGantt#5 name", alexa_name5, 100);
// Set the function that will be called to save the custom parameter after config
wifiManager.setSaveConfigCallback(saveConfigCallback);
// Hand the parameter defintions to the WifiManager for use during config
wifiManager.addParameter(&custom_alexa_name1);
wifiManager.addParameter(&custom_alexa_name2);
wifiManager.addParameter(&custom_alexa_name3);
wifiManager.addParameter(&custom_alexa_name4);
wifiManager.addParameter(&custom_alexa_name5);
//reset settings - for testing
//wifiManager.resetSettings();
//set minimu quality of signal so it ignores AP's under that quality
//defaults to 8%
//wifiManager.setMinimumSignalQuality();
//sets timeout until configuration portal gets turned off
//useful to make it all retry or go to sleep
//in seconds
//wifiManager.setTimeout(120);
if(forceConfigPortal) {
wifiManager.setSTAStaticIPConfig(IPAddress(10,0,1,99), IPAddress(10,0,1,1), IPAddress(255,255,255,0));
// Force config portal while jumper is set for flashing
if (!wifiManager.startConfigPortal(AP_Name)) {
Serial.println("** ERROR ** Failed to connect with new config / possibly hit config portal timeout; Resetting in 3sec...");
delay(3000);
//reset and try again, or maybe put it to deep sleep
ESP.reset();
delay(5000);
}
} else {
// Autoconnect if we can
// Fetches ssid and pass and tries to connect; if it does not connect it starts an access point with the specified name
// and goes into a blocking loop awaiting configuration
if (!wifiManager.autoConnect(AP_Name)) {
Serial.println("** ERROR ** Failed to connect with new config / possibly hit timeout; Resetting in 3sec...");
delay(3000);
//reset and try again, or maybe put it to deep sleep
ESP.reset();
delay(5000);
}
}
// --- If you get here you have connected to the WiFi ---
Serial.println("Connected to wifi");
// Save the connect info in case we need to reconnect
WiFi.SSID().toCharArray(saved_ssid, 100);
WiFi.psk().toCharArray(saved_psk, 100);
// Read updated parameters
strcpy(alexa_name1, custom_alexa_name1.getValue());
strcpy(alexa_name2, custom_alexa_name2.getValue());
strcpy(alexa_name3, custom_alexa_name3.getValue());
strcpy(alexa_name4, custom_alexa_name4.getValue());
strcpy(alexa_name5, custom_alexa_name5.getValue());
Serial.println("Read configured Alexa relay name #1: " + String(alexa_name1));
Serial.println("Read configured Alexa relay name #2: " + String(alexa_name2));
Serial.println("Read configured Alexa relay name CharlesJGantt#3: " + String(alexa_name3));
Serial.println("Read configured Alexa relay name CharlesJGantt#4: " + String(alexa_name4));
Serial.println("Read configured Alexa relay name CharlesJGantt#5: " + String(alexa_name5));
// Save the custom parameters to the ESP8266 filesystem if changed
if (shouldSaveConfig) {
Serial.println("Saving config to ESP8266 filesystem");
DynamicJsonDocument jsonDocument;
JsonObject& json = jsonDocument.createObject();
json["alexa_name1"] = alexa_name1;
json["alexa_name2"] = alexa_name2;
json["alexa_name3"] = alexa_name3;
json["alexa_name4"] = alexa_name4;
json["alexa_name5"] = alexa_name5;
Serial.println("Attempting to open config JSON file for writing");
File configFile = SPIFFS.open("/config.json", "w");
if (!configFile) {
Serial.println("** ERROR ** Failed to open JSON config file for writing");
} else {
json.printTo(Serial);
Serial.println();
json.printTo(configFile);
configFile.close();
Serial.println("File write complete");
}
}
Serial.print("SSID: " );
Serial.println(WiFi.SSID());
Serial.print("Local IP: ");
Serial.println(WiFi.localIP());
// -- ALEXA setup/handling --
upnpBroadcastResponder.beginUdpMulticast();
// Define your switches here. Max 14
// Format: Alexa invocation name, local port no, on callback, off callback
alexa_switch1 = new Switch(alexa_name1, 80, alexa_switch1On, alexa_switch1Off);
alexa_switch2 = new Switch(alexa_name2, 81, alexa_switch2On, alexa_switch2Off);
alexa_switch3 = new Switch(alexa_name3, 82, alexa_switch3On, alexa_switch3Off);
alexa_switch4 = new Switch(alexa_name4, 83, alexa_switch4On, alexa_switch4Off);
alexa_switch5 = new Switch(alexa_name5, 85, alexa_switch5On, alexa_switch5Off);
Serial.println("Adding switches upnp broadcast responder");
upnpBroadcastResponder.addDevice(*alexa_switch1);
upnpBroadcastResponder.addDevice(*alexa_switch2);
upnpBroadcastResponder.addDevice(*alexa_switch3);
upnpBroadcastResponder.addDevice(*alexa_switch4);
upnpBroadcastResponder.addDevice(*alexa_switch5);
// Setup RF Transmitter
RFSwitch.enableTransmit(RF_TX_PIN);
RFSwitch.setPulseLength(RF_PULSE_LENGTH);
}
/* If disconnected from Wifi, enter a blocking loop that periodically attempts reconnection */
void reconnectIfNecessary() {
while(WiFi.status() != WL_CONNECTED) {
Serial.println("Disconnected; Attempting reconnect to " + String(saved_ssid) + "...");
WiFi.disconnect();
WiFi.mode(WIFI_AP_STA);
WiFi.begin(saved_ssid, saved_psk);
// Output reconnection status info every second over the next 10 sec
for( int i = 0; i < 10 ; i++ ) {
delay(1000);
Serial.print("WiFi status = ");
if( WiFi.status() == WL_CONNECTED ) {
Serial.println("Connected");
break;
} else {
Serial.println("Disconnected");
}
}
if(WiFi.status() != WL_CONNECTED) {
Serial.println("Failure to establish connection after 10 sec. Will reattempt connection in 2 sec");
delay(2000);
}
}
}
void loop()
{
// Ensure wifi is connected (won't return until it has connected)
reconnectIfNecessary();
// Respond to any Alexa/discovery requests
upnpBroadcastResponder.serverLoop();
// Respond to any UPnP control requests
alexa_switch1->serverLoop();
alexa_switch2->serverLoop();
alexa_switch3->serverLoop();
alexa_switch4->serverLoop();
alexa_switch5->serverLoop();
}
void alexa_switch1On() {
Serial.println("Switch 1 turn on ...");
enableOutlet(1, true);
}
void alexa_switch1Off() {
Serial.println("Switch 1 turn off ...");
enableOutlet(1, false);
}
void alexa_switch2On() {
Serial.println("Switch 2 turn on ...");
enableOutlet(2, true);
}
void alexa_switch2Off() {
Serial.println("Switch 2 turn off ...");
enableOutlet(2, false);
}
void alexa_switch3On() {
Serial.println("Switch 3 turn on ...");
enableOutlet(3, true);
}
void alexa_switch3Off() {
Serial.println("Switch 3 turn off ...");
enableOutlet(3, false);
}
void alexa_switch4On() {
Serial.println("Switch 4 turn on ...");
enableOutlet(4, true);
}
void alexa_switch4Off() {
Serial.println("Switch 4 turn off ...");
enableOutlet(4, false);
}
void alexa_switch5On() {
Serial.println("Switch 5 turn on ...");
enableOutlet(5, true);
}
void alexa_switch5Off() {
Serial.println("Switch 5 turn off ...");
enableOutlet(5, false);
}
void enableOutlet(int outletNumber, bool onOrOff)
{
if (outletNumber < 1 || outletNumber > 5) {
Serial.println("Invalid outlet number");
return;
}
unsigned long *onOffCodes = rc_codes[outletNumber - 1];
unsigned long codeToSend = onOffCodes[onOrOff ? 0 : 1];
RFSwitch.send(codeToSend, RF_BIT_LENGTH);
char outletNumberString[1];
int retVal = snprintf(outletNumberString, 1, "%d", outletNumber);
if (retVal < 0) {
Serial.println("Log encoding error");
return;
}
Serial.print("Switch " + String(outletNumber) + " turned ");
if (onOrOff) {
Serial.println("on");
} else {
Serial.println("off");
}
}

How to get the URL from a localhost server without using libcurl

I've made a custom HTTP server that serves an HTML page with some text, an input text box for entering a command, and a submit button. Upon receiving a form submission, the server is supposed to run the given command and serve a response containing the results.
The issue I cant quite figure out is how to get the URLs of form submission requests so as to parse out the command to run. As presently implemented, the server runs on localhost:3838, and when the client browses to that URL the server responds correctly with the form. When the user enters (say) the command ls in the text box and clicks the "run" submission button, a request is issued to localhost:3838/run?command=ls. How can I obtain that URL in the server, so as to parse out and execute the command?
Here's the present server code:
CwebServer.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <signal.h>
#define PORT "3838" //port being connected to
#define MAXLEN 800
#define BACKLOG 10 //number of pending connections to be held in queue
//format of html page
char header []=
"HTTP/1.1 200 Ok\r\n"
"Content-Type: text/html; charset=UTF-8\r\n\r\n"
"<!DOCTYPE html>\r\n"
"<html>\n"
"<head>\n"
"<title>Web-Based Remote Command Server</title>\r\n"
"</head>\n"
"<body>\n\n";
char input []=
"<form action= \"/run\" method= \"GET\"> \n"
"Command: <input type=\"text\" size=\"100\" name=\"command\">\n"
"<input type=\"submit\" value=\"Run\">\n"
"</form>";
char output []=
"<p>Command that was run and testing this:</p>\n"
"<pre>Your server will include the command that was just run here.</pre>\n\n"
"<p>Standard Output:</p>\n""<pre>Your server will include the stdout results here.</pre>\n\n"
"<p>Standard Error:</p>\n"
"<pre>Your server will include the stderr results here.</pre>\r\n\r\n"
"</body>\r\n""</html>\r\n";
char *buff = header;
void sigchld_handler(int s)
{
(void)s; // quiet unused variable warning
// waitpid() might overwrite errno, so we save and restore it:
int saved_errno = errno;
while(waitpid(-1, NULL, WNOHANG) > 0);
errno = saved_errno;
}
void *get_in_addr(struct sockaddr *sa)
{
if (sa->sa_family == AF_INET) {
return &(((struct sockaddr_in*)sa)->sin_addr);
}
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
int main (void){
int sockfd;
int new_fd;
struct addrinfo hints;
struct addrinfo *serverinfo;
struct addrinfo *p;
struct sockaddr_storage client_addr;
socklen_t addrsize;
struct sigaction sa;
int yes = 1;
char s[INET6_ADDRSTRLEN];
int status;
memset(&hints, 0, sizeof hints); //makes struct empty
hints.ai_family = AF_UNSPEC; //IPv4 or v6
hints.ai_socktype = SOCK_STREAM; //TCP type need
hints.ai_flags = AI_PASSIVE; //Fill in IP for us
//if can't get address info print error
if((status = getaddrinfo(NULL, PORT, &hints, &serverinfo)) != 0){
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(status));
return 1;
}
for(p = serverinfo; p != NULL; p = p->ai_next){
if((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1){
perror("server: socket");
continue;
}
if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1){
perror("setsockopt");
exit(1);
}
if(bind(sockfd, p->ai_addr, p->ai_addrlen) == -1){
close(sockfd);
perror("server: bind");
continue;
}
break;
}
freeaddrinfo(serverinfo);
if(p == NULL){
fprintf(stderr, "server: failed to bind\n");
exit(1);
}
if(listen(sockfd, BACKLOG) == -1){
perror("listen");
exit(1);
}
sa.sa_handler = sigchld_handler; // reap all dead processes
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
if (sigaction(SIGCHLD, &sa, NULL) == -1) {
perror("sigaction");
exit(1);
}
printf("server: waiting for connections....\n");
while(1){
addrsize = sizeof client_addr;
new_fd = accept(sockfd, (struct sockaddr *)&client_addr, &addrsize);
if(new_fd == -1){
perror("Did not accept");
continue;
}
inet_ntop(client_addr.ss_family, get_in_addr((struct sockaddr *)&client_addr), s, sizeof s);
printf("server: got connection from %s\n", s);
if(!fork()){
close(sockfd);
int bufsize = 1024;
char *buffer = malloc(bufsize);
send(new_fd, header, bufsize, 0);
//write(new_fd, "HTTP/1.1 200 OK\n", 16);
//write(new_fd, "Content-length: 46\n", 19);
//write(new_fd, "Content-type: text/html\n\n", 25);
//write(new_fd, "<html><head>\n<head>\n<title>The CAvengers Web Page</title>\n</head>\n</html>", 46);
if(send(new_fd, buffer, MAXLEN, 0) == -1)
perror("send");
close(new_fd);
exit(0);
}
close(new_fd);
}
return 0;
}
Web servers and clients communicate via the HTTP protocol. That's what makes them web servers as opposed to some other kind. HTTP is a request / response protocol: the client sends a request to the server that contains information about what it's requesting, and the server processes that request to determine how to respond.
Your particular server seems to intend to implement HTTP 1.1. This is not the most recent version of the protocol, but that's ok. Pretty much every HTTP client in the world understands that dialect. But yours is a pretty minimally-functioning server, responding to every established connection with the same HTTP response, even if the client does not actually send an HTTP request.
Your question is how to get the request URI. The answer is to read it from the client, via the connected socket returned by accept(). The read() or recv() function would be appropos for that. The format you should expect the client to use is described in the HTTP specifications I linked above, but in very brief, you should expect the request to start with the request method name (GET), at least one space, the request URI, and a carriage-return / linefeed pair. You will need to parse the request URI to distinguish between an initial request for the form and a form submission, and in the latter case you will be able to parse the query parameters as well.
DO NOTE, however, that although HTTP is a comparatively simple protocol, it is still much more complicated than I've just described.

Get HTML of url link with Visual Studio

The code below works for the main site, but it does not work for the sub-links. For example, the code works when the url link is "www.reddit.com" or "www.wikipedia.org" but it will not work when it is "www.reddit.com/r/nba" or "www.wikipedia.org/wiki/2007_NASCAR_Nextel_Cup_Series" Do you know how to make it work to include sub-links as well?
#include "stdafx.h"
#include <winsock2.h>
#include <WS2tcpip.h>
#include <windows.h>
#include <iostream>
#pragma comment(lib,"ws2_32.lib")
using namespace std;
int main(){
// Initialize Dependencies to the Windows Socket.
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
cout << "WSAStartup failed.\n";
system("pause");
return -1;
}
// We first prepare some "hints" for the "getaddrinfo" function
// to tell it, that we are looking for a IPv4 TCP Connection.
struct addrinfo hints;
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET; // We are targeting IPv4
hints.ai_protocol = IPPROTO_TCP; // We are targeting TCP
hints.ai_socktype = SOCK_STREAM; // We are targeting TCP so its SOCK_STREAM
// Aquiring of the IPv4 address of a host using the newer
// "getaddrinfo" function which outdated "gethostbyname".
// It will search for IPv4 addresses using the TCP-Protocol.
struct addrinfo* targetAdressInfo = NULL;
DWORD getAddrRes = getaddrinfo("www.wikipedia.org/wiki/2007_NASCAR_Nextel_Cup_Series", NULL, &hints, &targetAdressInfo);
if (getAddrRes != 0 || targetAdressInfo == NULL)
{
cout << "Could not resolve the Host Name" << endl;
system("pause");
WSACleanup();
return -1;
}
// Create the Socket Address Informations, using IPv4
// We dont have to take care of sin_zero, it is only used to extend the length of SOCKADDR_IN to the size of SOCKADDR
SOCKADDR_IN sockAddr;
sockAddr.sin_addr = ((struct sockaddr_in*) targetAdressInfo->ai_addr)->sin_addr; // The IPv4 Address from the Address Resolution Result
sockAddr.sin_family = AF_INET; // IPv4
sockAddr.sin_port = htons(80); // HTTP Port: 80
// We have to free the Address-Information from getaddrinfo again
freeaddrinfo(targetAdressInfo);
// Creation of a socket for the communication with the Web Server,
// using IPv4 and the TCP-Protocol
SOCKET webSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (webSocket == INVALID_SOCKET)
{
cout << "Creation of the Socket Failed" << endl;
system("pause");
WSACleanup();
return -1;
}
// Establishing a connection to the web Socket
cout << "Connecting...\n";
if (connect(webSocket, (SOCKADDR*)&sockAddr, sizeof(sockAddr)) != 0)
{
cout << "Could not connect";
system("pause");
closesocket(webSocket);
WSACleanup();
return -1;
}
cout << "Connected.\n";
// Sending a HTTP-GET-Request to the Web Server
const char* httpRequest = "GET / HTTP/1.1\r\nHost: www.google.com\r\nConnection: close\r\n\r\n";
int sentBytes = send(webSocket, httpRequest, strlen(httpRequest), 0);
if (sentBytes < strlen(httpRequest) || sentBytes == SOCKET_ERROR)
{
cout << "Could not send the request to the Server" << endl;
system("pause");
closesocket(webSocket);
WSACleanup();
return -1;
}
// Receiving and Displaying an answer from the Web Server
char buffer[10000];
ZeroMemory(buffer, sizeof(buffer));
int dataLen;
while ((dataLen = recv(webSocket, buffer, sizeof(buffer), 0) > 0))
{
int i = 0;
while (buffer[i] >= 32 || buffer[i] == '\n' || buffer[i] == '\r') {
cout << buffer[i];
i += 1;
}
}
// Cleaning up Windows Socket Dependencies
closesocket(webSocket);
WSACleanup();
system("pause");
return 0;
}
You have to replace your GET / with GET /path/you/want/to/access.html and leave the server name as www.wikipedia.org but for heavens sake use WinHttpClient or Curl or something else more hi-level.
A URL is built by protocol, host and link. e.g. protocol://host/link --> http://www.wikipedia.org/wiki/2007_NASCAR_Nextel_Cup_Series. Here, http is the protocol, www.wikipedia.org is the host and /wiki/2007_NASCAR_Nextel_Cup_Series is the link.
Web Browsers internally split those parts up and then establish a Connection. e.g
http --> use port 80
www.wikipedia.org --> search for host and establish Connection
link (Here Comes the interesting part) --> Send the link through the TCP Connection as header
With a raw TCP Connection you can't directly open URL liks, you Need to send the link through the TCP Connection as Header. Or you use the Standart WebClients which do it for you.
I think the ultimate Problem is that you are trying to establish a TCP Connection with the entire URL instead of just the host.