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,20 @@ 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 ( 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+ } ;
144164
145165 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) ?,
147168 #[ cfg( any( target_os = "linux" , target_os = "android" ) ) ]
148169 Domain :: Vsock => {
149170 let ( cid, port) = parse_vscok ( sockaddrv) ?;
@@ -162,18 +183,41 @@ fn make_socket(sockaddr: &str) -> Result<(RawFd, Domain, Box<dyn SockaddrLike>)>
162183 Ok ( ( fd, domain, sockaddr) )
163184}
164185
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+
165207pub ( crate ) fn do_bind ( sockaddr : & str ) -> Result < ( RawFd , Domain ) > {
166208 let ( fd, domain, sockaddr) = make_socket ( sockaddr) ?;
167209
210+ set_socket_opts ( fd, domain, true ) ?;
168211 bind ( fd, sockaddr. as_ref ( ) ) . map_err ( err_to_others_err ! ( e, "" ) ) ?;
169212
170213 Ok ( ( fd, domain) )
171214}
172215
173216/// Creates a unix socket for client.
174217pub ( crate ) unsafe fn client_connect ( sockaddr : & str ) -> Result < RawFd > {
175- let ( fd, _ , sockaddr) = make_socket ( sockaddr) ?;
218+ let ( fd, domain , sockaddr) = make_socket ( sockaddr) ?;
176219
220+ set_socket_opts ( fd, domain, false ) ?;
177221 connect ( fd, sockaddr. as_ref ( ) ) ?;
178222
179223 Ok ( fd)
@@ -202,6 +246,12 @@ mod tests {
202246 true ,
203247 ) ,
204248 ( "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+ ) ,
205255 ] {
206256 let ( input, domain, addr, success) = ( i. 0 , i. 1 , i. 2 , i. 3 ) ;
207257 let r = parse_sockaddr ( input) ;
@@ -229,6 +279,12 @@ mod tests {
229279 ( "Vsock:///run/c.sock" , None , "" , false ) ,
230280 ( "unix://@/run/b.sock" , None , "" , false ) ,
231281 ( "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+ ) ,
232288 ] {
233289 let ( input, domain, addr, success) = ( i. 0 , i. 1 , i. 2 , i. 3 ) ;
234290 let r = parse_sockaddr ( input) ;
0 commit comments