Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Non-blocking SCTP Socket #41

Open
calee0219 opened this issue Dec 29, 2019 · 6 comments
Open

Non-blocking SCTP Socket #41

calee0219 opened this issue Dec 29, 2019 · 6 comments

Comments

@calee0219
Copy link

I have test the code like following:
In short it's just goroutine the accept and close the listener. In TCP test, accept will return error and we can use error handling to close the socket. But in SCTP, the accept will not return error and keep binding on the fd. Therefor, we cannot reuse the address.

After I take a look of TCP's implementation, I found that TCP is using non-blocking flag in syscall. Due to the reason, accept won't block the fd in system and can successfully return the error when listener close.

Is it possible to change the architecture of SCTP to non-blocking socket type?

package main

import (
        "fmt"
        "net"
        "time"

        "github.com/ishidawataru/sctp"
)

func main() {
        port := 38412
        ips := []net.IPAddr{}
        a, err := net.ResolveIPAddr("ip", "127.0.0.1")
        if err != nil {
                fmt.Print("err")
        }
        ips = append(ips, *a)

        addr := &sctp.SCTPAddr{
                IPAddrs: ips,
                Port:    port,
        }

        ln, err := sctp.ListenSCTP("sctp", addr)
        if err != nil {
                fmt.Print("err")
        }
        fmt.Println("Start listen")

        go func() {
                for {
                        sctpConn, err := ln.AcceptSCTP()
                        if err != nil {
                                fmt.Printf("err: %d\n", err)
                                return
                        }
                        defer sctpConn.Close()
                        fmt.Println("Accept from: ", sctpConn.RemoteAddr().String())
                        buffer := make([]byte, 8192)
                        n, _, err := sctpConn.SCTPRead(buffer)
                        fmt.Println(buffer[:n])
                        sctpConn.Close()
                }
        }()

        time.Sleep(10 * time.Second)

        ln.Close()
        fmt.Println("close socket")

        time.Sleep(50 * time.Second)
}
@vk-coder
Copy link

vk-coder commented Jul 6, 2023

I tried setting SCTP socket in non-blocking mode using SetNonblock() but then accept call fails with temporary failure and keeps logging errors. Everything else works as expected except these huge amount of logs.

Can we at least disable the log for the temporary failures?

specifically talking about


                        if ne, ok := e.(net.Error); ok && ne.Temporary() {
                                if tempDelay == 0 {
                                        tempDelay = 5 * time.Millisecond
                                } else {
                                        tempDelay *= 2
                                }
                                if max := 1 * time.Second; tempDelay > max {
                                        tempDelay = max
                                }
                                log.Printf("diam: accept error: %v; retrying in %v", e, tempDelay) <<<< this log statement
                                time.Sleep(tempDelay)
                                continue
                        }

@ishidawataru
Copy link
Owner

Are you talking about this line?
If so, it's not in this repo.

@vk-coder
Copy link

vk-coder commented Jul 6, 2023

my bad, i was working on go-diameter library and was having same issue there also. you can ignore/ delete my comments.

@georgeyanev
Copy link

georgeyanev commented Oct 11, 2023

@vk-coder can you elaborate how exactly are you using SetNonblock to make the sctp Accept nonblocking? The fd field in SCTPListener in not public.

@vk-coder
Copy link

vk-coder commented Oct 12, 2023

@vk-coder can you elaborate how exactly are you using SetNonblock to make the sctp Accept nonblocking? The fd field in SCTPListener in not public.

I followed example given at bare example

this is how I created Non Blocking sctp listner

        import (
             	sctp "github.com/thebagchi/sctp-go"
        )

	listener, err = sctp.ListenSCTP("sctp4", syscall.SOCK_STREAM,
		sctp.MakeSCTPAddr("sctp4", "127.0.0.1"),
		&sctp.SCTPInitMsg{
			NumOutStreams:  uint16(10),
			MaxInStreams:   uint16(10),
			MaxAttempts:    3,
			MaxInitTimeout: 5,
		},
	)
	if err != nil {
		log.Fatal(err)
		os.Exit(1)
	}
	defer listener.Close()

	err = listener(*sctp.SCTPListener).SetNonblock().  // I am doing casting because I have stored variable of type net.Listener simple listener.SetNonblock() should also be available
	if err != nil {
		log.Fatalf("could not make sctp non blocking, %v", err)
                os.Exit(1)
	}

then

    for {
        conn, err := listener.Accept()
        if err != nil {
            switch v := err.(type) {
            case syscall.Errno:
                if v == 11 {
                    // handle EAGAIN error, typical error for non-blocking sockets
                    time.Sleep(10 * time.Microsecond)
                }
            }
        } else {
            m, err := diam.ReadMessage(conn, dict.Default)
        }
   }

@georgeyanev
Copy link

@vk-coder Thank you for sharing your example. So you are using sctp-go from thebagchi and not ishidawataru sctp.
I wonder wouldn't two sctp libraries in a project seem too much for this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants