Linux Allows Only 99 TCP Connections with a single remote IP - linux

When I try to create more than 99 TCP connections in less than a millisecond from my local computer with a TCP listener running at a DigitalOcean droplet with Ubuntu, only 99 of them works and rest says connectex: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond. Sending the same amount of connection requests to multiple ports seem to work okay.
I already tried to increase tcp_max_syn_backlog and somaxconn but it didn't help. I tried to track TcpExtListenOverflows and TcpExtListenDrops but they don't seem to be increasing as well. I tried to do the same thing with another server to make sure the problem is not about my local computer. I also contacted to DigitalOcean support and they told they are not aware of any hard limits placed by their infrastructure.
Can anyone give me any pointers to create more than 99 TCP connections in less than a millisecond with a single port at an Ubuntu server and a single remote IP?
Scripts I'm using:
Listener:
package main
import (
"log"
"net"
)
const port = "1919"
func main() {
listener, err := net.Listen("tcp", ":"+port)
if err != nil {
log.Fatal(err)
}
for {
_, err := listener.Accept()
if err != nil {
log.Fatal(err)
}
}
}
Dialer:
package main
import (
"fmt"
"net"
"sync"
)
const ConnectionCount = 250
const raddr = "<IP_ADDRESS_IS_INSERTED_HERE>:1919"
func main() {
wg := &sync.WaitGroup{}
mu := &sync.Mutex{}
var success, fail int
for i := 0; i < ConnectionCount; i++ {
wg.Add(1)
go func() {
defer wg.Done()
_, err := net.Dial("tcp", raddr)
mu.Lock()
defer mu.Unlock()
if err == nil {
success++
} else {
fail++
}
fmt.Print("\033[2K\rSuccess: ", success, ", Fail: ", fail)
}()
}
wg.Wait()
}
Output is always 99 Success and 151 Fail. Tried to same thing with direct HTTP requests as well, still only 99 of them works if they are sent at the same time.

Related

AT commands exchange with /dev/tty*

I have a device with a GPRS onboard. GPRS connects with the third-party application and it works. I need to know the signal strength of the connection, so, I use ATZ, then AT+CSQ commands. When I work using some terminal software it works. Then, I had tried to use https://github.com/ishuah/bifrost soft as a terminal. It works as well. But how can I simply communicate with a device, not using terminal, without re-connection or connection abortion, etc?
I tried simply echo ATZ > /dev/ttyX - no answer
// This writes, but reads only zeros (((
package main
import (
"github.com/jacobsa/go-serial/serial"
"io"
"log"
"time"
"fmt"
)
func Sleep(duration int) {
time.Sleep(time.Second * time.Duration(duration))
}
func printBuf(b []byte){
for _, val:=range b {
fmt.Printf("%x ", val)
}
}
func main(){
options := serial.OpenOptions{
PortName: "/dev/ttyX",
BaudRate: 115200,
DataBits: 8,
StopBits: 1,
MinimumReadSize: 0,
InterCharacterTimeout: 50,
}
port, err := serial.Open(options)
if err != nil {
log.Printf("port.Read: %v", err)
return
}
// Make sure to close it later.
defer port.Close()
var s string = `AT+CSQ`
b:=[]byte(s)
n, err := port.Write(b)
if err != nil {
log.Printf("port.Write: %v", err)
}
log.Println("Written bytes: ", n)
//Sleep(1)
res := make([]byte, 64)
n, err = port.Read(res)
if err != nil && err != io.EOF {
log.Printf("port.Read: %v", err)
}
log.Println("READ bytes: ", n)
printBuf(res)
}
/*
I expect (for example):
---------
ATZ
OK
AT+CSQ
+CSQ 22.4
*/
Most serial devices need a termination character to react to the commands they receive.
If you add it, your code should work:
var s string = `AT+CSQ\r`
I don't see any other differences from your code and sending a command using a serial terminal. The same should apply when you echo the command directly onto the port file descriptor.

Sending a GUI/TUI Over a Socket Connection

Recently I have been trying to create a program in golang, which runs on a server, and accepts telnet connections. I would then like to open a TUI (text user interface) such as a curses menu (in the case of golang, something like: termui, gocui, etc) over that telnet connection. My question is, how exactly could I do this and/or would it even be possible? I have played around trying to start TUIs when a connection is accepted, but it just opens it on the server side, not on the telnet client side. From what I can tell, there is no easy way to just send a TUI over a telnet or any other socket IO connection for that matter.
Any help is appreciated in trying to figure this out. Thanks! :D
First, you should note that the example I give is completely insecure (don't expose it over the Internet!) and also doesn't provide for things like signal handling or resizing of the terminal (you may want to consider using SSH instead).
But to answer your question, here is an example of running a TCP server and connecting remote clients to a termui program running in a local PTY (uses both the https://github.com/gizak/termui and https://github.com/kr/pty packages):
package main
import (
"flag"
"io"
"log"
"net"
"os"
"os/exec"
ui "github.com/gizak/termui"
"github.com/kr/pty"
)
var termuiFlag = flag.Bool("termui", false, "run a termui example")
func main() {
flag.Parse()
var err error
if *termuiFlag {
err = runTermui()
} else {
err = runServer()
}
if err != nil {
log.Fatal(err)
}
}
// runTermui runs the termui "Hello World" example.
func runTermui() error {
if err := ui.Init(); err != nil {
return err
}
defer ui.Close()
p := ui.NewParagraph("Hello World!")
p.Width = 25
p.Height = 5
ui.Render(p)
for e := range ui.PollEvents() {
if e.Type == ui.KeyboardEvent {
break
}
}
return nil
}
// runServer listens for TCP connections on a random port and connects
// remote clients to a local PTY running the termui example.
func runServer() error {
ln, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
return err
}
defer ln.Close()
log.Printf("Listening for requests on %v", ln.Addr())
for {
conn, err := ln.Accept()
if err != nil {
return err
}
log.Printf("Connecting remote client %v to termui", conn.RemoteAddr())
go connectTermui(conn)
}
}
// connectTermui connects a client connection to a termui process running in a
// PTY.
func connectTermui(conn net.Conn) {
defer func() {
log.Printf("Closing remote client %v", conn.RemoteAddr())
conn.Close()
}()
t, err := pty.StartWithSize(
exec.Command(os.Args[0], "--termui"),
&pty.Winsize{Cols: 80, Rows: 24},
)
if err != nil {
log.Printf("Error starting termui: %v", err)
return
}
defer t.Close()
go io.Copy(t, conn)
io.Copy(conn, t)
}
Example usage is to run this program in one window and connect to it using nc in another:
$ go run server.go
2019/01/18 01:39:37 Listening for requests on 127.0.0.1:56192
$ nc 127.0.0.1 56192
You should see the "Hello world" box (hit enter to disconnect).

Hyperledger fabric metrics

Just wanted to confirm if the fabric metrics is working for anyone? I'm using 1.1.0 release.
metrics:
# enable or disable metrics server
enabled: true
# when enable metrics server, must specific metrics reporter type
# currently supported type: "statsd","prom"
reporter: statsd
# determines frequency of report metrics(unit: second)
interval: 1s
statsdReporter:
# statsd server address to connect
address: 172.18.19.29:8125
# determines frequency of push metrics to statsd server(unit: second)
flushInterval: 2s
# max size bytes for each push metrics request
# intranet recommend 1432 and internet recommend 512
flushBytes: 1432
promReporter:
# prometheus http server listen address for pull metrics
listenAddress: 0.0.0.0:8080
This is my core.yaml configuration, I tried with both Prometheus and Statsd but can't see any metrics with either of the methods. I can see the code present in the peer to export the metrics.
Can anyone please help with the configuration?
It's working on my environment with an exporter newly added by myself.
You need not only to change configuration in core.yaml, but also to implement your own exporter by using metrics package.
Making your exporter
Initialize viper & load core.yaml to enable metrics feature on peer node.
Configure metrics package by using core.yaml through viper.
Setup your metrics label. (In sample code below, label hyperledger_fabric_peer_blocknum is created)
Call Start() function. The function is blocked until when finishing export. So we need to execute it as a go routine.
And also you need to update your exported metrics periodically on another go routine. (In sample code below, the number of blocks is used as a metric)
In main thread, start to listen a channel to wait until interrupting.
package main
import (
"encoding/json"
"fmt"
"os"
"os/exec"
"time"
"github.com/hyperledger/fabric/common/flogging"
"github.com/hyperledger/fabric/common/metrics"
"github.com/hyperledger/fabric/peer/common"
)
var logger = flogging.MustGetLogger("fabexporter")
var block_num metrics.Gauge
func main() {
err := common.InitConfig("core")
if err != nil {
logger.Error(err)
}
opts := metrics.NewOpts()
if err := metrics.Init(opts); err != nil {
logger.Error(err)
return
}
s := metrics.RootScope.SubScope("peer")
block_num = s.Gauge("blocknum")
go startMonitor()
go func() {
metrics.RootScope.Start()
}()
server := make(chan int)
<-server
}
type Retdata struct {
Height int `json:"height"`
CurrentBlockHash string `json:"currentBlockHash"`
PreviousBlockHash string `json:"previousBlockHash"`
}
func startMonitor() {
var ret Retdata
for {
time.Sleep(5 * time.Second)
cmd := exec.Command("peer", "channel", "getinfo", "-c", "mychannel")
cmd.Env = os.Environ()
cmd.Env = append(cmd.Env, "CORE_LOGGING_LEVEL=CRITICAL")
out, err := cmd.Output()
if err != nil {
logger.Error(err)
continue
} else if len(out) == 0 {
continue
}
jsond := ([]byte)(out[17:]) // To trim "Blockchain info: "
if err := json.Unmarshal(jsond, &ret); err != nil {
logger.Error(err)
break
}
logger.Info(fmt.Sprintf("num of block : %d\n", ret.Height))
block_num.Update(float64(ret.Height))
}
}
I also wrote an article about it.
I hope it would be your help.
https://medium.com/#nekiaiken/hyperledger-fabric-meets-prometheus-649c452ba26a

making go http client work with non-standard http servers

Shoutcast servers basically speak http, with one important difference: they respond to GET requests with ICY 200 OK instead of HTTP/1.1 200 OK.
Go won't have a bar of it, and correctly fails with the error malformed HTTP version "ICY".
However I would like to make things work and am wondering what the best approach is. My ideas so far:
use a custom http.Transport.Proxy to change ICY to HTTP/1.1 in-flight
an out of process proxy that does the same thing
overload http.ParseHTTPVersion (but golang doesn't have function overloading)
duplicate the entire http package, just to modify ParseHTTPVersion
Number 1. seems the most attractive attractive, but I have no idea how to respect the http "scope" and actually modify all responses on a given http version. Is this the kind of thing http.Transport.Proxy can handle?
Can anyone give me any pointers?
I got this working by creating a custom Dial function that returns a wrapped connection. My wrapper intercepts the first read on the connection and replaces ICY with HTTP/1.1. Not super robust, but proves the concept:
package main
import (
"fmt"
"net"
"net/http"
)
type IcyConnWrapper struct {
net.Conn
haveReadAny bool
}
func (i *IcyConnWrapper) Read(b []byte) (int, error) {
if i.haveReadAny {
return i.Conn.Read(b)
}
i.haveReadAny = true
//bounds checking ommitted. There are a few ways this can go wrong.
//always check array sizes and returned n.
n, err := i.Conn.Read(b[:3])
if err != nil {
return n, err
}
if string(b[:3]) == "ICY" {
//write Correct http response into buffer
copy(b, []byte("HTTP/1.1"))
return 8, nil
}
return n, nil
}
func main() {
tr := &http.Transport{
Dial: func(network, a string) (net.Conn, error) {
realConn, err := net.Dial(network, a)
if err != nil {
return nil, err
}
return &IcyConnWrapper{Conn: realConn}, nil
},
}
client := &http.Client{Transport: tr}
http.DefaultClient = client
resp, err := http.Get("http://178.33.230.189:8100") //random url I found on the internet
fmt.Println(err)
fmt.Println(resp.StatusCode)
}

go websockets eof

I'm trying to make a simple command forwarder to connect my home computer to a server I own, so that I can push commands to my server and my home pc gets it. Those commands are simple pause/resume for my downloader. My design is, that on a server, I run a hub instance, which creates a window for passing commands and a window for backend to pass those commands to my pc. I'm bounding those two "windows" with a channel, they run a server. When a client connects and sends a message to the hub, it gets streamed through a channel to backend window and then to the real backend (on my home pc). When backend responds to the backend window on the hub, the hub prints the result back to the client.
With this approach, only the first message passes and works with my downloader. I have to reconnect the backend from my home pc with the hub each time I get a message to get this working properly. I don't think that's the proper way with websockets, so here I am. After one successful request (when the backend finishes it's work and replies the result), it gets looped forever with EOF error.
The important parts of the code are:
main executable
hub handlers
backend connector
If you put the source in your GOPATH (i'm developing it for the tip version of go to support modern websockets), to compile it:
go build gosab/cmd, to run it:
./cmd -mode="hub" hub
./cmd -mode="backend" --address="localhost:8082" backend
To pass messages to the hub, use this javascript:
var s = new WebSocket("ws://localhost:8082")
s.send("1 5")
So how do I handle it? Are channels a good way to communicate between two different requests?
I'm surprised you haven't received an answer to this.
What you need to do is something like the code below. When you receive an incoming websocket connection, a new goroutine is spawned for that connection. If you let that goroutine end, it'll disconnect the websocket client.
I'm making an assumption that you're not necessarily going to be running the client and server on the same computer. If you always are, then it'd be better to do the communication internally via channels or such instead of using websockets or a network port. I only mention this because I'm not completely sure what you're using this for. I just hope I answered the right part of your question.
package main
import (
"code.google.com/p/go.net/websocket"
"flag"
"fmt"
"net/http"
"os"
"time"
)
type Message struct {
RequestID int
Command string
SomeOtherThing string
Success bool
}
var mode *string = flag.String("mode", "<nil>", "Mode: server or client")
var address *string = flag.String("address", "localhost:8080", "Bind address:port")
func main() {
flag.Parse()
switch *mode {
case "server":
RunServer()
case "client":
RunClient()
default:
flag.Usage()
}
}
func RunServer() {
http.Handle("/", http.FileServer(http.Dir("www")))
http.Handle("/server", websocket.Handler(WSHandler))
fmt.Println("Starting Server")
err := http.ListenAndServe(*address, nil)
if err != nil {
fmt.Printf("HTTP failed: %s\n", err.Error())
os.Exit(1)
}
}
func WSHandler(ws *websocket.Conn) {
defer ws.Close()
fmt.Println("Client Connected")
for {
var message Message
err := websocket.JSON.Receive(ws, &message)
if err != nil {
fmt.Printf("Error: %s\n", err.Error())
return
}
fmt.Println(message)
// do something useful here...
response := new(Message)
response.RequestID = message.RequestID
response.Success = true
response.SomeOtherThing = "The hot dog left the castle as requested."
err = websocket.JSON.Send(ws, response)
if err != nil {
fmt.Printf("Send failed: %s\n", err.Error())
os.Exit(1)
}
}
}
func RunClient() {
fmt.Println("Starting Client")
ws, err := websocket.Dial(fmt.Sprintf("ws://%s/server", *address), "", fmt.Sprintf("http://%s/", *address))
if err != nil {
fmt.Printf("Dial failed: %s\n", err.Error())
os.Exit(1)
}
incomingMessages := make(chan Message)
go readClientMessages(ws, incomingMessages)
i := 0
for {
select {
case <-time.After(time.Duration(2e9)):
i++
response := new(Message)
response.RequestID = i
response.Command = "Eject the hot dog."
err = websocket.JSON.Send(ws, response)
if err != nil {
fmt.Printf("Send failed: %s\n", err.Error())
os.Exit(1)
}
case message := <-incomingMessages:
fmt.Println(message)
}
}
}
func readClientMessages(ws *websocket.Conn, incomingMessages chan Message) {
for {
var message Message
err := websocket.JSON.Receive(ws, &message)
if err != nil {
fmt.Printf("Error: %s\n", err.Error())
return
}
incomingMessages <- message
}
}

Resources