// SetTCPOptions sets our default TCP options on a TCP connection, possibly // digging through dialerConn to extract the *net.TCPConn func SetTCPOptions(conn net.Conn) error { switch conn := conn.(type) { case *net.TCPConn: var err error if err = conn.SetLinger(0); err != nil { return err } if err = conn.SetNoDelay(false); err != nil { return err } if err = conn.SetKeepAlivePeriod(60 * time.Second); err != nil { return err } if err = conn.SetKeepAlive(true); err != nil { return err } return nil case dialerConn: return SetTCPOptions(conn.Conn) default: return fmt.Errorf("unknown connection type %T", conn) } }
func (v *Rtmp) serve(c net.Conn) { // use gfork to serve the connection. v.wc.GFork("", func(wc core.WorkerContainer) { defer func() { if r := recover(); r != nil { if !core.IsNormalQuit(r) { core.Warn.Println("rtmp ignore", r) } core.Error.Println(string(debug.Stack())) } }() defer func() { if err := c.Close(); err != nil { core.Info.Println("ignore close failed. err is", err) } }() // for tcp connections. if c, ok := c.(*net.TCPConn); ok { // set TCP_NODELAY to false for performance issue. // TODO: FIXME: config it. // TODO: FIXME: refine for the realtime streaming. if err := c.SetNoDelay(false); err != nil { core.Error.Println("set TCP_NODELAY failed. err is", err) return } } core.Trace.Println("rtmp accept", c.RemoteAddr()) conn := protocol.NewRtmpConnection(c, v.wc) defer conn.Close() if err := v.cycle(conn); err != nil { if !core.IsNormalQuit(err) && !IsControlError(err) { core.Warn.Println("ignore error when cycle rtmp. err is", err) } else { core.Info.Println("rtmp cycle ok.") } return } return }) }