Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(172)

Side by Side Diff: probe/net.go

Issue 60550047: code review 60550047: ogle/probe: handle read requests from network (Closed)
Patch Set: diff -r e53db6031eee https://code.google.com/p/ogle Created 10 years, 1 month ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « probe/addr_test.go ('k') | probe/net_test.go » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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 }
OLDNEW
« no previous file with comments | « probe/addr_test.go ('k') | probe/net_test.go » ('j') | no next file with comments »

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b