package main import ( "net" "time" ) // Connection represents a network socket. type Connection struct { dialer net.Dialer socket net.Conn connectTimeout time.Duration sendTimeout time.Duration recvTimeout time.Duration protocol string endpoint *Endpoint } func init() { registerParam("connect-timeout-ms", 3000, "") registerParam("send-timeout-ms", 2000, "") registerParam("recv-timeout-ms", 1000, "") } // NewConnection creates a Connection object and optionally connects to an Endpoint. func NewConnection(endpoint *Endpoint) (*Connection, error) { conn := Connection{protocol: "tcp", endpoint: endpoint} conn.connectTimeout = getParamDurationMS("connect-timeout-ms") conn.sendTimeout = getParamDurationMS("send-timeout-ms") conn.recvTimeout = getParamDurationMS("recv-timeout-ms") if endpoint != nil { return &conn, conn.Connect() } else { return &conn, nil } } func (conn *Connection) Close() { if conn.socket != nil { conn.socket.Close() conn.socket = nil } } // Connect initiates a connection to an Endpoint. func (conn *Connection) Connect() (err error) { conn.endpoint.TakeMutex() address := conn.endpoint.String() conn.endpoint.ReleaseMutex() conn.dialer = net.Dialer{Timeout: conn.connectTimeout, KeepAlive: -1} start := time.Now() conn.socket, err = conn.dialer.Dial(conn.protocol, address) if err != nil { log("conn", 2, "cannot connect to \"%v\": %v", address, err.Error()) } conn.endpoint.TakeMutex() conn.endpoint.RegisterRTT(time.Since(start)) conn.endpoint.ReleaseMutex() return } // SetConnectTimeout sets a custom connect timeout on a Connection. func (conn *Connection) SetConnectTimeout(timeout time.Duration) { conn.connectTimeout = timeout } // Send writes data to a Connection. func (conn *Connection) Send(data []byte) (err error) { if len(data) == 0 { log("conn", 1, "tried to send empty buffer to a socket, ignoring") return nil } if conn.endpoint != nil { conn.endpoint.lastSentAt = time.Now() } conn.socket.SetWriteDeadline(time.Now().Add(conn.sendTimeout)) _, err = conn.socket.Write(data) return } // Recv receives data from a Connection. func (conn *Connection) Recv() (data []byte, err error) { if conn.endpoint != nil { conn.endpoint.lastReceivedAt = time.Now() } data = make([]byte, 1024) conn.socket.SetReadDeadline(time.Now().Add(conn.recvTimeout)) n, err := conn.socket.Read(data) if err != nil { return nil, err } data = data[:n] return }