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
|
use sys
use "alloc"
use "chartype"
use "dialparse"
use "die"
use "endian"
use "option"
use "result"
use "slcp"
use "sleq"
use "strfind"
use "striter"
use "syswrap"
use "utf"
pkg std =
const dial : (ds : 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 = {ds
match nameseg(ds)
| `Some ("net", str): -> dialsock(sys.Sockstream, str)
| `Some ("tcp", str): -> dialsock(sys.Sockstream, str)
| `Some ("udp", str): -> dialsock(sys.Sockdgram, str)
| `Some ("unix", u): -> dialunix(u)
| `Some (proto, str): -> `Err "unknown protocol"
| `None: -> `Err "missing protocol"
;;
}
const dialsock = {proto, str
var sa4 : sys.sockaddr_in
var sa6 : sys.sockaddr_in6
var sa : sys.sockaddr#
var hoststr, portstr, port
var sock, sz
var err
match nameseg(str)
| `None: -> `Err "required host!port for ip dial"
| `Some ("", _): -> `Err "empty host"
| `Some (_, ""): -> `Err "empty port"
| `Some segs: (hoststr, portstr) = segs
;;
match parseport(portstr)
| `Some p: port = p
| `None: -> `Err("invalid port")
;;
match getaddr(hoststr)
| `Ok `Ipv4 bits:
sa4=[.fam=sys.Afinet, .addr=bits, .port=hosttonet(port)]
sa = (&sa4 : sys.sockaddr#)
sz = sizeof(sys.sockaddr_in)
| `Ok `Ipv6 bits:
sa6=[.fam=sys.Afinet6, .addr=bits, .port=hosttonet(port)]
sa = (&sa6 : sys.sockaddr#)
sz = sizeof(sys.sockaddr_in6)
| `Err m:
-> `Err m
;;
sock = sys.socket(sa.fam, proto, 0)
if sock < 0
-> `Err "failed to create socket"
;;
err = sys.connect(sock, sa, sz)
if err < 0
sys.close(sock)
-> `Err "Failed to bind socket"
;;
-> `Ok (sock : fd)
}
const dialunix = {path
var sa : sys.sockaddr_un
var sock
sa = [.fam = sys.Afunix]
if path.len >= sa.path.len
-> `Err "path too long"
;;
sock = sys.socket(sys.Afunix, sys.Sockstream, 0)
if sock < 0
-> `Err "failed to create socket"
;;
slcp(sa.path[:path.len], path)
if sys.connect(sock, (&sa : sys.sockaddr#), sizeof(sys.sockaddr_un)) < 0
-> `Err "failed to bind address"
;;
-> `Ok (sock : fd)
}
|