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
|
use "alloc.use"
use "chartype.use"
use "die.use"
use "endian.use"
use "fmt.use"
use "hasprefix.use"
use "intparse.use"
use "ipparse.use"
use "option.use"
use "resolve.use"
use "result.use"
use "sleq.use"
use "sys.use"
use "syswrap.use"
use "utf.use"
pkg std =
const dial : (dialstr : byte[:] -> result(fd, byte[:]))
;;
/*
a map from service name to a list of (port,proto)
pairs in order of preference
*/
/* FIXME: implement
var services : htab(byte[:], [int, byte[:]][:])#
var inited = false
*/
/* takes a plan 9 style dial string */
const dial = {str
var proto, host, port
var socktype, portnum
var sa : sys.sockaddr_in /* we only support inet sockets right now.. ugh. */
var sock
(proto, str) = nameseg(str)
(host, str) = nameseg(str)
(port, str) = nameseg(str)
if proto.len == 0
-> `Fail "missing proto"
elif host.len == 0
-> `Fail "missing host"
elif port.len == 0
-> `Fail "missing port"
;;
if sleq(proto, "net")
-> `Fail "net wildcard proto not yet supported\n"
elif sleq(proto, "unix")
-> `Fail "net unix proto not yet supported\n"
elif sleq(proto, "tcp")
socktype = sys.Sockstream
elif sleq(proto, "udp")
socktype = sys.Sockdgram
;;
match parseport(port)
| `Some n: portnum = n
| `None: -> `Fail "bad port"
;;
match getaddr(host)
| `Ipv4 bits:
sa.fam = sys.Afinet
sa.addr = bits
sa.port = hosttonet(portnum)
| `Ipv6 bits:
-> `Fail "ipv6 not yet supported"
;;
sock = sys.socket(sa.fam, socktype, 0)
if sock < 0
-> `Fail "failed to connect to socket"
;;
var err
err = sys.connect(sock, (&sa) castto(sys.sockaddr#), sizeof(sys.sockaddr_in))
if err < 0
put("Errno %i\n", -err)
sys.close(sock)
-> `Fail "Failed to bind socket"
;;
-> `Ok (sock castto(fd))
}
const parseport = {port
match intparse(port)
| `Some n: -> `Some n
| `None:
/* a small number of hardcoded ports */
if sleq(port, "http")
-> `Some 80
elif sleq(port, "https")
-> `Some 443
elif sleq(port, "ircd")
-> `Some 6667
elif sleq(port, "dns")
-> `Some 53
;;
;;
-> `None
}
const getaddr = {addr
var ip
match ipparse(addr)
| `Some a: ip = a
| `None:
match resolve(addr)
| `Ok hi:
ip = hi[0].addr
slfree(hi)
| `Fail m:
;;
;;
-> ip
}
const nameseg = {str
var len
for len = 0; len < str.len; len++
if str[len] == '!' castto(byte)
-> (str[:len], str[len+1:])
;;
;;
-> (str[:], str[len:])
}
|