HTTP/2 COMPRESSION_ERROR occured when communication nghttp2 and Apache HttpClient 5.0-Async HTTP/2 Only - nghttp2

I would like to ask about the COMPRESSION_ERROR in HTTP/2 communication of CloseableHttpAsyncClient using H2AsyncClientBuilder with nghttp2.
nghttp2 ran after the source build as follows:
**./nghttpd -v --no-tls 8080 --echo-upload --header-table-size=0 -n 200**
The CloseableHttpAsyncClient has set H2Config as follows:
HEADER_TABLE_SIZE: 0
ENABLE_PUSH: 0
MAX_CONCURRENT_STREAMS: 2147483647
INITIAL_WINDOW_SIZE: 2147483647
MAX_FRAME_SIZE: 16384
MAX_HEADER_LIST_SIZE: 65535
When ClosableHttpAsyncClient send a json message to nghttpd that outputs the following error (finally COMPRESSION_ERROR), performs GOAWAY, and disconnects.
recv: [IB_READ_HEADER_BLOCK]
recv: readlen=100, payloadleft=0
recv: block final=1
recv: decoding header block 100 bytes
inflatehd: start state=0
**inflatehd: header table size change was expected, but saw 0x83 as first byteinflatehd: error return -523**
stream: adjusting kept idle streams num_idle_streams=0, max=100
send: frame preparation failed with The current session is closing
send: reset nghttp2_active_outbound_item
send: aob->item = (nil)
send: next frame: payloadlen=8, type=7, flags=0x00, stream_id=0
send: start transmitting frame type=7, length=17
[id=1] [1635.528] send GOAWAY frame <length=8, flags=0x00, stream_id=0>
(last_stream_id=1, **error_code=COMPRESSION_ERROR(0x09)**, opaque_data(0)=[])
stream: adjusting kept idle streams num_idle_streams=0, max=100
send: end transmission of a frame
send: reset nghttp2_active_outbound_item
send: aob->item = 0x7fc7c04560a0
stream: adjusting kept idle streams num_idle_streams=0, max=100
[id=1] [1635.528] closed
Is there a way to solve that problem by using ClosableHttpAsyncClient with nghttpd's table-header-size=0 MUST BE set?

Related

Rust on ESP32 - How to send (and receive) data using the MQTT protocol to AWS IoT (Core)?

First off: I know running Rust on an ESP32 isn't a very common practice yet, and some (quite a bit of) trouble is to be expected. But I seem to have hit a roadblock.
What works:
flashing and running the code on an ESP32
passing along the certificates in the src/certificates directory
WiFi connection (simple WPA Personal, nothing fancy like WPA Enterprise)
publishing and suscribing to topics using MQTT
What doesn't work:
publising and subscribing to AWS IoT (Core) using MQTT. This needs certificates, and as far as I'm aware I'm handling this properly (see code below).
Some additional info (see code below):
server.cert.crt is renamed from the AWS provided root-CA.crt
client.cert.pem is renamed from the AWS provided my-thing-rev1.cert.pem
client.private.key is renamed from the AWS provided my-thing-rev1.private.key
I also received my-thing-rev1.public.key and my-thing-rev1-Policy, but I don't think I need these...?
I know this is not the proper way of implementing this (I should not provide the certificates directly, instead use a service to get them, but this is a very basic POC)
the code works fine if I don't want to connect to AWS, but instead use my own broker or broker.emqx.io for testing (even with the certificates included)
This is the code I'm currently using (heavily based on Rust on ESP32 STD demo app):
use embedded_svc::httpd::Result;
use embedded_svc::mqtt::client::{Connection, MessageImpl, QoS};
use esp_idf_svc::mqtt::client::{EspMqttClient, MqttClientConfiguration};
use esp_idf_svc::tls::X509;
use esp_idf_sys::EspError;
// other needed imports (not relevant here)
extern crate dotenv_codegen;
extern crate core;
const AWS_IOT_ENDPOINT: &str = dotenv!("AWS_IOT_ENDPOINT");
const AWS_IOT_CLIENT_ID: &str = dotenv!("AWS_IOT_CLIENT_ID");
const AWS_IOT_TOPIC: &str = dotenv!("AWS_IOT_TOPIC");
fn main() -> Result<()> {
esp_idf_sys::link_patches();
// other code
let mqtt_client: EspMqttClient<ConnState<MessageImpl, EspError>> = test_mqtt_client()?;
// more code
Ok(())
}
fn convert_certificate(mut certificate_bytes: Vec<u8>) -> X509<'static> {
// append NUL
certificate_bytes.push(0);
// convert the certificate
let certificate_slice: &[u8] = unsafe {
let ptr: *const u8 = certificate_bytes.as_ptr();
let len: usize = certificate_bytes.len();
mem::forget(certificate_bytes);
slice::from_raw_parts(ptr, len)
};
// return the certificate file in the correct format
X509::pem_until_nul(certificate_slice)
}
fn test_mqtt_client() -> Result<EspMqttClient<ConnState<MessageImpl, EspError>>> {
info!("About to start MQTT client");
let server_cert_bytes: Vec<u8> = include_bytes!("certificates/server.cert.crt").to_vec();
let client_cert_bytes: Vec<u8> = include_bytes!("certificates/client.cert.pem").to_vec();
let private_key_bytes: Vec<u8> = include_bytes!("certificates/client.private.key").to_vec();
let server_cert: X509 = convert_certificate(server_cert_bytes);
let client_cert: X509 = convert_certificate(client_cert_bytes);
let private_key: X509 = convert_certificate(private_key_bytes);
// TODO: fix the following error: `E (16903) esp-tls-mbedtls: mbedtls_ssl_handshake returned -0x7280`
let conf = MqttClientConfiguration {
client_id: Some(AWS_IOT_CLIENT_ID),
crt_bundle_attach: Some(esp_idf_sys::esp_crt_bundle_attach),
server_certificate: Some(server_cert),
client_certificate: Some(client_cert),
private_key: Some(private_key),
..Default::default()
};
let (mut client, mut connection) =
EspMqttClient::new_with_conn(AWS_IOT_ENDPOINT, &conf)?;
info!("MQTT client started");
// Need to immediately start pumping the connection for messages, or else subscribe() and publish() below will not work
// Note that when using the alternative constructor - `EspMqttClient::new` - you don't need to
// spawn a new thread, as the messages will be pumped with a backpressure into the callback you provide.
// Yet, you still need to efficiently process each message in the callback without blocking for too long.
//
// Note also that if you go to http://tools.emqx.io/ and then connect and send a message to the specified topic,
// the client configured here should receive it.
thread::spawn(move || {
info!("MQTT Listening for messages");
while let Some(msg) = connection.next() {
match msg {
Err(e) => info!("MQTT Message ERROR: {}", e),
Ok(msg) => info!("MQTT Message: {:?}", msg),
}
}
info!("MQTT connection loop exit");
});
client.subscribe(AWS_IOT_TOPIC, QoS::AtMostOnce)?;
info!("Subscribed to all topics ({})", AWS_IOT_TOPIC);
client.publish(
AWS_IOT_TOPIC,
QoS::AtMostOnce,
false,
format!("Hello from {}!", AWS_IOT_TOPIC).as_bytes(),
)?;
info!("Published a hello message to topic \"{}\".", AWS_IOT_TOPIC);
Ok(client)
}
Here are the final lines of output when I try to run this on the device (it's setup to compile and flash to the device and monitor (debug mode) when running cargo run):
I (16913) esp32_aws_iot_with_std: About to start MQTT client
I (16923) esp32_aws_iot_with_std: MQTT client started
I (16923) esp32_aws_iot_with_std: MQTT Listening for messages
I (16933) esp32_aws_iot_with_std: MQTT Message: BeforeConnect
I (17473) esp-x509-crt-bundle: Certificate validated
E (19403) MQTT_CLIENT: mqtt_message_receive: transport_read() error: errno=119 # <- This is the actual error
E (19403) MQTT_CLIENT: esp_mqtt_connect: mqtt_message_receive() returned -1
E (19413) MQTT_CLIENT: MQTT connect failed
I (19413) esp32_aws_iot_with_std: MQTT Message ERROR: ESP_FAIL
I (19423) esp32_aws_iot_with_std: MQTT Message: Disconnected
E (19433) MQTT_CLIENT: Client has not connected
I (19433) esp32_aws_iot_with_std: MQTT connection loop exit
I (24423) esp_idf_svc::eventloop: Dropped
I (24423) esp_idf_svc::wifi: Stop requested
I (24423) wifi:state: run -> init (0)
I (24423) wifi:pm stop, total sleep time: 10737262 us / 14862601 us
W (24423) wifi:<ba-del>idx
I (24433) wifi:new:<1,0>, old:<1,1>, ap:<1,1>, sta:<1,0>, prof:1
W (24443) wifi:hmac tx: ifx0 stop, discard
I (24473) wifi:flush txq
I (24473) wifi:stop sw txq
I (24473) wifi:lmac stop hw txq
I (24473) esp_idf_svc::wifi: Stopping
I (24473) esp_idf_svc::wifi: Disconnect requested
I (24473) esp_idf_svc::wifi: Stop requested
I (24483) esp_idf_svc::wifi: Stopping
I (24483) wifi:Deinit lldesc rx mblock:10
I (24503) esp_idf_svc::wifi: Driver deinitialized
I (24503) esp_idf_svc::wifi: Dropped
I (24503) esp_idf_svc::eventloop: Dropped
Error: ESP_FAIL
This error seems to indicate the buffer holding the incoming data is full and can't hold any more data, but I'm not sure. And I definately don't know how to fix it.
(I assume the actual certificate handling is done properly)
When I run the following command, I do get the message in AWS IoT (MQTT test client):
mosquitto_pub -h my.amazonawsIoT.com --cafile server.cert.crt --cert client.cert.pem --key client.private.key -i basicPubSub -t my/topic -m 'test'
Does anyone have some more experience with this who can point me in the right direction?
Is this actually a buffer error, and if so: how do I mitigate this error? Do I need to increase the buffer size somehow (it is running on a basic ESP32 revision 1, ESP32_Devkitc_v4, if that helps). As far as I can tell this version has a 4MB flash size, so that might explain the buffer overlow, although I think this should be enough. The total memory used is under 35% of the total storage (App/part. size: 1347344/4128768 bytes, 32.63%)
UPDATE 1: I have been made aware that this data is stored in RAM, not in flash memory (didn't cross my mind at the time), but I'm not entirely sure on how large the RAM on my specific device is (ESP32 revision 1, ESP32_Devkitc_v4). My best guess is 320KB, but I'm not sure.
UPDATE 2: I've tried changing the buffer size like so:
let conf = MqttClientConfiguration {
client_id: Some(AWS_IOT_CLIENT_ID),
crt_bundle_attach: Some(esp_idf_sys::esp_crt_bundle_attach),
server_certificate: Some(server_cert),
client_certificate: Some(client_cert),
private_key: Some(private_key),
buffer_size: 50, // added this (tried various sizes)
out_buffer_size: 50, // added this (tried various sizes)
..Default::default()
};
I've tried various combinations, but this doesn't seem to change much: either I get the exact same error, or this one (when choosing smaller numbers, for example 10):
E (18303) MQTT_CLIENT: Connect message cannot be created
E (18303) MQTT_CLIENT: MQTT connect failed
E (18313) MQTT_CLIENT: Client has not connected
I'm not sure how big this buffer size should be (when sending simple timestamps to AWS IoT), and can't find any documentation on what this number represents: is it in Bit, KiloBit, ... No idea.

Sleeping causes increased UDP send/recv latency

I am experimenting with UDP loopback performance, and I discovered that sleeping my thread causes a large spike in minimum UDP latency. I have written approximately the same code in C and Rust to spin up two threads in the same process, send/receive UDP packets, and measure how long the send and recv calls take. I have run my experiments on both macOS and Linux.
What I have found is that using sleep() within the loop to throttle down the call/response loop a bit actually causes the recv() and send() calls to take much longer than they usually do. My full code is available as a gist, but I'll include the relevant loop in the client here:
while (1) {
// This sleep causes a large increase in latency
#ifdef ENABLE_SLEEP
usleep(10000);
#endif
double t_pre_send = curr_timestamp();
if (send(sockfd, NULL, 0, 0) == -1) {
perror("send failed");
}
avg_send_elapsed = 0.9*avg_send_elapsed + 0.1*(curr_timestamp() - t_pre_send);
double t_pre_recv = curr_timestamp();
socklen_t len = 0;
int num_bytes = recvfrom(sockfd, (char *)buffer, sizeof(buffer), 0, (struct sockaddr *) &cliaddr, &len);
avg_recv_elapsed = 0.9*avg_recv_elapsed + 0.1*(curr_timestamp() - t_pre_recv);
double curr_time = curr_timestamp();
if (curr_time - last_print > 1.0) {
last_print = curr_time;
printf("[%.1f] send: %.2fus\trecv: %.2fus\n", curr_time - t_start, avg_send_elapsed*1000000, avg_recv_elapsed*1000000);
}
}
The results look something like this without a sleep:
[1.0] send: 4.93us recv: 7.41us
[2.0] send: 4.68us recv: 7.04us
[3.0] send: 4.86us recv: 7.58us
[4.0] send: 4.79us recv: 7.60us
[5.0] send: 4.88us recv: 7.03us
[6.0] send: 4.70us recv: 7.57us
[7.0] send: 4.49us recv: 8.02us
[8.0] send: 4.47us recv: 7.23us
[9.0] send: 4.58us recv: 7.15us
And something like this with a sleep:
[1.0] send: 23.85us recv: 102.13us
[2.0] send: 35.41us recv: 78.07us
[3.0] send: 70.47us recv: 141.07us
[4.0] send: 29.90us recv: 107.35us
[5.0] send: 45.17us recv: 194.27us
[6.0] send: 32.49us recv: 117.74us
[7.0] send: 32.25us recv: 117.83us
[8.0] send: 35.48us recv: 85.67us
[9.1] send: 33.86us recv: 108.71us
I would expect the sleep to adjust the number of loop iterations we perform per second, but I would not expect it to impact how long it takes to run the send() and recvfrom() function calls. Does anyone have an explanation for why my UDP latency increases so drastically, and is there a technique I can use to throttle my transmissions without incurring this latency penalty?

Read/Write data returns null - Unable to perform any operations - node serialport

I am working with serialport for the first time and trying to establish a read and write connection with an UART device which is a controller of a height adjustment desk by using the below method. The application is a desktop application using electron.
const SerialPort = require('serialport')
const Readline = require('#serialport/parser-readline')
const parser = new Readline()
const port = new SerialPort("COM4", {
baudRate: 9600
})
This is the code I have used and port.read() always returns null value.
For the write operation I have used the code like below:
var buf = new Buffer([ 0XF1, 0XF1, 0X01, 0X00, 0X01, 0X7E]);
port.write(buf, function(err,n) {
if (err) {
return console.log('Error on write: ', err.message)
}
console.log(n)
console.log('message written')
})
The buffer values are the ones for moving the desk up but no operation takes place and it returns no error or returns undefined value in callback.
More details on the device and setup:
Using an RJ45 to USB connector to connect with the control box of the table.
The definition of the SCI is as below:
(Baud Rate):9600
(Data Mode):8
(Stop Bit):1
(Parity Type):None
Path: COM3
Handset is what is being referred to my system.
Basic write operation buffer vals:
Move Up=0XF1 0XF1 0X01 0X00 0X01 0X7E
Move Down=0XF1 0XF1 0X02 0X00 0X02 0X7E
Stop Action=0XF1 0XF1 0X0c 0X00 0X0c 0X7E
Read functionality example:
Current height(1000mm-0x03E8)
0XF2 0XF2 0X01 0X02 0X03 0XE8 0XEE 0X7E
(there is two bytes in ‘Data’,so ‘Data Length’ is 0x02;‘Checksum’= 0x01 + 0x02 +0x03 +0xE8 = 0xEE)
Expecting the read functionality to give the current height info and write functionality to be able to control the device.
Versions, Operating System and Hardware:
SerialPort# ^8.0.7
Node.js v10.16.0
Windows
Hardware and chipset?
COM4
FTDIBUS\VID_0403+PID_6001+AB0JIYQTA\0000
FTDI
Creating a read-line parser suggests that messages are terminated by \n, but your write does not include one, so that could explain why commands are not getting to the device.
For the reads, if you want to use the read-line parser, you need to pipe the serialPort to it, then listen for data from the parser, e.g.:
serialPort.pipe(parser);
parser.on('data', (data) => {
console.log(data)
})
Note: data will be a Buffer
You could skip the parser and call read directly. I assume you tried that. Docs say:
If no data is available to be read, null is returned.
https://serialport.io/docs/api-stream#serialport-read
So, it could be that the desk only outputs data after a message is received.

pcap_next return NULL

I am working in openwrt with libpcap 1.5.3.
I have init pcap as following:
handle = pcap_create(capnic, errbuf);
if(!handle) {
sys_err("pcap_create failed:%s\n", errbuf);
exit(-1);
}
if(pcap_set_snaplen(handle, BUFSIZE)) {
sys_err("pcap_set_snaplen failed\n");
exit(-1);
}
if(pcap_activate(handle)) {
sys_err("pcap_activate failed: %s\n",
pcap_geterr(handle));
exit(-1);
}
and capture packet with pcap_next:
struct pcap_pkthdr hdr;
const u_char * sysbuf;
if(!(sysbuf = pcap_next(handle, &hdr))) {
sys_err("recv packet failed\n");
return 0;
}
The program could catch packets, but there's a lot of error info:
recv packet failed
I have checked block state with function pcap_getnonblock, the handle is block.
To quote the pcap_next()/pcap_next_ex() man page on my machine:
pcap_next_ex() returns 1 if the packet was read without problems, 0 if
packets are being read from a live capture, and the timeout expired, -1
if an error occurred while reading the packet, and -2 if packets are
being read from a ``savefile'', and there are no more packets to read
from the savefile. If -1 is returned, pcap_geterr() or pcap_perror()
may be called with p as an argument to fetch or display the error text.
pcap_next() returns a pointer to the packet data on success, and
returns NULL if an error occured, or if no packets were read from a
live capture (if, for example, they were discarded because they didn't
pass the packet filter, or if, on platforms that support a read timeout
that starts before any packets arrive, the timeout expires before any
packets arrive, or if the file descriptor for the capture device is in
non-blocking mode and no packets were available to be read), or if no
more packets are available in a ``savefile.'' Unfortunately, there is
no way to determine whether an error occured or not.
Note especially
pcap_next() ... returns NULL if an error occured, *or if no packets were read from a live capture (if, for example, they were discarded because they didn't pass the packet filter, or if, on platforms that support a read timeout that starts before any packets arrive, the timeout expires before any packets arrive...)
Note also
Unfortunately, there is no way to determine whether an error occured or not.
which is the man page's way of telling you that you should probably be using pcap_next_ex(), which does distinguish between those two cases.

Why can't I end an active socket in node.js without causing a segmentation fault?

I'm trying to stop some http servers in node.js but I don't want to wait for all keep-alive connections to timeout before the servers can fully close. So, I've been trying to keep track of all active sockets and then when the server needs to be stopped I want to call .end() on them to let the client know that I want to close the socket. However, when I do this I get a segmentation fault.
I have used a segmentation-fault handler to get a better stack trace but I can't figure out what could be going wrong.
Here is the code to keep track of the connections:
connectionNum = 1
activeHttpConnections = {}
trackConnection = (map, socket) ->
# save active socket
id = connectionNum
map[id.toString()] = socket
# remove socket once it closes
socket.on 'close', ->
map[id.toString()] = null
delete map[id.toString()]
# reset connection number eventually
if connectionNum > 1000000
connectionNum = 1
else
connectionNum++
When the server is started I call:
httpServer.on 'connection', (socket) -> trackConnection activeHttpConnections, socket
And when I stop the servers I call:
# close active connection so that servers can stop
for key, socket of activeHttpConnections
socket.end()
When .end() is called I get the following stacktrace:
PID 29943 received SIGSEGV for address: 0x58
/home/ryan/git/openhim-core-js/node_modules/segfault-handler/build/Release/segfault-handler.node(+0x1185)[0x7f50a037e185]
/lib/x86_64-linux-gnu/libpthread.so.0(+0x10340)[0x7f50a2384340]
node(_ZN4node10StreamWrap8ShutdownERKN2v820FunctionCallbackInfoINS1_5ValueEEE+0x166)[0x9d1846]
node(_ZN2v88internal25FunctionCallbackArguments4CallEPFvRKNS_20FunctionCallbackInfoINS_5ValueEEEE+0x9b)[0x616d9b]
node[0x6356b6]
[0x270b80a060a2]
Any idea what I could be doing wrong, or what this stacktrace could point to?

Resources