Golang close net listener - go

I am having trouble closing a listener so that I can reopen it on the same port. I am writing a proxy server that is hot-configurable - i.e what it does (redirects/blocks etc) can be adjusted on the fly. The proxy runs in a go routine. The problem I am having is when I reconfigure the listener and proxy the listener is still using that port from the previous configuration. (FYI listener is a global pointer)
I'm trying something like:
to kill the listener:
func KillProxy() {
if listener != nil {
log.Println(" *** TRYING TO STOP THE PROXY SERVER")
(*listener).Close()
listener = nil
}
}
before reconfiguring it like:
log.Println("listener (S1): ", listener)
if listener == nil {
// Start the listener to listen on the connection.
l, err := net.Listen(CONN_TYPE, CONN_HOST + ":" + CONN_PORT)
if err != nil {
log.Println("error here: ", err)
}
listener = &l //set it as a pointer to the newly created listener
}
log.Println("listener (S2): ", listener)
however that doesnt seem to work - I get the error:
listener (S1):
error here: listen tcp 0.0.0.0:8080: bind: address already in use
listener (S2): 0xc2080015e0
and then a massive stack trace that summizes to:
panic: runtime error: invalid memory address or nil pointer dereference
EDIT IN RESPONSE TO JIM:
Interesting re pointers. OK. I am not handling waiting for the socket to close, Im not sure how that should be done. The proxy library I am using is this one: https://github.com/abourget/goproxy. The order things happen is:
KillProxy()
refreshProxy()
refreshProxy holds the code posted above that tries to repurpose the listener. The last thing that happens in refreshProxy() is:
go http.Serve(*listener, proxy)
So if I revert to listener being a global variable, not a pointer I can make KillProxy():
func KillProxy() {
if listener != nil {
listener.Close()
listener = nil
}
}
and then setup the listener again as
listener, err := net.Listen(CONN_TYPE, CONN_HOST + ":" + CONN_PORT)
if err != nil {
log.Println("error here: ", err)
}
However I don't know how to wait and check whether the socket has closed before trying to re create the listener object?

Ok this is far from perfect, but the only way I found of not having it error out on me was to artifically put a delay in my code so the socket had time to close.
This isn't great as it means the proxy is down for 2 seconds while the socket closes, but at least it doesnt error out.
If someone has a better solution I would like to hear it
func KillProxy() {
if listener != nil {
listener.Close()
log.Println("waiting for socket to close")
time.Sleep(2 * time.Second)
}
}

Related

i/o timeout issue when receiving the message on SQS and memory leak https usage

AWS SDK Version: v1.38.19
Go Version: go1.15.7
alpine 3.7
I am using the standard queue
I am initializing the SQS connection at once in my application like this;
// Connection connection to the SQS
var Connection *sqs.SQS
// InitSQS initialize the AWS SQS connection
func InitSQS() {
sess := session.Must(session.NewSessionWithOptions(session.Options{
SharedConfigState: session.SharedConfigEnable,
}))
Connection = sqs.New(sess, &aws.Config{
Region: aws.String("eu-west-1"),
DisableSSL: aws.Bool(true),
})
}
I am disabling the SSL because; I am having memory and CPU leaks when I am going with the SSL in my application (my application isn't open for the rest of the world btw it's an internal service for my other applications).
Here is the config I use to read a message from SQS:
func ConsumeUpdateMessage(db *database.MySQLWrap, sqsApi queue.SQSAPI) error {
result, err := sqsApi.ReceiveMessage(&sqs.ReceiveMessageInput{
AttributeNames: []*string{
aws.String(sqs.MessageSystemAttributeNameSentTimestamp),
},
MessageAttributeNames: []*string{
aws.String(sqs.QueueAttributeNameAll),
},
QueueUrl: &qURL,
MaxNumberOfMessages: aws.Int64(10),
WaitTimeSeconds: aws.Int64(20),
})
if err != nil {
return fmt.Errorf("error on receiving the message from queue: %s", err.Error())
}
for _, msg := range result.Messages {
// business logic
}
return err
}
this is how I am calling the ConsumeUpdateMessage method;
// InitializeUpdateMessage ..
func InitializeUpdateMessage(db *database.MySQLWrap, sqsApi queue.SQSAPI) {
go func() {
for {
time.Sleep(500 * time.Millisecond)
err := ConsumeUpdateMessage(db, sqsApi)
if err != nil {
log.Error(err)
continue
}
}
}()
}
but sometimes my subscriber return error like this;
*awserr.baseError: RequestError: send request failed
caused by: Post "http://sqs.eu-west-1.amazonaws.com/": dial tcp xx.x.xx.xxx:80: i/o timeout
(Note: I put xx instead of sharing the IP Address)
I made my search over the forums and other places but I can't find a solution for these two-issue,
Memory leak when I using the connection with SSL (idea: but since my application is an internal service I think I don't have to use with SSL)
i/o timeout

How to close a reading TCP connection from another goroutine?

My server senario is like this: One io thread is doing read on a tcp connection all the time. After a while the control thread may decide to close it due to low activity or some other reason. If c.Close() is called the io thread will report an error like this: read tcp xxx->xxx: use of closed network connection.
The code is like this:
func recv(c net.Conn) {
input := bufio.NewScanner(c)
for input.Scan() {
msg <- input.Text()
...
}
}
//main
conn, err := s.Accept()
...
go recv(conn)
for {
select {
case m := <-msg:
...
case <-timeout:
conn.Close() // oops!
}
}
I could ignore the error perhaps but I wonder whether there is a better way.
The options are to close the connection or set the read deadline to a time in the past. Either way, read on the connection will return an error.
The simplest approach for handling these errors is to handle all errors returned from read on the network connection uniformly: close the connection, clean up the resources associated with the connection and move on. It's OK to close the connection twice.
func recv(c net.Conn, msg chan string) {
defer close(msg) // Notify main goroutine that recv is done.
defer c.Close() // Release resources.
input := bufio.NewScanner(c)
// Loop reading lines until read on c returns an error.
// These errors include io.EOF (normal close by the peer),
// the error caused by the main goroutine closing the connection
// and other networking errors.
for input.Scan() {
msg <- input.Text()
}
}
// main
conn, err := s.Accept()
if err != nil {
// handle error
}
msg := make(chan string)
go recv(conn, msg)
for {
select {
case m, ok := <-msg:
if !ok {
// The recv goroutine closed the channel and the connection.
return
}
fmt.Println(m)
case <-timeout:
// Closing the connection causes the recv goroutine to break
// out of the loop. If the recv goroutine received a line of
// text and has yet sent the text to the msg channel, then
// a return from main at this point will cause the recv goroutine
// to block forever. To avoid this, continue looping until until
// the recv goroutine signals that it's done by closing the msg
// channel.
conn.Close()
}
}
}
The application can record that it's shutting down the connection and handle read errors after that point in a special way, but only do that if the application needs to do something special in this situation.
There're some errors that suggests handle alone like:
EOF: a long received message has finished read, everything is normal,so continue.
"An existing connection was forcibly closed by the remote host": client closes app.It's nomal and talking finished, so return.
else: some loginc or server error, need to be log and fix
handler(c net.Conn){
defer c.Close()
for {
...
if e!=nil {
if e == io.EOF{
continue
}
if strings.Contains(e.Error(), "An existing connection was forcibly closed by the remote host.") {
return
}
log.Println(e.Error())
return
}
}
}
On your case, you don't want to handle the error contains 'use of closed network connection'.It's ok ignore it and remember to close the loop.Otherwise some memory will leak and a routine is hung on.There might be a hidden error which you ignore throwing over and over again.
func recv(c *net.Conn) {
if c == nil {
return
}
input := bufio.NewScanner(*c)
for input.Scan() {
msg <- input.Text()
...
}
}
//main
conn, err := s.Accept()
c := &conn
...
go recv(&c)
for {
select {
case m := <-msg:
...
case <-timeout:
conn.Close()
c = nil
}
}
Not sure if this is the best approach. When you close the conn, you can set it to nil and not read from a nil conn value.

Websocket Control Message

I have two projects on Golang server and client.
Problem is when I send controll message from server, i can't get it by type on client side.
Few server code example:
send PingMessage:
ws.SetWriteDeadline(time.Now().Add(10 * time.Second))
ws.WriteMessage(websocket.PingMessage, new_msg)
send CloseMessage:
ws.WriteControl(websocket.CloseMessage,
websocket.FormatCloseMessage(websocket.CloseNormalClosure, "socket close"),
time.Now().Add(3 * time.Second))
client side:
for{
t, socketMsg, err := ws.ReadMessage()
if websocket.IsUnexpectedCloseError(err) {
webSock.keepLive()
}
switch t {
case websocket.CloseNormalClosure:
webSock.keepLive()
case websocket.PingMessage:
log.Warn("get ping!!!")
case websocket.TextMessage:
SocketChannel <- socketMsg
}
}
for example CloseNormalClosure message i can get only with:
if websocket.IsCloseError(err, websocket.CloseNormalClosure){
log.Warn("CloseNormalClosure message")
}
But PingMessage, I can't get by type:
case websocket.PingMessage:
log.Warn("get ping!!!")
Could you help me, please, what Im doing wrong ?
The documentation says:
Connections handle received close messages by calling the handler function set with the SetCloseHandler method and by returning a *CloseError from the NextReader, ReadMessage or the message Read method. The default close handler sends a close message to the peer.
Connections handle received ping messages by calling the handler function set with the SetPingHandler method. The default ping handler sends a pong message to the peer.
Connections handle received pong messages by calling the handler function set with the SetPongHandler method. The default pong handler does nothing. If an application sends ping messages, then the application should set a pong handler to receive the corresponding pong.
Write the code above as:
ws.SetPingHandler(func(s string) error {
log.Warn("get ping!!!")
return nil
})
for {
t, socketMsg, err := ws.ReadMessage()
switch {
case websocket.IsCloseError(websocket.CloseNormalClosure):
webSock.keepLive()
case websocket.IsUnexpectedCloseError(err):
webSock.keepLive()
case t == websocket.TextMessage:
SocketChannel <- socketMsg
}
}
Most applications break out of the receive loop on any error. A more typical approach is to write the code above as:
for {
t, socketMsg, err := ws.ReadMessage()
if err != nil {
break
}
SocketChannel <- socketMsg
}

Open URL on open port

I'm assuming I can run a service on port 3000 like many other code samples I've seen on Github.
Now I am trying to improve my code so that it looks for an open port in case 3000 is in use:
for port := 3000; port <= 3005; port++ {
fmt.Println(port)
err := http.ListenAndServe(":"+strconv.Itoa(port), nil)
if err == nil {
fmt.Println("lk is serving", dirPath, "from http://0.0.0.0:", string(port))
open.Start("http://0.0.0.0:" + string(port))
}
}
However it blocks on the http.ListenAndServe line and doesn't open.Start my browser. I'm told I should use goroutines but I am still a bit bewildered how to use them in this context.
This is a "client" Web app so I do need it to invoke my browser.
Instead of calling ListenAndServe, create the Listener in the application and then call Serve. When creating the listener, request a free port by specifying the listener address as ":0":
ln, err := net.Listen("tcp", ":0")
if err != nil {
// handle error
}
Once the listener is open, you can start the browser:
open.Start("http://" + ln.Addr().String())
and then start the server:
if err := http.Serve(ln, nil); err != nil {
// handle error
}
There's no need to use a goroutine.
The code above uses addr.String() to format the listener's address. If you do need to get the port number for some reason, use a type assertion:
if a, ok := ln.Addr().(*net.TCPAddr); ok {
fmt.Println("port", a.Port)
}

Gorilla websocket error: close 1007 Illegal UTF-8 Sequence

I'm trying to implement a websocket proxy server for GlassFish. If I try to connect more than one client I'm getting error:
ReadMessage Failed: websocket: close 1007 Illegal UTF-8 Sequence.
I'm sure the GlassFish server sending right data, because the same server works properly with another proxy server implemented with node.js.
func GlassFishHandler(conn *websocket.Conn){
defer conn.Close()
conn.SetReadDeadline(time.Now().Add(1000 * time.Second))
conn.SetWriteDeadline(time.Now().Add(1000 * time.Second))
fmt.Println("WS-GOLANG PROXY SERVER: Connected to GlassFish")
for {
messageType, reader, err := conn.NextReader()
if err != nil {
fmt.Println("ReadMessage Failed: ", err) // <- error here
} else {
message, err := ioutil.ReadAll(reader)
if (err == nil && messageType == websocket.TextMessage){
var dat map[string]interface{}
if err := json.Unmarshal(message, &dat); err != nil {
panic(err)
}
// get client destination id
clientId := dat["target"].(string)
fmt.Println("Msg from GlassFish for Client: ", dat);
// pass through
clients[clientId].WriteMessage(websocket.TextMessage, message)
}
}
}
}
Summing up my comments as an answer:
When you are writing to the client, you are taking the clientId from the GlassFish message, fetching the client from a map, and then writing to it - basically clients[clientId].WriteMessage(...).
While your map access can be thread safe, writing is not, as this can be seen as:
// map access - can be safe if you're using a concurrent map
client := clients[clientId]
// writing to a client, not protected at all
client.WriteMessage(...)
So what's probably happening is that two separate goroutines are writing to the same client at the same time. You should protect your client from it by adding a mutex in the WriteMessage method implementation.
BTW actually instead of protecting this method with a mutex, a better, more "go-ish" approach would be to use a channel to write the message, and a goroutine per client that consumes from the channel and writes to the actual socket.
So in the client struct I'd do something like this:
type message struct {
msgtype string
msg string
}
type client struct {
...
msgqueue chan *message
}
func (c *client)WriteMessage(messageType, messageText string) {
// I'm simplifying here, but you get the idea
c.msgqueue <- &message{msgtype: messageType, msg: messageText}
}
func (c *client)writeLoop() {
go func() {
for msg := ragne c.msgqueue {
c.actuallyWriteMessage(msg)
}
}()
}
and when creating a new client instance, just launch the write loop

Resources