How do I get the remote IP-Address of clients connecting to a Rebol3 based server? - tcp

I'm playing with these basic TCP test scripts and would like to know: "How to get the IP-Address of clients connecting to the server?"
Any ideas? I tried to probe a client subport at the server-side, but it doesn't show the remote-ip.
Can someone give me hints on gathering that information. I know how it works within Rebol2, but I'm not familiar with the Rebol3 port model.

You can obtain that information by calling QUERY on the client port!, which will return an object with remote-ip and remote-port fields.
Here's a simple example illustrating this, with a simple service that listens for connections on port 9090 and prints the address of clients connecting to that service:
rebol []
awake-server: func [event /local client info] [
if event/type = 'accept [
client: first event/port
info: query client
print ajoin ["Client connected: " info/remote-ip ":" info/remote-port]
close client
]
]
serve: func [endpoint /local listen-port] [
listen-port: open endpoint
listen-port/awake: :awake-server
wait listen-port
]
serve tcp://:9090

The system/standard/net-info object includes two values - local-ip and remote-ip. I'm not sure whether that they get set though.
Give system/standard/net-info/remote-ip a try and if it contains none, I would suggest submitting a bug report.

Related

Using Go standard libs, why do I leak TCP connections constantly in this two-tier architecture?

In this situation, I'm using all standard Go libraries -- net/http, most importantly.
The application consists of two layers. The first layer is the basic web application. The web application serves out the UI, and proxies a bunch of API calls back to the second layer based on username -- so, it's effectively a load balancer with consistent hashing -- each user is allocated to one of these second-layer nodes, and any requests pertaining to that user must be sent to that particular node.
Quick details
These API endpoints in the first layer effectively read in a JSON body, check the username, use that to figure out which of the layer 2 nodes to send the JSON body to, and then it sends it there. This is done using a global http.Client that has timeouts set on it, as appropriate.
The server side does a defer request.Body.Close() in each of the handlers after ensuring no error comes back from decoder.Decode(&obj) calls that unmarshal the JSON. If there is any codepath where that could happen, it isn't one that's likely to get followed very often.
Symptoms
On the node in the second layer (the application server) I get log lines like this because it's leaking sockets presumably and sucking up all the FDs:
2019/07/15 16:16:59 http: Accept error: accept tcp [::]:8100: accept4: too many open files; retrying in 1s
2019/07/15 16:17:00 http: Accept error: accept tcp [::]:8100: accept4: too many open files; retrying in 1s
And, when I do lsof 14k lines are output, of which 11,200 are TCP sockets. When I look into the contents of lsof, I see that nearly all these TCP sockets are in connection state CLOSE_WAIT, and are between my application server (second layer node) and the web server (the first layer node).
Interestingly, nothing seems to go wrong with the web application server (layer 1) during this timeframe.
Why does this happen?
I've seen lots of explanations, but most either point out that you need to specify custom defaults on a custom http.Client and not use the default, or they tell you to make sure to close the request bodies after reading from them in the layer 2 handlers.
Given all this information, does anyone have any idea what I can do to at least put this to bed once and for all? Everything I search on the internet is user error, and while I certainly hope that's the case here, I worry that I've nailed down every last quirk of the Go standard library I can find.
Been having trouble nailing down exactly how long it takes for this to happen -- the last time it happened, it was up for 3 days before I started to see this error, and at that point obviously nothing recovers until I kill and restart the process.
Any help would be hugely appreciated!
EDIT: example of client-side code
Here is an example of what I'm doing in the web application (layer 1) to call the layer 2 node:
var webHttpClient = &http.Client{
Transport: &http.Transport{
MaxIdleConnsPerHost: MaxIdleConnections,
},
Timeout: time.Second * 20,
}
// ...
uri := fmt.Sprintf("http://%s/%s", tsUri, "pms/all-venue-balances")
req, e := http.NewRequest("POST", uri, bytes.NewBuffer(b))
resp, err := webHttpClient.Do(req)
if err != nil {
log.Printf("Submit rebal error 3: %v\n", err)
w.WriteHeader(500)
return
}
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
w.WriteHeader(200)
w.Write(body)

Corda 3.1 - discovering which nodes are down and not operating

I have a question regarding Corda 3.1 and using the network map for the purpose of seeing if node is up - is it generally a good idea to use it for that ?
From these notes https://docs.corda.net/network-map.html#http-network-map-protocol as there is a polling of the network map participants data (in case that our cached data expired) it should be technically possible to do that.
Could you see any drawbacks of implementing this in that way ?
If the node is configured with the compatibilityZoneURL config then it first uploads its own signed NodeInfo to the server (and each time it changes on startup) and then proceeds to download the entire network map. The network map consists of a list of NodeInfo hashes. The node periodically polls for the network map (based on the HTTP cache expiry header) and any new entries are downloaded and cached. Entries which no longer exist are deleted from the node’s cache.
It is not a good idea to use the network map as a liveness service.
The network does have an event horizon parameter. If the node is offline for longer than the length of time specified by the event horizon parameter, it is ejected from the network map. However, the event horizon would usually be days (e.g. 30 days).
Instead, you can just ping the node's P2P port using a tool like Telnet. If you run telnet <node host> <P2P port> and the node is up, you'll see something like:
Trying ::1...
Connected to localhost.
Escape character is '^]'.
If the node is down, you'll see something like:
Trying ::1...
telnet: connect to address ::1: Connection refused
Trying 127.0.0.1...
telnet: connect to address 127.0.0.1: Connection refused
telnet: Unable to connect to remote host
Alternatively, if you want to check liveness automatically from within a flow, you can define a subflow like the one below. This flow will return a boolean indicating whether a given party on the network is offline.
#InitiatingFlow
class IsLiveFlow(val otherPartyName: CordaX500Name) : FlowLogic<Boolean>() {
#Suspendable
override fun call(): Boolean {
val otherPartyInfo = serviceHub.networkMapCache.getNodeByLegalName(otherPartyName)!!
val otherPartyP2PAddress = otherPartyInfo.addresses.single()
return try {
Socket().use { socket ->
socket.connect(InetSocketAddress(otherPartyP2PAddress.host, otherPartyP2PAddress.port), 1000)
true
}
} catch (e: IOException) {
false
}
}
}

lua-resty-http:connect method clarification

I've been implementing a kong plugin that needs to make HTTP requests to retrieve information to share it with the upstream services.
There is an excellent library called lua-resty-http that can be used to make HTTP requests.
The service that contains the information needed, it is configured behind the proxy, and it matches the path: /endpoint-providing-info.
The goal is to rely on the proxy capabilities to avoid having to parse the hostname which has some particular form that is not relevant to this question.
By playing around, I was able to achieve the desired behavior by doing the following:
local ok, err = http_client:connect("127.0.0.1", ngx.var.server_port)
if not ok and err then return nil, 'there was a failure opening a connection: ' .. err
local res, err = http_client:request({
method = 'GET',
path = '/endpoint-providing-info'
})
//parse the response, etc...
The request gets routed to the upstream service and works as expected.
My primary concern is the following:
By connecting to localhost, I assumed that the current Nginx node is the one attending the request. Will this affect the performance? Is it better/possible to connect to the cluster directly?
I suppose that you configure for current nginx a location which match /endpoint-providing-info, use proxy module and configure an upstream for a cluster.
If you would use lua-resty-http:
Pros - you may use body_reader - an iterator function for reading the body in a streaming fashion.
Cons - your request will go thru kernel boundary (loopback interface).
Another possibility is to issue a subrequest using ngx.location.capture API
Pros - subrequests just mimic the HTTP interface but there is no extra HTTP/TCP traffic nor IPC involved. Everything works internally, efficiently, on the C level.
Cons - it is full buffered approach, will not work efficiently for big responses.
Update - IMO:
If you expect from upstream server big responses -lua-resty-http is your choice.
If you expect from upstream server a lot of small responses - ngx.location.capture should be used.

Creating an HTTP server in NodeMCU through an access point created by the board

I am coding a robot, using NodeMCU (ESP8266) and want it to be remote controlled. My current solution is connecting to a nearby router, to the internet and creating a TCP HTTP server. Data is streamed from the mobile device (remote) to the NodeMCU (robot) via HTTP requests. The remote is loaded onto the mobile device through a browser with HTML/CSS/JavaScript.
What I want instead is for the NodeMCU to create its own hotspot, because:
A router is not required
The connection is more direct
I want the same TCP HTTP solution, but I don't know how to serve a webpage through a custom hotspot.
This is my code:
-- Connect to router
wifi.sta.config("ssid","password")
wifi.sta.connect()
-- Code for waiting for connection
-- Create server
srv = net.createServer(net.TCP)
srv:listen(80,function(conn)
conn:on("receive",function(conn,payload)
for line in string.gmatch(payload,'[^\r\n]+') do
s = string.find(line, "GET /&")
-- If query is there, control robot
if s ~= nil then
-- Do stuff with query
break;
-- If no query, serve webpage
else
file.open("index.html", "r")
while true do
s = file.read(1460)
if s == nil then
break
end
conn:send(s)
end
file.close()
end
break
end
conn:on("sent", function(conn) conn:close() end)
end)
end)
Creating custom hotspot:
wifi.setmode(wifi.STATIONAP)
cfg={}
cfg.ssid="custom_ssid"
cfg.pwd="custom_password"
wifi.ap.config(cfg)
So how do I make it so the mobile can access the server? How do I get/set the IP of the server? Basically, I just need it to work. Thanks!
Not sure I fully understand but I believe you're really close. Check the documentation for the AP functions at http://nodemcu.readthedocs.io/en/latest/en/modules/wifi/#wifiap-module.
wifi.ap.config(cfg) sets SSID and pwd as you noted. Your client then connects to this AP by joining the network.
If you then print wifi.ap.getip() you'll see that the device has the IP address 192.168.1.4 by default. Hence, for clients which joined this network your server is reachable at 192.168.1.4:80 unless you set a custom IP explicitly.
However, the sending of data seems broken. You have multiple conn:send(s) (in the loop) yet you also have conn:on("sent", function(conn) conn:close() end) which means that the connection will be closed after the first conn:send! Check the docs at http://nodemcu.readthedocs.io/en/latest/en/modules/net/#netsocketsend for an example as for how to do that properly.

How to interpret the json response from the signalr connect request

I'm trying to integrate signalr with an existing asp.net forms web app.
After initially connecting successfully and the server side then calling back to the client js function, signalr seems to have trouble maintaining a connection. I'm developing on a windows 7 machine so the 10 connections limit makes this somewhat challenging to debug. I have however, seen what appears to be the same issue when the website is deployed to a 2003 Enterprise Ed. Server so I don't think I'm seeing a connection limit issue (I stand ready to be corrected though)
Looking in fiddler, I do eventually get a 200 for the connection request but the only JSON I get back as this:
{"C":"B,0|7,4|8,0|9,0","T":1,"M":[]}
I have no idea what this represents. Initially when the connection is successful I get this (which includes the data payload I expect):
"C": "B,0|BK,1|BL,0|BM,0",
"M": [{
"H": "notifyHub",
"M": "notificationReceived",
"A": ["[{\"TransitionNotificationId\":527,\"AuthorizationJobId\":53,\"TransitionType\":2,\"IsWorkShop\":true},
{\"TransitionNotificationId\":528,\"AuthorizationJobId\":53,\"TransitionType\":12,\"IsWorkShop\":true},
{\"TransitionNotificationId\":580,\"AuthorizationJobId\":61,\"TransitionType\":2,\"IsWorkShop\":true}]"]
}]
If I could interpret the JSON in the 'failed' request properly I'd have an idea of where to look for the problem.
Cheers in advance.
T:1 means you got a connection timeout. When using longpolling the connection will timeout every 120 seconds (by default). This is because most load balancers/proxies will kill idle connections after sometime. The other transports send a keep alive to stop this from happening.
As for the rest of the payload:
C: Cursor
M: Messages
H: Hubname
M: Method name
A: Method args
T: Timeout
D: Disconnect

Resources