diff options
Diffstat (limited to 'usr/rsc')
-rw-r--r-- | usr/rsc/nacl/av/Makefile | 13 | ||||
-rw-r--r-- | usr/rsc/nacl/av/av.go | 311 | ||||
-rw-r--r-- | usr/rsc/nacl/av/event.go | 471 | ||||
-rw-r--r-- | usr/rsc/nacl/av/image.go | 95 | ||||
-rw-r--r-- | usr/rsc/nacl/srpc/Makefile | 13 | ||||
-rw-r--r-- | usr/rsc/nacl/srpc/client.go | 210 | ||||
-rw-r--r-- | usr/rsc/nacl/srpc/msg.go | 532 | ||||
-rw-r--r-- | usr/rsc/nacl/srpc/server.go | 204 |
8 files changed, 0 insertions, 1849 deletions
diff --git a/usr/rsc/nacl/av/Makefile b/usr/rsc/nacl/av/Makefile deleted file mode 100644 index 523a9fff1..000000000 --- a/usr/rsc/nacl/av/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright 2009 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -include $(GOROOT)/src/Make.$(GOARCH) - -TARG=nacl/av -GOFILES=\ - av.go\ - event.go\ - image.go\ - -include $(GOROOT)/src/Make.pkg diff --git a/usr/rsc/nacl/av/av.go b/usr/rsc/nacl/av/av.go deleted file mode 100644 index 0accf4612..000000000 --- a/usr/rsc/nacl/av/av.go +++ /dev/null @@ -1,311 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Native Client audio/video - -// Package av implements audio and video access for Native Client -// binaries running standalone or embedded in a web browser window. -// -// The C version of the API is documented at -// http://nativeclient.googlecode.com/svn/data/docs_tarball/nacl/googleclient/native_client/scons-out/doc/html/group__audio__video.html -package av - -import ( - "bytes"; - "draw"; - "log"; - "nacl/srpc"; - "os"; - "syscall"; - "unsafe"; -) - -var srpcEnabled = srpc.Enabled(); - -// native_client/src/trusted/service_runtime/include/sys/audio_video.h - -// Subsystem values for Init. -const ( - SubsystemVideo = 1<<iota; - SubsystemAudio; - SubsystemEmbed; -) -// SubsystemRawEvents; - -// Audio formats. -const ( - AudioFormatStereo44K = iota; - AudioFormatStereo48K; -) - -// A Window represents a connection to the Native Client window. -// It implements draw.Context. -type Window struct { - Embedded bool; // running as part of a web page? - *Image; // screen image - - mousec chan draw.Mouse; - kbdc chan int; - quitc chan bool; - resizec chan bool; -} - -// *Window implements draw.Context -var _ draw.Context = (*Window)(nil) - -func (w *Window) KeyboardChan() <-chan int { - return w.kbdc; -} - -func (w *Window) MouseChan() <-chan draw.Mouse { - return w.mousec; -} - -func (w *Window) QuitChan() <-chan bool { - return w.quitc; -} - -func (w *Window) ResizeChan() <-chan bool { - return w.resizec; -} - -func (w *Window) Screen() draw.Image { - return w.Image; -} - -// Init initializes the Native Client subsystems specified by subsys. -// Init must be called before using any of the other functions -// in this package, and it must be called only once. -// -// If the SubsystemVideo flag is set, Init requests a window of size dx×dy. -// When embedded in a web page, the web page's window specification -// overrides the parameters to Init, so the returned Window may have -// a different size than requested. -// -// If the SubsystemAudio flag is set, Init requests a connection to the -// audio device carrying 44 kHz 16-bit stereo PCM audio samples. -func Init(subsys int, dx, dy int) (*Window, os.Error) { - xsubsys := subsys; - if srpcEnabled { - waitBridge(); - xsubsys &^= SubsystemVideo|SubsystemEmbed; - } - - if xsubsys & SubsystemEmbed != 0 { - return nil, os.NewError("not embedded"); - } - - w := new(Window); - err := multimediaInit(xsubsys); - if err != nil { - return nil, err; - } - - if subsys&SubsystemVideo != 0 { - if dx, dy, err = videoInit(dx, dy); err != nil { - return nil, err; - } - w.Image = newImage(dx, dy, bridge.pixel); - w.resizec = make(chan bool, 64); - w.kbdc = make(chan int, 64); - w.mousec = make(chan draw.Mouse, 64); - w.quitc = make(chan bool); - } - - if subsys&SubsystemAudio != 0 { - var n int; - if n, err = audioInit(AudioFormatStereo44K, 2048); err != nil { - return nil, err; - } - println("audio", n); - } - - if subsys&SubsystemVideo != 0 { - go w.readEvents(); - } - - return w, nil; -} - -func (w *Window) FlushImage() { - if w.Image == nil { - return; - } - videoUpdate(w.Image.Linear); -} - -func multimediaInit(subsys int) (err os.Error) { - return os.NewSyscallError("multimedia_init", syscall.MultimediaInit(subsys)); -} - -func videoInit(dx, dy int) (ndx, ndy int, err os.Error) { - if srpcEnabled { - bridge.share.ready = 1; - return int(bridge.share.width), int(bridge.share.height), nil; - } - if e := syscall.VideoInit(dx, dy); e != 0 { - return 0, 0, os.NewSyscallError("video_init", int(e)); - } - return dx, dy, nil; -} - -func videoUpdate(data []Color) (err os.Error) { - if srpcEnabled { - bridge.flushRPC.Call("upcall", nil); - return; - } - return os.NewSyscallError("video_update", syscall.VideoUpdate((*uint32)(&data[0]))); -} - -var noEvents = os.NewError("no events"); - -func videoPollEvent(ev []byte) (err os.Error) { - if srpcEnabled { - r := bridge.share.eq.ri; - if r == bridge.share.eq.wi { - return noEvents; - } - bytes.Copy(ev, &bridge.share.eq.event[r]); - bridge.share.eq.ri = (r+1) % eqsize; - return nil; - } - return os.NewSyscallError("video_poll_event", syscall.VideoPollEvent(&ev[0])); -} - -func audioInit(fmt int, want int) (got int, err os.Error) { - var x int; - e := syscall.AudioInit(fmt, want, &x); - if e == 0 { - return x, nil; - } - return 0, os.NewSyscallError("audio_init", e); -} - -var audioSize uintptr - -// AudioStream provides access to the audio device. -// Each call to AudioStream writes the given data, -// which should be a slice of 16-bit stereo PCM audio samples, -// and returns the number of samples required by the next -// call to AudioStream. -// -// To find out the initial number of samples to write, call AudioStream(nil). -// -func AudioStream(data []uint16) (nextSize int, err os.Error) { - if audioSize == 0 { - e := os.NewSyscallError("audio_stream", syscall.AudioStream(nil, &audioSize)); - return int(audioSize), e; - } - if data == nil { - return int(audioSize), nil; - } - if uintptr(len(data))*2 != audioSize { - log.Stdoutf("invalid audio size want %d got %d", audioSize, len(data)); - } - e := os.NewSyscallError("audio_stream", syscall.AudioStream(&data[0], &audioSize)); - return int(audioSize), e; -} - -// Synchronization structure to wait for bridge to become ready. -var bridge struct { - c chan bool; - displayFd int; - rpcFd int; - share *videoShare; - pixel []Color; - client *srpc.Client; - flushRPC *srpc.RPC; -} - -// Wait for bridge to become ready. -// When chan is first created, there is nothing in it, -// so this blocks. Once the bridge is ready, multimediaBridge.Run -// will drop a value into the channel. Then any calls -// to waitBridge will finish, taking the value out and immediately putting it back. -func waitBridge() { - bridge.c <- <-bridge.c; -} - -const eqsize = 64; - -// Data structure shared with host via mmap. -type videoShare struct { - revision int32; // definition below is rev 100 unless noted - mapSize int32; - - // event queue - eq struct { - ri uint32; // read index [0,eqsize) - wi uint32; // write index [0,eqsize) - eof int32; - event [eqsize][64]byte; - }; - - // now unused - _, _, _, _ int32; - - // video backing store information - width, height, _, size int32; - ready int32; // rev 0x101 -} - -// The frame buffer data is videoShareSize bytes after -// the videoShare begins. -const videoShareSize = 16*1024 - -type multimediaBridge struct{} - -// If using SRPC, the runtime will call this method to pass in two file descriptors, -// one to mmap to get the display memory, and another to use for SRPCs back -// to the main process. -func (multimediaBridge) Run(arg, ret []interface{}, size []int) srpc.Errno { - bridge.displayFd = arg[0].(int); - bridge.rpcFd = arg[1].(int); - - var st syscall.Stat_t; - if errno := syscall.Fstat(bridge.displayFd, &st); errno != 0 { - log.Exitf("mmbridge stat display: %s", os.Errno(errno)); - } - - addr, _, errno := syscall.Syscall6(syscall.SYS_MMAP, - 0, - uintptr(st.Size), - syscall.PROT_READ|syscall.PROT_WRITE, - syscall.MAP_SHARED, - uintptr(bridge.displayFd), - 0); - if errno != 0 { - log.Exitf("mmap display: %s", os.Errno(errno)); - } - - bridge.share = (*videoShare)(unsafe.Pointer(addr)); - - // Overestimate frame buffer size - // (must use a compile-time constant) - // and then reslice. 256 megapixels (1 GB) should be enough. - fb := (*[256*1024*1024]Color)(unsafe.Pointer(addr+videoShareSize)); - bridge.pixel = fb[0:(st.Size - videoShareSize)/4]; - - // Configure RPC connection back to client. - var err os.Error; - bridge.client, err = srpc.NewClient(bridge.rpcFd); - if err != nil { - log.Exitf("NewClient: %s", err); - } - bridge.flushRPC = bridge.client.NewRPC(nil); - - // Notify waiters that the bridge is ready. - println("bridged", bridge.share.revision); - bridge.c <- true; - - return srpc.OK; -} - -func init() { - bridge.c = make(chan bool, 1); - if srpcEnabled { - srpc.Add("nacl_multimedia_bridge", "hh:", multimediaBridge{}); - } -} - diff --git a/usr/rsc/nacl/av/event.go b/usr/rsc/nacl/av/event.go deleted file mode 100644 index 62ecbc6e6..000000000 --- a/usr/rsc/nacl/av/event.go +++ /dev/null @@ -1,471 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// NaCl GUI events. -// Clients do not have raw access to the event stream -// (only filtered through the lens of package draw) -// but perhaps they will. - -package av - -import ( - "bytes"; - "debug/binary"; - "draw"; - "log"; - "os"; - "time"; -) - -// An eventType identifies the type of a Native Client Event. -type eventType uint8; -const ( - eventActive = 1+iota; - eventExpose; - eventKeyDown; - eventKeyUp; - eventMouseMotion; - eventMouseButtonDown; - eventMouseButtonUp; - eventQuit; - eventUnsupported; -) - -// A key represents a key on a keyboard. -type key uint16 -const ( - keyUnknown = 0; - keyFirst = 0; - keyBackspace = 8; - keyTab = 9; - keyClear = 12; - keyReturn = 13; - keyPause = 19; - keyEscape = 27; - keySpace = 32; - keyExclaim = 33; - keyQuotedbl = 34; - keyHash = 35; - keyDollar = 36; - keyAmpersand = 38; - keyQuote = 39; - keyLeftparen = 40; - keyRightparen = 41; - keyAsterisk = 42; - keyPlus = 43; - keyComma = 44; - keyMinus = 45; - keyPeriod = 46; - keySlash = 47; - key0 = 48; - key1 = 49; - key2 = 50; - key3 = 51; - key4 = 52; - key5 = 53; - key6 = 54; - key7 = 55; - key8 = 56; - key9 = 57; - keyColon = 58; - keySemicolon = 59; - keyLess = 60; - keyEquals = 61; - keyGreater = 62; - keyQuestion = 63; - keyAt = 64; - keyLeftbracket = 91; - keyBackslash = 92; - keyRightbracket = 93; - keyCaret = 94; - keyUnderscore = 95; - keyBackquote = 96; - keyA = 97; - keyB = 98; - keyC = 99; - keyD = 100; - keyE = 101; - keyF = 102; - keyG = 103; - keyH = 104; - keyI = 105; - keyJ = 106; - keyK = 107; - keyL = 108; - keyM = 109; - keyN = 110; - keyO = 111; - keyP = 112; - keyQ = 113; - keyR = 114; - keyS = 115; - keyT = 116; - keyU = 117; - keyV = 118; - keyW = 119; - keyX = 120; - keyY = 121; - keyZ = 122; - keyDelete = 127; - keyWorld0 = 160; - keyWorld1 = 161; - keyWorld2 = 162; - keyWorld3 = 163; - keyWorld4 = 164; - keyWorld5 = 165; - keyWorld6 = 166; - keyWorld7 = 167; - keyWorld8 = 168; - keyWorld9 = 169; - keyWorld10 = 170; - keyWorld11 = 171; - keyWorld12 = 172; - keyWorld13 = 173; - keyWorld14 = 174; - keyWorld15 = 175; - keyWorld16 = 176; - keyWorld17 = 177; - keyWorld18 = 178; - keyWorld19 = 179; - keyWorld20 = 180; - keyWorld21 = 181; - keyWorld22 = 182; - keyWorld23 = 183; - keyWorld24 = 184; - keyWorld25 = 185; - keyWorld26 = 186; - keyWorld27 = 187; - keyWorld28 = 188; - keyWorld29 = 189; - keyWorld30 = 190; - keyWorld31 = 191; - keyWorld32 = 192; - keyWorld33 = 193; - keyWorld34 = 194; - keyWorld35 = 195; - keyWorld36 = 196; - keyWorld37 = 197; - keyWorld38 = 198; - keyWorld39 = 199; - keyWorld40 = 200; - keyWorld41 = 201; - keyWorld42 = 202; - keyWorld43 = 203; - keyWorld44 = 204; - keyWorld45 = 205; - keyWorld46 = 206; - keyWorld47 = 207; - keyWorld48 = 208; - keyWorld49 = 209; - keyWorld50 = 210; - keyWorld51 = 211; - keyWorld52 = 212; - keyWorld53 = 213; - keyWorld54 = 214; - keyWorld55 = 215; - keyWorld56 = 216; - keyWorld57 = 217; - keyWorld58 = 218; - keyWorld59 = 219; - keyWorld60 = 220; - keyWorld61 = 221; - keyWorld62 = 222; - keyWorld63 = 223; - keyWorld64 = 224; - keyWorld65 = 225; - keyWorld66 = 226; - keyWorld67 = 227; - keyWorld68 = 228; - keyWorld69 = 229; - keyWorld70 = 230; - keyWorld71 = 231; - keyWorld72 = 232; - keyWorld73 = 233; - keyWorld74 = 234; - keyWorld75 = 235; - keyWorld76 = 236; - keyWorld77 = 237; - keyWorld78 = 238; - keyWorld79 = 239; - keyWorld80 = 240; - keyWorld81 = 241; - keyWorld82 = 242; - keyWorld83 = 243; - keyWorld84 = 244; - keyWorld85 = 245; - keyWorld86 = 246; - keyWorld87 = 247; - keyWorld88 = 248; - keyWorld89 = 249; - keyWorld90 = 250; - keyWorld91 = 251; - keyWorld92 = 252; - keyWorld93 = 253; - keyWorld94 = 254; - keyWorld95 = 255; - - // Numeric keypad - keyKp0 = 256; - keyKp1 = 257; - keyKp2 = 258; - keyKp3 = 259; - keyKp4 = 260; - keyKp5 = 261; - keyKp6 = 262; - keyKp7 = 263; - keyKp8 = 264; - keyKp9 = 265; - keyKpPeriod = 266; - keyKpDivide = 267; - keyKpMultiply = 268; - keyKpMinus = 269; - keyKpPlus = 270; - keyKpEnter = 271; - keyKpEquals = 272; - - // Arrow & insert/delete pad - keyUp = 273; - keyDown = 274; - keyRight = 275; - keyLeft = 276; - keyInsert = 277; - keyHome = 278; - keyEnd = 279; - keyPageup = 280; - keyPagedown = 281; - - // Function keys - keyF1 = 282; - keyF2 = 283; - keyF3 = 284; - keyF4 = 285; - keyF5 = 286; - keyF6 = 287; - keyF7 = 288; - keyF8 = 289; - keyF9 = 290; - keyF10 = 291; - keyF11 = 292; - keyF12 = 293; - keyF13 = 294; - keyF14 = 295; - keyF15 = 296; - - // Modifier keys - keyNumlock = 300; - keyCapslock = 301; - keyScrollock = 302; - keyRshift = 303; - keyLshift = 304; - keyRctrl = 305; - keyLctrl = 306; - keyRalt = 307; - keyLalt = 308; - keyRmeta = 309; - keyLmeta = 310; - keyLsuper = 311; - keyRsuper = 312; - keyMode = 313; - keyCompose = 314; - - // Misc keys - keyHelp = 315; - keyPrint = 316; - keySysreq = 317; - keyBreak = 318; - keyMenu = 319; - keyPower = 320; - keyEuro = 321; - keyUndo = 322; - - // Add any other keys here - keyLast -) - -// A keymod is a set of bit flags -type keymod uint16 -const ( - keymodNone = 0x0000; - keymodLshift= 0x0001; - keymodRshift= 0x0002; - keymodLctrl = 0x0040; - keymodRctrl = 0x0080; - keymodLalt = 0x0100; - keymodRalt = 0x0200; - keymodLmeta = 0x0400; - keymodRmeta = 0x0800; - keymodNum = 0x1000; - keymodCaps = 0x2000; - keymodMode = 0x4000; - keymodReserved = 0x8000 -) - -const ( - mouseButtonLeft = 1; - mouseButtonMiddle = 2; - mouseButtonRight = 3; - mouseScrollUp = 4; - mouseScrollDown = 5 -) - -const ( - mouseStateLeftButtonPressed = 1; - mouseStateMiddleButtonPressed = 2; - mouseStateRightButtonPressed = 4 -) - -const ( - activeMouse = 1; // mouse leaving/entering - activeInputFocus = 2; // input focus lost/restored - activeApplication = 4 // application minimized/restored -) - -const maxEventBytes = 64 - -type activeEvent struct { - EventType eventType; - Gain uint8; - State uint8; -} - -type exposeEvent struct { - EventType eventType; -} - -type keyboardEvent struct { - EventType eventType; - Device uint8; - State uint8; - Pad uint8; - ScanCode uint8; - Pad1 uint8; - Key key; - Mod keymod; - Unicode uint16; -} - -type mouseMotionEvent struct { - EventType eventType; - Device uint8; - Buttons uint8; - Pad uint8; - X uint16; - Y uint16; - Xrel int16; - Yrel int16; -} - -type mouseButtonEvent struct { - EventType eventType; - Device uint8; - Button uint8; - State uint8; - X uint16; - Y uint16; -} - -type quitEvent struct { - EventType eventType; -} - -type syncEvent struct { -} - -type event interface { -} - -type reader []byte -func (r *reader) Read(p []byte) (n int, err os.Error) { - b := *r; - if len(b) == 0 && len(p) > 0 { - return 0, os.EOF; - } - n = bytes.Copy(p, b); - *r = b[n:len(b)]; - return; -} - -func (w *Window) readEvents() { - buf := make([]byte, maxEventBytes); - clean := false; - var ( - ea *activeEvent; - ee *exposeEvent; - ke *keyboardEvent; - mme *mouseMotionEvent; - mbe *mouseButtonEvent; - qe *quitEvent; - ) - var m draw.Mouse; - for { - if err := videoPollEvent(buf); err != nil { - if !clean { - clean = w.resizec <- false; - } - time.Sleep(10e6); // 10ms - continue; - } - clean = false; - var e event; - switch buf[0] { - default: - log.Stdout("unsupported event type", buf[0]); - continue; - case eventActive: - ea = new(activeEvent); - e = ea; - case eventExpose: - ee = new(exposeEvent); - e = ee; - case eventKeyDown, eventKeyUp: - ke = new(keyboardEvent); - e = ke; - case eventMouseMotion: - mme = new(mouseMotionEvent); - e = mme; - case eventMouseButtonDown, eventMouseButtonUp: - mbe = new(mouseButtonEvent); - e = mbe; - case eventQuit: - qe = new(quitEvent); - e = qe; - } - r := reader(buf); - if err := binary.Read(&r, binary.LittleEndian, e); err != nil { - log.Stdout("unpacking %T event: %s", e, err); - continue; - } - // log.Stdoutf("%#v\n", e); - switch buf[0] { - case eventExpose: - w.resizec <- true - case eventKeyDown: - w.kbdc <- int(ke.Key); - case eventKeyUp: - w.kbdc <- -int(ke.Key); - case eventMouseMotion: - m.X = int(mme.X); - m.Y = int(mme.Y); - m.Buttons = int(mme.Buttons); - m.Nsec = time.Nanoseconds(); - _ = w.mousec <- m; - case eventMouseButtonDown: - m.X = int(mbe.X); - m.Y = int(mbe.Y); - // TODO(rsc): Remove uint cast once 8g bug is fixed. - m.Buttons |= 1<<uint(mbe.Button-1); - m.Nsec = time.Nanoseconds(); - _ = w.mousec <- m; - case eventMouseButtonUp: - m.X = int(mbe.X); - m.Y = int(mbe.Y); - // TODO(rsc): Remove uint cast once 8g bug is fixed. - m.Buttons &^= 1<<uint(mbe.Button-1); - m.Nsec = time.Nanoseconds(); - _ = w.mousec <- m; - case eventQuit: - w.quitc <- true; - } - } -} diff --git a/usr/rsc/nacl/av/image.go b/usr/rsc/nacl/av/image.go deleted file mode 100644 index 3aee3cad0..000000000 --- a/usr/rsc/nacl/av/image.go +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package av - -import ( - "image"; -) - -// Native Client image format: -// a single linear array of 32-bit ARGB as packed uint32s. - -// An Image represents a Native Client frame buffer. -// The pixels in the image can be accessed as a single -// linear slice or as a two-dimensional slice of slices. -// Image implements image.Image. -type Image struct { - Linear []Color; - Pixel [][]Color; -} - -var _ image.Image = (*Image)(nil); - -func (m *Image) ColorModel() image.ColorModel { - return ColorModel; -} - -func (m *Image) Width() int { - if len(m.Pixel) == 0 { - return 0; - } - return len(m.Pixel[0]); -} - -func (m *Image) Height() int { - return len(m.Pixel); -} - -func (m *Image) At(x, y int) image.Color { - return m.Pixel[y][x]; -} - -func (m *Image) Set(x, y int, color image.Color) { - if c, ok := color.(Color); ok { - m.Pixel[y][x] = c; - } - m.Pixel[y][x] = makeColor(color.RGBA()); -} - -func newImage(dx, dy int, linear []Color) *Image { - if linear == nil { - linear = make([]Color, dx*dy); - } - pix := make([][]Color, dy); - for i := range pix { - pix[i] = linear[dx*i : dx*(i+1)]; - } - return &Image{linear, pix}; -} - -// A Color represents a Native Client color value, -// a 32-bit R, G, B, A value packed as 0xAARRGGBB. -type Color uint32 -func (p Color) RGBA() (r, g, b, a uint32) { - x := uint32(p); - a = x>>24; - a |= a<<8; - a |= a<<16; - r = (x>>16) & 0xFF; - r |= r<<8; - r |= r<<16; - g = (x>>8) & 0xFF; - g |= g<<8; - g |= g<<16; - b = x & 0xFF; - b |= b<<8; - b |= b<<16; - return; -} - -func makeColor(r, g, b, a uint32) Color { - return Color(a>>24<<24 | r>>24<<16 | g>>24<<8 | b>>24); -} - -func toColor(color image.Color) image.Color { - if c, ok := color.(Color); ok { - return c; - } - return makeColor(color.RGBA()); -} - -// ColorModel is the color model corresponding to the Native Client Color. -var ColorModel = image.ColorModelFunc(toColor); - diff --git a/usr/rsc/nacl/srpc/Makefile b/usr/rsc/nacl/srpc/Makefile deleted file mode 100644 index 9014d2c3a..000000000 --- a/usr/rsc/nacl/srpc/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright 2009 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -include $(GOROOT)/src/Make.$(GOARCH) - -TARG=nacl/srpc -GOFILES=\ - client.go\ - msg.go\ - server.go\ - -include $(GOROOT)/src/Make.pkg diff --git a/usr/rsc/nacl/srpc/client.go b/usr/rsc/nacl/srpc/client.go deleted file mode 100644 index 4c375fe2a..000000000 --- a/usr/rsc/nacl/srpc/client.go +++ /dev/null @@ -1,210 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// This package implements Native Client's simple RPC (SRPC). -package srpc - -import ( - "bytes"; - "log"; - "os"; - "sync"; -) - -// A Client represents the client side of an SRPC connection. -type Client struct { - fd int; // fd to server - r msgReceiver; - s msgSender; - service map[string]srv; // services by name - out chan *msg; // send to out to write to connection - - mu sync.Mutex; // protects pending, idGen - pending map[uint64]*RPC; - idGen uint64; // generator for request IDs -} - -// A srv is a single method that the server offers. -type srv struct { - num uint32; // method number - fmt string; // argument format -} - -// An RPC represents a single RPC issued by a client. -type RPC struct { - Ret []interface{}; // Return values - Done chan *RPC; // Channel where notification of done arrives - Errno Errno; // Status code - c *Client; - id uint64; // request id -} - -// NewClient allocates a new client using the file descriptor fd. -func NewClient(fd int) (c *Client, err os.Error) { - c = new(Client); - c.fd = fd; - c.r.fd = fd; - c.s.fd = fd; - c.service = make(map[string]srv); - c.pending = make(map[uint64]*RPC); - - // service discovery request - m := &msg{ - protocol: protocol, - isReq: true, - Ret: []interface{}{ []byte(nil) }, - Size: []int{ 4000 }, - }; - m.packRequest(); - c.s.send(m); - m, err = c.r.recv(); - if err != nil { - return nil, err; - } - m.unpackResponse(); - if m.status != OK { - log.Stderrf("NewClient service_discovery: %s", m.status); - return nil, m.status; - } - for n, line := range bytes.Split(m.Ret[0].([]byte), []byte{'\n'}, 0) { - i := bytes.Index(line, []byte{':'}); - if i < 0 { - continue; - } - c.service[string(line[0:i])] = srv{uint32(n), string(line[i+1:len(line)])}; - } - - c.out = make(chan *msg); - go c.input(); - go c.output(); - return c, nil; -} - -func (c *Client) input() { - for { - m, err := c.r.recv(); - if err != nil { - log.Exitf("client recv: %s", err); - } - if m.unpackResponse(); m.status != OK { - log.Stderrf("invalid message: %s", m.status); - continue; - } - c.mu.Lock(); - rpc, ok := c.pending[m.requestId]; - if ok { - c.pending[m.requestId] = nil, false; - } - c.mu.Unlock(); - if !ok { - log.Stderrf("unexpected response"); - continue; - } - rpc.Ret = m.Ret; - rpc.Done <- rpc; - } -} - -func (c *Client) output() { - for m := range c.out { - c.s.send(m); - } -} - -// NewRPC creates a new RPC on the client connection. -func (c *Client) NewRPC(done chan *RPC) *RPC { - if done == nil { - done = make(chan *RPC); - } - c.mu.Lock(); - id := c.idGen; - c.idGen++; - c.mu.Unlock(); - return &RPC{nil, done, OK, c, id}; -} - -// Start issues an RPC request for method name with the given arguments. -// The RPC r must not be in use for another pending request. -// To wait for the RPC to finish, receive from r.Done and then -// inspect r.Ret and r.Errno. -func (r *RPC) Start(name string, arg []interface{}) { - var m msg; - - r.Errno = OK; - r.c.mu.Lock(); - srv, ok := r.c.service[name]; - if !ok { - r.c.mu.Unlock(); - r.Errno = ErrBadRPCNumber; - r.Done <- r; - return; - } - r.c.pending[r.id] = r; - r.c.mu.Unlock(); - - m.protocol = protocol; - m.requestId = r.id; - m.isReq = true; - m.rpcNumber = srv.num; - m.Arg = arg; - - // Fill in the return values and sizes to generate - // the right type chars. We'll take most any size. - - // Skip over input arguments. - // We could check them against arg, but the server - // will do that anyway. - i := 0; - for srv.fmt[i] != ':' { - i++; - } - fmt := srv.fmt[i+1:len(srv.fmt)]; - - // Now the return prototypes. - m.Ret = make([]interface{}, len(fmt) - i); - m.Size = make([]int, len(fmt) - i); - for i := 0; i < len(fmt); i++ { - switch fmt[i] { - default: - log.Exitf("unexpected service type %c", fmt[i]); - case 'b': - m.Ret[i] = false; - case 'C': - m.Ret[i] = []byte(nil); - m.Size[i] = 1<<30; - case 'd': - m.Ret[i] = float64(0); - case 'D': - m.Ret[i] = []float64(nil); - m.Size[i] = 1<<30; - case 'h': - m.Ret[i] = int(-1); - case 'i': - m.Ret[i] = int32(0); - case 'I': - m.Ret[i] = []int32(nil); - m.Size[i] = 1<<30; - case 's': - m.Ret[i] = ""; - m.Size[i] = 1<<30; - } - } - - m.packRequest(); - r.c.out <- &m; -} - -// Call is a convenient wrapper that starts the RPC request, -// waits for it to finish, and then returns the results. -// Its implementation is: -// -// r.Start(name, arg); -// <-r.Done; -// return r.Ret, r.Errno; -// -func (r *RPC) Call(name string, arg []interface{}) (ret []interface{}, err Errno) { - r.Start(name, arg); - <-r.Done; - return r.Ret, r.Errno; -} diff --git a/usr/rsc/nacl/srpc/msg.go b/usr/rsc/nacl/srpc/msg.go deleted file mode 100644 index 27fe7212f..000000000 --- a/usr/rsc/nacl/srpc/msg.go +++ /dev/null @@ -1,532 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// SRPC constants, data structures, and parsing. - -package srpc - -import ( - "bytes"; - "math"; - "os"; - "strconv"; - "syscall"; - "unsafe"; -) - -// An Errno is an SRPC status code. -type Errno uint32 -const ( - OK Errno = 256 + iota; - ErrBreak; - ErrMessageTruncated; - ErrNoMemory; - ErrProtocolMismatch; - ErrBadRPCNumber; - ErrBadArgType; - ErrTooFewArgs; - ErrTooManyArgs; - ErrInArgTypeMismatch; - ErrOutArgTypeMismatch; - ErrInternalError; - ErrAppError; -) - -var errstr = [...]string { - OK-OK: "ok", - ErrBreak-OK: "break", - ErrMessageTruncated-OK: "message truncated", - ErrNoMemory-OK: "out of memory", - ErrProtocolMismatch-OK: "protocol mismatch", - ErrBadRPCNumber-OK: "invalid RPC method number", - ErrBadArgType-OK: "unexpected argument type", - ErrTooFewArgs-OK: "too few arguments", - ErrTooManyArgs-OK: "too many arguments", - ErrInArgTypeMismatch-OK: "input argument type mismatch", - ErrOutArgTypeMismatch-OK: "output argument type mismatch", - ErrInternalError-OK: "internal error", - ErrAppError-OK: "application error", -} - -func (e Errno) String() string { - if e < OK || int(e-OK) >= len(errstr) { - return "Errno(" + strconv.Itoa64(int64(e)) + ")" - } - return errstr[e - OK]; -} - -// A *msgHdr is the data argument to the imc_recvmsg -// and imc_sendmsg system calls. Because it contains unchecked -// counts trusted by the system calls, the data structure is unsafe -// to expose to package clients. -type msgHdr struct { - iov *iov; - niov int32; - desc *int32; - ndesc int32; - flags uint32; -} - -// A single region for I/O. Just as unsafe as msgHdr. -type iov struct { - base *byte; - len int32; -} - -// A msg is the Go representation of a message. -type msg struct { - rdata []byte; // data being consumed during message parsing - rdesc []int32; // file descriptors being consumed during message parsing - wdata []byte; // data being generated when replying - - // parsed version of message - protocol uint32; - requestId uint64; - isReq bool; - rpcNumber uint32; - gotHeader bool; - status Errno; // error code sent in response - Arg []interface{}; // method arguments - Ret []interface{}; // method results - Size []int; // max sizes for arrays in method results - fmt string; // accumulated format string of arg+":"+ret -} - -// A msgReceiver receives messages from a file descriptor. -type msgReceiver struct { - fd int; - data [128*1024]byte; - desc [8]int32; - hdr msgHdr; - iov iov; -} - -func (r *msgReceiver) recv() (*msg, os.Error) { - // Init pointers to buffers where syscall recvmsg can write. - r.iov.base = &r.data[0]; - r.iov.len = int32(len(r.data)); - r.hdr.iov = &r.iov; - r.hdr.niov = 1; - r.hdr.desc = &r.desc[0]; - r.hdr.ndesc = int32(len(r.desc)); - n, _, e := syscall.Syscall(syscall.SYS_IMC_RECVMSG, uintptr(r.fd), uintptr(unsafe.Pointer(&r.hdr)), 0); - if e != 0 { - return nil, os.NewSyscallError("imc_recvmsg", int(e)); - } - - // Make a copy of the data so that the next recvmsg doesn't - // smash it. The system call did not update r.iov.len. Instead it - // returned the total byte count as n. - m := new(msg); - m.rdata = make([]byte, n); - bytes.Copy(m.rdata, &r.data); - - // Make a copy of the desc too. - // The system call *did* update r.hdr.ndesc. - if r.hdr.ndesc > 0 { - m.rdesc = make([]int32, r.hdr.ndesc); - for i := range m.rdesc { - m.rdesc[i] = r.desc[i]; - } - } - - return m, nil; -} - -// A msgSender sends messages on a file descriptor. -type msgSender struct { - fd int; - hdr msgHdr; - iov iov; - -} - -func (s *msgSender) send(m *msg) os.Error { - if len(m.wdata) > 0 { - s.iov.base = &m.wdata[0]; - } - s.iov.len = int32(len(m.wdata)); - s.hdr.iov = &s.iov; - s.hdr.niov = 1; - s.hdr.desc = nil; - s.hdr.ndesc = 0; - _, _, e := syscall.Syscall(syscall.SYS_IMC_SENDMSG, uintptr(s.fd), uintptr(unsafe.Pointer(&s.hdr)), 0); - if e != 0 { - return os.NewSyscallError("imc_sendmsg", int(e)); - } - return nil; -} - -// Reading from msg.rdata. -func (m *msg) uint8() uint8 { - if m.status != OK { - return 0; - } - if len(m.rdata) < 1 { - m.status = ErrMessageTruncated; - return 0; - } - x := m.rdata[0]; - m.rdata = m.rdata[1:len(m.rdata)]; - return x; -} - -func (m *msg) uint32() uint32 { - if m.status != OK { - return 0; - } - if len(m.rdata) < 4 { - m.status = ErrMessageTruncated; - return 0; - } - b := m.rdata[0:4]; - x := uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24; - m.rdata = m.rdata[4:len(m.rdata)]; - return x; -} - -func (m *msg) uint64() uint64 { - if m.status != OK { - return 0; - } - if len(m.rdata) < 8 { - m.status = ErrMessageTruncated; - return 0; - } - b := m.rdata[0:8]; - x := uint64(uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24); - x |= uint64(uint32(b[4]) | uint32(b[5])<<8 | uint32(b[6])<<16 | uint32(b[7])<<24)<<32; - m.rdata = m.rdata[8:len(m.rdata)]; - return x; -} - -func (m *msg) bytes(n int) []byte { - if m.status != OK { - return nil; - } - if len(m.rdata) < n { - m.status = ErrMessageTruncated; - return nil; - } - x := m.rdata[0:n]; - m.rdata = m.rdata[n:len(m.rdata)]; - return x; -} - -// Writing to msg.wdata. -func (m *msg) grow(n int) []byte { - i := len(m.wdata); - if i+n > cap(m.wdata) { - a := make([]byte, i, (i+n)*2); - bytes.Copy(a, m.wdata); - m.wdata = a; - } - m.wdata = m.wdata[0:i+n]; - return m.wdata[i:i+n]; -} - -func (m *msg) wuint8(x uint8) { - m.grow(1)[0] = x; -} - -func (m *msg) wuint32(x uint32) { - b := m.grow(4); - b[0] = byte(x); - b[1] = byte(x>>8); - b[2] = byte(x>>16); - b[3] = byte(x>>24); -} - -func (m *msg) wuint64(x uint64) { - b := m.grow(8); - lo := uint32(x); - b[0] = byte(lo); - b[1] = byte(lo>>8); - b[2] = byte(lo>>16); - b[3] = byte(lo>>24); - hi := uint32(x>>32); - b[4] = byte(hi); - b[5] = byte(hi>>8); - b[6] = byte(hi>>16); - b[7] = byte(hi>>24); -} - -func (m *msg) wbytes(p []byte) { - bytes.Copy(m.grow(len(p)), p); -} - -func (m *msg) wstring(s string) { - b := m.grow(len(s)); - for i := range b { - b[i] = s[i]; - } -} - -// Parsing of RPC header and arguments. -// -// The header format is: -// protocol uint32; -// requestId uint64; -// isReq bool; -// rpcNumber uint32; -// status uint32; // only for response -// -// Then a sequence of values follow, preceded by the length: -// nvalue uint32; -// -// Each value begins with a one-byte type followed by -// type-specific data. -// -// type uint8; -// 'b': x bool; -// 'C': len uint32; x [len]byte; -// 'd': x float64; -// 'D': len uint32; x [len]float64; -// 'h': x int; // handle aka file descriptor -// 'i': x int32; -// 'I': len uint32; x [len]int32; -// 's': len uint32; x [len]byte; -// -// If this is a request, a sequence of pseudo-values follows, -// preceded by its length (nvalue uint32). -// -// Each pseudo-value is a one-byte type as above, -// followed by a maximum length (len uint32) -// for the 'C', 'D', 'I', and 's' types. -// -// In the Go msg, we represent each argument by -// an empty interface containing the type of x in the -// corresponding case. - -// The current protocol number. -const protocol = 0xc0da0002 - -func (m *msg) unpackHeader() { - m.protocol = m.uint32(); - m.requestId = m.uint64(); - m.isReq = m.uint8() != 0; - m.rpcNumber = m.uint32(); - m.gotHeader = m.status == OK; // signal that header parsed successfully - if m.gotHeader && !m.isReq { - status := Errno(m.uint32()); - m.gotHeader = m.status == OK; // still ok? - if m.gotHeader { - m.status = status; - } - } -} - -func (m *msg) packHeader() { - m.wuint32(m.protocol); - m.wuint64(m.requestId); - if m.isReq { - m.wuint8(1); - } else { - m.wuint8(0); - } - m.wuint32(m.rpcNumber); - if !m.isReq { - m.wuint32(uint32(m.status)); - } -} - -func (m *msg) unpackValues(v []interface{}) { - for i := range v { - t := m.uint8(); - m.fmt += string(t); - switch t { - default: - if m.status == OK { - m.status = ErrBadArgType; - } - return; - case 'b': // bool[1] - v[i] = m.uint8() > 0; - case 'C': // char array - v[i] = m.bytes(int(m.uint32())); - case 'd': // double - v[i] = math.Float64frombits(m.uint64()); - case 'D': // double array - a := make([]float64, int(m.uint32())); - for j := range a { - a[j] = math.Float64frombits(m.uint64()); - } - v[i] = a; - case 'h': // file descriptor (handle) - if len(m.rdesc) == 0 { - if m.status == OK { - m.status = ErrBadArgType; - } - return; - } - v[i] = int(m.rdesc[0]); - m.rdesc = m.rdesc[1:len(m.rdesc)]; - case 'i': // int - v[i] = int32(m.uint32()); - case 'I': // int array - a := make([]int32, int(m.uint32())); - for j := range a { - a[j] = int32(m.uint32()); - } - v[i] = a; - case 's': // string - v[i] = string(m.bytes(int(m.uint32()))); - } - } -} - -func (m *msg) packValues(v []interface{}) { - for i := range v { - switch x := v[i].(type) { - default: - if m.status == OK { - m.status = ErrInternalError; - } - return; - case bool: - m.wuint8('b'); - if x { - m.wuint8(1); - } else { - m.wuint8(0); - } - case []byte: - m.wuint8('C'); - m.wuint32(uint32(len(x))); - m.wbytes(x); - case float64: - m.wuint8('d'); - m.wuint64(math.Float64bits(x)); - case []float64: - m.wuint8('D'); - m.wuint32(uint32(len(x))); - for _, f := range x { - m.wuint64(math.Float64bits(f)); - } - case int32: - m.wuint8('i'); - m.wuint32(uint32(x)); - case []int32: - m.wuint8('I'); - m.wuint32(uint32(len(x))); - for _, i := range x { - m.wuint32(uint32(i)); - } - case string: - m.wuint8('s'); - m.wuint32(uint32(len(x))); - m.wstring(x); - } - } -} - -func (m *msg) unpackRequest() { - m.status = OK; - if m.unpackHeader(); m.status != OK { - return; - } - if m.protocol != protocol || !m.isReq { - m.status = ErrProtocolMismatch; - return; - } - - // type-tagged argument values - m.Arg = make([]interface{}, m.uint32()); - m.unpackValues(m.Arg); - if m.status != OK { - return; - } - - // type-tagged expected return sizes. - // fill in zero values for each return value - // and save sizes. - m.fmt += ":"; - m.Ret = make([]interface{}, m.uint32()); - m.Size = make([]int, len(m.Ret)); - for i := range m.Ret { - t := m.uint8(); - m.fmt += string(t); - switch t { - default: - if m.status == OK { - m.status = ErrBadArgType; - } - return; - case 'b': // bool[1] - m.Ret[i] = false; - case 'C': // char array - m.Size[i] = int(m.uint32()); - m.Ret[i] = []byte(nil); - case 'd': // double - m.Ret[i] = float64(0); - case 'D': // double array - m.Size[i] = int(m.uint32()); - m.Ret[i] = []float64(nil); - case 'h': // file descriptor (handle) - m.Ret[i] = int(-1); - case 'i': // int - m.Ret[i] = int32(0); - case 'I': // int array - m.Size[i] = int(m.uint32()); - m.Ret[i] = []int32(nil); - case 's': // string - m.Size[i] = int(m.uint32()); - m.Ret[i] = ""; - } - } -} - -func (m *msg) packRequest() { - m.packHeader(); - m.wuint32(uint32(len(m.Arg))); - m.packValues(m.Arg); - m.wuint32(uint32(len(m.Ret))); - for i, v := range m.Ret { - switch x := v.(type) { - case bool: - m.wuint8('b'); - case []byte: - m.wuint8('C'); - m.wuint32(uint32(m.Size[i])); - case float64: - m.wuint8('d'); - case []float64: - m.wuint8('D'); - m.wuint32(uint32(m.Size[i])); - case int: - m.wuint8('h'); - case int32: - m.wuint8('i'); - case []int32: - m.wuint8('I'); - m.wuint32(uint32(m.Size[i])); - case string: - m.wuint8('s'); - m.wuint32(uint32(m.Size[i])); - } - } -} - -func (m *msg) unpackResponse() { - m.status = OK; - if m.unpackHeader(); m.status != OK { - return; - } - if m.protocol != protocol || m.isReq { - m.status = ErrProtocolMismatch; - return; - } - - // type-tagged return values - m.fmt = ""; - m.Ret = make([]interface{}, m.uint32()); - m.unpackValues(m.Ret); -} - -func (m *msg) packResponse() { - m.packHeader(); - m.wuint32(uint32(len(m.Ret))); - m.packValues(m.Ret); -} - diff --git a/usr/rsc/nacl/srpc/server.go b/usr/rsc/nacl/srpc/server.go deleted file mode 100644 index c4dc0a6c7..000000000 --- a/usr/rsc/nacl/srpc/server.go +++ /dev/null @@ -1,204 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// SRPC server - -package srpc - -import ( - "bytes"; - "log"; - "os"; - "syscall"; -) - -// TODO(rsc): I'd prefer to make this -// type Handler func(m *msg) Errno -// but NaCl can't use closures. -// The explicit interface is a way to attach state. - -// A Handler is a handler for an SRPC method. -// It reads arguments from arg, checks size for array limits, -// writes return values to ret, and returns an Errno status code. -type Handler interface { - Run(arg, ret []interface{}, size []int) Errno -} - -type method struct { - name string; - fmt string; - handler Handler; -} - -var rpcMethod []method - -// BUG(rsc): Add's format string should be replaced by analyzing the -// type of an arbitrary func passed in an interface{} using reflection. - -// Add registers a handler for the named method. -// Fmt is a Native Client format string, a sequence of -// alphabetic characters representing the types of the parameter values, -// a colon, and then a sequence of alphabetic characters -// representing the types of the returned values. -// The format characters and corresponding dynamic types are: -// -// b bool -// C []byte -// d float64 -// D []float64 -// h int // a file descriptor (aka handle) -// i int32 -// I []int32 -// s string -// -func Add(name, fmt string, handler Handler) { - n := len(rpcMethod); - if n >= cap(rpcMethod) { - a := make([]method, n, (n+4)*2); - for i := range a { - a[i] = rpcMethod[i]; - } - rpcMethod = a; - } - rpcMethod = rpcMethod[0:n+1]; - rpcMethod[n] = method{name, fmt, handler}; -} - -// Serve accepts new SRPC connections from the file descriptor fd -// and answers RPCs issued on those connections. -// It closes fd and returns an error if the imc_accept system call fails. -func Serve(fd int) os.Error { - defer syscall.Close(fd); - - for { - cfd, _, e := syscall.Syscall(syscall.SYS_IMC_ACCEPT, uintptr(fd), 0, 0); - if e != 0 { - return os.NewSyscallError("imc_accept", int(e)); - } - go serveLoop(int(cfd)); - } - panic("unreachable"); -} - -func serveLoop(fd int) { - c := make(chan *msg); - go sendLoop(fd, c); - - var r msgReceiver; - r.fd = fd; - for { - m, err := r.recv(); - if err != nil { - break; - } - m.unpackRequest(); - if !m.gotHeader { - log.Stderrf("cannot unpack header: %s", m.status); - continue; - } - // log.Stdoutf("<- %#v", m); - m.isReq = false; // set up for response - go serveMsg(m, c); - } - close(c); -} - -func sendLoop(fd int, c <-chan *msg) { - var s msgSender; - s.fd = fd; - for m := range c { - // log.Stdoutf("-> %#v", m); - m.packResponse(); - s.send(m); - } - syscall.Close(fd); -} - -func serveMsg(m *msg, c chan<- *msg) { - if m.status != OK { - c <- m; - return; - } - if m.rpcNumber >= uint32(len(rpcMethod)) { - m.status = ErrBadRPCNumber; - c <- m; - return; - } - - meth := &rpcMethod[m.rpcNumber]; - if meth.fmt != m.fmt { - switch { - case len(m.fmt) < len(meth.fmt): - m.status = ErrTooFewArgs; - case len(m.fmt) > len(meth.fmt): - m.status = ErrTooManyArgs; - default: - // There's a type mismatch. - // It's an in-arg mismatch if the mismatch happens - // before the colon; otherwise it's an out-arg mismatch. - m.status = ErrInArgTypeMismatch; - for i := 0; i < len(m.fmt) && m.fmt[i] == meth.fmt[i]; i++ { - if m.fmt[i] == ':' { - m.status = ErrOutArgTypeMismatch; - break; - } - } - } - c <- m; - return; - } - - m.status = meth.handler.Run(m.Arg, m.Ret, m.Size); - c <- m; -} - -// ServeRuntime serves RPCs issued by the Native Client embedded runtime. -// This should be called by main once all methods have been registered using Add. -func ServeRuntime() os.Error { - // Call getFd to check that we are running embedded. - if _, err := getFd(); err != nil { - return err; - } - - // We are running embedded. - // The fd returned by getFd is a red herring. - // Accept connections on magic fd 3. - return Serve(3); -} - -// getFd runs the srpc_get_fd system call. -func getFd() (fd int, err os.Error) { - r1, _, e := syscall.Syscall(syscall.SYS_SRPC_GET_FD, 0, 0, 0); - return int(r1), os.NewSyscallError("srpc_get_fd", int(e)); -} - -// Enabled returns true if SRPC is enabled in the Native Client runtime. -func Enabled() bool { - _, err:= getFd(); - return err == nil; -} - -// Service #0, service_discovery, returns a list of the other services -// and their argument formats. -type serviceDiscovery struct{} - -func (serviceDiscovery) Run(arg, ret []interface{}, size []int) Errno { - var b bytes.Buffer; - for _, m := range rpcMethod { - b.WriteString(m.name); - b.WriteByte(':'); - b.WriteString(m.fmt); - b.WriteByte('\n'); - } - if b.Len() > size[0] { - return ErrNoMemory; - } - ret[0] = b.Bytes(); - return OK; -} - -func init() { - Add("service_discovery", ":C", serviceDiscovery{}); -} - |