8
8
9
9
use nix:: fcntl:: { fcntl, FcntlArg , OFlag } ;
10
10
use nix:: sys:: socket:: * ;
11
- use std:: os:: unix:: io:: RawFd ;
11
+ use std:: str:: FromStr ;
12
+ use std:: { env, os:: unix:: io:: RawFd } ;
12
13
13
14
use crate :: error:: { Error , Result } ;
14
15
15
16
#[ derive( Debug , Clone , Copy , PartialEq ) ]
16
17
pub ( crate ) enum Domain {
17
18
Unix ,
19
+ Tcp ,
18
20
#[ cfg( any( target_os = "linux" , target_os = "android" ) ) ]
19
21
Vsock ,
20
22
}
@@ -39,6 +41,10 @@ fn parse_sockaddr(addr: &str) -> Result<(Domain, &str)> {
39
41
return Ok ( ( Domain :: Vsock , addr) ) ;
40
42
}
41
43
44
+ if let Some ( addr) = addr. strip_prefix ( "tcp://" ) {
45
+ return Ok ( ( Domain :: Tcp , addr) ) ;
46
+ }
47
+
42
48
Err ( Error :: Others ( format ! ( "Scheme {addr:?} is not supported" ) ) )
43
49
}
44
50
@@ -53,6 +59,10 @@ fn parse_sockaddr(addr: &str) -> Result<(Domain, &str)> {
53
59
return Ok ( ( Domain :: Unix , addr) ) ;
54
60
}
55
61
62
+ if let Some ( addr) = addr. strip_prefix ( "tcp://" ) {
63
+ return Ok ( ( Domain :: Tcp , addr) ) ;
64
+ }
65
+
56
66
Err ( Error :: Others ( format ! ( "Scheme {addr:?} is not supported" ) ) )
57
67
}
58
68
@@ -83,8 +93,8 @@ fn make_addr(domain: Domain, sockaddr: &str) -> Result<UnixAddr> {
83
93
UnixAddr :: new ( sockaddr) . map_err ( err_to_others_err ! ( e, "" ) )
84
94
}
85
95
}
86
- Domain :: Vsock => Err ( Error :: Others (
87
- "function make_addr does not support create vsock socket" . to_string ( ) ,
96
+ Domain :: Vsock | Domain :: Tcp => Err ( Error :: Others (
97
+ "function make_addr does not support create vsock/tcp socket" . to_string ( ) ,
88
98
) ) ,
89
99
}
90
100
}
@@ -130,7 +140,7 @@ fn parse_vscok(addr: &str) -> Result<(u32, u32)> {
130
140
fn make_socket ( sockaddr : & str ) -> Result < ( RawFd , Domain , Box < dyn SockaddrLike > ) > {
131
141
let ( domain, sockaddrv) = parse_sockaddr ( sockaddr) ?;
132
142
133
- let get_sock_addr = |domain, sockaddr| -> Result < ( RawFd , Box < dyn SockaddrLike > ) > {
143
+ let get_unix_addr = |domain, sockaddr| -> Result < ( RawFd , Box < dyn SockaddrLike > ) > {
134
144
let fd = socket ( AddressFamily :: Unix , SockType :: Stream , SOCK_CLOEXEC , None )
135
145
. map_err ( |e| Error :: Socket ( e. to_string ( ) ) ) ?;
136
146
@@ -141,9 +151,20 @@ fn make_socket(sockaddr: &str) -> Result<(RawFd, Domain, Box<dyn SockaddrLike>)>
141
151
let sockaddr = make_addr ( domain, sockaddr) ?;
142
152
Ok ( ( fd, Box :: new ( sockaddr) ) )
143
153
} ;
154
+ let get_tcp_addr = |sockaddr : & str | -> Result < ( RawFd , Box < dyn SockaddrLike > ) > {
155
+ let fd = socket ( AddressFamily :: Inet , SockType :: Stream , SOCK_CLOEXEC , None )
156
+ . map_err ( |e| Error :: Socket ( e. to_string ( ) ) ) ?;
157
+
158
+ #[ cfg( target_os = "macos" ) ]
159
+ set_fd_close_exec ( fd) ?;
160
+ let sockaddr = SockaddrIn :: from_str ( sockaddr) . map_err ( err_to_others_err ! ( e, "" ) ) ?;
161
+
162
+ Ok ( ( fd, Box :: new ( sockaddr) ) )
163
+ } ;
144
164
145
165
let ( fd, sockaddr) : ( i32 , Box < dyn SockaddrLike > ) = match domain {
146
- Domain :: Unix => get_sock_addr ( domain, sockaddrv) ?,
166
+ Domain :: Unix => get_unix_addr ( domain, sockaddrv) ?,
167
+ Domain :: Tcp => get_tcp_addr ( sockaddrv) ?,
147
168
#[ cfg( any( target_os = "linux" , target_os = "android" ) ) ]
148
169
Domain :: Vsock => {
149
170
let ( cid, port) = parse_vscok ( sockaddrv) ?;
@@ -162,18 +183,41 @@ fn make_socket(sockaddr: &str) -> Result<(RawFd, Domain, Box<dyn SockaddrLike>)>
162
183
Ok ( ( fd, domain, sockaddr) )
163
184
}
164
185
186
+ fn set_socket_opts ( fd : RawFd , domain : Domain , is_bind : bool ) -> Result < ( ) > {
187
+ if domain != Domain :: Tcp {
188
+ return Ok ( ( ) ) ;
189
+ }
190
+
191
+ if is_bind {
192
+ setsockopt ( fd, sockopt:: ReusePort , & true ) ?;
193
+ }
194
+
195
+ let tcp_nodelay_enabled = match env:: var ( "TTRPC_TCP_NODELAY_ENABLED" ) {
196
+ Ok ( val) if val == "1" || val. eq_ignore_ascii_case ( "true" ) => true ,
197
+ Ok ( val) if val == "0" || val. eq_ignore_ascii_case ( "false" ) => false ,
198
+ _ => false ,
199
+ } ;
200
+ if tcp_nodelay_enabled {
201
+ setsockopt ( fd, sockopt:: TcpNoDelay , & true ) ?;
202
+ }
203
+
204
+ Ok ( ( ) )
205
+ }
206
+
165
207
pub ( crate ) fn do_bind ( sockaddr : & str ) -> Result < ( RawFd , Domain ) > {
166
208
let ( fd, domain, sockaddr) = make_socket ( sockaddr) ?;
167
209
210
+ set_socket_opts ( fd, domain, true ) ?;
168
211
bind ( fd, sockaddr. as_ref ( ) ) . map_err ( err_to_others_err ! ( e, "" ) ) ?;
169
212
170
213
Ok ( ( fd, domain) )
171
214
}
172
215
173
216
/// Creates a unix socket for client.
174
217
pub ( crate ) unsafe fn client_connect ( sockaddr : & str ) -> Result < RawFd > {
175
- let ( fd, _ , sockaddr) = make_socket ( sockaddr) ?;
218
+ let ( fd, domain , sockaddr) = make_socket ( sockaddr) ?;
176
219
220
+ set_socket_opts ( fd, domain, false ) ?;
177
221
connect ( fd, sockaddr. as_ref ( ) ) ?;
178
222
179
223
Ok ( fd)
@@ -202,6 +246,12 @@ mod tests {
202
246
true ,
203
247
) ,
204
248
( "abc:///run/c.sock" , None , "" , false ) ,
249
+ (
250
+ "tcp://127.0.0.1:65500" ,
251
+ Some ( Domain :: Tcp ) ,
252
+ "127.0.0.1:65500" ,
253
+ true ,
254
+ ) ,
205
255
] {
206
256
let ( input, domain, addr, success) = ( i. 0 , i. 1 , i. 2 , i. 3 ) ;
207
257
let r = parse_sockaddr ( input) ;
@@ -229,6 +279,12 @@ mod tests {
229
279
( "Vsock:///run/c.sock" , None , "" , false ) ,
230
280
( "unix://@/run/b.sock" , None , "" , false ) ,
231
281
( "abc:///run/c.sock" , None , "" , false ) ,
282
+ (
283
+ "tcp://127.0.0.1:65500" ,
284
+ Some ( Domain :: Tcp ) ,
285
+ "127.0.0.1:65500" ,
286
+ true ,
287
+ ) ,
232
288
] {
233
289
let ( input, domain, addr, success) = ( i. 0 , i. 1 , i. 2 , i. 3 ) ;
234
290
let r = parse_sockaddr ( input) ;
0 commit comments