...

Source file src/github.com/jezek/xgb/xgb.go

Documentation: github.com/jezek/xgb

     1  package xgb
     2  
     3  import (
     4  	"errors"
     5  	"io"
     6  	"log"
     7  	"net"
     8  	"os"
     9  	"sync"
    10  )
    11  
    12  var (
    13  	// Where to log error-messages. Defaults to stderr.
    14  	// To disable logging, just set this to log.New(ioutil.Discard, "", 0)
    15  	Logger = log.New(os.Stderr, "XGB: ", log.Lshortfile)
    16  )
    17  
    18  const (
    19  	// cookieBuffer represents the queue size of cookies existing at any
    20  	// point in time. The size of the buffer is really only important when
    21  	// there are many requests without replies made in sequence. Once the
    22  	// buffer fills, a round trip request is made to clear the buffer.
    23  	cookieBuffer = 1000
    24  
    25  	// xidBuffer represents the queue size of the xid channel.
    26  	// I don't think this value matters much, since xid generation is not
    27  	// that expensive.
    28  	xidBuffer = 5
    29  
    30  	// seqBuffer represents the queue size of the sequence number channel.
    31  	// I don't think this value matters much, since sequence number generation
    32  	// is not that expensive.
    33  	seqBuffer = 5
    34  
    35  	// reqBuffer represents the queue size of the number of requests that
    36  	// can be made until new ones block. This value seems OK.
    37  	reqBuffer = 100
    38  
    39  	// eventBuffer represents the queue size of the number of events or errors
    40  	// that can be loaded off the wire and not grabbed with WaitForEvent
    41  	// until reading an event blocks. This value should be big enough to handle
    42  	// bursts of events.
    43  	eventBuffer = 5000
    44  )
    45  
    46  // A Conn represents a connection to an X server.
    47  type Conn struct {
    48  	host          string
    49  	conn          net.Conn
    50  	display       string
    51  	DisplayNumber int
    52  	DefaultScreen int
    53  	SetupBytes    []byte
    54  
    55  	setupResourceIdBase uint32
    56  	setupResourceIdMask uint32
    57  
    58  	eventChan  chan eventOrError
    59  	cookieChan chan *Cookie
    60  	xidChan    chan xid
    61  	seqChan    chan uint16
    62  	reqChan    chan *request
    63  	doneSend   chan struct{}
    64  	doneRead   chan struct{}
    65  
    66  	// ExtLock is a lock used whenever new extensions are initialized.
    67  	// It should not be used. It is exported for use in the extension
    68  	// sub-packages.
    69  	ExtLock sync.RWMutex
    70  
    71  	// Extensions is a map from extension name to major opcode. It should
    72  	// not be used. It is exported for use in the extension sub-packages.
    73  	Extensions map[string]byte
    74  }
    75  
    76  // NewConn creates a new connection instance. It initializes locks, data
    77  // structures, and performs the initial handshake. (The code for the handshake
    78  // has been relegated to conn.go.)
    79  // It is up to user to close connection with Close() method to finish all unfinished requests and clean up spawned goroutines.
    80  // If the connection unexpectedly closes itself and WaitForEvent() returns "nil, nil", everything is cleaned by that moment, but nothing bad happens if you call Close() after.
    81  func NewConn() (*Conn, error) {
    82  	return NewConnDisplay("")
    83  }
    84  
    85  // NewConnDisplay is just like NewConn (see closing instructions), but allows a specific DISPLAY
    86  // string to be used.
    87  // If 'display' is empty it will be taken from os.Getenv("DISPLAY").
    88  //
    89  // Examples:
    90  //	NewConn(":1") -> net.Dial("unix", "", "/tmp/.X11-unix/X1")
    91  //	NewConn("/tmp/launch-12/:0") -> net.Dial("unix", "", "/tmp/launch-12/:0")
    92  //	NewConn("hostname:2.1") -> net.Dial("tcp", "", "hostname:6002")
    93  //	NewConn("tcp/hostname:1.0") -> net.Dial("tcp", "", "hostname:6001")
    94  func NewConnDisplay(display string) (*Conn, error) {
    95  	c := &Conn{}
    96  
    97  	// First connect. This reads authority, checks DISPLAY environment
    98  	// variable, and loads the initial Setup info.
    99  	err := c.connect(display)
   100  	if err != nil {
   101  		return nil, err
   102  	}
   103  
   104  	return postNewConn(c)
   105  }
   106  
   107  // NewConnNet is just like NewConn (see closing instructions), but allows a specific net.Conn
   108  // to be used.
   109  func NewConnNet(netConn net.Conn) (*Conn, error) {
   110  	c := &Conn{}
   111  
   112  	// First connect. This reads authority, checks DISPLAY environment
   113  	// variable, and loads the initial Setup info.
   114  	err := c.connectNet(netConn)
   115  
   116  	if err != nil {
   117  		return nil, err
   118  	}
   119  
   120  	return postNewConn(c)
   121  }
   122  
   123  func postNewConn(c *Conn) (*Conn, error) {
   124  	c.Extensions = make(map[string]byte)
   125  
   126  	c.cookieChan = make(chan *Cookie, cookieBuffer)
   127  	c.xidChan = make(chan xid, xidBuffer)
   128  	c.seqChan = make(chan uint16, seqBuffer)
   129  	c.reqChan = make(chan *request, reqBuffer)
   130  	c.eventChan = make(chan eventOrError, eventBuffer)
   131  	c.doneSend = make(chan struct{})
   132  	c.doneRead = make(chan struct{})
   133  
   134  	go c.generateXIds()
   135  	go c.generateSeqIds()
   136  	go c.sendRequests()
   137  	go c.readResponses()
   138  
   139  	return c, nil
   140  }
   141  
   142  // Close gracefully closes the connection to the X server.
   143  // When everything is cleaned up, the WaitForEvent method will return (nil, nil)
   144  func (c *Conn) Close() {
   145  	select {
   146  	case c.reqChan <- nil:
   147  	case <-c.doneSend:
   148  	}
   149  }
   150  
   151  // Event is an interface that can contain any of the events returned by the
   152  // server. Use a type assertion switch to extract the Event structs.
   153  type Event interface {
   154  	Bytes() []byte
   155  	String() string
   156  }
   157  
   158  // NewEventFun is the type of function use to construct events from raw bytes.
   159  // It should not be used. It is exported for use in the extension sub-packages.
   160  type NewEventFun func(buf []byte) Event
   161  
   162  // NewEventFuncs is a map from event numbers to functions that create
   163  // the corresponding event. It should not be used. It is exported for use
   164  // in the extension sub-packages.
   165  var NewEventFuncs = make(map[int]NewEventFun)
   166  
   167  // NewExtEventFuncs is a temporary map that stores event constructor functions
   168  // for each extension. When an extension is initialized, each event for that
   169  // extension is added to the 'NewEventFuncs' map. It should not be used. It is
   170  // exported for use in the extension sub-packages.
   171  var NewExtEventFuncs = make(map[string]map[int]NewEventFun)
   172  
   173  // Error is an interface that can contain any of the errors returned by
   174  // the server. Use a type assertion switch to extract the Error structs.
   175  type Error interface {
   176  	SequenceId() uint16
   177  	BadId() uint32
   178  	Error() string
   179  }
   180  
   181  // NewErrorFun is the type of function use to construct errors from raw bytes.
   182  // It should not be used. It is exported for use in the extension sub-packages.
   183  type NewErrorFun func(buf []byte) Error
   184  
   185  // NewErrorFuncs is a map from error numbers to functions that create
   186  // the corresponding error. It should not be used. It is exported for use in
   187  // the extension sub-packages.
   188  var NewErrorFuncs = make(map[int]NewErrorFun)
   189  
   190  // NewExtErrorFuncs is a temporary map that stores error constructor functions
   191  // for each extension. When an extension is initialized, each error for that
   192  // extension is added to the 'NewErrorFuncs' map. It should not be used. It is
   193  // exported for use in the extension sub-packages.
   194  var NewExtErrorFuncs = make(map[string]map[int]NewErrorFun)
   195  
   196  // eventOrError corresponds to values that can be either an event or an
   197  // error.
   198  type eventOrError interface{}
   199  
   200  // NewId generates a new unused ID for use with requests like CreateWindow.
   201  // If no new ids can be generated, the id returned is 0 and error is non-nil.
   202  // This shouldn't be used directly, and is exported for use in the extension
   203  // sub-packages.
   204  // If you need identifiers, use the appropriate constructor.
   205  // e.g., For a window id, use xproto.NewWindowId. For
   206  // a new pixmap id, use xproto.NewPixmapId. And so on.
   207  // Returns (0, io.EOF) when the connection is closed.
   208  func (c *Conn) NewId() (uint32, error) {
   209  	xid, ok := <-c.xidChan
   210  	if !ok {
   211  		return 0, io.EOF
   212  	}
   213  	if xid.err != nil {
   214  		return 0, xid.err
   215  	}
   216  	return xid.id, nil
   217  }
   218  
   219  // xid encapsulates a resource identifier being sent over the Conn.xidChan
   220  // channel. If no new resource id can be generated, id is set to 0 and a
   221  // non-nil error is set in xid.err.
   222  type xid struct {
   223  	id  uint32
   224  	err error
   225  }
   226  
   227  // generateXids sends new Ids down the channel for NewId to use.
   228  // generateXids should be run in its own goroutine.
   229  // This needs to be updated to use the XC Misc extension once we run out of
   230  // new ids.
   231  // Thanks to libxcb/src/xcb_xid.c. This code is greatly inspired by it.
   232  func (c *Conn) generateXIds() {
   233  	defer close(c.xidChan)
   234  
   235  	// This requires some explanation. From the horse's mouth:
   236  	// "The resource-id-mask contains a single contiguous set of bits (at least
   237  	// 18).  The client allocates resource IDs for types WINDOW, PIXMAP,
   238  	// CURSOR, FONT, GCONTEXT, and COLORMAP by choosing a value with only some
   239  	// subset of these bits set and ORing it with resource-id-base. Only values
   240  	// constructed in this way can be used to name newly created resources over
   241  	// this connection."
   242  	// So for example (using 8 bit integers), the mask might look like:
   243  	// 00111000
   244  	// So that valid values would be 00101000, 00110000, 00001000, and so on.
   245  	// Thus, the idea is to increment it by the place of the last least
   246  	// significant '1'. In this case, that value would be 00001000. To get
   247  	// that value, we can AND the original mask with its two's complement:
   248  	// 00111000 & 11001000 = 00001000.
   249  	// And we use that value to increment the last resource id to get a new one.
   250  	// (And then, of course, we OR it with resource-id-base.)
   251  	inc := c.setupResourceIdMask & -c.setupResourceIdMask
   252  	max := c.setupResourceIdMask
   253  	last := uint32(0)
   254  	for {
   255  		id := xid{}
   256  		if last > 0 && last >= max-inc+1 {
   257  			// TODO: Use the XC Misc extension to look for released ids.
   258  			id = xid{
   259  				id:  0,
   260  				err: errors.New("There are no more available resource identifiers."),
   261  			}
   262  		} else {
   263  			last += inc
   264  			id = xid{
   265  				id:  last | c.setupResourceIdBase,
   266  				err: nil,
   267  			}
   268  		}
   269  
   270  		select {
   271  		case c.xidChan <- id:
   272  		case <-c.doneSend:
   273  			// c.sendRequests is down and since this id is used by requests, we don't need this goroutine running anymore.
   274  			return
   275  		}
   276  	}
   277  }
   278  
   279  // newSeqId fetches the next sequence id from the Conn.seqChan channel.
   280  func (c *Conn) newSequenceId() uint16 {
   281  	return <-c.seqChan
   282  }
   283  
   284  // generateSeqIds returns new sequence ids. It is meant to be run in its
   285  // own goroutine.
   286  // A sequence id is generated for *every* request. It's the identifier used
   287  // to match up replies with requests.
   288  // Since sequence ids can only be 16 bit integers we start over at zero when it
   289  // comes time to wrap.
   290  // N.B. As long as the cookie buffer is less than 2^16, there are no limitations
   291  // on the number (or kind) of requests made in sequence.
   292  func (c *Conn) generateSeqIds() {
   293  	defer close(c.seqChan)
   294  
   295  	seqid := uint16(1)
   296  	for {
   297  		select {
   298  		case c.seqChan <- seqid:
   299  			if seqid == uint16((1<<16)-1) {
   300  				seqid = 0
   301  			} else {
   302  				seqid++
   303  			}
   304  		case <-c.doneSend:
   305  			// c.sendRequests is down and since only that function uses sequence ids (via newSequenceId method), we don't need this goroutine running anymore.
   306  			return
   307  		}
   308  	}
   309  }
   310  
   311  // request encapsulates a buffer of raw bytes (containing the request data)
   312  // and a cookie, which when combined represents a single request.
   313  // The cookie is used to match up the reply/error.
   314  type request struct {
   315  	buf    []byte
   316  	cookie *Cookie
   317  
   318  	// seq is closed when the request (cookie) has been sequenced by the Conn.
   319  	seq chan struct{}
   320  }
   321  
   322  // NewRequest takes the bytes and a cookie of a particular request, constructs
   323  // a request type, and sends it over the Conn.reqChan channel.
   324  // Note that the sequence number is added to the cookie after it is sent
   325  // over the request channel, but before it is sent to X.
   326  //
   327  // Note that you may safely use NewRequest to send arbitrary byte requests
   328  // to X. The resulting cookie can be used just like any normal cookie and
   329  // abides by the same rules, except that for replies, you'll get back the
   330  // raw byte data. This may be useful for performance critical sections where
   331  // every allocation counts, since all X requests in XGB allocate a new byte
   332  // slice. In contrast, NewRequest allocates one small request struct and
   333  // nothing else. (Except when the cookie buffer is full and has to be flushed.)
   334  //
   335  // If you're using NewRequest manually, you'll need to use NewCookie to create
   336  // a new cookie.
   337  //
   338  // In all likelihood, you should be able to copy and paste with some minor
   339  // edits the generated code for the request you want to issue.
   340  func (c *Conn) NewRequest(buf []byte, cookie *Cookie) {
   341  	seq := make(chan struct{})
   342  	select {
   343  	case c.reqChan <- &request{buf: buf, cookie: cookie, seq: seq}:
   344  		// request is in buffer
   345  		// wait until request is processed or connection is closed
   346  		select {
   347  		case <-seq:
   348  			// request was successfully sent to X server
   349  		case <-c.doneSend:
   350  			// c.sendRequests is down, your request was not handled
   351  		}
   352  	case <-c.doneSend:
   353  		// c.sendRequests is down, nobody is listening to your requests
   354  	}
   355  }
   356  
   357  // sendRequests is run as a single goroutine that takes requests and writes
   358  // the bytes to the wire and adds the cookie to the cookie queue.
   359  // It is meant to be run as its own goroutine.
   360  func (c *Conn) sendRequests() {
   361  	defer close(c.cookieChan)
   362  	defer c.conn.Close()
   363  	defer close(c.doneSend)
   364  
   365  	for {
   366  		select {
   367  		case req := <-c.reqChan:
   368  			if req == nil {
   369  				// a request by c.Close() to gracefully exit
   370  				// Flush the response reading goroutine.
   371  				if err := c.noop(); err != nil {
   372  					c.conn.Close()
   373  					<-c.doneRead
   374  				}
   375  				return
   376  			}
   377  			// ho there! if the cookie channel is nearly full, force a round
   378  			// trip to clear out the cookie buffer.
   379  			// Note that we circumvent the request channel, because we're *in*
   380  			// the request channel.
   381  			if len(c.cookieChan) == cookieBuffer-1 {
   382  				if err := c.noop(); err != nil {
   383  					// Shut everything down.
   384  					c.conn.Close()
   385  					<-c.doneRead
   386  					return
   387  				}
   388  			}
   389  			req.cookie.Sequence = c.newSequenceId()
   390  			c.cookieChan <- req.cookie
   391  			if err := c.writeBuffer(req.buf); err != nil {
   392  				c.conn.Close()
   393  				<-c.doneRead
   394  				return
   395  			}
   396  			close(req.seq)
   397  		case <-c.doneRead:
   398  			return
   399  		}
   400  	}
   401  }
   402  
   403  // noop circumvents the usual request sending goroutines and forces a round
   404  // trip request manually.
   405  func (c *Conn) noop() error {
   406  	cookie := c.NewCookie(true, true)
   407  	cookie.Sequence = c.newSequenceId()
   408  	c.cookieChan <- cookie
   409  	if err := c.writeBuffer(c.getInputFocusRequest()); err != nil {
   410  		return err
   411  	}
   412  	cookie.Reply() // wait for the buffer to clear
   413  	return nil
   414  }
   415  
   416  // writeBuffer is a convenience function for writing a byte slice to the wire.
   417  func (c *Conn) writeBuffer(buf []byte) error {
   418  	if _, err := c.conn.Write(buf); err != nil {
   419  		Logger.Printf("A write error is unrecoverable: %s", err)
   420  		return err
   421  	}
   422  	return nil
   423  }
   424  
   425  // readResponses is a goroutine that reads events, errors and
   426  // replies off the wire.
   427  // When an event is read, it is always added to the event channel.
   428  // When an error is read, if it corresponds to an existing checked cookie,
   429  // it is sent to that cookie's error channel. Otherwise it is added to the
   430  // event channel.
   431  // When a reply is read, it is added to the corresponding cookie's reply
   432  // channel. (It is an error if no such cookie exists in this case.)
   433  // Finally, cookies that came "before" this reply are always cleaned up.
   434  func (c *Conn) readResponses() {
   435  	defer close(c.eventChan)
   436  	defer c.conn.Close()
   437  	defer close(c.doneRead)
   438  
   439  	var (
   440  		err        Error
   441  		seq        uint16
   442  		replyBytes []byte
   443  	)
   444  
   445  	for {
   446  		buf := make([]byte, 32)
   447  		err, seq = nil, 0
   448  		if _, err := io.ReadFull(c.conn, buf); err != nil {
   449  			select {
   450  			case <-c.doneSend:
   451  				// gracefully closing
   452  				return
   453  			default:
   454  			}
   455  			Logger.Printf("A read error is unrecoverable: %s", err)
   456  			c.eventChan <- err
   457  			return
   458  		}
   459  		switch buf[0] {
   460  		case 0: // This is an error
   461  			// Use the constructor function for this error (that is auto
   462  			// generated) by looking it up by the error number.
   463  			newErrFun, ok := NewErrorFuncs[int(buf[1])]
   464  			if !ok {
   465  				Logger.Printf("BUG: Could not find error constructor function "+
   466  					"for error with number %d.", buf[1])
   467  				continue
   468  			}
   469  			err = newErrFun(buf)
   470  			seq = err.SequenceId()
   471  
   472  			// This error is either sent to the event channel or a specific
   473  			// cookie's error channel below.
   474  		case 1: // This is a reply
   475  			seq = Get16(buf[2:])
   476  
   477  			// check to see if this reply has more bytes to be read
   478  			size := Get32(buf[4:])
   479  			if size > 0 {
   480  				byteCount := 32 + size*4
   481  				biggerBuf := make([]byte, byteCount)
   482  				copy(biggerBuf[:32], buf)
   483  				if _, err := io.ReadFull(c.conn, biggerBuf[32:]); err != nil {
   484  					Logger.Printf("A read error is unrecoverable: %s", err)
   485  					c.eventChan <- err
   486  					return
   487  				}
   488  				replyBytes = biggerBuf
   489  			} else {
   490  				replyBytes = buf
   491  			}
   492  
   493  			// This reply is sent to its corresponding cookie below.
   494  		default: // This is an event
   495  			// Use the constructor function for this event (like for errors,
   496  			// and is also auto generated) by looking it up by the event number.
   497  			// Note that we AND the event number with 127 so that we ignore
   498  			// the most significant bit (which is set when it was sent from
   499  			// a SendEvent request).
   500  			evNum := int(buf[0] & 127)
   501  			newEventFun, ok := NewEventFuncs[evNum]
   502  			if !ok {
   503  				Logger.Printf("BUG: Could not find event construct function "+
   504  					"for event with number %d.", evNum)
   505  				continue
   506  			}
   507  			c.eventChan <- newEventFun(buf)
   508  			continue
   509  		}
   510  
   511  		// At this point, we have a sequence number and we're either
   512  		// processing an error or a reply, which are both responses to
   513  		// requests. So all we have to do is find the cookie corresponding
   514  		// to this error/reply, and send the appropriate data to it.
   515  		// In doing so, we make sure that any cookies that came before it
   516  		// are marked as successful if they are void and checked.
   517  		// If there's a cookie that requires a reply that is before this
   518  		// reply, then something is wrong.
   519  		for cookie := range c.cookieChan {
   520  			// This is the cookie we're looking for. Process and break.
   521  			if cookie.Sequence == seq {
   522  				if err != nil { // this is an error to a request
   523  					// synchronous processing
   524  					if cookie.errorChan != nil {
   525  						cookie.errorChan <- err
   526  					} else { // asynchronous processing
   527  						c.eventChan <- err
   528  						// if this is an unchecked reply, ping the cookie too
   529  						if cookie.pingChan != nil {
   530  							cookie.pingChan <- true
   531  						}
   532  					}
   533  				} else { // this is a reply
   534  					if cookie.replyChan == nil {
   535  						Logger.Printf("Reply with sequence id %d does not "+
   536  							"have a cookie with a valid reply channel.", seq)
   537  						continue
   538  					} else {
   539  						cookie.replyChan <- replyBytes
   540  					}
   541  				}
   542  				break
   543  			}
   544  
   545  			switch {
   546  			// Checked requests with replies
   547  			case cookie.replyChan != nil && cookie.errorChan != nil:
   548  				Logger.Printf("Found cookie with sequence id %d that is "+
   549  					"expecting a reply but will never get it. Currently "+
   550  					"on sequence number %d", cookie.Sequence, seq)
   551  			// Unchecked requests with replies
   552  			case cookie.replyChan != nil && cookie.pingChan != nil:
   553  				Logger.Printf("Found cookie with sequence id %d that is "+
   554  					"expecting a reply (and not an error) but will never "+
   555  					"get it. Currently on sequence number %d",
   556  					cookie.Sequence, seq)
   557  			// Checked requests without replies
   558  			case cookie.pingChan != nil && cookie.errorChan != nil:
   559  				cookie.pingChan <- true
   560  				// Unchecked requests without replies don't have any channels,
   561  				// so we can't do anything with them except let them pass by.
   562  			}
   563  		}
   564  	}
   565  }
   566  
   567  // processEventOrError takes an eventOrError, type switches on it,
   568  // and returns it in Go idiomatic style.
   569  func processEventOrError(everr eventOrError) (Event, Error) {
   570  	switch ee := everr.(type) {
   571  	case Event:
   572  		return ee, nil
   573  	case Error:
   574  		return nil, ee
   575  	case error:
   576  		// c.conn read error
   577  	case nil:
   578  		// c.eventChan is closed
   579  	default:
   580  		Logger.Printf("Invalid event/error type: %T", everr)
   581  	}
   582  	return nil, nil
   583  }
   584  
   585  // WaitForEvent returns the next event from the server.
   586  // It will block until an event is available.
   587  // WaitForEvent returns either an Event or an Error. (Returning both
   588  // is a bug.) Note than an Error here is an X error and not an XGB error. That
   589  // is, X errors are sometimes completely expected (and you may want to ignore
   590  // them in some cases).
   591  //
   592  // If both the event and error are nil, then the connection has been closed.
   593  func (c *Conn) WaitForEvent() (Event, Error) {
   594  	return processEventOrError(<-c.eventChan)
   595  }
   596  
   597  // PollForEvent returns the next event from the server if one is available in
   598  // the internal queue without blocking. Note that unlike WaitForEvent, both
   599  // Event and Error could be nil. Indeed, they are both nil when the event queue
   600  // is empty.
   601  func (c *Conn) PollForEvent() (Event, Error) {
   602  	select {
   603  	case everr := <-c.eventChan:
   604  		return processEventOrError(everr)
   605  	default:
   606  		return nil, nil
   607  	}
   608  }
   609  

View as plain text