Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
int
Rust
提交
6d411342
R
Rust
项目概览
int
/
Rust
大约 1 年 前同步成功
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
Rust
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
6d411342
编写于
7月 02, 2012
作者:
B
Brian Anderson
浏览文件
操作
浏览文件
下载
差异文件
Merge remote-tracking branch 'brson/uv'
Conflicts: src/libstd/net_ip.rs src/libstd/net_tcp.rs
上级
c74b3fd6
483aee8d
变更
7
展开全部
隐藏空白更改
内联
并排
Showing
7 changed file
with
1303 addition
and
585 deletion
+1303
-585
src/libcore/vec.rs
src/libcore/vec.rs
+1
-0
src/libstd/net_ip.rs
src/libstd/net_ip.rs
+319
-24
src/libstd/net_tcp.rs
src/libstd/net_tcp.rs
+605
-534
src/libstd/std.rc
src/libstd/std.rc
+1
-1
src/libstd/uv_ll.rs
src/libstd/uv_ll.rs
+273
-10
src/rt/rust_uv.cpp
src/rt/rust_uv.cpp
+87
-16
src/rt/rustrt.def.in
src/rt/rustrt.def.in
+17
-0
未找到文件。
src/libcore/vec.rs
浏览文件 @
6d411342
...
...
@@ -31,6 +31,7 @@
export
rsplit
;
export
rsplitn
;
export
shift
;
export
unshift
;
export
pop
;
export
push
,
push_all
,
push_all_move
;
export
grow
;
...
...
src/libstd/net_ip.rs
浏览文件 @
6d411342
...
...
@@ -4,16 +4,35 @@
import
vec
;
import
uint
;
import
iotask
=
uv
::
iotask
::
iotask
;
import
interact
=
uv
::
iotask
::
interact
;
import
comm
::
methods
;
import
sockaddr_in
=
uv
::
ll
::
sockaddr_in
;
import
sockaddr_in6
=
uv
::
ll
::
sockaddr_in6
;
import
addrinfo
=
uv
::
ll
::
addrinfo
;
import
uv_getaddrinfo_t
=
uv
::
ll
::
uv_getaddrinfo_t
;
import
uv_ip4_addr
=
uv
::
ll
::
ip4_addr
;
import
uv_ip4_name
=
uv
::
ll
::
ip4_name
;
import
uv_ip6_addr
=
uv
::
ll
::
ip6_addr
;
import
uv_ip6_name
=
uv
::
ll
::
ip6_name
;
import
uv_getaddrinfo
=
uv
::
ll
::
getaddrinfo
;
import
uv_freeaddrinfo
=
uv
::
ll
::
freeaddrinfo
;
import
create_uv_getaddrinfo_t
=
uv
::
ll
::
getaddrinfo_t
;
import
set_data_for_req
=
uv
::
ll
::
set_data_for_req
;
import
get_data_for_req
=
uv
::
ll
::
get_data_for_req
;
import
ll
=
uv
::
ll
;
export
ip_addr
,
parse_addr_err
;
export
format_addr
;
export
v4
;
export
v4
,
v6
;
export
get_addr
;
#[doc
=
"An IP address"
]
enum
ip_addr
{
#[doc=
"An IPv4 address"
]
ipv4
(
u8
,
u8
,
u8
,
u8
),
ipv6
(
u16
,
u16
,
u16
,
u16
,
u16
,
u16
,
u16
,
u1
6
)
ipv4
(
sockaddr_in
),
ipv6
(
sockaddr_in
6
)
}
#[doc=
"
...
...
@@ -32,22 +51,88 @@ enum ip_addr {
"
]
fn
format_addr
(
ip
:
ip_addr
)
->
str
{
alt
ip
{
ipv4
(
a
,
b
,
c
,
d
)
{
#
fmt
[
"%u.%u.%u.%u"
,
a
as
uint
,
b
as
uint
,
c
as
uint
,
d
as
uint
]
ipv4
(
addr
)
{
unsafe
{
let
result
=
uv_ip4_name
(
&
addr
);
if
result
==
""
{
fail
"failed to convert inner sockaddr_in address to str"
}
result
}
}
ipv6
(
_
,
_
,
_
,
_
,
_
,
_
,
_
,
_
)
{
fail
"FIXME (#2651) impl parsing of ipv6 addr"
;
ipv6
(
addr
)
{
unsafe
{
let
result
=
uv_ip6_name
(
&
addr
);
if
result
==
""
{
fail
"failed to convert inner sockaddr_in address to str"
}
result
}
}
}
}
#[doc=
"
Represents errors returned from `net::ip::get_addr()`
"
]
enum
ip_get_addr_err
{
get_addr_unknown_error
}
#[doc=
"
Attempts name resolution on the provided `node` string
# Arguments
* `node` - a string representing some host address
* `iotask` - a `uv::iotask` used to interact with the underlying event loop
# Returns
A `result<[ip_addr]/~, ip_get_addr_err>` instance that will contain
a vector of `ip_addr` results, in the case of success, or an error
object in the case of failure
"
]
fn
get_addr
(
++
node
:
str
,
iotask
:
iotask
)
->
result
::
result
<
[
ip_addr
]
/~
,
ip_get_addr_err
>
unsafe
{
do
comm
::
listen
|
output_ch
|
{
do
str
::
unpack_slice
(
node
)
|
node_ptr
,
len
|
{
log
(
debug
,
#
fmt
(
"slice len %?"
,
len
));
let
handle
=
create_uv_getaddrinfo_t
();
let
handle_ptr
=
ptr
::
addr_of
(
handle
);
let
handle_data
:
get_addr_data
=
{
output_ch
:
output_ch
};
let
handle_data_ptr
=
ptr
::
addr_of
(
handle_data
);
do
interact
(
iotask
)
|
loop_ptr
|
{
let
result
=
uv_getaddrinfo
(
loop_ptr
,
handle_ptr
,
get_addr_cb
,
node_ptr
,
ptr
::
null
(),
ptr
::
null
());
alt
result
{
0i32
{
set_data_for_req
(
handle_ptr
,
handle_data_ptr
);
}
_
{
output_ch
.send
(
result
::
err
(
get_addr_unknown_error
));
}
}
};
output_ch
.recv
()
}
}
}
mod
v4
{
#[doc
=
"
Convert a str to `ip_addr`
# Failure
j
Fails if the string is not a valid IPv4 address
Fails if the string is not a valid IPv4 address
# Arguments
...
...
@@ -59,13 +144,22 @@ mod v4 {
"
]
fn
parse_addr
(
ip
:
str
)
->
ip_addr
{
alt
try_parse_addr
(
ip
)
{
result
::
ok
(
addr
)
{
addr
}
result
::
ok
(
addr
)
{
copy
(
addr
)
}
result
::
err
(
err_data
)
{
fail
err_data
.err_msg
}
}
}
fn
try_parse_addr
(
ip
:
str
)
->
result
::
result
<
ip_addr
,
parse_addr_err
>
{
// the simple, old style numberic representation of
// ipv4
type
ipv4_rep
=
{
a
:
u8
,
b
:
u8
,
c
:
u8
,
d
:
u8
};
impl
x
for
ipv4_rep
{
// this is pretty dastardly, i know
unsafe
fn
as_u32
()
->
u32
{
*
((
ptr
::
addr_of
(
self
))
as
*
u32
)
}
}
fn
parse_to_ipv4_rep
(
ip
:
str
)
->
result
::
result
<
ipv4_rep
,
str
>
{
let
parts
=
vec
::
map
(
str
::
split_char
(
ip
,
'.'
),
|
s
|
{
alt
uint
::
from_str
(
s
)
{
some
(
n
)
if
n
<=
255u
{
n
}
...
...
@@ -73,31 +167,232 @@ fn try_parse_addr(ip: str) -> result::result<ip_addr,parse_addr_err> {
}
});
if
vec
::
len
(
parts
)
!=
4u
{
result
::
err
({
err_msg
:
#
fmt
(
"'%s' doesn't have 4 parts"
,
ip
)})
}
result
::
err
(
#
fmt
(
"'%s' doesn't have 4 parts"
,
ip
))
}
else
if
vec
::
contains
(
parts
,
256u
)
{
result
::
err
({
err_msg
:
#
fmt
(
"invalid octal in provided addr '%s'"
,
ip
)})
result
::
err
(
#
fmt
(
"invalid octal in addr '%s'"
,
ip
))
}
else
{
result
::
ok
({
a
:
parts
[
0
]
as
u8
,
b
:
parts
[
1
]
as
u8
,
c
:
parts
[
2
]
as
u8
,
d
:
parts
[
3
]
as
u8
})
}
}
fn
try_parse_addr
(
ip
:
str
)
->
result
::
result
<
ip_addr
,
parse_addr_err
>
{
unsafe
{
let
INADDR_NONE
=
ll
::
get_INADDR_NONE
();
let
ip_rep_result
=
parse_to_ipv4_rep
(
ip
);
if
result
::
is_err
(
ip_rep_result
)
{
let
err_str
=
result
::
get_err
(
ip_rep_result
);
ret
result
::
err
({
err_msg
:
err_str
})
}
// ipv4_rep.as_u32 is unsafe :/
let
input_is_inaddr_none
=
result
::
get
(
ip_rep_result
)
.as_u32
()
==
INADDR_NONE
;
let
new_addr
=
uv_ip4_addr
(
ip
,
22
);
let
reformatted_name
=
uv_ip4_name
(
&
new_addr
);
log
(
debug
,
#
fmt
(
"try_parse_addr: input ip: %s reparsed ip: %s"
,
ip
,
reformatted_name
));
let
ref_ip_rep_result
=
parse_to_ipv4_rep
(
reformatted_name
);
if
result
::
is_err
(
ref_ip_rep_result
)
{
let
err_str
=
result
::
get_err
(
ref_ip_rep_result
);
ret
result
::
err
({
err_msg
:
err_str
})
}
if
result
::
get
(
ref_ip_rep_result
)
.as_u32
()
==
INADDR_NONE
&&
!
input_is_inaddr_none
{
ret
result
::
err
(
{
err_msg
:
"uv_ip4_name produced invalid result."
})
}
else
{
result
::
ok
(
ipv4
(
copy
(
new_addr
)))
}
}
}
}
mod
v6
{
#[doc
=
"
Convert a str to `ip_addr`
# Failure
Fails if the string is not a valid IPv6 address
# Arguments
* ip - an ipv6 string. See RFC2460 for spec.
# Returns
* an `ip_addr` of the `ipv6` variant
"
]
fn
parse_addr
(
ip
:
str
)
->
ip_addr
{
alt
try_parse_addr
(
ip
)
{
result
::
ok
(
addr
)
{
copy
(
addr
)
}
result
::
err
(
err_data
)
{
fail
err_data
.err_msg
}
}
}
fn
try_parse_addr
(
ip
:
str
)
->
result
::
result
<
ip_addr
,
parse_addr_err
>
{
unsafe
{
// need to figure out how to establish a parse failure..
let
new_addr
=
uv_ip6_addr
(
ip
,
22
);
let
reparsed_name
=
uv_ip6_name
(
&
new_addr
);
log
(
debug
,
#
fmt
(
"v6::try_parse_addr ip: '%s' reparsed '%s'"
,
ip
,
reparsed_name
));
// '::' appears to be uv_ip6_name() returns for bogus
// parses..
if
ip
!=
"::"
&&
reparsed_name
==
"::"
{
result
::
err
({
err_msg
:
#
fmt
(
"failed to parse '%s'"
,
ip
)})
}
else
{
result
::
ok
(
ipv6
(
new_addr
))
}
}
}
}
type
get_addr_data
=
{
output_ch
:
comm
::
chan
<
result
::
result
<
[
ip_addr
]
/~
,
ip_get_addr_err
>>
};
crust
fn
get_addr_cb
(
handle
:
*
uv_getaddrinfo_t
,
status
:
libc
::
c_int
,
res
:
*
addrinfo
)
unsafe
{
log
(
debug
,
"in get_addr_cb"
);
let
handle_data
=
get_data_for_req
(
handle
)
as
*
get_addr_data
;
if
status
==
0i32
{
if
res
!=
(
ptr
::
null
::
<
addrinfo
>
())
{
let
mut
out_vec
=
[]
/~
;
log
(
debug
,
#
fmt
(
"initial addrinfo: %?"
,
res
));
let
mut
curr_addr
=
res
;
loop
{
let
new_ip_addr
=
if
ll
::
is_ipv4_addrinfo
(
curr_addr
)
{
ipv4
(
copy
((
*
ll
::
addrinfo_as_sockaddr_in
(
curr_addr
))))
}
else
if
ll
::
is_ipv6_addrinfo
(
curr_addr
)
{
ipv6
(
copy
((
*
ll
::
addrinfo_as_sockaddr_in6
(
curr_addr
))))
}
else
{
log
(
debug
,
"curr_addr is not of family AF_INET or "
+
"AF_INET6. Error."
);
(
*
handle_data
)
.output_ch
.send
(
result
::
err
(
get_addr_unknown_error
));
break
;
};
out_vec
+=
[
new_ip_addr
]
/~
;
let
next_addr
=
ll
::
get_next_addrinfo
(
curr_addr
);
if
next_addr
==
ptr
::
null
::
<
addrinfo
>
()
as
*
addrinfo
{
log
(
debug
,
"null next_addr encountered. no mas"
);
break
;
}
else
{
curr_addr
=
next_addr
;
log
(
debug
,
#
fmt
(
"next_addr addrinfo: %?"
,
curr_addr
));
}
}
log
(
debug
,
#
fmt
(
"successful process addrinfo result, len: %?"
,
vec
::
len
(
out_vec
)));
(
*
handle_data
)
.output_ch
.send
(
result
::
ok
(
out_vec
));
}
else
{
result
::
ok
(
ipv4
(
parts
[
0
]
as
u8
,
parts
[
1
]
as
u8
,
parts
[
2
]
as
u8
,
parts
[
3
]
as
u8
))
log
(
debug
,
"addrinfo pointer is NULL"
);
(
*
handle_data
)
.output_ch
.send
(
result
::
err
(
get_addr_unknown_error
));
}
}
else
{
log
(
debug
,
"status != 0 error in get_addr_cb"
);
(
*
handle_data
)
.output_ch
.send
(
result
::
err
(
get_addr_unknown_error
));
}
if
res
!=
(
ptr
::
null
::
<
addrinfo
>
())
{
uv_freeaddrinfo
(
res
);
}
log
(
debug
,
"leaving get_addr_cb"
);
}
#[cfg(test)]
mod
test
{
#[test]
fn
test_format_ip
()
{
assert
(
format_addr
(
ipv4
(
127u8
,
0u8
,
0u8
,
1u8
))
==
"127.0.0.1"
)
fn
test_ip_ipv4_parse_and_format_ip
()
{
let
localhost_str
=
"127.0.0.1"
;
assert
(
format_addr
(
v4
::
parse_addr
(
localhost_str
))
==
localhost_str
)
}
#[test]
fn
test_ip_ipv6_parse_and_format_ip
()
{
let
localhost_str
=
"::1"
;
let
format_result
=
format_addr
(
v6
::
parse_addr
(
localhost_str
));
log
(
debug
,
#
fmt
(
"results: expected: '%s' actual: '%s'"
,
localhost_str
,
format_result
));
assert
format_result
==
localhost_str
;
}
#[test]
fn
test_ip_ipv4_bad_parse
()
{
alt
v4
::
try_parse_addr
(
"b4df00d"
)
{
result
::
err
(
err_info
)
{
log
(
debug
,
#
fmt
(
"got error as expected %?"
,
err_info
));
assert
true
;
}
result
::
ok
(
addr
)
{
fail
#
fmt
(
"Expected failure, but got addr %?"
,
addr
);
}
}
}
#[test]
#[ignore(target_os=
"win32"
)]
fn
test_ip_ipv6_bad_parse
()
{
alt
v6
::
try_parse_addr
(
"::,~2234k;"
)
{
result
::
err
(
err_info
)
{
log
(
debug
,
#
fmt
(
"got error as expected %?"
,
err_info
));
assert
true
;
}
result
::
ok
(
addr
)
{
fail
#
fmt
(
"Expected failure, but got addr %?"
,
addr
);
}
}
}
#[test]
#[ignore(reason
=
"valgrind says it's leaky"
)]
fn
test_ip_get_addr
()
{
let
localhost_name
=
"localhost"
;
let
iotask
=
uv
::
global_loop
::
get
();
let
ga_result
=
get_addr
(
localhost_name
,
iotask
);
if
result
::
is_err
(
ga_result
)
{
fail
"got err result from net::ip::get_addr();"
}
// note really sure how to realiably test/assert
// this.. mostly just wanting to see it work, atm.
let
results
=
result
::
unwrap
(
ga_result
);
log
(
debug
,
#
fmt
(
"test_get_addr: Number of results for %s: %?"
,
localhost_name
,
vec
::
len
(
results
)));
for
vec
::
each
(
results
)
|
r
|
{
let
ipv_prefix
=
alt
r
{
ipv4
(
_
)
{
"IPv4"
}
ipv6
(
_
)
{
"IPv6"
}
};
log
(
debug
,
#
fmt
(
"test_get_addr: result %s: '%s'"
,
ipv_prefix
,
format_addr
(
r
)));
}
// at least one result.. this is going to vary from system
// to system, based on stuff like the contents of /etc/hosts
assert
vec
::
len
(
results
)
>
0
;
}
#[test]
fn
test_parse_ip
()
{
assert
(
v4
::
parse_addr
(
"127.0.0.1"
)
==
ipv4
(
127u8
,
0u8
,
0u8
,
1u8
));
#[ignore(reason
=
"valgrind says it's leaky"
)]
fn
test_ip_get_addr_bad_input
()
{
let
localhost_name
=
"sjkl234m,./sdf"
;
let
iotask
=
uv
::
global_loop
::
get
();
let
ga_result
=
get_addr
(
localhost_name
,
iotask
);
assert
result
::
is_err
(
ga_result
);
}
}
\ No newline at end of file
src/libstd/net_tcp.rs
浏览文件 @
6d411342
此差异已折叠。
点击以展开。
src/libstd/std.rc
浏览文件 @
6d411342
...
...
@@ -15,7 +15,7 @@
use core(vers = "0.2");
import core::*;
export net, net_tcp;
export net, net_tcp
, net_ip
;
export uv, uv_ll, uv_iotask, uv_global_loop;
export c_vec, util, timer;
export bitv, deque, fun_treemap, list, map, smallintmap, sort, treemap;
...
...
src/libstd/uv_ll.rs
浏览文件 @
6d411342
...
...
@@ -223,10 +223,81 @@ enum uv_handle_type {
mut
sin_zero
:
(
u8
,
u8
,
u8
,
u8
,
u8
,
u8
,
u8
,
u8
)
};
// unix size: 28 .. make due w/ 32
// unix size: 28 .. FIXME #1645
// stuck with 32 becuse of rust padding structs?
#[cfg(target_arch=
"x86_64"
)]
type
sockaddr_in6
=
{
a0
:
*
u8
,
a1
:
*
u8
,
a2
:
*
u8
,
a3
:
*
u8
};
#[cfg(target_arch=
"x86"
)]
type
sockaddr_in6
=
{
a0
:
*
u8
,
a1
:
*
u8
,
a2
:
*
u8
,
a3
:
(
u8
,
u8
,
u8
,
u8
)
a2
:
*
u8
,
a3
:
*
u8
,
a4
:
*
u8
,
a5
:
*
u8
,
a6
:
*
u8
,
a7
:
*
u8
};
// unix size: 28 .. FIXME #1645
// stuck with 32 becuse of rust padding structs?
type
addr_in
=
addr_in_impl
::
addr_in
;
#[cfg(unix)]
mod
addr_in_impl
{
#[cfg(target_arch=
"x86_64"
)]
type
addr_in
=
{
a0
:
*
u8
,
a1
:
*
u8
,
a2
:
*
u8
,
a3
:
*
u8
};
#[cfg(target_arch=
"x86"
)]
type
addr_in
=
{
a0
:
*
u8
,
a1
:
*
u8
,
a2
:
*
u8
,
a3
:
*
u8
,
a4
:
*
u8
,
a5
:
*
u8
,
a6
:
*
u8
,
a7
:
*
u8
,
};
}
#[cfg(windows)]
mod
addr_in_impl
{
type
addr_in
=
{
a0
:
*
u8
,
a1
:
*
u8
,
a2
:
*
u8
,
a3
:
*
u8
};
}
// unix size: 48, 32bit: 32
type
addrinfo
=
addrinfo_impl
::
addrinfo
;
#[cfg(target_os=
"linux"
)]
mod
addrinfo_impl
{
#[cfg(target_arch=
"x86_64"
)]
type
addrinfo
=
{
a00
:
*
u8
,
a01
:
*
u8
,
a02
:
*
u8
,
a03
:
*
u8
,
a04
:
*
u8
,
a05
:
*
u8
};
#[cfg(target_arch=
"x86"
)]
type
addrinfo
=
{
a00
:
*
u8
,
a01
:
*
u8
,
a02
:
*
u8
,
a03
:
*
u8
,
a04
:
*
u8
,
a05
:
*
u8
,
a06
:
*
u8
,
a07
:
*
u8
};
}
#[cfg(target_os=
"macos"
)]
mod
addrinfo_impl
{
type
addrinfo
=
{
a00
:
*
u8
,
a01
:
*
u8
,
a02
:
*
u8
,
a03
:
*
u8
,
a04
:
*
u8
,
a05
:
*
u8
};
}
#[cfg(windows)]
mod
addrinfo_impl
{
type
addrinfo
=
{
a00
:
*
u8
,
a01
:
*
u8
,
a02
:
*
u8
,
a03
:
*
u8
,
a04
:
*
u8
,
a05
:
*
u8
};
}
// unix size: 72
type
uv_getaddrinfo_t
=
{
a00
:
*
u8
,
a01
:
*
u8
,
a02
:
*
u8
,
a03
:
*
u8
,
a04
:
*
u8
,
a05
:
*
u8
,
a06
:
*
u8
,
a07
:
*
u8
,
a08
:
*
u8
};
mod
uv_ll_struct_stubgen
{
...
...
@@ -474,10 +545,18 @@ fn gen_stub_uv_write_t() -> uv_write_t {
a12
:
0
as
*
u8
};
}
fn
gen_stub_uv_getaddrinfo_t
()
->
uv_getaddrinfo_t
{
{
a00
:
0
as
*
u8
,
a01
:
0
as
*
u8
,
a02
:
0
as
*
u8
,
a03
:
0
as
*
u8
,
a04
:
0
as
*
u8
,
a05
:
0
as
*
u8
,
a06
:
0
as
*
u8
,
a07
:
0
as
*
u8
,
a08
:
0
as
*
u8
}
}
}
#[nolink]
native
mod
rustrt
{
// libuv public API
fn
rust_uv_loop_new
()
->
*
libc
::
c_void
;
fn
rust_uv_loop_delete
(
lp
:
*
libc
::
c_void
);
fn
rust_uv_loop_refcount
(
loop_ptr
:
*
libc
::
c_void
)
->
libc
::
c_int
;
...
...
@@ -500,6 +579,12 @@ fn rust_uv_buf_init(out_buf: *uv_buf_t, base: *u8,
fn
rust_uv_err_name
(
err
:
*
uv_err_t
)
->
*
libc
::
c_char
;
fn
rust_uv_ip4_addr
(
ip
:
*
u8
,
port
:
libc
::
c_int
)
->
sockaddr_in
;
fn
rust_uv_ip6_addr
(
ip
:
*
u8
,
port
:
libc
::
c_int
)
->
sockaddr_in6
;
fn
rust_uv_ip4_name
(
src
:
*
sockaddr_in
,
dst
:
*
u8
,
size
:
libc
::
size_t
)
->
libc
::
c_int
;
fn
rust_uv_ip6_name
(
src
:
*
sockaddr_in6
,
dst
:
*
u8
,
size
:
libc
::
size_t
)
->
libc
::
c_int
;
// FIXME ref #2064
fn
rust_uv_tcp_connect
(
connect_ptr
:
*
uv_connect_t
,
tcp_handle_ptr
:
*
uv_tcp_t
,
...
...
@@ -508,6 +593,14 @@ fn rust_uv_tcp_connect(connect_ptr: *uv_connect_t,
// FIXME ref #2064
fn
rust_uv_tcp_bind
(
tcp_server
:
*
uv_tcp_t
,
++
addr
:
*
sockaddr_in
)
->
libc
::
c_int
;
// FIXME ref #2064
fn
rust_uv_tcp_connect6
(
connect_ptr
:
*
uv_connect_t
,
tcp_handle_ptr
:
*
uv_tcp_t
,
++
after_cb
:
*
u8
,
++
addr
:
*
sockaddr_in6
)
->
libc
::
c_int
;
// FIXME ref #2064
fn
rust_uv_tcp_bind6
(
tcp_server
:
*
uv_tcp_t
,
++
addr
:
*
sockaddr_in6
)
->
libc
::
c_int
;
fn
rust_uv_listen
(
stream
:
*
libc
::
c_void
,
backlog
:
libc
::
c_int
,
cb
:
*
u8
)
->
libc
::
c_int
;
fn
rust_uv_accept
(
server
:
*
libc
::
c_void
,
client
:
*
libc
::
c_void
)
...
...
@@ -527,7 +620,22 @@ fn rust_uv_timer_start(
repeat
:
libc
::
c_uint
)
->
libc
::
c_int
;
fn
rust_uv_timer_stop
(
handle
:
*
uv_timer_t
)
->
libc
::
c_int
;
fn
rust_uv_getaddrinfo
(
loop_ptr
:
*
libc
::
c_void
,
handle
:
*
uv_getaddrinfo_t
,
cb
:
*
u8
,
node_name_ptr
:
*
u8
,
service_name_ptr
:
*
u8
,
// should probably only pass ptr::null()
hints
:
*
addrinfo
)
->
libc
::
c_int
;
fn
rust_uv_freeaddrinfo
(
res
:
*
addrinfo
);
// data accessors/helpers for rust-mapped uv structs
fn
rust_uv_helper_get_INADDR_NONE
()
->
u32
;
fn
rust_uv_is_ipv4_addrinfo
(
input
:
*
addrinfo
)
->
bool
;
fn
rust_uv_is_ipv6_addrinfo
(
input
:
*
addrinfo
)
->
bool
;
fn
rust_uv_get_next_addrinfo
(
input
:
*
addrinfo
)
->
*
addrinfo
;
fn
rust_uv_addrinfo_as_sockaddr_in
(
input
:
*
addrinfo
)
->
*
sockaddr_in
;
fn
rust_uv_addrinfo_as_sockaddr_in6
(
input
:
*
addrinfo
)
->
*
sockaddr_in6
;
fn
rust_uv_malloc_buf_base_of
(
sug_size
:
libc
::
size_t
)
->
*
u8
;
fn
rust_uv_free_base_of_buf
(
++
buf
:
uv_buf_t
);
fn
rust_uv_get_stream_handle_from_connect_req
(
...
...
@@ -558,8 +666,12 @@ fn rust_uv_set_data_for_req(req: *libc::c_void,
fn
rust_uv_helper_uv_write_t_size
()
->
libc
::
c_uint
;
fn
rust_uv_helper_uv_err_t_size
()
->
libc
::
c_uint
;
fn
rust_uv_helper_sockaddr_in_size
()
->
libc
::
c_uint
;
fn
rust_uv_helper_sockaddr_in6_size
()
->
libc
::
c_uint
;
fn
rust_uv_helper_uv_async_t_size
()
->
libc
::
c_uint
;
fn
rust_uv_helper_uv_timer_t_size
()
->
libc
::
c_uint
;
fn
rust_uv_helper_uv_getaddrinfo_t_size
()
->
libc
::
c_uint
;
fn
rust_uv_helper_addrinfo_size
()
->
libc
::
c_uint
;
fn
rust_uv_helper_addr_in_size
()
->
libc
::
c_uint
;
}
unsafe
fn
loop_new
()
->
*
libc
::
c_void
{
...
...
@@ -598,11 +710,26 @@ unsafe fn tcp_connect(connect_ptr: *uv_connect_t,
after_connect_cb
,
addr_ptr
);
}
// FIXME ref #2064
unsafe
fn
tcp_connect6
(
connect_ptr
:
*
uv_connect_t
,
tcp_handle_ptr
:
*
uv_tcp_t
,
addr_ptr
:
*
sockaddr_in6
,
++
after_connect_cb
:
*
u8
)
->
libc
::
c_int
{
ret
rustrt
::
rust_uv_tcp_connect6
(
connect_ptr
,
tcp_handle_ptr
,
after_connect_cb
,
addr_ptr
);
}
// FIXME ref #2064
unsafe
fn
tcp_bind
(
tcp_server_ptr
:
*
uv_tcp_t
,
addr_ptr
:
*
sockaddr_in
)
->
libc
::
c_int
{
ret
rustrt
::
rust_uv_tcp_bind
(
tcp_server_ptr
,
addr_ptr
);
}
// FIXME ref #2064
unsafe
fn
tcp_bind6
(
tcp_server_ptr
:
*
uv_tcp_t
,
addr_ptr
:
*
sockaddr_in6
)
->
libc
::
c_int
{
ret
rustrt
::
rust_uv_tcp_bind6
(
tcp_server_ptr
,
addr_ptr
);
}
unsafe
fn
listen
<
T
>
(
stream
:
*
T
,
backlog
:
libc
::
c_int
,
cb
:
*
u8
)
->
libc
::
c_int
{
...
...
@@ -677,14 +804,59 @@ unsafe fn buf_init(++input: *u8, len: uint) -> uv_buf_t {
}
unsafe
fn
ip4_addr
(
ip
:
str
,
port
:
int
)
->
sockaddr_in
{
let
mut
addr_vec
=
str
::
bytes
(
ip
);
vec
::
push
(
addr_vec
,
0u8
);
// add null terminator
let
addr_vec_ptr
=
vec
::
unsafe
::
to_ptr
(
addr_vec
);
let
ip_back
=
str
::
from_bytes
(
addr_vec
);
log
(
debug
,
#
fmt
(
"vec val: '%s' length: %u"
,
ip_back
,
vec
::
len
(
addr_vec
)));
ret
rustrt
::
rust_uv_ip4_addr
(
addr_vec_ptr
,
port
as
libc
::
c_int
);
do
str
::
as_c_str
(
ip
)
|
ip_buf
|
{
rustrt
::
rust_uv_ip4_addr
(
ip_buf
as
*
u8
,
port
as
libc
::
c_int
)
}
}
unsafe
fn
ip6_addr
(
ip
:
str
,
port
:
int
)
->
sockaddr_in6
{
do
str
::
as_c_str
(
ip
)
|
ip_buf
|
{
rustrt
::
rust_uv_ip6_addr
(
ip_buf
as
*
u8
,
port
as
libc
::
c_int
)
}
}
unsafe
fn
ip4_name
(
src
:
&
sockaddr_in
)
->
str
{
// ipv4 addr max size: 15 + 1 trailing null byte
let
dst
:
[
u8
]
/~
=
[
0u8
,
0u8
,
0u8
,
0u8
,
0u8
,
0u8
,
0u8
,
0u8
,
0u8
,
0u8
,
0u8
,
0u8
,
0u8
,
0u8
,
0u8
,
0u8
]
/~
;
let
size
=
16
as
libc
::
size_t
;
do
vec
::
as_buf
(
dst
)
|
dst_buf
|
{
rustrt
::
rust_uv_ip4_name
(
src
as
*
sockaddr_in
,
dst_buf
,
size
);
// seems that checking the result of uv_ip4_name
// doesn't work too well..
// you're stuck looking at the value of dst_buf
// to see if it is the string representation of
// INADDR_NONE (0xffffffff or 255.255.255.255 on
// many platforms)
str
::
unsafe
::
from_buf
(
dst_buf
)
}
}
unsafe
fn
ip6_name
(
src
:
&
sockaddr_in6
)
->
str
{
// ipv6 addr max size: 45 + 1 trailing null byte
let
dst
:
[
u8
]
/~
=
[
0u8
,
0u8
,
0u8
,
0u8
,
0u8
,
0u8
,
0u8
,
0u8
,
0u8
,
0u8
,
0u8
,
0u8
,
0u8
,
0u8
,
0u8
,
0u8
,
0u8
,
0u8
,
0u8
,
0u8
,
0u8
,
0u8
,
0u8
,
0u8
,
0u8
,
0u8
,
0u8
,
0u8
,
0u8
,
0u8
,
0u8
,
0u8
,
0u8
,
0u8
,
0u8
,
0u8
,
0u8
,
0u8
,
0u8
,
0u8
,
0u8
,
0u8
,
0u8
,
0u8
,
0u8
,
0u8
]
/~
;
let
size
=
46
as
libc
::
size_t
;
do
vec
::
as_buf
(
dst
)
|
dst_buf
|
{
let
src_unsafe_ptr
=
src
as
*
sockaddr_in6
;
log
(
debug
,
#
fmt
(
"val of src *sockaddr_in6: %? sockaddr_in6: %?"
,
src_unsafe_ptr
,
src
));
let
result
=
rustrt
::
rust_uv_ip6_name
(
src_unsafe_ptr
,
dst_buf
,
size
);
alt
result
{
0i32
{
str
::
unsafe
::
from_buf
(
dst_buf
)
}
_
{
""
}
}
}
}
unsafe
fn
timer_init
(
loop_ptr
:
*
libc
::
c_void
,
...
...
@@ -699,6 +871,22 @@ unsafe fn timer_start(timer_ptr: *uv_timer_t, cb: *u8, timeout: uint,
unsafe
fn
timer_stop
(
timer_ptr
:
*
uv_timer_t
)
->
libc
::
c_int
{
ret
rustrt
::
rust_uv_timer_stop
(
timer_ptr
);
}
unsafe
fn
getaddrinfo
(
loop_ptr
:
*
libc
::
c_void
,
handle
:
*
uv_getaddrinfo_t
,
cb
:
*
u8
,
node_name_ptr
:
*
u8
,
service_name_ptr
:
*
u8
,
hints
:
*
addrinfo
)
->
libc
::
c_int
{
rustrt
::
rust_uv_getaddrinfo
(
loop_ptr
,
handle
,
cb
,
node_name_ptr
,
service_name_ptr
,
hints
)
}
unsafe
fn
freeaddrinfo
(
res
:
*
addrinfo
)
{
rustrt
::
rust_uv_freeaddrinfo
(
res
);
}
// libuv struct initializers
unsafe
fn
tcp_t
()
->
uv_tcp_t
{
...
...
@@ -716,6 +904,9 @@ unsafe fn async_t() -> uv_async_t {
unsafe
fn
timer_t
()
->
uv_timer_t
{
ret
uv_ll_struct_stubgen
::
gen_stub_uv_timer_t
();
}
unsafe
fn
getaddrinfo_t
()
->
uv_getaddrinfo_t
{
ret
uv_ll_struct_stubgen
::
gen_stub_uv_getaddrinfo_t
();
}
// data access helpers
unsafe
fn
get_loop_for_uv_handle
<
T
>
(
handle
:
*
T
)
...
...
@@ -791,6 +982,25 @@ unsafe fn get_last_err_data(uv_loop: *libc::c_void) -> uv_err_data {
err_msg
:
str
};
unsafe
fn
is_ipv4_addrinfo
(
input
:
*
addrinfo
)
->
bool
{
rustrt
::
rust_uv_is_ipv4_addrinfo
(
input
)
}
unsafe
fn
is_ipv6_addrinfo
(
input
:
*
addrinfo
)
->
bool
{
rustrt
::
rust_uv_is_ipv6_addrinfo
(
input
)
}
unsafe
fn
get_INADDR_NONE
()
->
u32
{
rustrt
::
rust_uv_helper_get_INADDR_NONE
()
}
unsafe
fn
get_next_addrinfo
(
input
:
*
addrinfo
)
->
*
addrinfo
{
rustrt
::
rust_uv_get_next_addrinfo
(
input
)
}
unsafe
fn
addrinfo_as_sockaddr_in
(
input
:
*
addrinfo
)
->
*
sockaddr_in
{
rustrt
::
rust_uv_addrinfo_as_sockaddr_in
(
input
)
}
unsafe
fn
addrinfo_as_sockaddr_in6
(
input
:
*
addrinfo
)
->
*
sockaddr_in6
{
rustrt
::
rust_uv_addrinfo_as_sockaddr_in6
(
input
)
}
#[cfg(test)]
mod
test
{
enum
tcp_read_data
{
...
...
@@ -1366,6 +1576,33 @@ fn test_uv_ll_struct_size_sockaddr_in() {
log
(
debug
,
output
);
assert
foreign_handle_size
as
uint
==
rust_handle_size
;
}
#[test]
#[ignore(cfg(target_os
=
"freebsd"
))]
fn
test_uv_ll_struct_size_sockaddr_in6
()
{
let
native_handle_size
=
rustrt
::
rust_uv_helper_sockaddr_in6_size
();
let
rust_handle_size
=
sys
::
size_of
::
<
sockaddr_in6
>
();
let
output
=
#
fmt
(
"sockaddr_in6 -- native: %u rust: %u"
,
native_handle_size
as
uint
,
rust_handle_size
);
log
(
debug
,
output
);
// FIXME #1645 .. rust appears to pad structs to the nearest byte..?
// .. can't get the uv::ll::sockaddr_in6 to == 28 :/
// .. so the type always appears to be 32 in size.. which is
// good, i guess.. better too big than too little
assert
(
4u
+
native_handle_size
as
uint
)
==
rust_handle_size
;
}
#[test]
#[ignore(reason
=
"questionable size calculations"
)]
fn
test_uv_ll_struct_size_addr_in
()
{
let
native_handle_size
=
rustrt
::
rust_uv_helper_addr_in_size
();
let
rust_handle_size
=
sys
::
size_of
::
<
addr_in
>
();
let
output
=
#
fmt
(
"addr_in -- native: %u rust: %u"
,
native_handle_size
as
uint
,
rust_handle_size
);
log
(
debug
,
output
);
// FIXME #1645 .. see note above about struct padding
assert
(
4u
+
native_handle_size
as
uint
)
==
rust_handle_size
;
}
#[test]
#[ignore(cfg(target_os
=
"freebsd"
))]
...
...
@@ -1390,4 +1627,30 @@ fn test_uv_ll_struct_size_uv_timer_t() {
log
(
debug
,
output
);
assert
foreign_handle_size
as
uint
==
rust_handle_size
;
}
#[test]
#[ignore(cfg(target_os
=
"freebsd"
))]
#[ignore(cfg(target_os
=
"win32"
))]
fn
test_uv_ll_struct_size_uv_getaddrinfo_t
()
{
let
native_handle_size
=
rustrt
::
rust_uv_helper_uv_getaddrinfo_t_size
();
let
rust_handle_size
=
sys
::
size_of
::
<
uv_getaddrinfo_t
>
();
let
output
=
#
fmt
(
"uv_getaddrinfo_t -- native: %u rust: %u"
,
native_handle_size
as
uint
,
rust_handle_size
);
log
(
debug
,
output
);
assert
native_handle_size
as
uint
==
rust_handle_size
;
}
#[test]
#[ignore(cfg(target_os
=
"freebsd"
))]
#[ignore(cfg(target_os
=
"macos"
))]
#[ignore(cfg(target_os
=
"win32"
))]
fn
test_uv_ll_struct_size_addrinfo
()
{
let
native_handle_size
=
rustrt
::
rust_uv_helper_addrinfo_size
();
let
rust_handle_size
=
sys
::
size_of
::
<
addrinfo
>
();
let
output
=
#
fmt
(
"addrinfo -- native: %u rust: %u"
,
native_handle_size
as
uint
,
rust_handle_size
);
log
(
debug
,
output
);
assert
native_handle_size
as
uint
==
rust_handle_size
;
}
}
src/rt/rust_uv.cpp
浏览文件 @
6d411342
...
...
@@ -238,32 +238,36 @@ rust_uv_tcp_connect(uv_connect_t* connect_ptr,
uv_tcp_t
*
tcp_ptr
,
uv_connect_cb
cb
,
sockaddr_in
*
addr_ptr
)
{
rust_task
*
task
=
rust_get_current_task
();
LOG
(
task
,
stdlib
,
"inside rust_uv_tcp_connect"
);
// FIXME ref #2064
sockaddr_in
addr
=
*
addr_ptr
;
LOG
(
task
,
stdlib
,
"before tcp_connect .. port: %d"
,
addr
.
sin_port
);
LOG
(
task
,
stdlib
,
"before tcp_connect.. tcp stream:"
\
"%lu cb ptr: %lu"
,
(
unsigned
long
int
)
tcp_ptr
,
(
unsigned
long
int
)
cb
);
int
result
=
uv_tcp_connect
(
connect_ptr
,
tcp_ptr
,
addr
,
cb
);
LOG
(
task
,
stdlib
,
"leaving rust_uv_tcp_connect.."
\
"and result: %d"
,
result
);
return
result
;
}
extern
"C"
int
rust_uv_tcp_bind
(
uv_tcp_t
*
tcp_server
,
sockaddr_in
*
addr_ptr
)
{
// FIXME ref #2064
rust_task
*
task
=
rust_get_current_task
();
sockaddr_in
addr
=
*
addr_ptr
;
LOG
(
task
,
stdlib
,
"before uv_tcp_bind .. tcp_server:"
\
"%lu port: %d"
,
(
unsigned
long
int
)
tcp_server
,
addr
.
sin_port
);
return
uv_tcp_bind
(
tcp_server
,
addr
);
}
extern
"C"
int
rust_uv_tcp_connect6
(
uv_connect_t
*
connect_ptr
,
uv_tcp_t
*
tcp_ptr
,
uv_connect_cb
cb
,
sockaddr_in6
*
addr_ptr
)
{
// FIXME ref #2064
sockaddr_in6
addr
=
*
addr_ptr
;
int
result
=
uv_tcp_connect6
(
connect_ptr
,
tcp_ptr
,
addr
,
cb
);
return
result
;
}
extern
"C"
int
rust_uv_tcp_bind6
(
uv_tcp_t
*
tcp_server
,
sockaddr_in6
*
addr_ptr
)
{
// FIXME ref #2064
sockaddr_in6
addr
=
*
addr_ptr
;
return
uv_tcp_bind6
(
tcp_server
,
addr
);
}
extern
"C"
int
rust_uv_listen
(
uv_stream_t
*
stream
,
int
backlog
,
...
...
@@ -301,6 +305,10 @@ rust_uv_helper_sockaddr_in_size() {
return
sizeof
(
sockaddr_in
);
}
extern
"C"
size_t
rust_uv_helper_sockaddr_in6_size
()
{
return
sizeof
(
sockaddr_in6
);
}
extern
"C"
size_t
rust_uv_helper_uv_async_t_size
()
{
return
sizeof
(
uv_async_t
);
}
...
...
@@ -308,7 +316,22 @@ extern "C" size_t
rust_uv_helper_uv_timer_t_size
()
{
return
sizeof
(
uv_timer_t
);
}
extern
"C"
size_t
rust_uv_helper_addr_in_size
()
{
return
sizeof
(
sockaddr_in6
);
}
extern
"C"
size_t
rust_uv_helper_uv_getaddrinfo_t_size
()
{
return
sizeof
(
uv_getaddrinfo_t
);
}
extern
"C"
size_t
rust_uv_helper_addrinfo_size
()
{
return
sizeof
(
addrinfo
);
}
extern
"C"
unsigned
int
rust_uv_helper_get_INADDR_NONE
()
{
return
INADDR_NONE
;
}
extern
"C"
uv_stream_t
*
rust_uv_get_stream_handle_from_connect_req
(
uv_connect_t
*
connect
)
{
return
connect
->
handle
;
...
...
@@ -436,11 +459,27 @@ extern "C" struct sockaddr_in
rust_uv_ip4_addr
(
const
char
*
ip
,
int
port
)
{
rust_task
*
task
=
rust_get_current_task
();
LOG
(
task
,
stdlib
,
"before creating addr_ptr.. ip %s"
\
"
port %d
"
,
ip
,
port
);
"
port %d
\n
"
,
ip
,
port
);
struct
sockaddr_in
addr
=
uv_ip4_addr
(
ip
,
port
);
LOG
(
task
,
stdlib
,
"after creating .. port: %d"
,
addr
.
sin_port
);
return
addr
;
}
extern
"C"
struct
sockaddr_in6
rust_uv_ip6_addr
(
const
char
*
ip
,
int
port
)
{
rust_task
*
task
=
rust_get_current_task
();
LOG
(
task
,
stdlib
,
"before creating addr_ptr.. ip %s"
\
" port %d
\n
"
,
ip
,
port
);
return
uv_ip6_addr
(
ip
,
port
);
}
extern
"C"
int
rust_uv_ip4_name
(
struct
sockaddr_in
*
src
,
char
*
dst
,
size_t
size
)
{
return
uv_ip4_name
(
src
,
dst
,
size
);
}
extern
"C"
int
rust_uv_ip6_name
(
struct
sockaddr_in6
*
src
,
char
*
dst
,
size_t
size
)
{
int
result
=
uv_ip6_name
(
src
,
dst
,
size
);
return
result
;
}
extern
"C"
uintptr_t
*
rust_uv_get_kernel_global_chan_ptr
()
{
...
...
@@ -460,3 +499,35 @@ extern "C" void
rust_uv_current_kernel_free
(
void
*
mem
)
{
current_kernel_free
(
mem
);
}
extern
"C"
int
rust_uv_getaddrinfo
(
uv_loop_t
*
loop
,
uv_getaddrinfo_t
*
handle
,
uv_getaddrinfo_cb
cb
,
char
*
node
,
char
*
service
,
addrinfo
*
hints
)
{
return
uv_getaddrinfo
(
loop
,
handle
,
cb
,
node
,
service
,
hints
);
}
extern
"C"
void
rust_uv_freeaddrinfo
(
addrinfo
*
res
)
{
uv_freeaddrinfo
(
res
);
}
extern
"C"
bool
rust_uv_is_ipv4_addrinfo
(
addrinfo
*
input
)
{
return
input
->
ai_family
==
AF_INET
;
}
extern
"C"
bool
rust_uv_is_ipv6_addrinfo
(
addrinfo
*
input
)
{
return
input
->
ai_family
==
AF_INET6
;
}
extern
"C"
addrinfo
*
rust_uv_get_next_addrinfo
(
addrinfo
*
input
)
{
return
input
->
ai_next
;
}
extern
"C"
sockaddr_in
*
rust_uv_addrinfo_as_sockaddr_in
(
addrinfo
*
input
)
{
return
(
sockaddr_in
*
)
input
->
ai_addr
;
}
extern
"C"
sockaddr_in6
*
rust_uv_addrinfo_as_sockaddr_in6
(
addrinfo
*
input
)
{
return
(
sockaddr_in6
*
)
input
->
ai_addr
;
}
src/rt/rustrt.def.in
浏览文件 @
6d411342
...
...
@@ -111,8 +111,13 @@ rust_uv_last_error
rust_uv_strerror
rust_uv_err_name
rust_uv_ip4_addr
rust_uv_ip4_name
rust_uv_ip6_addr
rust_uv_ip6_name
rust_uv_tcp_connect
rust_uv_tcp_bind
rust_uv_tcp_connect6
rust_uv_tcp_bind6
rust_uv_listen
rust_uv_accept
rust_uv_write
...
...
@@ -120,12 +125,22 @@ rust_uv_read_start
rust_uv_read_stop
rust_uv_malloc_buf_base_of
rust_uv_free_base_of_buf
rust_uv_is_ipv4_addrinfo
rust_uv_is_ipv6_addrinfo
rust_uv_get_next_addrinfo
rust_uv_addrinfo_as_sockaddr_in
rust_uv_addrinfo_as_sockaddr_in6
rust_uv_helper_uv_tcp_t_size
rust_uv_helper_uv_connect_t_size
rust_uv_helper_uv_buf_t_size
rust_uv_helper_uv_write_t_size
rust_uv_helper_uv_err_t_size
rust_uv_helper_sockaddr_in_size
rust_uv_helper_sockaddr_in6_size
rust_uv_helper_addr_in_size
rust_uv_helper_addrinfo_size
rust_uv_helper_uv_getaddrinfo_t_size
rust_uv_helper_get_INADDR_NONE
rust_uv_helper_uv_async_t_size
rust_uv_helper_uv_timer_t_size
rust_uv_get_stream_handle_from_connect_req
...
...
@@ -142,6 +157,8 @@ rust_uv_get_len_from_buf
rust_uv_get_kernel_global_chan_ptr
rust_uv_current_kernel_malloc
rust_uv_current_kernel_free
rust_uv_getaddrinfo
rust_uv_freeaddrinfo
rust_dbg_lock_create
rust_dbg_lock_destroy
rust_dbg_lock_lock
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录