github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/src/cmd/fix/testdata/reflect.export.go.out (about)

     1  // Copyright 2010 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  /*
     6  	The netchan package implements type-safe networked channels:
     7  	it allows the two ends of a channel to appear on different
     8  	computers connected by a network.  It does this by transporting
     9  	data sent to a channel on one machine so it can be recovered
    10  	by a receive of a channel of the same type on the other.
    11  
    12  	An exporter publishes a set of channels by name.  An importer
    13  	connects to the exporting machine and imports the channels
    14  	by name. After importing the channels, the two machines can
    15  	use the channels in the usual way.
    16  
    17  	Networked channels are not synchronized; they always behave
    18  	as if they are buffered channels of at least one element.
    19  */
    20  package netchan
    21  
    22  // BUG: can't use range clause to receive when using ImportNValues to limit the count.
    23  
    24  import (
    25  	"io"
    26  	"log"
    27  	"net"
    28  	"os"
    29  	"reflect"
    30  	"strconv"
    31  	"sync"
    32  )
    33  
    34  // Export
    35  
    36  // expLog is a logging convenience function.  The first argument must be a string.
    37  func expLog(args ...interface{}) {
    38  	args[0] = "netchan export: " + args[0].(string)
    39  	log.Print(args...)
    40  }
    41  
    42  // An Exporter allows a set of channels to be published on a single
    43  // network port.  A single machine may have multiple Exporters
    44  // but they must use different ports.
    45  type Exporter struct {
    46  	*clientSet
    47  }
    48  
    49  type expClient struct {
    50  	*encDec
    51  	exp     *Exporter
    52  	chans   map[int]*netChan // channels in use by client
    53  	mu      sync.Mutex       // protects remaining fields
    54  	errored bool             // client has been sent an error
    55  	seqNum  int64            // sequences messages sent to client; has value of highest sent
    56  	ackNum  int64            // highest sequence number acknowledged
    57  	seqLock sync.Mutex       // guarantees messages are in sequence, only locked under mu
    58  }
    59  
    60  func newClient(exp *Exporter, conn io.ReadWriter) *expClient {
    61  	client := new(expClient)
    62  	client.exp = exp
    63  	client.encDec = newEncDec(conn)
    64  	client.seqNum = 0
    65  	client.ackNum = 0
    66  	client.chans = make(map[int]*netChan)
    67  	return client
    68  }
    69  
    70  func (client *expClient) sendError(hdr *header, err string) {
    71  	error := &error{err}
    72  	expLog("sending error to client:", error.Error)
    73  	client.encode(hdr, payError, error) // ignore any encode error, hope client gets it
    74  	client.mu.Lock()
    75  	client.errored = true
    76  	client.mu.Unlock()
    77  }
    78  
    79  func (client *expClient) newChan(hdr *header, dir Dir, name string, size int, count int64) *netChan {
    80  	exp := client.exp
    81  	exp.mu.Lock()
    82  	ech, ok := exp.names[name]
    83  	exp.mu.Unlock()
    84  	if !ok {
    85  		client.sendError(hdr, "no such channel: "+name)
    86  		return nil
    87  	}
    88  	if ech.dir != dir {
    89  		client.sendError(hdr, "wrong direction for channel: "+name)
    90  		return nil
    91  	}
    92  	nch := newNetChan(name, hdr.Id, ech, client.encDec, size, count)
    93  	client.chans[hdr.Id] = nch
    94  	return nch
    95  }
    96  
    97  func (client *expClient) getChan(hdr *header, dir Dir) *netChan {
    98  	nch := client.chans[hdr.Id]
    99  	if nch == nil {
   100  		return nil
   101  	}
   102  	if nch.dir != dir {
   103  		client.sendError(hdr, "wrong direction for channel: "+nch.name)
   104  	}
   105  	return nch
   106  }
   107  
   108  // The function run manages sends and receives for a single client.  For each
   109  // (client Recv) request, this will launch a serveRecv goroutine to deliver
   110  // the data for that channel, while (client Send) requests are handled as
   111  // data arrives from the client.
   112  func (client *expClient) run() {
   113  	hdr := new(header)
   114  	hdrValue := reflect.ValueOf(hdr)
   115  	req := new(request)
   116  	reqValue := reflect.ValueOf(req)
   117  	error := new(error)
   118  	for {
   119  		*hdr = header{}
   120  		if err := client.decode(hdrValue); err != nil {
   121  			if err != os.EOF {
   122  				expLog("error decoding client header:", err)
   123  			}
   124  			break
   125  		}
   126  		switch hdr.PayloadType {
   127  		case payRequest:
   128  			*req = request{}
   129  			if err := client.decode(reqValue); err != nil {
   130  				expLog("error decoding client request:", err)
   131  				break
   132  			}
   133  			if req.Size < 1 {
   134  				panic("netchan: remote requested " + strconv.Itoa(req.Size) + " values")
   135  			}
   136  			switch req.Dir {
   137  			case Recv:
   138  				// look up channel before calling serveRecv to
   139  				// avoid a lock around client.chans.
   140  				if nch := client.newChan(hdr, Send, req.Name, req.Size, req.Count); nch != nil {
   141  					go client.serveRecv(nch, *hdr, req.Count)
   142  				}
   143  			case Send:
   144  				client.newChan(hdr, Recv, req.Name, req.Size, req.Count)
   145  				// The actual sends will have payload type payData.
   146  				// TODO: manage the count?
   147  			default:
   148  				error.Error = "request: can't handle channel direction"
   149  				expLog(error.Error, req.Dir)
   150  				client.encode(hdr, payError, error)
   151  			}
   152  		case payData:
   153  			client.serveSend(*hdr)
   154  		case payClosed:
   155  			client.serveClosed(*hdr)
   156  		case payAck:
   157  			client.mu.Lock()
   158  			if client.ackNum != hdr.SeqNum-1 {
   159  				// Since the sequence number is incremented and the message is sent
   160  				// in a single instance of locking client.mu, the messages are guaranteed
   161  				// to be sent in order.  Therefore receipt of acknowledgement N means
   162  				// all messages <=N have been seen by the recipient.  We check anyway.
   163  				expLog("sequence out of order:", client.ackNum, hdr.SeqNum)
   164  			}
   165  			if client.ackNum < hdr.SeqNum { // If there has been an error, don't back up the count.
   166  				client.ackNum = hdr.SeqNum
   167  			}
   168  			client.mu.Unlock()
   169  		case payAckSend:
   170  			if nch := client.getChan(hdr, Send); nch != nil {
   171  				nch.acked()
   172  			}
   173  		default:
   174  			log.Fatal("netchan export: unknown payload type", hdr.PayloadType)
   175  		}
   176  	}
   177  	client.exp.delClient(client)
   178  }
   179  
   180  // Send all the data on a single channel to a client asking for a Recv.
   181  // The header is passed by value to avoid issues of overwriting.
   182  func (client *expClient) serveRecv(nch *netChan, hdr header, count int64) {
   183  	for {
   184  		val, ok := nch.recv()
   185  		if !ok {
   186  			if err := client.encode(&hdr, payClosed, nil); err != nil {
   187  				expLog("error encoding server closed message:", err)
   188  			}
   189  			break
   190  		}
   191  		// We hold the lock during transmission to guarantee messages are
   192  		// sent in sequence number order.  Also, we increment first so the
   193  		// value of client.SeqNum is the value of the highest used sequence
   194  		// number, not one beyond.
   195  		client.mu.Lock()
   196  		client.seqNum++
   197  		hdr.SeqNum = client.seqNum
   198  		client.seqLock.Lock() // guarantee ordering of messages
   199  		client.mu.Unlock()
   200  		err := client.encode(&hdr, payData, val.Interface())
   201  		client.seqLock.Unlock()
   202  		if err != nil {
   203  			expLog("error encoding client response:", err)
   204  			client.sendError(&hdr, err.String())
   205  			break
   206  		}
   207  		// Negative count means run forever.
   208  		if count >= 0 {
   209  			if count--; count <= 0 {
   210  				break
   211  			}
   212  		}
   213  	}
   214  }
   215  
   216  // Receive and deliver locally one item from a client asking for a Send
   217  // The header is passed by value to avoid issues of overwriting.
   218  func (client *expClient) serveSend(hdr header) {
   219  	nch := client.getChan(&hdr, Recv)
   220  	if nch == nil {
   221  		return
   222  	}
   223  	// Create a new value for each received item.
   224  	val := reflect.Zero(nch.ch.Type().Elem())
   225  	if err := client.decode(val); err != nil {
   226  		expLog("value decode:", err, "; type ", nch.ch.Type())
   227  		return
   228  	}
   229  	nch.send(val)
   230  }
   231  
   232  // Report that client has closed the channel that is sending to us.
   233  // The header is passed by value to avoid issues of overwriting.
   234  func (client *expClient) serveClosed(hdr header) {
   235  	nch := client.getChan(&hdr, Recv)
   236  	if nch == nil {
   237  		return
   238  	}
   239  	nch.close()
   240  }
   241  
   242  func (client *expClient) unackedCount() int64 {
   243  	client.mu.Lock()
   244  	n := client.seqNum - client.ackNum
   245  	client.mu.Unlock()
   246  	return n
   247  }
   248  
   249  func (client *expClient) seq() int64 {
   250  	client.mu.Lock()
   251  	n := client.seqNum
   252  	client.mu.Unlock()
   253  	return n
   254  }
   255  
   256  func (client *expClient) ack() int64 {
   257  	client.mu.Lock()
   258  	n := client.seqNum
   259  	client.mu.Unlock()
   260  	return n
   261  }
   262  
   263  // Serve waits for incoming connections on the listener
   264  // and serves the Exporter's channels on each.
   265  // It blocks until the listener is closed.
   266  func (exp *Exporter) Serve(listener net.Listener) {
   267  	for {
   268  		conn, err := listener.Accept()
   269  		if err != nil {
   270  			expLog("listen:", err)
   271  			break
   272  		}
   273  		go exp.ServeConn(conn)
   274  	}
   275  }
   276  
   277  // ServeConn exports the Exporter's channels on conn.
   278  // It blocks until the connection is terminated.
   279  func (exp *Exporter) ServeConn(conn io.ReadWriter) {
   280  	exp.addClient(conn).run()
   281  }
   282  
   283  // NewExporter creates a new Exporter that exports a set of channels.
   284  func NewExporter() *Exporter {
   285  	e := &Exporter{
   286  		clientSet: &clientSet{
   287  			names:   make(map[string]*chanDir),
   288  			clients: make(map[unackedCounter]bool),
   289  		},
   290  	}
   291  	return e
   292  }
   293  
   294  // ListenAndServe exports the exporter's channels through the
   295  // given network and local address defined as in net.Listen.
   296  func (exp *Exporter) ListenAndServe(network, localaddr string) os.Error {
   297  	listener, err := net.Listen(network, localaddr)
   298  	if err != nil {
   299  		return err
   300  	}
   301  	go exp.Serve(listener)
   302  	return nil
   303  }
   304  
   305  // addClient creates a new expClient and records its existence
   306  func (exp *Exporter) addClient(conn io.ReadWriter) *expClient {
   307  	client := newClient(exp, conn)
   308  	exp.mu.Lock()
   309  	exp.clients[client] = true
   310  	exp.mu.Unlock()
   311  	return client
   312  }
   313  
   314  // delClient forgets the client existed
   315  func (exp *Exporter) delClient(client *expClient) {
   316  	exp.mu.Lock()
   317  	exp.clients[client] = false, false
   318  	exp.mu.Unlock()
   319  }
   320  
   321  // Drain waits until all messages sent from this exporter/importer, including
   322  // those not yet sent to any client and possibly including those sent while
   323  // Drain was executing, have been received by the importer.  In short, it
   324  // waits until all the exporter's messages have been received by a client.
   325  // If the timeout (measured in nanoseconds) is positive and Drain takes
   326  // longer than that to complete, an error is returned.
   327  func (exp *Exporter) Drain(timeout int64) os.Error {
   328  	// This wrapper function is here so the method's comment will appear in godoc.
   329  	return exp.clientSet.drain(timeout)
   330  }
   331  
   332  // Sync waits until all clients of the exporter have received the messages
   333  // that were sent at the time Sync was invoked.  Unlike Drain, it does not
   334  // wait for messages sent while it is running or messages that have not been
   335  // dispatched to any client.  If the timeout (measured in nanoseconds) is
   336  // positive and Sync takes longer than that to complete, an error is
   337  // returned.
   338  func (exp *Exporter) Sync(timeout int64) os.Error {
   339  	// This wrapper function is here so the method's comment will appear in godoc.
   340  	return exp.clientSet.sync(timeout)
   341  }
   342  
   343  func checkChan(chT interface{}, dir Dir) (reflect.Value, os.Error) {
   344  	chanType := reflect.TypeOf(chT)
   345  	if chanType.Kind() != reflect.Chan {
   346  		return reflect.Value{}, os.NewError("not a channel")
   347  	}
   348  	if dir != Send && dir != Recv {
   349  		return reflect.Value{}, os.NewError("unknown channel direction")
   350  	}
   351  	switch chanType.ChanDir() {
   352  	case reflect.BothDir:
   353  	case reflect.SendDir:
   354  		if dir != Recv {
   355  			return reflect.Value{}, os.NewError("to import/export with Send, must provide <-chan")
   356  		}
   357  	case reflect.RecvDir:
   358  		if dir != Send {
   359  			return reflect.Value{}, os.NewError("to import/export with Recv, must provide chan<-")
   360  		}
   361  	}
   362  	return reflect.ValueOf(chT), nil
   363  }
   364  
   365  // Export exports a channel of a given type and specified direction.  The
   366  // channel to be exported is provided in the call and may be of arbitrary
   367  // channel type.
   368  // Despite the literal signature, the effective signature is
   369  //	Export(name string, chT chan T, dir Dir)
   370  func (exp *Exporter) Export(name string, chT interface{}, dir Dir) os.Error {
   371  	ch, err := checkChan(chT, dir)
   372  	if err != nil {
   373  		return err
   374  	}
   375  	exp.mu.Lock()
   376  	defer exp.mu.Unlock()
   377  	_, present := exp.names[name]
   378  	if present {
   379  		return os.NewError("channel name already being exported:" + name)
   380  	}
   381  	exp.names[name] = &chanDir{ch, dir}
   382  	return nil
   383  }
   384  
   385  // Hangup disassociates the named channel from the Exporter and closes
   386  // the channel.  Messages in flight for the channel may be dropped.
   387  func (exp *Exporter) Hangup(name string) os.Error {
   388  	exp.mu.Lock()
   389  	chDir, ok := exp.names[name]
   390  	if ok {
   391  		exp.names[name] = nil, false
   392  	}
   393  	// TODO drop all instances of channel from client sets
   394  	exp.mu.Unlock()
   395  	if !ok {
   396  		return os.NewError("netchan export: hangup: no such channel: " + name)
   397  	}
   398  	chDir.ch.Close()
   399  	return nil
   400  }