1
2
3
4
5
6
7
8
9
10
11
12
13
14 package main
15
16 import (
17 "encoding/json"
18 "flag"
19 "fmt"
20 "io"
21 "io/ioutil"
22 "net"
23 "net/http"
24 "os"
25 "time"
26 )
27
28 func main() {
29 port := flag.Int("port", 8080, "listen port")
30 dataDir := flag.String("data-dir", "/var/run/data", "data dir is the dir to write temp file, only used in io test")
31
32 flag.Parse()
33
34 s := newServer(*dataDir)
35 err := s.setupUDPServer()
36 if err != nil {
37 fmt.Println("failed to serve udp server", err)
38 os.Exit(1)
39 }
40
41 addr := fmt.Sprintf("0.0.0.0:%d", *port)
42 if err := http.ListenAndServe(addr, s.mux); err != nil {
43 fmt.Println("failed to serve http server", err)
44 os.Exit(1)
45 }
46 }
47
48 type server struct {
49 mux *http.ServeMux
50 dataDir string
51
52
53 recvBuf []byte
54 }
55
56 func newServer(dataDir string) *server {
57 s := &server{
58 mux: http.NewServeMux(),
59 dataDir: dataDir,
60 recvBuf: make([]byte, 5),
61 }
62 s.mux.HandleFunc("/ping", pong)
63 s.mux.HandleFunc("/time", s.timer)
64 s.mux.HandleFunc("/io", s.ioTest)
65 s.mux.HandleFunc("/network/send", s.networkSendTest)
66 s.mux.HandleFunc("/network/recv", s.networkRecvTest)
67 s.mux.HandleFunc("/network/ping", s.networkPingTest)
68 return s
69 }
70
71 func pong(w http.ResponseWriter, _ *http.Request) {
72 w.Write([]byte("pong"))
73 }
74
75 func (s *server) setupUDPServer() error {
76 pc, err := net.ListenPacket("udp", "0.0.0.0:1070")
77 if err != nil {
78 return err
79 }
80
81 go func() {
82 for {
83 _, _, err := pc.ReadFrom(s.recvBuf)
84 if err != nil {
85 return
86 }
87 }
88 }()
89
90 return nil
91 }
92
93
94 func (s *server) timer(w http.ResponseWriter, _ *http.Request) {
95 w.Write([]byte(time.Now().Format(time.RFC3339Nano)))
96 }
97
98
99 func (s *server) ioTest(w http.ResponseWriter, _ *http.Request) {
100 t1 := time.Now()
101 f, err := ioutil.TempFile(s.dataDir, "e2e-test")
102 if err != nil {
103 w.Write([]byte(fmt.Sprintf("failed to create temp file %v", err)))
104 return
105 }
106 if _, err := f.Write([]byte("hello world")); err != nil {
107 w.Write([]byte(fmt.Sprintf("failed to write file %v", err)))
108 return
109 }
110 t2 := time.Now()
111 w.Write([]byte(t2.Sub(t1).String()))
112 }
113
114 type networkSendTestBody struct {
115 TargetIP string `json:"targetIP"`
116 }
117
118
119 func (s *server) networkPingTest(w http.ResponseWriter, r *http.Request) {
120 var body networkSendTestBody
121
122 err := json.NewDecoder(r.Body).Decode(&body)
123 if err != nil {
124 http.Error(w, err.Error(), http.StatusBadRequest)
125 return
126 }
127
128 c := http.Client{
129 Timeout: 10 * time.Second,
130 }
131 startTime := time.Now()
132 resp, err := c.Get(fmt.Sprintf("http://%s:8080/ping", body.TargetIP))
133 endTime := time.Now()
134 out, err := ioutil.ReadAll(resp.Body)
135 defer resp.Body.Close()
136 if string(out) != "pong" {
137 http.Error(w, "response is not pong", http.StatusBadRequest)
138 return
139 }
140
141 w.Write([]byte(fmt.Sprintf("OK %d", endTime.UnixNano()-startTime.UnixNano())))
142 }
143
144
145 func (s *server) networkSendTest(w http.ResponseWriter, r *http.Request) {
146 var body networkSendTestBody
147
148 err := json.NewDecoder(r.Body).Decode(&body)
149 if err != nil {
150 http.Error(w, err.Error(), http.StatusBadRequest)
151 return
152 }
153
154 conn, err := net.DialUDP("udp", nil, &net.UDPAddr{
155 IP: net.ParseIP(body.TargetIP),
156 Port: 1070,
157 })
158 if err != nil {
159 http.Error(w, err.Error(), http.StatusBadRequest)
160 return
161 }
162 defer conn.Close()
163
164 n, err := io.WriteString(conn, "ping\n")
165 if err != nil {
166 http.Error(w, err.Error(), http.StatusBadRequest)
167 return
168 }
169 if n != 5 {
170 http.Error(w, "udp send less than 5 bytes", http.StatusBadRequest)
171 return
172 }
173 w.Write([]byte("send successfully\n"))
174 }
175
176
177 func (s *server) networkRecvTest(w http.ResponseWriter, r *http.Request) {
178 w.Write(s.recvBuf)
179
180 for index := range s.recvBuf {
181 s.recvBuf[index] = 0
182 }
183 }
184