GRPC Objective-C not calling handler on response - objective-c

I'm running into an issue where I'm sending the message to the server (golang) but the response is not getting to the client (objective-c). To be clear, I see the log statement from the server with the correct message from the client. However, I don't see the response on the client. Furthermore, I've noticed that if my server is shutdown, the client does not have any issues getting to the same wait(), but that may be just my lack of understanding of the API. One important thing to note is that I'm not using cocopods or any other build tool for the client. As a learning exercise I'm attempting to build directly against the grpc objective-c source. I've attached my Makefile. Take note of the GRPC_CLIENT_SOURCE variable in the Makefile. I've had to do that as there are header files included there that do not exist in the grpc repo. That "feels" like where the problem is but I've learning that my feelings were useless through the years.
Many thanks in advance!
Here is my code:
Server:
package main
import (
"context"
"log"
"net"
"github.com/asharif/chatterbox/pb"
"google.golang.org/grpc"
)
// UserService is used for creating accounts and logins
type UserService struct{}
func main() {
initLogger()
startServer()
}
func initLogger() {
log.SetFlags(log.Ldate | log.Ltime | log.Lmicroseconds | log.Llongfile)
}
func startServer() {
log.Println("Starting server on port 9000")
lis, err := net.Listen("tcp", ":9000")
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
s := grpc.NewServer()
pb.RegisterUserServiceServer(s, &UserService{})
if err := s.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}
// Create creates a new user
func (i *UserService) Create(ctx context.Context, req *pb.Request) (*pb.Response, error) {
log.Printf("Received: %v", req.Username)
return &pb.Response{Success: true, Msg: "Hello from server"}, nil
}
// Login attempts a login
func (i *UserService) Login(ctx context.Context, req *pb.Request) (*pb.Response, error) {
return &pb.Response{Success: true, Msg: "Hello "}, nil
}
Client:
#import <Foundation/Foundation.h>
#import "pb/User.pbobjc.h"
#import "pb/User.pbrpc.h"
int main (int argc, const char * argv[]) {
#autoreleasepool {
NSString* host = #"localhost:9000";
[GRPCCall useInsecureConnectionsForHost:host];
UserService* client = [[UserService alloc] initWithHost:host];
Request* req = [Request message];
req.username = #"yo from obj-c";
NSLog(#"callling server yo...");
NSCondition* cond = [[NSCondition alloc] init];
__block BOOL done = NO;
[client createWithRequest:req handler:^(Response *response, NSError *error) {
if (response) {
// Successful response received
NSLog(#"YES");
} else {
// RPC error
NSLog(#"GAH");
}
[cond lock];
done=YES;
[cond signal];
[cond unlock];
}];
[cond lock];
while(!done)
[cond wait];
[cond unlock];
}
return 0;
}
Makefile:
SHELL:=/bin/bash
VERSION:=local
BIN_DIR:=bin
# Protobuf stuff
PB_SOURCE_DIR:=/opt/protobuf/objectivec/
PB_SOURCE:=$(PB_SOURCE_DIR)/GPBProtocolBuffers.m
PB_DIR:=`pwd`/src/protobuf
PB_DEF_DIR:=`pwd`/src/protobuf/def
DEF:=$(shell find $(PB_DEF_DIR) -name '*.proto')
PB:=$(patsubst %.proto, %.pb, $(DEF))
# GRPC stuff
GRPC_SOURCE_DIR:=/opt/grpc/src/objective-c
GRPC_INC:=-I $(GRPC_SOURCE_DIR)
GRPC_CLIENT_SOURCE:=$(GRPC_SOURCE_DIR)/GRPCClient/GRPCCall.m $(GRPC_SOURCE_DIR)/GRPCClient/GRPCCallOptions.m $(GRPC_SOURCE_DIR)/GRPCClient/private/GRPCCallInternal.m $(GRPC_SOURCE_DIR)/GRPCClient/GRPCInterceptor.m $(GRPC_SOURCE_DIR)/GRPCClient/private/GRPCChannelPool.m $(GRPC_SOURCE_DIR)/GRPCClient/private/GRPCChannel.m $(GRPC_SOURCE_DIR)/GRPCClient/private/GRPCCompletionQueue.m $(GRPC_SOURCE_DIR)/GRPCClient/private/GRPCCronetChannelFactory.m $(GRPC_SOURCE_DIR)/GRPCClient/GRPCCall+ChannelCredentials.m $(GRPC_SOURCE_DIR)/GRPCClient/private/GRPCHost.m $(GRPC_SOURCE_DIR)/GRPCClient/private/GRPCInsecureChannelFactory.m $(GRPC_SOURCE_DIR)/GRPCClient/private/ChannelArgsUtil.m $(GRPC_SOURCE_DIR)/GRPCClient/private/GRPCWrappedCall.m $(GRPC_SOURCE_DIR)/GRPCClient/private/GRPCRequestHeaders.m $(GRPC_SOURCE_DIR)/GRPCClient/private/GRPCSecureChannelFactory.m $(GRPC_SOURCE_DIR)/GRPCClient/private/NSError+GRPC.m $(GRPC_SOURCE_DIR)/GRPCClient/GRPCCall+Interceptor.m $(GRPC_SOURCE_DIR)/GRPCClient/private/NSDictionary+GRPC.m $(GRPC_SOURCE_DIR)/GRPCClient/private/NSData+GRPC.m $(GRPC_SOURCE_DIR)/GRPCClient/GRPCCall+Tests.m
GRPC_PROTORPC_SOURCE:=$(shell find $(GRPC_SOURCE_DIR)/ProtoRPC -name '*.m')
GRPC_RXLIBRARY_SOURCE:=$(shell find $(GRPC_SOURCE_DIR)/RxLibrary -name '*.m')
GRPC_CLIENT_OBJ:=$(patsubst %.m, %.o, $(GRPC_CLIENT_SOURCE))
GRPC_PROTORPC_OBJ:=$(patsubst %.m, %.o, $(GRPC_PROTORPC_SOURCE))
GRPC_RXLIBRARY_OBJ:=$(patsubst %.m, %.o, $(GRPC_RXLIBRARY_SOURCE))
# Server stuff
SERVER_DIR:=`pwd`/src/server
SERVER_PB_DIR:=$(SERVER_DIR)/pb
SERVER_BIN:=$(shell basename $(CURDIR))-server
# Client stuff
CC:=clang
grpc: CFLAGS:=-fobjc-arc
PB_OBJ:=$(patsubst %.m, %.o, $(PB_SOURCE))
CLIENT_DIR:=`pwd`/src/client
CLIENT_PB_DIR:=$(CLIENT_DIR)/pb
CLIENT_INC:=-I $(PB_SOURCE_DIR) $(GRPC_INC)
CLIENT_LIBS:=-lgrpc
CLIENT_SOURCE:=$(shell find $(CLIENT_DIR) -name '*.m')
CLIENT_OBJ:=$(patsubst %.m, %.o, $(CLIENT_SOURCE))
CLIENT_FRAMEWORKS:=-framework Foundation
CLIENT_OBJ_DIR:=$(CLIENT_DIR)/obj
CLIENT_BIN:=$(shell basename $(CURDIR))-client
# Build the protobuf dist
protobuf: $(PB)
#mv $(PB_DIR)/*.go $(SERVER_PB_DIR)
#mv $(PB_DIR)/*.h $(CLIENT_PB_DIR)
#mv $(PB_DIR)/*.m $(CLIENT_PB_DIR)
%.pb : %.proto
#protoc -I $(PB_DEF_DIR) $< --go_out=plugins=grpc:$(PB_DIR)
#protoc -I $(PB_DEF_DIR) $< --objc_out=$(PB_DIR) --objcgrpc_out=$(PB_DIR)
# Build the server
server:
#mkdir -p $(BIN_DIR)
#cd src/server/; go build -o ../../$(BIN_DIR)/$(SERVER_BIN)-$(VERSION)
# Build the client
client: |dir pb grpc $(CLIENT_OBJ)
#mv *.o $(CLIENT_OBJ_DIR)
#$(CC) $(CFLAGS) $(CLIENT_FRAMEWORKS) $(CLIENT_LIBS) -o $(BIN_DIR)/$(CLIENT_BIN)-$(VERSION) $(CLIENT_OBJ_DIR)/**
pb: $(PB_OBJ)
grpc: $(GRPC_PROTORPC_OBJ) $(GRPC_CLIENT_OBJ) $(GRPC_RXLIBRARY_OBJ)
%.o: %.m
$(CC) $(CFLAGS) -c $(CLIENT_INC) $<
dir:
#mkdir -p $(BIN_DIR)
#mkdir -p $(CLIENT_OBJ_DIR)
clean:
#rm -f bin/*
#rm -f src/server/pb/**
#rm -f src/client/pb/**
#for i in `find . -iname "*.o"`; do rm $$i; done;
#for i in `find $(PB_SOURCE_DIR)/ -iname "*.o"`; do rm $$i; done;

GRPC puts your handler methods in dispatch_queue. You need to process your dispatch queue since your are using a command line application.
Just replace return 0 with dispatch_main() and you should be able to get into your handler.
Once you used dispatch_main() your program has no idea if all the handlers are processed or not so it blocks forever. You can do this to exit your program normally once all your handlers has been processed.
// create a dispatch group
dispatch_group_t serviceGroup = dispatch_group_create();
dispatch_group_enter(serviceGroup);
[client createWithRequest:req handler:^(Response *response, NSError *error) {
...
dispatch_group_leave(serviceGroup);
}];
...
// exit once the main queue is dispatched
dispatch_group_notify(serviceGroup, dispatch_get_main_queue(), ^{
exit(EXIT_SUCCESS);
});
This is the link to another example.

Related

How do I ensure the pty associated with an ssh connection in expect is closed properly?

I have an expect script running on a raspberry pi, connecting via ssh to another box, running a few commands, and then logging out. This is supposed to then run a million times over a few days. The script however crashes consistantly after about 8000 iterations with the following error:
Connection no: 8303
Error message: The system has no more ptys. Ask your system administrator to create more.
Error info:
The system has no more ptys. Ask your system administrator to create more.
while executing
"spawn ssh testuser#$ip_addr"
(procedure "login_root" line 17)
invoked from within
"login_root "0.0.0.0" session1"
The script is as follows:
#!/usr/bin/expect -f
#run file using nohup scriptname > /dev/null & for background running
source "~/expect_scripts/expect_commands.sh"
for {set i 0} {$i < 1000000} {incr i} {
if {[catch {
send_user "******************************************$i\n"
set ret [login_root "0.0.0.0" session1 pty1]
set ret [report_folder_size "/tmp"]
send_cmd "logout\"
close $session1
#close -slave pty1
} errmsg]} {
#handle error messages here
set outFileId [open $outputFilename "a"]
puts -nonewline $outFileId "Connection no: $i \nError message: $errmsg\n"
puts -nonewline $outFileId "Error info: \n\n$errorInfo\n\n"
}
}
And the relevant login_root function from commandss.sh:
proc login_root { ip_addr session_id pty_id {tout 30}} {
global spawn_id
global connection_stack
global root_prompt
global root_password
global testuser_password
global testuser
global test_prompt
upvar $session_id sess_id
upvar $pty_id ptyID
set timeout $tout
if {[info exists spawn_id]} {
set current_spawn_id $spawn_id
send_user "\n***DEBUG: current_spawn_id = $current_spawn_id\n"
set ret [spawn ssh testuser#$ip_addr]
if { $ret == 0 } {
send_user "\n***DEBUG: login_root: spawn failed\n"
set spawn_id $current_spawn_id
return 1
} else {
set ptyID spawn_out(slave,fd)
}
} else {
send_user "\n***DEBUG: spawn_id doesn exist yet (no session opened yet)\n"
set ret [spawn ssh testuser#$ip_addr]
if { $ret == 0 } {
send_user "\n***DEBUG: login_root: spawn failed\n"
return 1
} else {
set ptyID spawn_out(slave,fd)
}
}
expect {
timeout { # We timed out
send_user "\n***DEBUG: login_root: timed out. popped to spawn_id = $spawn_id\n"
return 1
}
"(yes/no)?" { # This is a new target
send "yes\n"
exp_continue
}
"testuser#0.0.0.0's password" {
send "$testuser_password\n"
exp_continue
}
"$root_prompt" { # All done - success
set sess_id $spawn_id
return 0
}
default { # We got an unexpected response
send_user "\n***DEBUG: login_root: Login failed. popped to spawn_id = $spawn_id\n"
return 1
}
}
set sess_id $spawn_id
return 0
}
I have checked and found that kernal/pty/max is 4k, half of the 8k connections I am getting through. the line "close -slave" or "close -slave pty1" is an attempt to ensure the pty associated with the ssh connection created by spawn ssh is closed properly, but it errors out every time saying
testuser# cannot find channel named "-slave"
while executing
"close -slave $pty1"

Why doesnt client.connect accept a full adress

i am trying to write a piece of code in which the ESP32 connect securely to my api-server and post some sensor data. For this i use the WifiClientSecure library.
Through trial and error i have found out that client.connect(www.myserver.com, 443); works.
But client.connect(www.myserver.com/api, 443); will throw an error.
I have searched the internet for a solution but can't manage to find one.
Full code:
#include <arduino.h>
#include <WiFiClientSecure.h>
const char* ssid = "filled out ssid"; // your network SSID
const char* password = "filled out password"; // your network password
const char* server = "www.server.com/api"; // Server URL
/* use
openssl s_client -showcerts -connect www.howsmyssl.com:443 </dev/null
to get this certificate */
const char* ca_cert = \
"-----BEGIN CERTIFICATE-----\n" \
"MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCB\n" \
"iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl\n" \
"cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV\n" \
"BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAw\n" \
"MjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNV\n" \
"BAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU\n" \
"aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2Vy\n" \
"dGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK\n" \
"AoICAQCAEmUXNg7D2wiz0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B\n" \
"3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2jY0K2dvKpOyuR+OJv0OwWIJAJPuLodMkY\n" \
"tJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFnRghRy4YUVD+8M/5+bJz/\n" \
"Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O+T23LLb2\n" \
"VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT\n" \
"79uq/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6\n" \
"c0Plfg6lZrEpfDKEY1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmT\n" \
"Yo61Zs8liM2EuLE/pDkP2QKe6xJMlXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97l\n" \
"c6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8yexDJtC/QV9AqURE9JnnV4ee\n" \
"UB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+eLf8ZxXhyVeE\n" \
"Hg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd\n" \
"BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8G\n" \
"A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPF\n" \
"Up/L+M+ZBn8b2kMVn54CVVeWFPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KO\n" \
"VWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ7l8wXEskEVX/JJpuXior7gtNn3/3\n" \
"ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQEg9zKC7F4iRO/Fjs\n" \
"8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM8WcR\n" \
"iQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYze\n" \
"Sf7dNXGiFSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZ\n" \
"XHlKYC6SQK5MNyosycdiyA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/\n" \
"qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9cJ2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRB\n" \
"VXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGwsAvgnEzDHNb842m1R0aB\n" \
"L6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gxQ+6IHdfG\n" \
"jjxDah2nGN59PRbxYvnKkKj9\n" \
"-----END CERTIFICATE-----\n" ;
/* create an instance of WiFiClientSecure */
WiFiClientSecure client;
void setup() {
Serial.begin(115200);
WiFi.begin(ssid, password);
/* waiting for WiFi connect */
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
delay(100);
}
Serial.print("Connected to ");
Serial.println(ssid);
/* set SSL/TLS certificate */
client.setCACert(ca_cert);
Serial.println("Connect to server via port 443");
if (!client.connect(server, 443)){
Serial.println("Connection failed!");
} else {
Serial.println("Connected to server!");
/* create HTTP request */
Serial.print("Waiting for response ");
while (!client.available()){
delay(50); //
Serial.print(".");
}
/* if data is available then receive and print to Terminal */
while (client.available()) {
char c = client.read();
Serial.write(c);
}
/* if the server disconnected, stop the client */
if (!client.connected()) {
Serial.println();
Serial.println("Server disconnected");
client.stop();
}
}
}
void loop() {
}
www.server.com/api is a partial URL. The complete URL will be https://www.server.com/api,
where:
https - This part is called scheme or protocol. HTTPS implies a default TCP port 443 (http mean port 80 by default)
www.server.com - The domain part, can be called also server address.
api- This is a path on the server
WiFiClient, or WiFiClientSecure, is the TCP client, it doesn't know anything about URLs. TCP client recognizes just address, given in form of IP address (192.168.1.20) or FQDN (which is then translated into IP address).
It is easier to use HTTPClient for requesting HTTP resources.
edit: FNDQ->FQDN

ESP32 MQTT TLS errors (self signed cert)

I cannot seem to make MQTT+TLS+self signed certs work on my ESP32.
I am using this "setup" in my home network without major hickups with paho-python and mosquitto_pub/sub. The latter works with the following bash command (note the insecure there):
mosquitto_pub -h 192.168.1.X -p 8883 --cafile /etc/mosquitto/ca_certificates/mosq_ca.crt --cert /etc/mosquitto/certs/mosq_client.crt --key /etc/mosquitto/certs/mosq_client.key --debug --insecure --topic "test/message" -m "off"
My broker's mosquitto config file contains these lines apart from cert paths and general settings:
tls_version tlsv1.3
require_certificate true
When I send the sketch to my ESP32, the result is that it is stuck in the reconnect() loop (see sketch below).
When I do not specify a client cert and key ( // for client verification rows are commented in setup()), I get the following error (I guess it is attributable to the config which requires certificate):
1594936874: New connection from 192.168.1.162 on port 8883.
1594936874: OpenSSL Error: error:14094412:SSL routines:ssl3_read_bytes:sslv3 alert bad certificate
1594936874: Socket error on client <unknown>, disconnecting.
When I do specify a client certificate, I get this:
1594936887: New connection from 192.168.1.162 on port 8883.
1594936888: Socket error on client <unknown>, disconnecting.
Not sure if it is a host name mismatch on the certificate or what. This would be my main tip, but I am uncertain. I also do not know if a similar option to --insecure can be specified for WiFiClientSecure class, so far I have not found anything like that. But I am a beginner, too.
My sketch if pretty unpolished yet, but it should be still readable:
#include <WiFiClientSecure.h>
#include <time.h>
#include <PubSubClient.h>
const char* ssid = "mySSID";
const char* password = "myPasswd";
const char* server = "192.168.1.X"; // Server URL
const char* MQTT_subscribe_topic = "test/esp32";
int timediff_hr = 2;
const char* root_ca = \
"-----BEGIN CERTIFICATE-----\n" \
"pem format broken into lines\n" \
"pem format broken into lines\n" \
"pem format broken into lines\n" \
"-----END CERTIFICATE-----\n" ;
// You can use x.509 client certificates if you want
const char* test_client_key = \
"-----BEGIN CERTIFICATE-----\n" \
"pem format broken into lines\n" \
"pem format broken into lines\n" \
"pem format broken into lines\n" \
"-----END CERTIFICATE-----\n" ;
const char* test_client_cert = \
"-----BEGIN CERTIFICATE-----\n" \
"pem format broken into lines\n" \
"pem format broken into lines\n" \
"pem format broken into lines\n" \
"-----END CERTIFICATE-----\n" ;
WiFiClientSecure wifiClient;
time_t now;
void msgReceived(char* topic, byte* payload, unsigned int len);
PubSubClient pubSubClient(server, 8883, msgReceived, wifiClient);
void setup() {
//Initialize serial and wait for port to open:
Serial.begin(115200);
delay(100);
Serial.print("Attempting to connect to SSID: ");
Serial.println(ssid);
WiFi.begin(ssid, password);
// attempt to connect to Wifi network:
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
// wait 1 second for re-trying
delay(1000);
}
Serial.print("Connected to ");
Serial.println(ssid);
getTime();
wifiClient.setCACert(root_ca);
wifiClient.setCertificate(test_client_key); // for client verification
wifiClient.setPrivateKey(test_client_cert); // for client verification
}
unsigned long lastPublish;
int msgCount;
void loop() {
if (!pubSubClient.connected()) {
reconnect();
}
pubSubClient.loop();
if (millis() - lastPublish > 10000) {
String msg = String("Hello from ESP32: ") + ++msgCount;
boolean rc = pubSubClient.publish("outTopic", msg.c_str());
Serial.print("Published, rc="); Serial.print( (rc ? "OK: " : "FAILED: ") );
Serial.println(msg);
lastPublish = millis();
}
}
void msgReceived(char* topic, byte* payload, unsigned int length) {
Serial.print("Message received on "); Serial.print(topic); Serial.print(": ");
for (int i = 0; i < length; i++) {
Serial.print((char)payload[i]);
}
Serial.println();
}
void reconnect() {
Serial.print(F("PubSubClient attempting connection to: ")); Serial.println(server);
uint8_t i = 0;
while ( ! pubSubClient.connected()) {
// Attempt to connect
if (pubSubClient.connect("ESP32Client")) { //or "ESP8266Client"
Serial.println("connected");
// Subscribe
pubSubClient.subscribe(MQTT_subscribe_topic);
} else { //unsuccessful connect
Serial.print("failed, rc=");
Serial.print(pubSubClient.state());
Serial.print("\nNext try in 5 seconds: connection to "); Serial.println(server);
// Wait 5 seconds before retrying
delay(5000);
}
}
}
void getTime(){
// Synchronize time useing SNTP. This is necessary to verify that
// the TLS certificates offered by the server are currently valid.
Serial.print("Setting time using SNTP");
configTime(timediff_hr * 3600, 0, "de.pool.ntp.org");
time_t now = time(nullptr);
while (now < 1000) {
delay(500);
Serial.print(".");
now = time(nullptr);
}
Serial.println("");
struct tm timeinfo;
gmtime_r(&now, &timeinfo);
Serial.print("Current time: ");
Serial.print(asctime(&timeinfo));
}
P.S.: The base of this sketch is a test sketch of mine for MQTT:1883 unsecured, which also works fine. So the issue should definitely be in the TLS part.
Your test_client_key contains a certificate.
It would be helpful if you post the sample code with keys and certificates. Obviously not the ones you will be using later, but as you are self signing, generate some test key material that you can post here.
The configuration of your broker would also be useful.

Spawn ssh works in parent process, Using fork then try to spwan fail to return buffer to expect

I am trying to Spawn a new SSH session with TCL but first i fork a 4 diffrent process each with unique ip as follow :
foreach vendor $vendorList {
set pid [fork]
switch $pid {
-1 {
puts "Fork attempt #$vendor failed."
}
0 {
puts "I am child process vendor = $vendor ."
$vendor ConnectSSH
exec kill [pid]
}
default {
lappend pids $pid
puts "The parent just spawned child process #$vendor."
}
}
}
foreach id $pids {
wait $id ;#need to add maximum time to wait
puts "process id $id is done"
}
puts "all done"
While ConnectSSH is :
#ConnectSSH
puts "===== Function - Vendor:openConnection ====="
set sid [spawn ssh "$user#$managementIP "]
puts $sid
set sid $spawn_id
set logged_in 0
set retry 0
while {!$logged_in} {
expect -i $sid timeout {
if {$retry < 5} {
puts "retry = $retry"
after 5000
incr retry
} else {
timedout "in while loop"
return -1
}
} eof {
# for some reason we lost connection to the application.
timedout "spawn failed with eof"
return -1
} "Are you sure you want to continue connecting (yes/no)? " {
exp_send -i $sid -- "yes\r"
} "password" {
exp_send -i $sid -- "$password\r"
exp_send -i $sid -- "\r\r\r"
} "$user" {
set logged_in 1
exp_send -i $sid -- "\r\r"
} "No route to host" {
puts "Failed to open ssh connection. No route to host. Exit."
return -1
} "timed out" {
puts "Failed to open ssh connection. Connection timed out. Exit."
return -1
}
}
I am getting new sid from Spawn but expect return "in while loop", seems like timeout.
When running not under "fork" all works great.

Go Lang exec/spawn a ssh session

I'm trying to work out the mechanism to fork/start a ssh terminal session
i.e I want to be logged into remote server (my keys are on server) if I execute this program.
Right now it just executes but nothing happens.
package main
import (
"os/exec"
"os"
)
func main() {
cmd := exec.Command("ssh","root#SERVER-IP")
cmd.Stdout = os.Stdout
//cmd.Stderr = os.Stderr
cmd.Run()
}
cmd.Run waits for the command to complete. Your ssh session should (normally) not exit without user interaction. Therefore your program blocks, since it waits for the ssh process to finish.
You may want to either
also redirect Stdin, so you can interact with the ssh session
execute ssh me#server somecommand. In the last form a specific command gets executed and the output of this command gets redirected.
take a look at the ssh package
I've done library that can cover your requiremenets: https://github.com/shagabutdinov/shell; checkout if it helps or not.
You can use this library to start ssh session and execute the commands:
key, err := ssh.ParsePrivateKey([]byte(YOUR_PRIVATE_KEY))
if(err != nil) {
panic(err)
}
shell, err = shell.NewRemote(shell.RemoteConfig{
Host: "root#example.com:22",
Auth: []ssh.AuthMethod{ssh.PublicKeys(key)},
})
if(err != nil) {
panic(err)
}
shell.Run("cat /etc/hostname", func(_ int, message string) {
log.Println(message) // example.com
})
This is simple wrapper over golang ssh library that helps to execute consequent commands over /bin/sh.