aboutsummaryrefslogtreecommitdiff
path: root/nexgb/conn.go
diff options
context:
space:
mode:
Diffstat (limited to 'nexgb/conn.go')
-rw-r--r--nexgb/conn.go161
1 files changed, 161 insertions, 0 deletions
diff --git a/nexgb/conn.go b/nexgb/conn.go
new file mode 100644
index 0000000..235402d
--- /dev/null
+++ b/nexgb/conn.go
@@ -0,0 +1,161 @@
+package xgb
+
+import (
+ "errors"
+ "fmt"
+ "io"
+ "net"
+ "os"
+ "strconv"
+ "strings"
+)
+
+// connect connects to the X server given in the 'display' string.
+// If 'display' is empty it will be taken from os.Getenv("DISPLAY").
+// Note that you should read and understand the "Connection Setup" of the
+// X Protocol Reference Manual before changing this function:
+// http://goo.gl/4zGQg
+func (c *Conn) connect(display string) error {
+ err := c.dial(display)
+ if err != nil {
+ return err
+ }
+
+ // Get authentication data
+ authName, authData, err := readAuthority(c.host, c.display)
+ noauth := false
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Could not get authority info: %v\n", err)
+ fmt.Fprintf(os.Stderr, "Trying connection without authority info...\n")
+ authName = ""
+ authData = []byte{}
+ noauth = true
+ }
+
+ // Assume that the authentication protocol is "MIT-MAGIC-COOKIE-1".
+ if !noauth && (authName != "MIT-MAGIC-COOKIE-1" || len(authData) != 16) {
+ return errors.New("unsupported auth protocol " + authName)
+ }
+
+ buf := make([]byte, 12+pad(len(authName))+pad(len(authData)))
+ buf[0] = 0x6c
+ buf[1] = 0
+ Put16(buf[2:], 11)
+ Put16(buf[4:], 0)
+ Put16(buf[6:], uint16(len(authName)))
+ Put16(buf[8:], uint16(len(authData)))
+ Put16(buf[10:], 0)
+ copy(buf[12:], []byte(authName))
+ copy(buf[12+pad(len(authName)):], authData)
+ if _, err = c.conn.Write(buf); err != nil {
+ return err
+ }
+
+ head := make([]byte, 8)
+ if _, err = io.ReadFull(c.conn, head[0:8]); err != nil {
+ return err
+ }
+ code := head[0]
+ reasonLen := head[1]
+ major := Get16(head[2:])
+ minor := Get16(head[4:])
+ dataLen := Get16(head[6:])
+
+ if major != 11 || minor != 0 {
+ return errors.New(fmt.Sprintf("x protocol version mismatch: %d.%d",
+ major, minor))
+ }
+
+ buf = make([]byte, int(dataLen)*4+8, int(dataLen)*4+8)
+ copy(buf, head)
+ if _, err = io.ReadFull(c.conn, buf[8:]); err != nil {
+ return err
+ }
+
+ if code == 0 {
+ reason := buf[8 : 8+reasonLen]
+ return errors.New(fmt.Sprintf("x protocol authentication refused: %s",
+ string(reason)))
+ }
+
+ ReadSetupInfo(buf, &c.Setup)
+
+ if c.defaultScreen >= len(c.Setup.Roots) {
+ c.defaultScreen = 0
+ }
+
+ return nil
+}
+
+func (c *Conn) dial(display string) error {
+ if len(display) == 0 {
+ display = os.Getenv("DISPLAY")
+ }
+
+ display0 := display
+ if len(display) == 0 {
+ return errors.New("empty display string")
+ }
+
+ colonIdx := strings.LastIndex(display, ":")
+ if colonIdx < 0 {
+ return errors.New("bad display string: " + display0)
+ }
+
+ var protocol, socket string
+
+ if display[0] == '/' {
+ socket = display[0:colonIdx]
+ } else {
+ slashIdx := strings.LastIndex(display, "/")
+ if slashIdx >= 0 {
+ protocol = display[0:slashIdx]
+ c.host = display[slashIdx+1 : colonIdx]
+ } else {
+ c.host = display[0:colonIdx]
+ }
+ }
+
+ display = display[colonIdx+1 : len(display)]
+ if len(display) == 0 {
+ return errors.New("bad display string: " + display0)
+ }
+
+ var scr string
+ dotIdx := strings.LastIndex(display, ".")
+ if dotIdx < 0 {
+ c.display = display[0:]
+ } else {
+ c.display = display[0:dotIdx]
+ scr = display[dotIdx+1:]
+ }
+
+ dispnum, err := strconv.Atoi(c.display)
+ if err != nil || dispnum < 0 {
+ return errors.New("bad display string: " + display0)
+ }
+
+ if len(scr) != 0 {
+ c.defaultScreen, err = strconv.Atoi(scr)
+ if err != nil {
+ return errors.New("bad display string: " + display0)
+ }
+ }
+
+ // Connect to server
+ if len(socket) != 0 {
+ c.conn, err = net.Dial("unix", socket+":"+c.display)
+ } else if len(c.host) != 0 {
+ if protocol == "" {
+ protocol = "tcp"
+ }
+ c.conn, err = net.Dial(protocol, c.host+":"+strconv.Itoa(6000+dispnum))
+ } else {
+ c.conn, err = net.Dial("unix", "/tmp/.X11-unix/X"+c.display)
+ }
+
+ if err != nil {
+ return errors.New("cannot connect to " + display0 + ": " + err.Error())
+ }
+ return nil
+}