HTTP2 expects streams to be opened following the sequence - protocols

I haven't seen this claim in the official HTTP2 spec but it seems that if you open streams with IDs that do not represent sequential numbers, the server responds with a GoAway frame having ProtocolError as a reason.
Example (INVALID):
=> HEADER{sid: 3}
=> HEADER{sid: 1}
<= GoAway{ProtoclError}
Example (VALID):
=> HEADER{sid: 1}
=> HEADER{sid: 3}
<= ... All good ...
Why is that? Can someone point me to the right section in the spec, pelase?

This is stated in the [HTTP/2 specification, section 5.1.1]:(https://datatracker.ietf.org/doc/html/rfc7540#section-5.1.1)
The identifier of a newly established stream MUST be numerically
greater than all streams that the initiating endpoint has opened or
reserved.
...
An endpoint that
receives an unexpected stream identifier MUST respond with a
connection error (Section 5.4.1) of type PROTOCOL_ERROR.

Related

zeromq.js - Await connection

The documentation for connect method says,
Connects to the socket at the given remote address and returns immediately. The connection will be made asynchronously in the background.
But, await does not seem to be applicable as shown in their example of subscriber code.
subscriber.js
const zmq = require("zeromq")
async function run() {
const sock = new zmq.Subscriber
sock.connect("tcp://127.0.0.1:3000") //Happens async; can we await this?
sock.subscribe("kitty cats")
console.log("Subscriber connected to port 3000")
for await (const [topic, msg] of sock) {
console.log("received a message related to:", topic, "containing message:", msg)
}
}
run()
Also, what error(s) maybe raised by the connect() method? I provided an 'obscene' port number such as, 8124000, to connect. I was hoping for some error messages to be raised.
Q : "what error(s) maybe raised by the connect() method?"
The Error(s) part
The ZeroMQ native API distinguishes ( unchanged since v2.1 ) these errors for this :
EINVAL
The endpoint supplied is invalid.
EPROTONOSUPPORT
The requested transport protocol is not supported.
ENOCOMPATPROTO
The requested transport protocol is not compatible with the socket type.
ETERM
The ØMQ context associated with the specified socket was terminated.
ENOTSOCK
The provided socket was invalid.
EMTHREAD
No I/O thread is available to accomplish the task.
Yet your actual observer is dependent on the zeromq.js re-wrapping these principal states, so the best next step is to re-read the wrapper source code, so as to see, how these native API error states get actually handled inside the zeromq.js-wrapper.
The remarks :
The following socket events can be generated. This list may be different depending on the ZeroMQ version that is used.
Note that the error event is avoided by design, since this has a special behaviour in Node.js causing an exception to be thrown if it is unhandled.
Other error names are adjusted to be as close to possible as other networking related event names in Node.js and/or to the corresponding ZeroMQ.js method call. Events (including any errors) that correspond to a specific operation are namespaced with a colon :, e.g. bind:error or connect:retry.
are nevertheless quite warning, aren't they?
The await part
The MCVE-code ( as-is ) is unable to reproduce the live-session, so best adapt the MCVE-code so as to get run-able and we can proceed further on this.

Why is ZeroMQ message scrambled?

I am using nodejs to call my tcp subscriber to read messages.
var zmq = require("zeromq"),
sock = zmq.socket("sub");
sock.connect("tcp://pubsub.besteffortc.com:7658");
sock.subscribe("/ASD/Travel");
console.log("Subscriber connected to port 3000");
sock.on("message", function(topic, message) {
console.log(
"received a message related to:",
topic.toString(),
"containing message:",
message.toString()
);
});
Output I am getting is the following. What might be the issue ?
- can it be that my IP address needs to be whitelisted to see actual data ?
Note: Topic and URL name is not the actual value its dummy values.
Q : What might be the issue ?
There is one sure point in the ZeroMQ - if a message gets delivered at all ( for which a Zen-of-Zero does not pose any warranty ), then it is sure to be an exact bit-by-bit copy of the message, that the originator ( the PUB in the case here ) was intending to .send()
If you .recv() anything ( be it by the native API level .recv()-method or the wrapper provided .on( "message", f(...){...} )-handler ), be sure it carries the 1:1 bitmap of the payload provided by the originator ( unless your language wrapper did a dirty job of obfuscating your use of the documented ZeroMQ API, producing some nasty garbage ( which I would not bet on, yet it might be an issue - try any other ZeroMQ message-source, that is under your own control, to see if this happens or not ) )
Q : can it be that my IP address needs to be whitelisted to see actual data ?
As explained in detail above, this item is not a ZeroMQ issue. If your app-level / ISO-OSI-above-5 behaviour depends on contracting some kind of abonnement, only after which you get "access-validation" ( be it by whitelisting or other kind ), then your problem stays in the business domain, not the programming one.
ZeroMQ has nothing to do with any of this. ZMQ/RFC-documentation is explicit on each ZeroMQ service-composition and leaves zero-space for random or undocumented behaviours.

Understanding basic websocket API with node.js and "ws"-package (API: bitfinex)

I'm trying to figure out basic websocket communication using node.js, the "ws"-package (which seems to be a very popular websocket package from npmjs.com) and the bitfinex.com (a cryptocurrency exchange) websocket API.
I want to read the public Ticker for a certain currency-pair, the docs are here: https://docs.bitfinex.com/v2/reference#ws-public-ticker
My result so far is working but is still much different from what I am supposed to get according to the docs.
I am working with this code snippet taken from the documentation linked above:
const ws = require('ws')
const w = new ws('wss://api.bitfinex.com/ws/2')
w.on('message', (msg) => {
console.log(msg)
})
let msg = JSON.stringify({
event: 'subscribe',
channel: 'ticker',
symbol: 'tBTCUSD'
})
w.on('open', () => {
w.send(msg)
})
Which works so far by outputting to the console the message from the subscribed channel:
[1,[14873,23.49464465,14874,61.09031263,1087,0.0789,14872,56895.20497085,15500,13891]]
But now, and here is the issue, in the docs the response looks different. How would I determine which number is what? I should be able to get all kinds of more information from the response, no?
The given example response looks like this:
// response - trading
{
event: "subscribed",
channel: "ticker",
chanId: CHANNEL_ID,
pair: "BTCUSD"
}
How does this relate to that array of numbers I get? How would I for example read the "pair:" field ("BTCUSD") or any of the other listed fields, like (BID, BID_PERIOD, VOLUME, HIGH, LOW etc.)? Am I missing something obvious?
I know this is a lot to ask at once but maybe someone knows one or two good examples or hints to enlighten me. Thanks in advance!
Kind regards,
s
The overall websocket scheme for this API is described in https://bitfinex.readme.io/v2/docs/ws-general If you haven't already read that page, now would be a good time to do it.
For your example program you should have seen info and subscribed events as the first two messages from the websocket. info should have been sent as soon as the websocket connection was established, and subscribed should have been sent in response to your subscribe request.
After that, you should see a ticker snapshot message followed by periodic ticker update messages for the channel that you subscribed to. These are the JSON arrays that you're seeing. The format of these messages for a public ticker channel is is described at https://bitfinex.readme.io/v2/reference#ws-public-ticker -- click the Snapshot and Update headings in the dark green 'details' bar to see the definitions. In this case snapshots and updates use the same format:
[ CHANNEL_ID,
[ FRR, BID, BID_PERIOD, BID_SIZE, ASK, ASK_PERIOD, ASK_SIZE,
DAILY_CHANGE, DAILY_CHANGE_PERC, LAST_PRICE, VOLUME, HIGH, LOW
]
]
with meanings as described in the 'Stream Fields' table at the above URL.
You can parse these messages as JSON strings and access the field values just as you would for any array.
It's a little strange that the API sends these as arrays rather than as objects with named attributes. I imagine they're looking to keep these messages compact because they make up the bulk of the traffic.

Why doesn't peer send handshake message in response to the handshake message I send?

I've started writing my own BitTorrent client in Python 3 recently. And all was perfect until I faced the following issue:
Instead of a response handshake when I send a formatted handshake message to one of the peers, I do not get anything (b'' when buff is not decoded). Here is the code:
handshakemsg = chr(19)+"BitTorrent protocol"+8*chr(0)+
getinfohash()+"HAHA-0142421214125A-")
s.send(handshakemsg.encode())
print("Connection to peer accepted")
buff = s.recv(len(handshakemsg))
print(buff)
That's the proper way of sending handshake message I think, but the response doesn't look like the one described in the specification. I'm wondering why is that happening, and how can I avoid that?
http://bittorrent.org/beps/bep_0003.html#peer-protocol
After the fixed headers come eight reserved bytes, which are all zero in all current implementations. If you wish to extend the protocol using these bytes, please coordinate with Bram Cohen to make sure all extensions are done compatibly.
Next comes the 20 byte sha1 hash of the bencoded form of the info value from the metainfo file.
Yours is 40 (hex-encoded). Bittorrent is a binary protocol, not text.
Make sure the whole handshake message is sent to remote peer, so try to use socket.sendall() method.
change:
s.send(handshakemsg.encode())
to:
s.sendall(handshakemsg.encode())

Netty: Pipe-ing output of one Channel to the input of an other

Netty-Gurus,
I've been wondering if there is a shortcut/Netty-Utility/smart-trick
for connecting the input of one Channel to the output of
an other channel. In more details consider the following:
Set-Up a Netty (http) server
For an incoming MessageEvent get its ChannelBuffer
and pipe its input to a NettyClient-ChannelBuffer
(which is to be set up along the lines of the NettyServer).
I'm interested in how to achieve bullet-point 3. since my first
thoughts along the lines
// mock messageReceived(ChannelHandlerContext ctx, MessageEvent e):
ChannelBuffer bufIn = (ChannelBuffer) e.getMessage();
ChannelBuffer bufOut = getClientChannelBuffer();// Set-up somewhere else
bufOut.write(bufIn);
seem to me awkward because
A. I have to determine for each and every messageReceived-Event
the target ChannelBuffer
B. To much Low-Level tinkering
My wish/vision would be to connect
--> the input of one Channel
--> to the output of an other channel
and let them do their I/O without any additional coding.
Many thanks in advance!,
Traude
P.S: Issue has arisen as I'm trying to dispatch the various HTTP-requests to the
server (one entry point) to several other servers, depending on
the input content (mapping based on the first HTTP request line).
Obviously, I also need to do the inverse trick -- pipeing back client
to server -- but I guess it'll be similar to the solution of
the question before.
Looks like you need to use a multiplexer in you business handler. The business handler could have a map. With key as "first http request line" and value as the output channel for the server. Once you do a lookup you just do a channel.write(channelBuffer);
Also take a look at bruno de carvalho's tcp tunnel, which may give you more ideas on how to deal with these kind of requirements.

Resources