OLD | NEW |
(Empty) | |
| 1 // Copyright 2014 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 // TODO: Document the protocol once it settles. |
| 6 |
| 7 package probe |
| 8 |
| 9 import ( |
| 10 "errors" |
| 11 "io" // Used only for the definitions of the various interfaces and erro
rs. |
| 12 "net" |
| 13 ) |
| 14 |
| 15 var ( |
| 16 port = ":54321" // TODO: how to choose port number? |
| 17 tracing = false |
| 18 ) |
| 19 |
| 20 // init starts a network listener and leaves it in the background waiting for co
nnections. |
| 21 func init() { |
| 22 go demon() |
| 23 } |
| 24 |
| 25 // demon answers consecutive connection requests and starts a server to manage e
ach one. |
| 26 // The server runs in the same goroutine as the demon, so a new connection canno
t be |
| 27 // established until the previous one is completed. |
| 28 func demon() { |
| 29 listener, err := net.Listen("tcp", port) |
| 30 if err != nil { |
| 31 trace("listen:", err) |
| 32 return |
| 33 } |
| 34 trace("listening") |
| 35 for { |
| 36 conn, err := listener.Accept() |
| 37 if err != nil { |
| 38 trace("accept", err) |
| 39 continue |
| 40 } |
| 41 trace("accepted a connection") |
| 42 serve(conn) |
| 43 conn.Close() |
| 44 } |
| 45 } |
| 46 |
| 47 // stringer is the same as fmt.Stringer. We redefine it here to avoid pulling in
fmt. |
| 48 type stringer interface { |
| 49 String() string |
| 50 } |
| 51 |
| 52 func printHex(b byte) { |
| 53 const hex = "0123456789ABCDEF" |
| 54 b1, b0 := b>>4&0xF, b&0xF |
| 55 print(hex[b1:b1+1], hex[b0:b0+1]) |
| 56 } |
| 57 |
| 58 // trace is a simple version of println that is enabled by the tracing boolean. |
| 59 func trace(args ...interface{}) { |
| 60 if !tracing { |
| 61 return |
| 62 } |
| 63 print("ogle demon: ") |
| 64 for i, arg := range args { |
| 65 if i > 0 { |
| 66 print(" ") |
| 67 } |
| 68 // A little help. Built-in print isn't very capable. |
| 69 switch arg := arg.(type) { |
| 70 case stringer: |
| 71 print(arg.String()) |
| 72 case error: |
| 73 print(arg.Error()) |
| 74 case []byte: |
| 75 print("[") |
| 76 for i := range arg { |
| 77 if i > 0 { |
| 78 print(" ") |
| 79 } |
| 80 printHex(arg[i]) |
| 81 } |
| 82 print("]") |
| 83 case int: |
| 84 print(arg) |
| 85 case string: |
| 86 print(arg) |
| 87 case uintptr: |
| 88 print("0x") |
| 89 for i := ptrSize - 1; i >= 0; i-- { |
| 90 printHex(byte(arg >> uint(8*i))) |
| 91 } |
| 92 default: |
| 93 print(arg) |
| 94 } |
| 95 } |
| 96 print("\n") |
| 97 } |
| 98 |
| 99 func serve(conn net.Conn) { |
| 100 const ( |
| 101 bufSize = 1 << 16 |
| 102 ) |
| 103 var buf [bufSize]byte |
| 104 network := &pipe{ |
| 105 rw: conn, |
| 106 } |
| 107 for { |
| 108 // One message per loop. |
| 109 n, err := network.Read(buf[:1]) |
| 110 if n != 1 || err != nil { |
| 111 return |
| 112 } |
| 113 switch buf[0] { |
| 114 case 'r': |
| 115 // Read: ['r', address, size] => [0, size, size bytes] |
| 116 u, err := network.readUintptr() |
| 117 if err != nil { |
| 118 return |
| 119 } |
| 120 n, err := network.readInt() |
| 121 if err != nil { |
| 122 return |
| 123 } |
| 124 if !validRead(u, n) { |
| 125 trace("read", err) |
| 126 network.error("invalid read address") |
| 127 continue |
| 128 } |
| 129 network.sendReadResponse(u, n) |
| 130 default: |
| 131 // TODO: shut down connection? |
| 132 trace("unknown message type:", buf[0]) |
| 133 } |
| 134 } |
| 135 } |
| 136 |
| 137 // pipe is a buffered network connection (actually just a reader/writer) that |
| 138 // implements Read and ReadByte as well as readFull. |
| 139 // It also has support routines to make it easier to read and write |
| 140 // network messages. |
| 141 type pipe struct { |
| 142 rw io.ReadWriter |
| 143 pos int |
| 144 end int |
| 145 oneByte [1]byte |
| 146 buf [4096]byte |
| 147 } |
| 148 |
| 149 // readFull fills the argument slice with data from the wire. If it cannot fill
the |
| 150 // slice, it returns an error. |
| 151 // TODO: unused for now; write will need it. |
| 152 func (p *pipe) readFull(buf []byte) error { |
| 153 for len(buf) > 0 { |
| 154 n, err := p.rw.Read(buf) |
| 155 if n == len(buf) { |
| 156 return nil |
| 157 } |
| 158 if err != nil { |
| 159 if err == io.EOF { |
| 160 err = io.ErrUnexpectedEOF |
| 161 } |
| 162 return err |
| 163 } |
| 164 if n == 0 { |
| 165 return io.EOF |
| 166 } |
| 167 buf = buf[n:] |
| 168 } |
| 169 return nil |
| 170 } |
| 171 |
| 172 // Read satisfies io.Reader. |
| 173 func (p *pipe) Read(buf []byte) (int, error) { |
| 174 n := len(buf) |
| 175 if p.end == p.pos { |
| 176 p.pos = 0 |
| 177 // Read from network |
| 178 var err error |
| 179 p.end, err = p.rw.Read(p.buf[:]) |
| 180 if err != nil { |
| 181 trace("read:", err) |
| 182 return p.end, err |
| 183 } |
| 184 if p.end == 0 { |
| 185 trace("read: eof") |
| 186 return p.end, io.EOF |
| 187 } |
| 188 } |
| 189 if n > p.end-p.pos { |
| 190 n = p.end - p.pos |
| 191 } |
| 192 copy(buf, p.buf[p.pos:p.pos+n]) |
| 193 p.pos += n |
| 194 return n, nil |
| 195 } |
| 196 |
| 197 // ReadByte satisfies io.ByteReader. |
| 198 func (p *pipe) ReadByte() (byte, error) { |
| 199 _, err := p.Read(p.oneByte[:]) |
| 200 return p.oneByte[0], err |
| 201 } |
| 202 |
| 203 // readUintptr reads a varint-encoded uinptr value from the connection. |
| 204 func (p *pipe) readUintptr() (uintptr, error) { |
| 205 u, err := readUvarint(p) |
| 206 if err != nil { |
| 207 trace("read uintptr:", err) |
| 208 return 0, err |
| 209 } |
| 210 if u > uint64(^uintptr(0)) { |
| 211 trace("read uintptr: overflow") |
| 212 return 0, err |
| 213 } |
| 214 return uintptr(u), nil |
| 215 } |
| 216 |
| 217 var intOverflow = errors.New("ogle probe: varint overflows int") |
| 218 |
| 219 // readInt reads an varint-encoded int value from the connection. |
| 220 // The transported value is always a uint64; this routine |
| 221 // verifies that it fits in an int. |
| 222 func (p *pipe) readInt() (int, error) { |
| 223 u, err := readUvarint(p) |
| 224 if err != nil { |
| 225 trace("read int:", err) |
| 226 return 0, err |
| 227 } |
| 228 // Does it fit in an int? |
| 229 if u > maxInt { |
| 230 trace("int overflow") |
| 231 return 0, intOverflow |
| 232 } |
| 233 return int(u), nil |
| 234 } |
| 235 |
| 236 // error writes an error message to the connection. |
| 237 // The format is [size, size bytes]. |
| 238 func (p *pipe) error(msg string) { |
| 239 // A zero-length message is problematic. It should never arise, but be s
afe. |
| 240 if len(msg) == 0 { |
| 241 msg = "undefined error" |
| 242 } |
| 243 // Truncate if necessary. Extremely unlikely. |
| 244 if len(msg) > len(p.buf)-maxVarintLen64 { |
| 245 msg = msg[:len(p.buf)-maxVarintLen64] |
| 246 } |
| 247 n := putUvarint(p.buf[:], uint64(len(msg))) |
| 248 n += copy(p.buf[n:], msg) |
| 249 _, err := p.rw.Write(p.buf[:n]) |
| 250 if err != nil { |
| 251 trace("write:", err) |
| 252 // TODO: shut down connection? |
| 253 } |
| 254 } |
| 255 |
| 256 // sendReadResponse sends a read response to the connection. |
| 257 // The format is [0, size, size bytes]. |
| 258 func (p *pipe) sendReadResponse(addr uintptr, size int) { |
| 259 trace("sendRead:", addr, size) |
| 260 m := 0 |
| 261 m += putUvarint(p.buf[m:], 0) // No error. |
| 262 m += putUvarint(p.buf[m:], uint64(size)) // Number of bytes to follow. |
| 263 for m > 0 || size > 0 { |
| 264 n := len(p.buf) - m |
| 265 if n > size { |
| 266 n = size |
| 267 } |
| 268 if !read(addr, p.buf[m:m+n]) { |
| 269 trace("copy error") |
| 270 // TODO: shut down connection? |
| 271 // TODO: for now, continue delivering data. We said we w
ould. |
| 272 } |
| 273 _, err := p.rw.Write(p.buf[:m+n]) |
| 274 if err != nil { |
| 275 trace("write:", err) |
| 276 // TODO: shut down connection? |
| 277 } |
| 278 addr += uintptr(n) |
| 279 size -= n |
| 280 // Next time we can use the whole buffer. |
| 281 m = 0 |
| 282 } |
| 283 } |
OLD | NEW |