forked from dropbox/godropbox
-
Notifications
You must be signed in to change notification settings - Fork 0
/
server.go
90 lines (82 loc) · 2.31 KB
/
server.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
package cinterop
import (
"bytes"
"crypto/rand"
"encoding/base64"
"encoding/hex"
"errors"
"io"
"log"
"net"
"os"
)
func messageOnCloseAndRun(exitChan chan<- bool,
socketRead io.ReadCloser, socketWrite io.Writer, process func(io.ReadCloser, io.Writer)) {
process(socketRead, socketWrite)
exitChan <- true
}
func validateAndRun(token []byte,
socketRead io.ReadCloser, socketWrite io.Writer, process func(io.ReadCloser, io.Writer)) {
test := make([]byte, len(token))
_, token_err := io.ReadFull(socketRead, test[:])
if token_err == nil && bytes.Equal(token, test[:]) {
process(socketRead, socketWrite)
} else {
log.Print("Error: token mismatch from new client")
}
}
func listenAccept(newConnection chan<- net.Conn, l net.Listener) {
for {
fd, err := l.Accept()
if err != nil {
log.Print("accept error:", err)
} else {
newConnection <- fd
}
}
}
// header structure
// 58000000 <-- 88 bytes past this hex encoded size; 0100 major version 1 minor 0; 60c1 magic num
// 00000000 reserved 000000\n reserved
const Header = "58000000" + "0100" + "60c1" + "00000000" + "0000000\n"
func StartServer(process func(io.ReadCloser, io.Writer)) {
uuid := make([]byte, 16)
rand.Read(uuid)
hexToken := make([]byte, 32)
{
token := make([]byte, 16)
rand.Read(token)
hex.Encode(hexToken, token)
}
filePathReturn := []byte("/tmp/go-" + base64.URLEncoding.EncodeToString(uuid))
if len(filePathReturn) != 32 {
log.Fatal("File path is not 32 bytes " + string(filePathReturn))
}
filePathReturn[31] = '\n' // newline instead of padding with =
filePath := string(filePathReturn[:31])
l, err := net.Listen("unix", string(filePath))
if err != nil {
log.Print("listen error:", err)
}
defer os.Remove(filePath)
headerPathAndToken := Header + string(filePathReturn) + string(hexToken)
var size int
size, err = os.Stdout.Write([]byte(headerPathAndToken))
if err != nil {
panic(err)
} else if size != len([]byte(headerPathAndToken)) {
panic(errors.New("Short Write: io.Writer not compliant with the golang contract"))
}
exitChan := make(chan bool)
connectionChan := make(chan net.Conn)
go messageOnCloseAndRun(exitChan, os.Stdin, os.Stdout, process)
go listenAccept(connectionChan, l)
for {
select {
case <-exitChan:
return
case fd := <-connectionChan:
go validateAndRun(hexToken, fd, fd, process)
}
}
}