Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
G
golang
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
go
golang
Commits
9350ef4e
Commit
9350ef4e
authored
Sep 17, 2008
by
Russ Cox
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
add network listening & tests
R=r,presotto OCL=15410 CL=15440
parent
a4564638
Show whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
368 additions
and
30 deletions
+368
-30
io.go
src/lib/io.go
+7
-13
make.bash
src/lib/make.bash
+7
-0
ip.go
src/lib/net/ip.go
+8
-4
net.go
src/lib/net/net.go
+124
-9
socket_darwin.go
src/lib/net/socket_darwin.go
+6
-1
socket_linux.go
src/lib/net/socket_linux.go
+20
-1
proc.c
src/runtime/proc.c
+1
-1
syscall_amd64_linux.s
src/syscall/syscall_amd64_linux.s
+0
-1
dialgoogle.go
test/dialgoogle.go
+96
-0
tcpserver.go
test/tcpserver.go
+99
-0
No files found.
src/lib/io.go
View file @
9350ef4e
...
...
@@ -4,17 +4,7 @@
package
io
import
os
"os"
export
func
StringToBytes
(
b
*
[]
byte
,
s
string
)
bool
{
if
len
(
s
)
>=
len
(
b
)
{
return
false
}
for
i
:=
0
;
i
<
len
(
s
);
i
++
{
b
[
i
]
=
s
[
i
]
}
b
[
len
(
s
)]
=
'\000'
;
// not necessary - memory is zeroed - but be explicit
return
true
}
import
syscall
"syscall"
export
type
Read
interface
{
Read
(
p
*
[]
byte
)
(
n
int
,
err
*
os
.
Error
);
...
...
@@ -24,13 +14,17 @@ export type Write interface {
Write
(
p
*
[]
byte
)
(
n
int
,
err
*
os
.
Error
);
}
export
type
ReadWrite
interface
{
Read
(
p
*
[]
byte
)
(
n
int
,
err
*
os
.
Error
);
Write
(
p
*
[]
byte
)
(
n
int
,
err
*
os
.
Error
);
}
export
func
WriteString
(
w
Write
,
s
string
)
(
n
int
,
err
*
os
.
Error
)
{
b
:=
new
([]
byte
,
len
(
s
)
+
1
)
if
!
StringToBytes
(
b
,
s
)
{
if
!
syscall
.
StringToBytes
(
b
,
s
)
{
return
-
1
,
os
.
EINVAL
}
// BUG return w.Write(b[0:len(s)])
r
,
e
:=
w
.
Write
(
b
[
0
:
len
(
s
)])
return
r
,
e
}
src/lib/make.bash
View file @
9350ef4e
...
...
@@ -22,3 +22,10 @@ do
6g
-o
$GOROOT
/pkg/
$base
.6
$i
done
for
i
in
net
do
echo
;
echo
;
echo
%%%% making lib/
$i
%%%%
;
echo
cd
$i
make
install
cd
..
done
src/lib/net/ip.go
View file @
9350ef4e
...
...
@@ -336,6 +336,10 @@ func ParseIPv6(s string) *[]byte {
if
len
(
s
)
>=
2
&&
s
[
0
]
==
':'
&&
s
[
1
]
==
':'
{
ellipsis
=
0
;
i
=
2
// Might be only ellipsis
if
i
==
len
(
s
)
{
return
p
}
}
// Loop, parsing hex numbers followed by colon.
...
...
@@ -343,12 +347,12 @@ func ParseIPv6(s string) *[]byte {
L
:
for
j
<
IPv6len
{
// Hex number.
n
,
i1
,
ok
:=
xtoi
(
s
,
i
)
if
!
ok
||
n
>
=
0xFFFF
{
if
!
ok
||
n
>
0xFFFF
{
return
nil
}
// If followed by dot, might be in trailing IPv4.
if
s
[
i1
]
==
'.'
{
if
i1
<
len
(
s
)
&&
s
[
i1
]
==
'.'
{
if
ellipsis
<
0
&&
j
!=
IPv6len
-
IPv4len
{
// Not the right place.
return
nil
...
...
@@ -389,7 +393,7 @@ L: for j < IPv6len {
i
++
// Look for ellipsis.
if
s
[
i
+
1
]
==
':'
{
if
s
[
i
]
==
':'
{
if
ellipsis
>=
0
{
// already have one
return
nil
}
...
...
@@ -411,7 +415,7 @@ L: for j < IPv6len {
return
nil
}
n
:=
IPv6len
-
j
for
k
:=
j
;
k
>=
ellipsis
;
k
--
{
for
k
:=
j
-
1
;
k
>=
ellipsis
;
k
--
{
p
[
k
+
n
]
=
p
[
k
]
}
for
k
:=
ellipsis
+
n
-
1
;
k
>=
ellipsis
;
k
--
{
...
...
src/lib/net/net.go
View file @
9350ef4e
...
...
@@ -19,7 +19,8 @@ func NewError(s string) *os.Error {
}
export
var
(
BadAddress
=
NewError
(
"malformed addres"
);
BadAddress
=
NewError
(
"malformed address"
);
MissingAddress
=
NewError
(
"missing address"
);
UnknownNetwork
=
NewError
(
"unknown network"
);
UnknownHost
=
NewError
(
"unknown host"
);
UnknownPort
=
NewError
(
"unknown port"
);
...
...
@@ -69,6 +70,20 @@ func JoinHostPort(host, port string) string {
return
host
+
":"
+
port
}
func
dtoi
(
s
string
)
(
n
int
,
ok
bool
)
{
if
s
==
""
||
s
[
0
]
<
'0'
||
s
[
0
]
>
'9'
{
return
0
,
false
}
n
=
0
;
for
i
:=
0
;
i
<
len
(
s
)
&&
'0'
<=
s
[
i
]
&&
s
[
i
]
<=
'9'
;
i
++
{
n
=
n
*
10
+
int
(
s
[
i
]
-
'0'
)
if
n
>=
1000000
{
// bigger than we need
return
0
,
false
}
}
return
n
,
true
}
// Convert "host:port" into IP address and port.
// For now, host and port must be numeric literals.
// Eventually, we'll have name resolution.
...
...
@@ -83,13 +98,12 @@ func HostPortToIP(net string, hostport string) (ip *[]byte, iport int, err *os.E
addr
:=
ip
.
ParseIP
(
host
);
if
addr
==
nil
{
print
(
"Failed to parse: "
,
host
,
"
\n
"
);
return
nil
,
0
,
UnknownHost
}
// TODO: Resolve port.
p
,
ok
:=
strings
.
a
toi
(
port
);
p
,
ok
:=
d
toi
(
port
);
if
!
ok
||
p
<
0
||
p
>
0xFFFF
{
return
nil
,
0
,
UnknownPort
}
...
...
@@ -128,6 +142,9 @@ func Socket(f, p, t int64, la, ra *socket.Sockaddr) (fd int64, err *os.Error) {
return
-
1
,
e
}
// Allow reuse of recently-used addresses.
socket
.
setsockopt_int
(
s
,
socket
.
SOL_SOCKET
,
socket
.
SO_REUSEADDR
,
1
)
var
r
int64
if
la
!=
nil
{
r
,
e
=
socket
.
bind
(
s
,
la
)
...
...
@@ -256,11 +273,18 @@ func (c *ConnBase) SetLinger(sec int) *os.Error {
// PreferIPv4 here should fall back to the IPv4 socket interface when possible.
const
PreferIPv4
=
false
func
DialIntern
et
(
net
,
laddr
,
raddr
string
,
proto
int64
)
(
fd
int64
,
err
*
os
.
Error
)
{
func
InternetSock
et
(
net
,
laddr
,
raddr
string
,
proto
int64
)
(
fd
int64
,
err
*
os
.
Error
)
{
// Parse addresses (unless they are empty).
var
lip
,
rip
*
[]
byte
var
lport
,
rport
int
var
lerr
,
rerr
*
os
.
Error
// BUG 6g doesn't zero var lists
lip
=
nil
;
rip
=
nil
;
lport
=
0
;
rport
=
0
;
lerr
=
nil
;
rerr
=
nil
if
laddr
!=
""
{
lip
,
lport
,
lerr
=
HostPortToIP
(
net
,
laddr
)
if
lerr
!=
nil
{
...
...
@@ -305,6 +329,9 @@ func DialInternet(net, laddr, raddr string, proto int64) (fd int64, err *os.Erro
}
var
la
,
ra
*
socket
.
Sockaddr
;
// BUG
la
=
nil
;
ra
=
nil
if
lip
!=
nil
{
la
,
lerr
=
cvt
(
lip
,
lport
);
if
lerr
!=
nil
{
...
...
@@ -388,15 +415,23 @@ func (c *ConnTCP) SetKeepAlive(keepalive bool) *os.Error {
return
(
&
c
.
base
)
.
SetKeepAlive
(
keepalive
)
}
func
NewConnTCP
(
fd
int64
,
raddr
string
)
*
ConnTCP
{
c
:=
new
(
ConnTCP
);
c
.
base
.
fd
=
os
.
NewFD
(
fd
);
c
.
base
.
raddr
=
raddr
;
c
.
SetNoDelay
(
true
);
return
c
}
export
func
DialTCP
(
net
,
laddr
,
raddr
string
)
(
c
*
ConnTCP
,
err
*
os
.
Error
)
{
fd
,
e
:=
DialInternet
(
net
,
laddr
,
raddr
,
socket
.
SOCK_STREAM
)
if
raddr
==
""
{
return
nil
,
MissingAddress
}
fd
,
e
:=
InternetSocket
(
net
,
laddr
,
raddr
,
socket
.
SOCK_STREAM
)
if
e
!=
nil
{
return
nil
,
e
}
c
=
new
(
ConnTCP
);
c
.
base
.
fd
=
os
.
NewFD
(
fd
);
c
.
SetNoDelay
(
true
)
return
c
,
nil
return
NewConnTCP
(
fd
,
raddr
),
nil
}
...
...
@@ -481,3 +516,83 @@ export func Dial(net, laddr, raddr string) (c Conn, err *os.Error) {
return
nil
,
UnknownNetwork
}
export
type
Listener
interface
{
Accept
()
(
c
Conn
,
raddr
string
,
err
*
os
.
Error
);
Close
()
*
os
.
Error
;
}
type
NoListener
struct
{
unused
int
}
func
(
l
*
NoListener
)
Accept
()
(
c
Conn
,
raddr
string
,
err
*
os
.
Error
)
{
return
&
noconn
,
""
,
os
.
EINVAL
}
func
(
l
*
NoListener
)
Close
()
*
os
.
Error
{
return
os
.
EINVAL
}
var
nolistener
NoListener
export
type
ListenerTCP
struct
{
fd
*
os
.
FD
;
laddr
string
}
export
func
ListenTCP
(
net
,
laddr
string
)
(
l
*
ListenerTCP
,
err
*
os
.
Error
)
{
fd
,
e
:=
InternetSocket
(
net
,
laddr
,
""
,
socket
.
SOCK_STREAM
)
if
e
!=
nil
{
return
nil
,
e
}
r
,
e1
:=
socket
.
listen
(
fd
,
socket
.
ListenBacklog
())
if
e1
!=
nil
{
syscall
.
close
(
fd
)
return
nil
,
e1
}
l
=
new
(
ListenerTCP
);
l
.
fd
=
os
.
NewFD
(
fd
);
return
l
,
nil
}
func
(
l
*
ListenerTCP
)
AcceptTCP
()
(
c
*
ConnTCP
,
raddr
string
,
err
*
os
.
Error
)
{
if
l
==
nil
||
l
.
fd
==
nil
||
l
.
fd
.
fd
<
0
{
return
nil
,
""
,
os
.
EINVAL
}
var
sa
socket
.
Sockaddr
;
fd
,
e
:=
socket
.
accept
(
l
.
fd
.
fd
,
&
sa
)
if
e
!=
nil
{
return
nil
,
""
,
e
}
raddr
,
e
=
SockaddrToHostPort
(
&
sa
)
if
e
!=
nil
{
syscall
.
close
(
fd
)
return
nil
,
""
,
e
}
return
NewConnTCP
(
fd
,
raddr
),
raddr
,
nil
}
func
(
l
*
ListenerTCP
)
Accept
()
(
c
Conn
,
raddr
string
,
err
*
os
.
Error
)
{
c1
,
r1
,
e1
:=
l
.
AcceptTCP
()
if
e1
!=
nil
{
return
&
noconn
,
""
,
e1
}
return
c1
,
r1
,
nil
}
func
(
l
*
ListenerTCP
)
Close
()
*
os
.
Error
{
if
l
==
nil
||
l
.
fd
==
nil
{
return
os
.
EINVAL
}
return
l
.
fd
.
Close
()
}
export
func
Listen
(
net
,
laddr
string
)
(
l
Listener
,
err
*
os
.
Error
)
{
switch
net
{
case
"tcp"
,
"tcp4"
,
"tcp6"
:
l
,
err
:=
ListenTCP
(
net
,
laddr
)
if
err
!=
nil
{
return
&
nolistener
,
err
}
return
l
,
nil
/*
more here
*/
}
return
nil
,
UnknownNetwork
}
src/lib/net/socket_darwin.go
View file @
9350ef4e
...
...
@@ -53,6 +53,8 @@ export const (
IPPROTO_UDP
=
17
;
TCP_NODELAY
=
0x01
;
SOMAXCONN
=
128
;
)
export
type
SockaddrUnix
struct
{
...
...
@@ -127,7 +129,7 @@ export func listen(fd, n int64) (ret int64, err *os.Error) {
}
export
func
accept
(
fd
int64
,
sa
*
Sockaddr
)
(
ret
int64
,
err
*
os
.
Error
)
{
n
:=
int32
(
sa
.
len
)
;
n
:=
SizeofSockaddr
;
r1
,
r2
,
e
:=
syscall
.
Syscall
(
ACCEPT
,
fd
,
SockaddrPtr
(
sa
),
Int32Ptr
(
&
n
));
return
r1
,
os
.
ErrnoToError
(
e
)
}
...
...
@@ -229,3 +231,6 @@ export func SockaddrToIP(sa1 *Sockaddr) (p *[]byte, port int, err *os.Error) {
return
nil
,
0
,
nil
// not reached
}
export
func
ListenBacklog
()
int64
{
return
SOMAXCONN
}
src/lib/net/socket_linux.go
View file @
9350ef4e
...
...
@@ -63,6 +63,8 @@ export const (
IPPROTO_UDP
=
17
;
TCP_NODELAY
=
0x01
;
SOMAXCONN
=
128
;
)
export
type
SockaddrUnix
struct
{
...
...
@@ -145,7 +147,7 @@ export func listen(fd, n int64) (ret int64, err *os.Error) {
}
export
func
accept
(
fd
int64
,
sa
*
Sockaddr
)
(
ret
int64
,
err
*
os
.
Error
)
{
n
:=
int32
(
sa
.
Len
())
;
n
:=
SizeofSockaddr
;
r1
,
r2
,
e
:=
syscall
.
Syscall
(
ACCEPT
,
fd
,
SockaddrPtr
(
sa
),
Int32Ptr
(
&
n
));
return
r1
,
os
.
ErrnoToError
(
e
)
}
...
...
@@ -208,11 +210,21 @@ export func IPv4ToSockaddr(p *[]byte, port int) (sa1 *Sockaddr, err *os.Error) {
return
SockaddrInet4ToSockaddr
(
sa
),
nil
}
var
IPv6zero
[
ip
.
IPv6len
]
byte
;
export
func
IPv6ToSockaddr
(
p
*
[]
byte
,
port
int
)
(
sa1
*
Sockaddr
,
err
*
os
.
Error
)
{
p
=
ip
.
ToIPv6
(
p
)
if
p
==
nil
||
port
<
0
||
port
>
0xFFFF
{
return
nil
,
os
.
EINVAL
}
// IPv4 callers use 0.0.0.0 to mean "announce on any available address".
// In IPv6 mode, Linux treats that as meaning "announce on 0.0.0.0",
// which it refuses to do. Rewrite to the IPv6 all zeros.
if
p4
:=
ip
.
ToIPv4
(
p
);
p4
!=
nil
&&
p4
[
0
]
==
0
&&
p4
[
1
]
==
0
&&
p4
[
2
]
==
0
&&
p4
[
3
]
==
0
{
p
=
&
IPv6zero
;
}
sa
:=
new
(
SockaddrInet6
);
sa
.
family
=
AF_INET6
;
sa
.
port
[
0
]
=
byte
(
port
>>
8
);
...
...
@@ -245,3 +257,10 @@ export func SockaddrToIP(sa1 *Sockaddr) (p *[]byte, port int, err *os.Error) {
return
nil
,
0
,
nil
// not reached
}
export
func
ListenBacklog
()
int64
{
// TODO: maybe /proc/sys/net/core/somaxconn
// and read the limit out of there, to take advantage of kernels
// that have increased the limit
return
SOMAXCONN
}
src/runtime/proc.c
View file @
9350ef4e
...
...
@@ -78,7 +78,7 @@ schedinit(void)
byte
*
p
;
sched
.
mmax
=
1
;
p
=
getenv
(
"
gomaxprocs
"
);
p
=
getenv
(
"
GOMAXPROCS
"
);
if
(
p
!=
nil
&&
(
n
=
atoi
(
p
))
!=
0
)
sched
.
mmax
=
n
;
sched
.
mcount
=
1
;
...
...
src/syscall/syscall_amd64_linux.s
View file @
9350ef4e
...
...
@@ -37,7 +37,6 @@ TEXT syscall·Syscall6(SB),7,$-8
MOVQ 48(SP), R8
MOVQ 56(SP), R9
MOVQ 8(SP), AX // syscall entry
ADDQ $0x2000000, AX
SYSCALL
JLS 6(PC)
MOVQ $-1, 64(SP) // r1
...
...
test/dialgoogle.go
0 → 100644
View file @
9350ef4e
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// $G $F.go && $L $F.$A && ./$A.out
package
main
import
(
"net"
;
"flag"
;
"os"
;
"syscall"
)
// If an IPv6 tunnel is running (see go/stubl), we can try dialing a real IPv6 address.
var
ipv6
=
false
var
ipv6_flag
=
flag
.
Bool
(
"ipv6"
,
false
,
&
ipv6
,
"assume ipv6 tunnel is present"
)
func
StringToBuf
(
s
string
)
*
[]
byte
{
l
:=
len
(
s
);
b
:=
new
([]
byte
,
l
);
for
i
:=
0
;
i
<
l
;
i
++
{
b
[
i
]
=
s
[
i
];
}
return
b
;
}
// fd is already connected to www.google.com port 80.
// Run an HTTP request to fetch the main page.
func
FetchGoogle
(
fd
net
.
Conn
)
{
req
:=
StringToBuf
(
"GET / HTTP/1.0
\r\n
Host: www.google.com
\r\n\r\n
"
);
n
,
errno
:=
fd
.
Write
(
req
);
buf
:=
new
([
1000
]
byte
);
n
,
errno
=
fd
.
Read
(
buf
);
fd
.
Close
();
if
n
<
1000
{
panic
(
"short http read"
);
}
}
func
TestDial
(
network
,
addr
string
)
{
fd
,
err
:=
net
.
Dial
(
network
,
""
,
addr
)
if
err
!=
nil
{
panic
(
"net.Dial "
,
network
,
" "
,
addr
,
": "
,
err
.
String
())
}
FetchGoogle
(
fd
)
}
func
TestDialTCP
(
network
,
addr
string
)
{
fd
,
err
:=
net
.
DialTCP
(
network
,
""
,
addr
)
if
err
!=
nil
{
panic
(
"net.DialTCP "
,
network
,
" "
,
addr
,
": "
,
err
.
String
())
}
FetchGoogle
(
fd
)
}
var
addrs
=
[]
string
{
"74.125.19.99:80"
,
"074.125.019.099:0080"
,
"[::ffff:74.125.19.99]:80"
,
"[::ffff:4a7d:1363]:80"
,
"[0:0:0:0:0000:ffff:74.125.19.99]:80"
,
"[0:0:0:0:000000:ffff:74.125.19.99]:80"
,
"[0:0:0:0:0:ffff::74.125.19.99]:80"
,
"[2001:4860:0:2001::68]:80"
// ipv6.google.com; removed if ipv6 flag not set
}
func
main
()
{
flag
.
Parse
()
// If no ipv6 tunnel, don't try the last address.
if
!
ipv6
{
addrs
[
len
(
addrs
)
-
1
]
=
""
}
for
i
:=
0
;
i
<
len
(
addrs
);
i
++
{
addr
:=
addrs
[
i
]
if
addr
==
""
{
continue
}
// print(addr, "\n");
TestDial
(
"tcp"
,
addr
);
TestDialTCP
(
"tcp"
,
addr
)
if
addr
[
0
]
!=
'['
{
TestDial
(
"tcp4"
,
addr
);
TestDialTCP
(
"tcp4"
,
addr
)
}
TestDial
(
"tcp6"
,
addr
);
TestDialTCP
(
"tcp6"
,
addr
)
}
}
test/tcpserver.go
0 → 100644
View file @
9350ef4e
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// $G $F.go && $L $F.$A && GOMAXPROCS=3 ./$A.out
// # TODO(rsc): GOMAXPROCS will go away eventually.
// # 3 is one for Echo, one for Serve, one for Connect.
package
main
import
(
"os"
;
"io"
;
"net"
;
"syscall"
)
func
StringToBuf
(
s
string
)
*
[]
byte
{
l
:=
len
(
s
);
b
:=
new
([]
byte
,
l
);
for
i
:=
0
;
i
<
l
;
i
++
{
b
[
i
]
=
s
[
i
];
}
return
b
;
}
func
Echo
(
fd
io
.
ReadWrite
,
done
*
chan
<-
int
)
{
var
buf
[
1024
]
byte
;
for
{
n
,
err
:=
fd
.
Read
(
&
buf
);
if
err
!=
nil
||
n
==
0
{
break
;
}
fd
.
Write
((
&
buf
)[
0
:
n
])
}
done
<-
1
}
func
Serve
(
network
,
addr
string
,
listening
,
done
*
chan
<-
int
)
{
l
,
err
:=
net
.
Listen
(
network
,
addr
);
if
err
!=
nil
{
panic
(
"listen: "
+
err
.
String
());
}
listening
<-
1
;
for
{
fd
,
addr
,
err
:=
l
.
Accept
();
if
err
!=
nil
{
break
;
}
echodone
:=
new
(
chan
int
)
go
Echo
(
fd
,
echodone
);
<-
echodone
;
// make sure Echo stops
l
.
Close
();
}
done
<-
1
}
func
Connect
(
network
,
addr
string
)
{
fd
,
err
:=
net
.
Dial
(
network
,
""
,
addr
);
if
err
!=
nil
{
panic
(
"connect: "
+
err
.
String
());
}
b
:=
StringToBuf
(
"hello, world
\n
"
);
var
b1
[
100
]
byte
;
n
,
errno
:=
fd
.
Write
(
b
);
if
n
!=
len
(
b
)
{
panic
(
"syscall.write in connect"
);
}
n
,
errno
=
fd
.
Read
(
&
b1
);
if
n
!=
len
(
b
)
{
panic
(
"syscall.read in connect"
);
}
// os.Stdout.Write((&b1)[0:n]);
fd
.
Close
();
}
func
Test
(
network
,
listenaddr
,
dialaddr
string
)
{
// print("Test ", network, " ", listenaddr, " ", dialaddr, "\n");
listening
:=
new
(
chan
int
);
done
:=
new
(
chan
int
);
go
Serve
(
network
,
listenaddr
,
listening
,
done
);
<-
listening
;
// wait for server to start
Connect
(
network
,
dialaddr
);
<-
done
;
// make sure server stopped
}
func
main
()
{
Test
(
"tcp"
,
"0.0.0.0:9999"
,
"127.0.0.1:9999"
);
Test
(
"tcp"
,
"[::]:9999"
,
"[::ffff:127.0.0.1]:9999"
);
Test
(
"tcp"
,
"[::]:9999"
,
"127.0.0.1:9999"
);
Test
(
"tcp"
,
"0.0.0.0:9999"
,
"[::ffff:127.0.0.1]:9999"
);
sys
.
exit
(
0
);
// supposed to happen on return, doesn't
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment