@@ -31,7 +31,7 @@ static SOCKET_PATH: &str = "/tmp/security-daemon-socket";
31
31
///
32
32
/// Only works on Unix systems.
33
33
pub struct DomainSocketListener {
34
- listener : Option < UnixListener > ,
34
+ listener : UnixListener ,
35
35
timeout : Duration ,
36
36
}
37
37
@@ -42,36 +42,39 @@ impl DomainSocketListener {
42
42
/// - if a file/socket exists at the path specified for the socket and `remove_file`
43
43
/// fails
44
44
/// - if binding to the socket path fails
45
- fn init ( & mut self ) {
46
- if cfg ! ( feature = "systemd-daemon" ) {
47
- // The PARSEC service is socket activated (see parsec.socket file).
48
- // systemd creates the PARSEC service giving it an initialised socket as the file
49
- // descriptor number 3 (see sd_listen_fds(3) man page).
50
- // If an instance of PARSEC compiled with the "systemd-daemon" feature is run directly
51
- // instead of by systemd, this call will still work but the next accept call on the
52
- // UnixListener will generate a Linux error 9 (Bad file number), as checked below.
53
- unsafe {
54
- self . listener = Some ( UnixListener :: from_raw_fd ( 3 ) ) ;
55
- }
56
- } else {
57
- let socket = Path :: new ( SOCKET_PATH ) ;
45
+ pub fn new ( timeout : Duration ) -> Self {
46
+ // If this PARSEC instance was socket activated (see the `parsec.socket`
47
+ // file), the listener will be opened by systemd and passed to the
48
+ // process.
49
+ // If PARSEC was service activated or not started under systemd, this
50
+ // will return `0`.
51
+ let listener =
52
+ match sd_notify:: listen_fds ( ) . expect ( "Could not retrieve listener from systemd" ) {
53
+ 0 => {
54
+ let socket = Path :: new ( SOCKET_PATH ) ;
58
55
59
- if socket. exists ( ) {
60
- fs:: remove_file ( & socket) . unwrap ( ) ;
61
- }
56
+ if socket. exists ( ) {
57
+ fs:: remove_file ( & socket) . unwrap ( ) ;
58
+ }
62
59
63
- let listener_val = match UnixListener :: bind ( SOCKET_PATH ) {
64
- Ok ( listener) => listener,
65
- Err ( err) => panic ! ( err) ,
66
- } ;
60
+ let listener =
61
+ UnixListener :: bind ( SOCKET_PATH ) . expect ( "Could not bind listen socket" ) ;
62
+ listener
63
+ . set_nonblocking ( true )
64
+ . expect ( "Could not set the socket as non-blocking" ) ;
67
65
68
- // Set the socket as non-blocking.
69
- listener_val
70
- . set_nonblocking ( true )
71
- . expect ( "Could not set the socket as non-blocking" ) ;
66
+ listener
67
+ }
68
+ 1 => {
69
+ // No need to set the socket as non-blocking, parsec.service
70
+ // already requests that.
71
+ let nfd = sd_notify:: SD_LISTEN_FDS_START ;
72
+ unsafe { UnixListener :: from_raw_fd ( nfd) }
73
+ }
74
+ _ => panic ! ( "Received too many file descriptors" ) ,
75
+ } ;
72
76
73
- self . listener = Some ( listener_val) ;
74
- }
77
+ Self { listener, timeout }
75
78
}
76
79
}
77
80
@@ -81,44 +84,30 @@ impl Listen for DomainSocketListener {
81
84
}
82
85
83
86
fn accept ( & self ) -> Option < Box < dyn ReadWrite + Send > > {
84
- if let Some ( listener) = & self . listener {
85
- let stream_result = listener. accept ( ) ;
86
- match stream_result {
87
- Ok ( ( stream, _) ) => {
88
- if let Err ( err) = stream. set_read_timeout ( Some ( self . timeout ) ) {
89
- error ! ( "Failed to set read timeout ({})" , err) ;
90
- None
91
- } else if let Err ( err) = stream. set_write_timeout ( Some ( self . timeout ) ) {
92
- error ! ( "Failed to set write timeout ({})" , err) ;
93
- None
94
- } else if let Err ( err) = stream. set_nonblocking ( false ) {
95
- error ! ( "Failed to set stream as blocking ({})" , err) ;
96
- None
97
- } else {
98
- Some ( Box :: from ( stream) )
99
- }
100
- }
101
- Err ( err) => {
102
- if cfg ! ( feature = "systemd-daemon" ) {
103
- // When run as a systemd daemon, a file descriptor mapping to the Domain Socket
104
- // should have been passed to this process.
105
- if let Some ( os_error) = err. raw_os_error ( ) {
106
- // On Linux, 9 is EBADF (Bad file number)
107
- if os_error == 9 {
108
- panic ! ( "The Unix Domain Socket file descriptor (number 3) should have been given to this process." ) ;
109
- }
110
- }
111
- }
112
- // Check if the error is because no connections are currently present.
113
- if err. kind ( ) != ErrorKind :: WouldBlock {
114
- // Only log the real errors.
115
- error ! ( "Failed to connect with a UnixStream ({})" , err) ;
116
- }
87
+ let stream_result = self . listener . accept ( ) ;
88
+ match stream_result {
89
+ Ok ( ( stream, _) ) => {
90
+ if let Err ( err) = stream. set_read_timeout ( Some ( self . timeout ) ) {
91
+ error ! ( "Failed to set read timeout ({})" , err) ;
92
+ None
93
+ } else if let Err ( err) = stream. set_write_timeout ( Some ( self . timeout ) ) {
94
+ error ! ( "Failed to set write timeout ({})" , err) ;
117
95
None
96
+ } else if let Err ( err) = stream. set_nonblocking ( false ) {
97
+ error ! ( "Failed to set stream as blocking ({})" , err) ;
98
+ None
99
+ } else {
100
+ Some ( Box :: from ( stream) )
101
+ }
102
+ }
103
+ Err ( err) => {
104
+ // Check if the error is because no connections are currently present.
105
+ if err. kind ( ) != ErrorKind :: WouldBlock {
106
+ // Only log the real errors.
107
+ error ! ( "Failed to connect with a UnixStream ({})" , err) ;
118
108
}
109
+ None
119
110
}
120
- } else {
121
- panic ! ( "The Unix Domain Socket has not been initialised." ) ;
122
111
}
123
112
}
124
113
}
@@ -139,12 +128,7 @@ impl DomainSocketListenerBuilder {
139
128
}
140
129
141
130
pub fn build ( self ) -> DomainSocketListener {
142
- let mut listener = DomainSocketListener {
143
- timeout : self . timeout . expect ( "FrontEndHandler missing" ) ,
144
- listener : None ,
145
- } ;
146
- listener. init ( ) ;
147
-
148
- listener
131
+ let timeout = self . timeout . expect ( "The listener timeout was not set" ) ;
132
+ DomainSocketListener :: new ( timeout)
149
133
}
150
134
}
0 commit comments