/
main.go
157 lines (132 loc) · 3.09 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
/*
A devdraw listener. Maybe I've named this wrong.
It's the devdraw interceptor
*/
package main
import (
// "fmt"
"log"
// "code.google.com/p/goplan9/draw"
// "image"
"9fans.net/go/draw/drawfcall"
"io"
"os"
"strings"
"sync"
"syscall"
)
/*
Strip DEVDRAW from environment so that the plan9 go code
Doesn't invoke the interceptor program recursively.
TODO(rjkroege): Note that I might explicitly want to specify which
DEVDRAW is to be invoked for real.
*/
func modifyEnvironment() {
envs := os.Environ()
os.Clearenv()
for _, v := range envs {
// log.Print("env contents", v)
if !strings.HasPrefix(v, "DEVDRAW") {
ss := strings.Split(v, "=")
// log.Print("env chunks", ss)
err := os.Setenv(ss[0], ss[1])
if err != nil {
log.Fatal("setting env")
}
} else {
log.Print("clearing DEVDRAW from environment")
}
}
}
type App struct {
w sync.Mutex
o *os.File
i *os.File
}
func checkedClose(f *os.File, msg string) {
err := f.Close()
if err != nil {
log.Fatal(msg, err)
}
}
func marshalsxtx(inbuffy []byte, app *App, devdraw *drawfcall.Conn, json *JsonRecorder) {
tx := new(drawfcall.Msg)
rx := new(drawfcall.Msg)
tag := inbuffy[4]
log.Print("set inbuffy to something, tag ", tag)
log.Print("bar")
err := tx.Unmarshal(inbuffy)
json.Record(tx, tag)
if err != nil {
log.Fatal("build a msg: ", err)
}
// Write message to real devdraw and get response.
log.Print("sending tx to real devdraw, getting rx back")
err = devdraw.RPC(tx, rx)
if err != nil {
if err != io.EOF {
log.Print("send/receive to real devdraw had error: ", err)
}
app.w.Lock()
checkedClose(app.o, "couldn't close channel to host: ")
app.w.Unlock()
checkedClose(app.i, "Couldn't close channel from host: ")
return
}
// TODO(rjkroege): Time-stamp the records.
// TODO(rjkroege): I want the actual original tag.
json.Record(rx, tag)
// write to cout
outbuffy := rx.Marshal()
// log.Print("returned tag ", outbuffy[4])
// log.Print("changing tag")
outbuffy[4] = tag
app.w.Lock()
_, err = app.o.Write(outbuffy)
app.w.Unlock()
if err != nil {
log.Fatal("write to app: ", err)
}
}
func main() {
// I assume that in is 0
in2, err := syscall.Dup(0)
if err != nil {
log.Fatal("dupping 0", err)
}
out2, err := syscall.Dup(1)
if err != nil {
log.Fatal("dupping 1", err)
}
os.Stdin.Close()
os.Stdout.Close()
os.Stdout = os.NewFile(uintptr(2), "/dev/stdout")
/* Connections to the application. */
cin := os.NewFile(uintptr(in2), "fromapp")
cout := os.NewFile(uintptr(out2), "toapp")
modifyEnvironment()
// Fire up a new devdraw here
devdraw, err := drawfcall.New()
if err != nil {
log.Fatal("making a Conn", err)
}
// There is probably a nicer way to do this.
// TODO(rjkroege): do it the nicer way.
var app App
app.o = cout
app.i = cin
json := NewJsonRecorder()
for {
// read crap from cin
log.Print("about to read from host")
inbuffy, err := drawfcall.ReadMsg(cin)
log.Print("read from host")
if err != nil {
devdraw.Close()
break
}
go marshalsxtx(inbuffy, &app, devdraw, json)
}
log.Print("waiting on completion")
json.WaitToComplete()
}