zorldo

Goofing around with Ebiten
git clone git://bsandro.tech/zorldo
Log | Files | Refs | README

conn.go (4607B)


      1 package xgb
      2 
      3 /*
      4 conn.go contains a couple of functions that do some real dirty work related
      5 to the initial connection handshake with X.
      6 
      7 This code is largely unmodified from the original XGB package that I forked.
      8 */
      9 
     10 import (
     11 	"errors"
     12 	"fmt"
     13 	"io"
     14 	"net"
     15 	"os"
     16 	"strconv"
     17 	"strings"
     18 )
     19 
     20 // connect connects to the X server given in the 'display' string,
     21 // and does all the necessary setup handshaking.
     22 // If 'display' is empty it will be taken from os.Getenv("DISPLAY").
     23 // Note that you should read and understand the "Connection Setup" of the
     24 // X Protocol Reference Manual before changing this function:
     25 // http://goo.gl/4zGQg
     26 func (c *Conn) connect(display string) error {
     27 	err := c.dial(display)
     28 	if err != nil {
     29 		return err
     30 	}
     31 
     32 	return c.postConnect()
     33 }
     34 
     35 // connect init from to the net.Conn,
     36 func (c *Conn) connectNet(netConn net.Conn) error {
     37 	c.conn = netConn
     38 	return c.postConnect()
     39 }
     40 
     41 // do the postConnect action after Conn get it's underly net.Conn
     42 func (c *Conn) postConnect() error {
     43 	// Get authentication data
     44 	authName, authData, err := readAuthority(c.host, c.display)
     45 	noauth := false
     46 	if err != nil {
     47 		Logger.Printf("Could not get authority info: %v", err)
     48 		Logger.Println("Trying connection without authority info...")
     49 		authName = ""
     50 		authData = []byte{}
     51 		noauth = true
     52 	}
     53 
     54 	// Assume that the authentication protocol is "MIT-MAGIC-COOKIE-1".
     55 	if !noauth && (authName != "MIT-MAGIC-COOKIE-1" || len(authData) != 16) {
     56 		return errors.New("unsupported auth protocol " + authName)
     57 	}
     58 
     59 	buf := make([]byte, 12+Pad(len(authName))+Pad(len(authData)))
     60 	buf[0] = 0x6c
     61 	buf[1] = 0
     62 	Put16(buf[2:], 11)
     63 	Put16(buf[4:], 0)
     64 	Put16(buf[6:], uint16(len(authName)))
     65 	Put16(buf[8:], uint16(len(authData)))
     66 	Put16(buf[10:], 0)
     67 	copy(buf[12:], []byte(authName))
     68 	copy(buf[12+Pad(len(authName)):], authData)
     69 	if _, err = c.conn.Write(buf); err != nil {
     70 		return err
     71 	}
     72 
     73 	head := make([]byte, 8)
     74 	if _, err = io.ReadFull(c.conn, head[0:8]); err != nil {
     75 		return err
     76 	}
     77 	code := head[0]
     78 	reasonLen := head[1]
     79 	major := Get16(head[2:])
     80 	minor := Get16(head[4:])
     81 	dataLen := Get16(head[6:])
     82 
     83 	if major != 11 || minor != 0 {
     84 		return fmt.Errorf("x protocol version mismatch: %d.%d", major, minor)
     85 	}
     86 
     87 	buf = make([]byte, int(dataLen)*4+8, int(dataLen)*4+8)
     88 	copy(buf, head)
     89 	if _, err = io.ReadFull(c.conn, buf[8:]); err != nil {
     90 		return err
     91 	}
     92 
     93 	if code == 0 {
     94 		reason := buf[8 : 8+reasonLen]
     95 		return fmt.Errorf("x protocol authentication refused: %s",
     96 			string(reason))
     97 	}
     98 
     99 	// Unfortunately, it isn't really feasible to read the setup bytes here,
    100 	// since the code to do so is in a different package.
    101 	// Users must call 'xproto.Setup(X)' to get the setup info.
    102 	c.SetupBytes = buf
    103 
    104 	// But also read stuff that we *need* to get started.
    105 	c.setupResourceIdBase = Get32(buf[12:])
    106 	c.setupResourceIdMask = Get32(buf[16:])
    107 
    108 	return nil
    109 }
    110 
    111 // dial initializes the actual net connection with X.
    112 func (c *Conn) dial(display string) error {
    113 	if len(display) == 0 {
    114 		display = os.Getenv("DISPLAY")
    115 	}
    116 
    117 	display0 := display
    118 	if len(display) == 0 {
    119 		return errors.New("empty display string")
    120 	}
    121 
    122 	colonIdx := strings.LastIndex(display, ":")
    123 	if colonIdx < 0 {
    124 		return errors.New("bad display string: " + display0)
    125 	}
    126 
    127 	var protocol, socket string
    128 
    129 	if display[0] == '/' {
    130 		socket = display[0:colonIdx]
    131 	} else {
    132 		slashIdx := strings.LastIndex(display, "/")
    133 		if slashIdx >= 0 {
    134 			protocol = display[0:slashIdx]
    135 			c.host = display[slashIdx+1 : colonIdx]
    136 		} else {
    137 			c.host = display[0:colonIdx]
    138 		}
    139 	}
    140 
    141 	display = display[colonIdx+1 : len(display)]
    142 	if len(display) == 0 {
    143 		return errors.New("bad display string: " + display0)
    144 	}
    145 
    146 	var scr string
    147 	dotIdx := strings.LastIndex(display, ".")
    148 	if dotIdx < 0 {
    149 		c.display = display[0:]
    150 	} else {
    151 		c.display = display[0:dotIdx]
    152 		scr = display[dotIdx+1:]
    153 	}
    154 
    155 	var err error
    156 	c.DisplayNumber, err = strconv.Atoi(c.display)
    157 	if err != nil || c.DisplayNumber < 0 {
    158 		return errors.New("bad display string: " + display0)
    159 	}
    160 
    161 	if len(scr) != 0 {
    162 		c.DefaultScreen, err = strconv.Atoi(scr)
    163 		if err != nil {
    164 			return errors.New("bad display string: " + display0)
    165 		}
    166 	}
    167 
    168 	// Connect to server
    169 	if len(socket) != 0 {
    170 		c.conn, err = net.Dial("unix", socket+":"+c.display)
    171 	} else if len(c.host) != 0 && c.host != "unix" {
    172 		if protocol == "" {
    173 			protocol = "tcp"
    174 		}
    175 		c.conn, err = net.Dial(protocol,
    176 			c.host+":"+strconv.Itoa(6000+c.DisplayNumber))
    177 	} else {
    178 		c.host = ""
    179 		c.conn, err = net.Dial("unix", "/tmp/.X11-unix/X"+c.display)
    180 	}
    181 
    182 	if err != nil {
    183 		return errors.New("cannot connect to " + display0 + ": " + err.Error())
    184 	}
    185 	return nil
    186 }