56 lines
1.7 KiB
Go
56 lines
1.7 KiB
Go
package goricochet
|
|
|
|
import (
|
|
"github.com/s-rah/go-ricochet/utils"
|
|
"github.com/s-rah/go-ricochet/connection"
|
|
"io"
|
|
"net"
|
|
"log"
|
|
)
|
|
// Open establishes a protocol session on an established net.Conn, and returns a new
|
|
// OpenConnection instance representing this connection. On error, the connection
|
|
// will be closed. This function blocks until version negotiation has completed.
|
|
// The application should call Process() on the returned OpenConnection to continue
|
|
// handling protocol messages.
|
|
func Open(remoteHostname string) (*connection.Connection, error) {
|
|
networkResolver := utils.NetworkResolver{}
|
|
log.Printf("Connecting...")
|
|
conn, remoteHostname, err := networkResolver.Resolve(remoteHostname)
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
log.Printf("Connected...negotiating version")
|
|
rc, err := negotiateVersion(conn, remoteHostname)
|
|
if err != nil {
|
|
conn.Close()
|
|
return nil, err
|
|
}
|
|
log.Printf("Connected...negotiated version")
|
|
return rc, nil
|
|
}
|
|
|
|
|
|
// negotiate version takes an open network connection and executes
|
|
// the ricochet version negotiation procedure.
|
|
func negotiateVersion(conn net.Conn, remoteHostname string) (*connection.Connection, error) {
|
|
versions := []byte{0x49, 0x4D, 0x01, 0x01}
|
|
if n, err := conn.Write(versions); err != nil || n < len(versions) {
|
|
return nil, utils.VersionNegotiationError
|
|
}
|
|
|
|
res := make([]byte, 1)
|
|
if _, err := io.ReadAtLeast(conn, res, len(res)); err != nil {
|
|
return nil, utils.VersionNegotiationError
|
|
}
|
|
|
|
if res[0] != 0x01 {
|
|
return nil, utils.VersionNegotiationFailed
|
|
}
|
|
rc := connection.NewOutboundConnection(conn,remoteHostname)
|
|
return rc, nil
|
|
}
|
|
|
|
|