github.com/yanyiwu/go@v0.0.0-20150106053140-03d6637dbb7f/src/syscall/srpc_nacl.go (about)

     1  // Copyright 2013 The Go Authors.  All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Native Client SRPC message passing.
     6  // This code is needed to invoke SecureRandom, the NaCl equivalent of /dev/random.
     7  
     8  package syscall
     9  
    10  import (
    11  	"errors"
    12  	"sync"
    13  	"unsafe"
    14  )
    15  
    16  // An srpcClient represents the client side of an SRPC connection.
    17  type srpcClient struct {
    18  	fd      int // to server
    19  	r       msgReceiver
    20  	s       msgSender
    21  	service map[string]srpcService // services by name
    22  
    23  	outMu sync.Mutex // protects writing to connection
    24  
    25  	mu      sync.Mutex // protects following fields
    26  	muxer   bool       // is someone reading and muxing responses
    27  	pending map[uint32]*srpc
    28  	idGen   uint32 // generator for request IDs
    29  }
    30  
    31  // An srpcService is a single method that the server offers.
    32  type srpcService struct {
    33  	num uint32 // method number
    34  	fmt string // argument format; see "parsing of RPC messages" below
    35  }
    36  
    37  // An srpc represents a single srpc issued by a client.
    38  type srpc struct {
    39  	Ret  []interface{}
    40  	Done chan *srpc
    41  	Err  error
    42  	c    *srpcClient
    43  	id   uint32
    44  }
    45  
    46  // newClient allocates a new SRPC client using the file descriptor fd.
    47  func newClient(fd int) (*srpcClient, error) {
    48  	c := new(srpcClient)
    49  	c.fd = fd
    50  	c.r.fd = fd
    51  	c.s.fd = fd
    52  	c.service = make(map[string]srpcService)
    53  	c.pending = make(map[uint32]*srpc)
    54  
    55  	// service discovery request
    56  	m := &msg{
    57  		isRequest: 1,
    58  		template:  []interface{}{[]byte(nil)},
    59  		size:      []int{4000}, // max size to accept for returned byte slice
    60  	}
    61  	if err := m.pack(); err != nil {
    62  		return nil, errors.New("Native Client SRPC service_discovery: preparing request: " + err.Error())
    63  	}
    64  	c.s.send(m)
    65  	m, err := c.r.recv()
    66  	if err != nil {
    67  		return nil, err
    68  	}
    69  	m.unpack()
    70  	if m.status != uint32(srpcOK) {
    71  		return nil, errors.New("Native Client SRPC service_discovery: " + srpcErrno(m.status).Error())
    72  	}
    73  	list := m.value[0].([]byte)
    74  	var n uint32
    75  	for len(list) > 0 {
    76  		var line []byte
    77  		i := byteIndex(list, '\n')
    78  		if i < 0 {
    79  			line, list = list, nil
    80  		} else {
    81  			line, list = list[:i], list[i+1:]
    82  		}
    83  		i = byteIndex(line, ':')
    84  		if i >= 0 {
    85  			c.service[string(line)] = srpcService{n, string(line[i+1:])}
    86  		}
    87  		n++
    88  	}
    89  
    90  	return c, nil
    91  }
    92  
    93  func byteIndex(b []byte, c byte) int {
    94  	for i, bi := range b {
    95  		if bi == c {
    96  			return i
    97  		}
    98  	}
    99  	return -1
   100  }
   101  
   102  var yourTurn srpc
   103  
   104  func (c *srpcClient) wait(r *srpc) {
   105  	var rx *srpc
   106  	for rx = range r.Done {
   107  		if rx != &yourTurn {
   108  			break
   109  		}
   110  		c.input()
   111  	}
   112  	return
   113  }
   114  
   115  func (c *srpcClient) input() {
   116  	// read message
   117  	m, err := c.r.recv()
   118  	if err != nil {
   119  		println("Native Client SRPC receive error:", err.Error())
   120  		return
   121  	}
   122  	if m.unpack(); m.status != uint32(srpcOK) {
   123  		println("Native Client SRPC receive error: invalid message: ", srpcErrno(m.status).Error())
   124  		return
   125  	}
   126  
   127  	// deliver to intended recipient
   128  	c.mu.Lock()
   129  	rpc, ok := c.pending[m.id]
   130  	if ok {
   131  		delete(c.pending, m.id)
   132  	}
   133  
   134  	// wake a new muxer if there are more RPCs to read
   135  	c.muxer = false
   136  	for _, rpc := range c.pending {
   137  		c.muxer = true
   138  		rpc.Done <- &yourTurn
   139  		break
   140  	}
   141  	c.mu.Unlock()
   142  	if !ok {
   143  		println("Native Client: unexpected response for ID", m.id)
   144  		return
   145  	}
   146  	rpc.Ret = m.value
   147  	rpc.Done <- rpc
   148  }
   149  
   150  // Wait blocks until the RPC has finished.
   151  func (r *srpc) Wait() {
   152  	r.c.wait(r)
   153  }
   154  
   155  // Start issues an RPC request for method name with the given arguments.
   156  // The RPC r must not be in use for another pending request.
   157  // To wait for the RPC to finish, receive from r.Done and then
   158  // inspect r.Ret and r.Errno.
   159  func (r *srpc) Start(name string, arg []interface{}) {
   160  	r.Err = nil
   161  	r.c.mu.Lock()
   162  	srv, ok := r.c.service[name]
   163  	if !ok {
   164  		r.c.mu.Unlock()
   165  		r.Err = srpcErrBadRPCNumber
   166  		r.Done <- r
   167  		return
   168  	}
   169  	r.c.pending[r.id] = r
   170  	if !r.c.muxer {
   171  		r.c.muxer = true
   172  		r.Done <- &yourTurn
   173  	}
   174  	r.c.mu.Unlock()
   175  
   176  	var m msg
   177  	m.id = r.id
   178  	m.isRequest = 1
   179  	m.rpc = srv.num
   180  	m.value = arg
   181  
   182  	// Fill in the return values and sizes to generate
   183  	// the right type chars.  We'll take most any size.
   184  
   185  	// Skip over input arguments.
   186  	// We could check them against arg, but the server
   187  	// will do that anyway.
   188  	i := 0
   189  	for srv.fmt[i] != ':' {
   190  		i++
   191  	}
   192  	format := srv.fmt[i+1:]
   193  
   194  	// Now the return prototypes.
   195  	m.template = make([]interface{}, len(format))
   196  	m.size = make([]int, len(format))
   197  	for i := 0; i < len(format); i++ {
   198  		switch format[i] {
   199  		default:
   200  			println("Native Client SRPC: unexpected service type " + string(format[i]))
   201  			r.Err = srpcErrBadRPCNumber
   202  			r.Done <- r
   203  			return
   204  		case 'b':
   205  			m.template[i] = false
   206  		case 'C':
   207  			m.template[i] = []byte(nil)
   208  			m.size[i] = 1 << 30
   209  		case 'd':
   210  			m.template[i] = float64(0)
   211  		case 'D':
   212  			m.template[i] = []float64(nil)
   213  			m.size[i] = 1 << 30
   214  		case 'h':
   215  			m.template[i] = int(-1)
   216  		case 'i':
   217  			m.template[i] = int32(0)
   218  		case 'I':
   219  			m.template[i] = []int32(nil)
   220  			m.size[i] = 1 << 30
   221  		case 's':
   222  			m.template[i] = ""
   223  			m.size[i] = 1 << 30
   224  		}
   225  	}
   226  
   227  	if err := m.pack(); err != nil {
   228  		r.Err = errors.New("Native Client RPC Start " + name + ": preparing request: " + err.Error())
   229  		r.Done <- r
   230  		return
   231  	}
   232  
   233  	r.c.outMu.Lock()
   234  	r.c.s.send(&m)
   235  	r.c.outMu.Unlock()
   236  }
   237  
   238  // Call is a convenience wrapper that starts the RPC request,
   239  // waits for it to finish, and then returns the results.
   240  // Its implementation is:
   241  //
   242  //	r.Start(name, arg)
   243  //	r.Wait()
   244  //	return r.Ret, r.Errno
   245  //
   246  func (c *srpcClient) Call(name string, arg ...interface{}) (ret []interface{}, err error) {
   247  	r := c.NewRPC(nil)
   248  	r.Start(name, arg)
   249  	r.Wait()
   250  	return r.Ret, r.Err
   251  }
   252  
   253  // NewRPC creates a new RPC on the client connection.
   254  func (c *srpcClient) NewRPC(done chan *srpc) *srpc {
   255  	if done == nil {
   256  		done = make(chan *srpc, 1)
   257  	}
   258  	c.mu.Lock()
   259  	id := c.idGen
   260  	c.idGen++
   261  	c.mu.Unlock()
   262  	return &srpc{Done: done, c: c, id: id}
   263  }
   264  
   265  // The current protocol number.
   266  // Kind of useless, since there have been backwards-incompatible changes
   267  // to the wire protocol that did not update the protocol number.
   268  // At this point it's really just a sanity check.
   269  const protocol = 0xc0da0002
   270  
   271  // An srpcErrno is an SRPC status code.
   272  type srpcErrno uint32
   273  
   274  const (
   275  	srpcOK srpcErrno = 256 + iota
   276  	srpcErrBreak
   277  	srpcErrMessageTruncated
   278  	srpcErrNoMemory
   279  	srpcErrProtocolMismatch
   280  	srpcErrBadRPCNumber
   281  	srpcErrBadArgType
   282  	srpcErrTooFewArgs
   283  	srpcErrTooManyArgs
   284  	srpcErrInArgTypeMismatch
   285  	srpcErrOutArgTypeMismatch
   286  	srpcErrInternalError
   287  	srpcErrAppError
   288  )
   289  
   290  var srpcErrstr = [...]string{
   291  	srpcOK - srpcOK:                    "ok",
   292  	srpcErrBreak - srpcOK:              "break",
   293  	srpcErrMessageTruncated - srpcOK:   "message truncated",
   294  	srpcErrNoMemory - srpcOK:           "out of memory",
   295  	srpcErrProtocolMismatch - srpcOK:   "protocol mismatch",
   296  	srpcErrBadRPCNumber - srpcOK:       "invalid RPC method number",
   297  	srpcErrBadArgType - srpcOK:         "unexpected argument type",
   298  	srpcErrTooFewArgs - srpcOK:         "too few arguments",
   299  	srpcErrTooManyArgs - srpcOK:        "too many arguments",
   300  	srpcErrInArgTypeMismatch - srpcOK:  "input argument type mismatch",
   301  	srpcErrOutArgTypeMismatch - srpcOK: "output argument type mismatch",
   302  	srpcErrInternalError - srpcOK:      "internal error",
   303  	srpcErrAppError - srpcOK:           "application error",
   304  }
   305  
   306  func (e srpcErrno) Error() string {
   307  	if e < srpcOK || int(e-srpcOK) >= len(srpcErrstr) {
   308  		return "srpcErrno(" + itoa(int(e)) + ")"
   309  	}
   310  	return srpcErrstr[e-srpcOK]
   311  }
   312  
   313  // A msgHdr is the data argument to the imc_recvmsg
   314  // and imc_sendmsg system calls.
   315  type msgHdr struct {
   316  	iov   *iov
   317  	niov  int32
   318  	desc  *int32
   319  	ndesc int32
   320  	flags uint32
   321  }
   322  
   323  // A single region for I/O.
   324  type iov struct {
   325  	base *byte
   326  	len  int32
   327  }
   328  
   329  const maxMsgSize = 1<<16 - 4*4
   330  
   331  // A msgReceiver receives messages from a file descriptor.
   332  type msgReceiver struct {
   333  	fd   int
   334  	data [maxMsgSize]byte
   335  	desc [8]int32
   336  	hdr  msgHdr
   337  	iov  iov
   338  }
   339  
   340  func (r *msgReceiver) recv() (*msg, error) {
   341  	// Init pointers to buffers where syscall recvmsg can write.
   342  	r.iov.base = &r.data[0]
   343  	r.iov.len = int32(len(r.data))
   344  	r.hdr.iov = &r.iov
   345  	r.hdr.niov = 1
   346  	r.hdr.desc = &r.desc[0]
   347  	r.hdr.ndesc = int32(len(r.desc))
   348  	n, _, e := Syscall(sys_imc_recvmsg, uintptr(r.fd), uintptr(unsafe.Pointer(&r.hdr)), 0)
   349  	if e != 0 {
   350  		println("Native Client imc_recvmsg: ", e.Error())
   351  		return nil, e
   352  	}
   353  
   354  	// Make a copy of the data so that the next recvmsg doesn't
   355  	// smash it.  The system call did not update r.iov.len.  Instead it
   356  	// returned the total byte count as n.
   357  	m := new(msg)
   358  	m.data = make([]byte, n)
   359  	copy(m.data, r.data[0:])
   360  
   361  	// Make a copy of the desc too.
   362  	// The system call *did* update r.hdr.ndesc.
   363  	if r.hdr.ndesc > 0 {
   364  		m.desc = make([]int32, r.hdr.ndesc)
   365  		copy(m.desc, r.desc[:])
   366  	}
   367  
   368  	return m, nil
   369  }
   370  
   371  // A msgSender sends messages on a file descriptor.
   372  type msgSender struct {
   373  	fd  int
   374  	hdr msgHdr
   375  	iov iov
   376  }
   377  
   378  func (s *msgSender) send(m *msg) error {
   379  	if len(m.data) > 0 {
   380  		s.iov.base = &m.data[0]
   381  	}
   382  	s.iov.len = int32(len(m.data))
   383  	s.hdr.iov = &s.iov
   384  	s.hdr.niov = 1
   385  	s.hdr.desc = nil
   386  	s.hdr.ndesc = 0
   387  	_, _, e := Syscall(sys_imc_sendmsg, uintptr(s.fd), uintptr(unsafe.Pointer(&s.hdr)), 0)
   388  	if e != 0 {
   389  		println("Native Client imc_sendmsg: ", e.Error())
   390  		return e
   391  	}
   392  	return nil
   393  }
   394  
   395  // A msg is the Go representation of an SRPC message.
   396  type msg struct {
   397  	data []byte  // message data
   398  	desc []int32 // message file descriptors
   399  
   400  	// parsed version of message
   401  	id        uint32
   402  	isRequest uint32
   403  	rpc       uint32
   404  	status    uint32
   405  	value     []interface{}
   406  	template  []interface{}
   407  	size      []int
   408  	format    string
   409  	broken    bool
   410  }
   411  
   412  // reading from a msg
   413  
   414  func (m *msg) uint32() uint32 {
   415  	if m.broken {
   416  		return 0
   417  	}
   418  	if len(m.data) < 4 {
   419  		m.broken = true
   420  		return 0
   421  	}
   422  	b := m.data[:4]
   423  	x := uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
   424  	m.data = m.data[4:]
   425  	return x
   426  }
   427  
   428  func (m *msg) uint64() uint64 {
   429  	x := uint64(m.uint32()) | uint64(m.uint32())<<32
   430  	if m.broken {
   431  		return 0
   432  	}
   433  	return x
   434  }
   435  
   436  func (m *msg) bytes(n int) []byte {
   437  	if m.broken {
   438  		return nil
   439  	}
   440  	if len(m.data) < n {
   441  		m.broken = true
   442  		return nil
   443  	}
   444  	x := m.data[0:n]
   445  	m.data = m.data[n:]
   446  	return x
   447  }
   448  
   449  // writing to a msg
   450  
   451  func (m *msg) wuint32(x uint32) {
   452  	m.data = append(m.data, byte(x), byte(x>>8), byte(x>>16), byte(x>>24))
   453  }
   454  
   455  func (m *msg) wuint64(x uint64) {
   456  	lo := uint32(x)
   457  	hi := uint32(x >> 32)
   458  	m.data = append(m.data, byte(lo), byte(lo>>8), byte(lo>>16), byte(lo>>24), byte(hi), byte(hi>>8), byte(hi>>16), byte(hi>>24))
   459  }
   460  
   461  func (m *msg) wbytes(p []byte) {
   462  	m.data = append(m.data, p...)
   463  }
   464  
   465  func (m *msg) wstring(s string) {
   466  	m.data = append(m.data, s...)
   467  }
   468  
   469  // Parsing of RPC messages.
   470  //
   471  // Each message begins with
   472  //	total_size uint32
   473  //	total_descs uint32
   474  //	fragment_size uint32
   475  //	fragment_descs uint32
   476  //
   477  // If fragment_size < total_size or fragment_descs < total_descs, the actual
   478  // message is broken up in multiple messages; follow-up messages omit
   479  // the "total" fields and begin with the "fragment" fields.
   480  // We do not support putting fragmented messages back together.
   481  // To do this we would need to change the message receiver.
   482  //
   483  // After that size information, the message header follows:
   484  //	protocol uint32
   485  //	requestID uint32
   486  //	isRequest uint32
   487  //	rpcNumber uint32
   488  //	status uint32
   489  //	numValue uint32
   490  //	numTemplate uint32
   491  //
   492  // After the header come numTemplate fixed-size arguments,
   493  // numValue fixed-size arguments, and then the variable-sized
   494  // part of the values. The templates describe the expected results
   495  // and have no associated variable sized data in the request.
   496  //
   497  // Each fixed-size argument has the form:
   498  //	tag uint32 // really a char, like 'b' or 'C'
   499  //	pad uint32 // unused
   500  //	val1 uint32
   501  //	val2 uint32
   502  //
   503  // The tags are:
   504  //	'b':	bool; val1 == 0 or 1
   505  //	'C':	[]byte; val1 == len, data in variable-sized section
   506  //	'd':	float64; (val1, val2) is data
   507  //	'D':	[]float64; val1 == len, data in variable-sized section
   508  //	'h':	int; val1 == file descriptor
   509  //	'i':	int32; descriptor in next entry in m.desc
   510  //	'I':	[]int; val1 == len, data in variable-sized section
   511  //	's':	string; val1 == len, data in variable-sized section
   512  //
   513  
   514  func (m *msg) pack() error {
   515  	m.data = m.data[:0]
   516  	m.desc = m.desc[:0]
   517  
   518  	// sizes, to fill in later
   519  	m.wuint32(0)
   520  	m.wuint32(0)
   521  	m.wuint32(0)
   522  	m.wuint32(0)
   523  
   524  	// message header
   525  	m.wuint32(protocol)
   526  	m.wuint32(m.id)
   527  	m.wuint32(m.isRequest)
   528  	m.wuint32(m.rpc)
   529  	m.wuint32(m.status)
   530  	m.wuint32(uint32(len(m.value)))
   531  	m.wuint32(uint32(len(m.template)))
   532  
   533  	// fixed-size templates
   534  	for i, x := range m.template {
   535  		var tag, val1, val2 uint32
   536  		switch x.(type) {
   537  		default:
   538  			return errors.New("unexpected template type")
   539  		case bool:
   540  			tag = 'b'
   541  		case []byte:
   542  			tag = 'C'
   543  			val1 = uint32(m.size[i])
   544  		case float64:
   545  			tag = 'd'
   546  		case []float64:
   547  			tag = 'D'
   548  			val1 = uint32(m.size[i])
   549  		case int:
   550  			tag = 'h'
   551  		case int32:
   552  			tag = 'i'
   553  		case []int32:
   554  			tag = 'I'
   555  			val1 = uint32(m.size[i])
   556  		case string:
   557  			tag = 's'
   558  			val1 = uint32(m.size[i])
   559  		}
   560  		m.wuint32(tag)
   561  		m.wuint32(0)
   562  		m.wuint32(val1)
   563  		m.wuint32(val2)
   564  	}
   565  
   566  	// fixed-size values
   567  	for _, x := range m.value {
   568  		var tag, val1, val2 uint32
   569  		switch x := x.(type) {
   570  		default:
   571  			return errors.New("unexpected value type")
   572  		case bool:
   573  			tag = 'b'
   574  			if x {
   575  				val1 = 1
   576  			}
   577  		case []byte:
   578  			tag = 'C'
   579  			val1 = uint32(len(x))
   580  		case float64:
   581  			tag = 'd'
   582  			v := float64bits(x)
   583  			val1 = uint32(v)
   584  			val2 = uint32(v >> 32)
   585  		case []float64:
   586  			tag = 'D'
   587  			val1 = uint32(len(x))
   588  		case int32:
   589  			tag = 'i'
   590  			m.desc = append(m.desc, x)
   591  		case []int32:
   592  			tag = 'I'
   593  			val1 = uint32(len(x))
   594  		case string:
   595  			tag = 's'
   596  			val1 = uint32(len(x) + 1)
   597  		}
   598  		m.wuint32(tag)
   599  		m.wuint32(0)
   600  		m.wuint32(val1)
   601  		m.wuint32(val2)
   602  	}
   603  
   604  	// variable-length data for values
   605  	for _, x := range m.value {
   606  		switch x := x.(type) {
   607  		case []byte:
   608  			m.wbytes(x)
   609  		case []float64:
   610  			for _, f := range x {
   611  				m.wuint64(float64bits(f))
   612  			}
   613  		case []int32:
   614  			for _, j := range x {
   615  				m.wuint32(uint32(j))
   616  			}
   617  		case string:
   618  			m.wstring(x)
   619  			m.wstring("\x00")
   620  		}
   621  	}
   622  
   623  	// fill in sizes
   624  	data := m.data
   625  	m.data = m.data[:0]
   626  	m.wuint32(uint32(len(data)))
   627  	m.wuint32(uint32(len(m.desc)))
   628  	m.wuint32(uint32(len(data)))
   629  	m.wuint32(uint32(len(m.desc)))
   630  	m.data = data
   631  
   632  	return nil
   633  }
   634  
   635  func (m *msg) unpack() error {
   636  	totalSize := m.uint32()
   637  	totalDesc := m.uint32()
   638  	fragSize := m.uint32()
   639  	fragDesc := m.uint32()
   640  	if totalSize != fragSize || totalDesc != fragDesc {
   641  		return errors.New("Native Client: fragmented RPC messages not supported")
   642  	}
   643  	if m.uint32() != protocol {
   644  		return errors.New("Native Client: RPC protocol mismatch")
   645  	}
   646  
   647  	// message header
   648  	m.id = m.uint32()
   649  	m.isRequest = m.uint32()
   650  	m.rpc = m.uint32()
   651  	m.status = m.uint32()
   652  	m.value = make([]interface{}, m.uint32())
   653  	m.template = make([]interface{}, m.uint32())
   654  	m.size = make([]int, len(m.template))
   655  	if m.broken {
   656  		return errors.New("Native Client: malformed message")
   657  	}
   658  
   659  	// fixed-size templates
   660  	for i := range m.template {
   661  		tag := m.uint32()
   662  		m.uint32() // padding
   663  		val1 := m.uint32()
   664  		m.uint32() // val2
   665  		switch tag {
   666  		default:
   667  			return errors.New("Native Client: unexpected template type " + string(rune(tag)))
   668  		case 'b':
   669  			m.template[i] = false
   670  		case 'C':
   671  			m.template[i] = []byte(nil)
   672  			m.size[i] = int(val1)
   673  		case 'd':
   674  			m.template[i] = float64(0)
   675  		case 'D':
   676  			m.template[i] = []float64(nil)
   677  			m.size[i] = int(val1)
   678  		case 'i':
   679  			m.template[i] = int32(0)
   680  		case 'I':
   681  			m.template[i] = []int32(nil)
   682  			m.size[i] = int(val1)
   683  		case 'h':
   684  			m.template[i] = int(0)
   685  		case 's':
   686  			m.template[i] = ""
   687  			m.size[i] = int(val1)
   688  		}
   689  	}
   690  
   691  	// fixed-size values
   692  	var (
   693  		strsize []uint32
   694  		d       int
   695  	)
   696  	for i := range m.value {
   697  		tag := m.uint32()
   698  		m.uint32() // padding
   699  		val1 := m.uint32()
   700  		val2 := m.uint32()
   701  		switch tag {
   702  		default:
   703  			return errors.New("Native Client: unexpected value type " + string(rune(tag)))
   704  		case 'b':
   705  			m.value[i] = val1 > 0
   706  		case 'C':
   707  			m.value[i] = []byte(nil)
   708  			strsize = append(strsize, val1)
   709  		case 'd':
   710  			m.value[i] = float64frombits(uint64(val1) | uint64(val2)<<32)
   711  		case 'D':
   712  			m.value[i] = make([]float64, val1)
   713  		case 'i':
   714  			m.value[i] = int32(val1)
   715  		case 'I':
   716  			m.value[i] = make([]int32, val1)
   717  		case 'h':
   718  			m.value[i] = int(m.desc[d])
   719  			d++
   720  		case 's':
   721  			m.value[i] = ""
   722  			strsize = append(strsize, val1)
   723  		}
   724  	}
   725  
   726  	// variable-sized parts of values
   727  	for i, x := range m.value {
   728  		switch x := x.(type) {
   729  		case []byte:
   730  			m.value[i] = m.bytes(int(strsize[0]))
   731  			strsize = strsize[1:]
   732  		case []float64:
   733  			for i := range x {
   734  				x[i] = float64frombits(m.uint64())
   735  			}
   736  		case []int32:
   737  			for i := range x {
   738  				x[i] = int32(m.uint32())
   739  			}
   740  		case string:
   741  			m.value[i] = string(m.bytes(int(strsize[0])))
   742  			strsize = strsize[1:]
   743  		}
   744  	}
   745  
   746  	if len(m.data) > 0 {
   747  		return errors.New("Native Client: junk at end of message")
   748  	}
   749  	return nil
   750  }
   751  
   752  func float64bits(x float64) uint64 {
   753  	return *(*uint64)(unsafe.Pointer(&x))
   754  }
   755  
   756  func float64frombits(x uint64) float64 {
   757  	return *(*float64)(unsafe.Pointer(&x))
   758  }
   759  
   760  // At startup, connect to the name service.
   761  var nsClient = nsConnect()
   762  
   763  func nsConnect() *srpcClient {
   764  	var ns int32 = -1
   765  	_, _, errno := Syscall(sys_nameservice, uintptr(unsafe.Pointer(&ns)), 0, 0)
   766  	if errno != 0 {
   767  		println("Native Client nameservice:", errno.Error())
   768  		return nil
   769  	}
   770  
   771  	sock, _, errno := Syscall(sys_imc_connect, uintptr(ns), 0, 0)
   772  	if errno != 0 {
   773  		println("Native Client nameservice connect:", errno.Error())
   774  		return nil
   775  	}
   776  
   777  	c, err := newClient(int(sock))
   778  	if err != nil {
   779  		println("Native Client nameservice init:", err.Error())
   780  		return nil
   781  	}
   782  
   783  	return c
   784  }
   785  
   786  const (
   787  	nsSuccess               = 0
   788  	nsNameNotFound          = 1
   789  	nsDuplicateName         = 2
   790  	nsInsufficientResources = 3
   791  	nsPermissionDenied      = 4
   792  	nsInvalidArgument       = 5
   793  )
   794  
   795  func openNamedService(name string, mode int32) (fd int, err error) {
   796  	if nsClient == nil {
   797  		return 0, errors.New("no name service")
   798  	}
   799  	ret, err := nsClient.Call("lookup:si:ih", name, int32(mode))
   800  	if err != nil {
   801  		return 0, err
   802  	}
   803  	status := ret[0].(int32)
   804  	fd = ret[1].(int)
   805  	switch status {
   806  	case nsSuccess:
   807  		// ok
   808  	case nsNameNotFound:
   809  		return -1, ENOENT
   810  	case nsDuplicateName:
   811  		return -1, EEXIST
   812  	case nsInsufficientResources:
   813  		return -1, EWOULDBLOCK
   814  	case nsPermissionDenied:
   815  		return -1, EPERM
   816  	case nsInvalidArgument:
   817  		return -1, EINVAL
   818  	default:
   819  		return -1, EINVAL
   820  	}
   821  	return fd, nil
   822  }