88
99use nix:: fcntl:: { fcntl, FcntlArg , OFlag } ;
1010use nix:: sys:: socket:: * ;
11- use std:: os:: unix:: io:: RawFd ;
11+ use std:: str:: FromStr ;
12+ use std:: { env, os:: unix:: io:: RawFd } ;
1213
1314use crate :: error:: { Error , Result } ;
1415
1516#[ derive( Debug , Clone , Copy , PartialEq ) ]
1617pub ( crate ) enum Domain {
1718 Unix ,
19+ Tcp ,
1820 #[ cfg( any( target_os = "linux" , target_os = "android" ) ) ]
1921 Vsock ,
2022}
@@ -39,6 +41,10 @@ fn parse_sockaddr(addr: &str) -> Result<(Domain, &str)> {
3941 return Ok ( ( Domain :: Vsock , addr) ) ;
4042 }
4143
44+ if let Some ( addr) = addr. strip_prefix ( "tcp://" ) {
45+ return Ok ( ( Domain :: Tcp , addr) ) ;
46+ }
47+
4248 Err ( Error :: Others ( format ! ( "Scheme {addr:?} is not supported" ) ) )
4349}
4450
@@ -53,6 +59,10 @@ fn parse_sockaddr(addr: &str) -> Result<(Domain, &str)> {
5359 return Ok ( ( Domain :: Unix , addr) ) ;
5460 }
5561
62+ if let Some ( addr) = addr. strip_prefix ( "tcp://" ) {
63+ return Ok ( ( Domain :: Tcp , addr) ) ;
64+ }
65+
5666 Err ( Error :: Others ( format ! ( "Scheme {addr:?} is not supported" ) ) )
5767}
5868
@@ -83,8 +93,8 @@ fn make_addr(domain: Domain, sockaddr: &str) -> Result<UnixAddr> {
8393 UnixAddr :: new ( sockaddr) . map_err ( err_to_others_err ! ( e, "" ) )
8494 }
8595 }
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 ( ) ,
8898 ) ) ,
8999 }
90100}
@@ -130,7 +140,7 @@ fn parse_vscok(addr: &str) -> Result<(u32, u32)> {
130140fn make_socket ( sockaddr : & str ) -> Result < ( RawFd , Domain , Box < dyn SockaddrLike > ) > {
131141 let ( domain, sockaddrv) = parse_sockaddr ( sockaddr) ?;
132142
133- let get_sock_addr = |domain, sockaddr| -> Result < ( RawFd , Box < dyn SockaddrLike > ) > {
143+ let get_unix_addr = |domain, sockaddr| -> Result < ( RawFd , Box < dyn SockaddrLike > ) > {
134144 let fd = socket ( AddressFamily :: Unix , SockType :: Stream , SOCK_CLOEXEC , None )
135145 . map_err ( |e| Error :: Socket ( e. to_string ( ) ) ) ?;
136146
@@ -141,9 +151,25 @@ fn make_socket(sockaddr: &str) -> Result<(RawFd, Domain, Box<dyn SockaddrLike>)>
141151 let sockaddr = make_addr ( domain, sockaddr) ?;
142152 Ok ( ( fd, Box :: new ( sockaddr) ) )
143153 } ;
154+ let get_tcp_addr = |sockaddr : & str | -> Result < ( RawFd , Box < dyn SockaddrLike > ) > {
155+ let fd = socket (
156+ AddressFamily :: Inet ,
157+ SockType :: Stream ,
158+ SockFlag :: SOCK_CLOEXEC ,
159+ None ,
160+ )
161+ . map_err ( |e| Error :: Socket ( e. to_string ( ) ) ) ?;
162+
163+ #[ cfg( target_os = "macos" ) ]
164+ set_fd_close_exec ( fd) ?;
165+ let sockaddr = SockaddrIn :: from_str ( sockaddr) . map_err ( err_to_others_err ! ( e, "" ) ) ?;
166+
167+ Ok ( ( fd, Box :: new ( sockaddr) ) )
168+ } ;
144169
145170 let ( fd, sockaddr) : ( i32 , Box < dyn SockaddrLike > ) = match domain {
146- Domain :: Unix => get_sock_addr ( domain, sockaddrv) ?,
171+ Domain :: Unix => get_unix_addr ( domain, sockaddrv) ?,
172+ Domain :: Tcp => get_tcp_addr ( sockaddrv) ?,
147173 #[ cfg( any( target_os = "linux" , target_os = "android" ) ) ]
148174 Domain :: Vsock => {
149175 let ( cid, port) = parse_vscok ( sockaddrv) ?;
@@ -162,18 +188,41 @@ fn make_socket(sockaddr: &str) -> Result<(RawFd, Domain, Box<dyn SockaddrLike>)>
162188 Ok ( ( fd, domain, sockaddr) )
163189}
164190
191+ fn set_socket_opts ( fd : RawFd , domain : Domain , is_bind : bool ) -> Result < ( ) > {
192+ if domain != Domain :: Tcp {
193+ return Ok ( ( ) ) ;
194+ }
195+
196+ if is_bind {
197+ setsockopt ( fd, sockopt:: ReusePort , & true ) ?;
198+ }
199+
200+ let tcp_nodelay_enabled = match env:: var ( "TTRPC_TCP_NODELAY_ENABLED" ) {
201+ Ok ( val) if val == "1" || val. eq_ignore_ascii_case ( "true" ) => true ,
202+ Ok ( val) if val == "0" || val. eq_ignore_ascii_case ( "false" ) => false ,
203+ _ => false ,
204+ } ;
205+ if tcp_nodelay_enabled {
206+ setsockopt ( fd, sockopt:: TcpNoDelay , & true ) ?;
207+ }
208+
209+ Ok ( ( ) )
210+ }
211+
165212pub ( crate ) fn do_bind ( sockaddr : & str ) -> Result < ( RawFd , Domain ) > {
166213 let ( fd, domain, sockaddr) = make_socket ( sockaddr) ?;
167214
215+ set_socket_opts ( fd, domain, true ) ?;
168216 bind ( fd, sockaddr. as_ref ( ) ) . map_err ( err_to_others_err ! ( e, "" ) ) ?;
169217
170218 Ok ( ( fd, domain) )
171219}
172220
173221/// Creates a unix socket for client.
174222pub ( crate ) unsafe fn client_connect ( sockaddr : & str ) -> Result < RawFd > {
175- let ( fd, _ , sockaddr) = make_socket ( sockaddr) ?;
223+ let ( fd, domain , sockaddr) = make_socket ( sockaddr) ?;
176224
225+ set_socket_opts ( fd, domain, false ) ?;
177226 connect ( fd, sockaddr. as_ref ( ) ) ?;
178227
179228 Ok ( fd)
@@ -202,6 +251,12 @@ mod tests {
202251 true ,
203252 ) ,
204253 ( "abc:///run/c.sock" , None , "" , false ) ,
254+ (
255+ "tcp://127.0.0.1:65500" ,
256+ Some ( Domain :: Tcp ) ,
257+ "127.0.0.1:65500" ,
258+ true ,
259+ ) ,
205260 ] {
206261 let ( input, domain, addr, success) = ( i. 0 , i. 1 , i. 2 , i. 3 ) ;
207262 let r = parse_sockaddr ( input) ;
@@ -229,6 +284,12 @@ mod tests {
229284 ( "Vsock:///run/c.sock" , None , "" , false ) ,
230285 ( "unix://@/run/b.sock" , None , "" , false ) ,
231286 ( "abc:///run/c.sock" , None , "" , false ) ,
287+ (
288+ "tcp://127.0.0.1:65500" ,
289+ Some ( Domain :: Tcp ) ,
290+ "127.0.0.1:65500" ,
291+ true ,
292+ ) ,
232293 ] {
233294 let ( input, domain, addr, success) = ( i. 0 , i. 1 , i. 2 , i. 3 ) ;
234295 let r = parse_sockaddr ( input) ;
0 commit comments