Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
S
systemd
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Labels
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Commits
Open sidebar
steam
systemd
Commits
6cf6bbc2
Commit
6cf6bbc2
authored
Jun 19, 2010
by
Lennart Poettering
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
socket: enforce limit on number of concurrent connections
parent
a3d4e06d
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
132 additions
and
30 deletions
+132
-30
fixme
fixme
+3
-5
src/load-fragment.c
src/load-fragment.c
+1
-0
src/mount.c
src/mount.c
+2
-2
src/service.c
src/service.c
+55
-13
src/service.h
src/service.h
+2
-1
src/socket.c
src/socket.c
+64
-9
src/socket.h
src/socket.h
+5
-0
No files found.
fixme
View file @
6cf6bbc2
* calendar time support in timer
* enforce max number of concurrent connection limit in sockets.
* complete dbus exposure
* make conf parser work more like .desktop parsers
...
...
@@ -51,11 +49,13 @@
* follow property change dbus spec
* make systemd bus activatable (?)
* pam module
* selinux
* make systemd bus activatable
External:
* systemd-sysvinit as package
...
...
@@ -63,8 +63,6 @@
if [ $PPID -ne 1 && mountpoint /cgroup/systemd ] ; then echo "You suck!" ; fi
* remove MANAGER_SYSTEM
Regularly:
* look for close() vs. close_nointr() vs. close_nointr_nofail()
...
...
src/load-fragment.c
View file @
6cf6bbc2
...
...
@@ -1516,6 +1516,7 @@ static int load_from_path(Unit *u, const char *path) {
{
"SocketMode"
,
config_parse_mode
,
&
u
->
socket
.
socket_mode
,
"Socket"
},
{
"KillMode"
,
config_parse_kill_mode
,
&
u
->
socket
.
kill_mode
,
"Socket"
},
{
"Accept"
,
config_parse_bool
,
&
u
->
socket
.
accept
,
"Socket"
},
{
"MaxConnections"
,
config_parse_unsigned
,
&
u
->
socket
.
max_connections
,
"Socket"
},
EXEC_CONTEXT_CONFIG_ITEMS
(
u
->
socket
.
exec_context
,
"Socket"
),
{
"What"
,
config_parse_string
,
&
u
->
mount
.
parameters_fragment
.
what
,
"Mount"
},
...
...
src/mount.c
View file @
6cf6bbc2
...
...
@@ -645,7 +645,7 @@ static void mount_enter_unmounting(Mount *m, bool success) {
return
;
fail:
log_warning
(
"%s failed to run
umount exectuable
: %s"
,
UNIT
(
m
)
->
meta
.
id
,
strerror
(
-
r
));
log_warning
(
"%s failed to run
'umount' task
: %s"
,
UNIT
(
m
)
->
meta
.
id
,
strerror
(
-
r
));
mount_enter_mounted
(
m
,
false
);
}
...
...
@@ -688,7 +688,7 @@ static void mount_enter_mounting(Mount *m) {
return
;
fail:
log_warning
(
"%s failed to run
mount exectuable
: %s"
,
UNIT
(
m
)
->
meta
.
id
,
strerror
(
-
r
));
log_warning
(
"%s failed to run
'mount' task
: %s"
,
UNIT
(
m
)
->
meta
.
id
,
strerror
(
-
r
));
mount_enter_dead
(
m
,
false
);
}
...
...
src/service.c
View file @
6cf6bbc2
...
...
@@ -157,6 +157,16 @@ static void service_close_socket_fd(Service *s) {
s
->
socket_fd
=
-
1
;
}
static
void
service_connection_unref
(
Service
*
s
)
{
assert
(
s
);
if
(
!
s
->
socket
)
return
;
socket_connection_unref
(
s
->
socket
);
s
->
socket
=
NULL
;
}
static
void
service_done
(
Unit
*
u
)
{
Service
*
s
=
SERVICE
(
u
);
...
...
@@ -190,6 +200,7 @@ static void service_done(Unit *u) {
}
service_close_socket_fd
(
s
);
service_connection_unref
(
s
);
unit_unwatch_timer
(
u
,
&
s
->
timer_watch
);
}
...
...
@@ -800,6 +811,11 @@ static int service_verify(Service *s) {
return
-
EINVAL
;
}
if
(
s
->
exec_command
[
SERVICE_EXEC_START
]
->
command_next
)
{
log_error
(
"%s has more than one ExecStart setting. Refusing."
,
UNIT
(
s
)
->
meta
.
id
);
return
-
EINVAL
;
}
if
(
s
->
type
==
SERVICE_DBUS
&&
!
s
->
bus_name
)
{
log_error
(
"%s is of type D-Bus but no D-Bus service name has been specified. Refusing."
,
UNIT
(
s
)
->
meta
.
id
);
return
-
EINVAL
;
...
...
@@ -993,6 +1009,9 @@ static int service_get_sockets(Service *s, Set **_set) {
assert
(
s
);
assert
(
_set
);
if
(
s
->
socket_fd
>=
0
)
return
0
;
/* Collects all Socket objects that belong to this
* service. Note that a service might have multiple sockets
* via multiple names. */
...
...
@@ -1038,6 +1057,9 @@ static int service_notify_sockets_dead(Service *s) {
assert
(
s
);
if
(
s
->
socket_fd
>=
0
)
return
0
;
/* Notifies all our sockets when we die */
if
((
r
=
service_get_sockets
(
s
,
&
set
))
<
0
)
return
r
;
...
...
@@ -1107,8 +1129,19 @@ static void service_set_state(Service *s, ServiceState state) {
if
(
state
!=
SERVICE_START_PRE
&&
state
!=
SERVICE_START
&&
!
(
state
==
SERVICE_DEAD
&&
UNIT
(
s
)
->
meta
.
job
))
state
!=
SERVICE_START_POST
&&
state
!=
SERVICE_RUNNING
&&
state
!=
SERVICE_RELOAD
&&
state
!=
SERVICE_STOP
&&
state
!=
SERVICE_STOP_SIGTERM
&&
state
!=
SERVICE_STOP_SIGKILL
&&
state
!=
SERVICE_STOP_POST
&&
state
!=
SERVICE_FINAL_SIGTERM
&&
state
!=
SERVICE_FINAL_SIGKILL
&&
!
(
state
==
SERVICE_DEAD
&&
UNIT
(
s
)
->
meta
.
job
))
{
service_close_socket_fd
(
s
);
service_connection_unref
(
s
);
}
if
(
old_state
!=
state
)
log_debug
(
"%s changed %s -> %s"
,
UNIT
(
s
)
->
meta
.
id
,
service_state_to_string
(
old_state
),
service_state_to_string
(
state
));
...
...
@@ -1194,6 +1227,9 @@ static int service_collect_fds(Service *s, int **fds, unsigned *n_fds) {
assert
(
fds
);
assert
(
n_fds
);
if
(
s
->
socket_fd
>=
0
)
return
0
;
if
((
r
=
service_get_sockets
(
s
,
&
set
))
<
0
)
return
r
;
...
...
@@ -1255,7 +1291,7 @@ static int service_spawn(
pid_t
pid
;
int
r
;
int
*
fds
=
NULL
;
int
*
fds
=
NULL
,
*
fdsbuf
=
NULL
;
unsigned
n_fds
=
0
;
char
**
argv
=
NULL
,
**
env
=
NULL
;
...
...
@@ -1263,12 +1299,20 @@ static int service_spawn(
assert
(
c
);
assert
(
_pid
);
if
(
pass_fds
)
{
if
(
pass_fds
||
s
->
exec_context
.
std_input
==
EXEC_INPUT_SOCKET
||
s
->
exec_context
.
std_output
==
EXEC_OUTPUT_SOCKET
||
s
->
exec_context
.
std_error
==
EXEC_OUTPUT_SOCKET
)
{
if
(
s
->
socket_fd
>=
0
)
{
fds
=
&
s
->
socket_fd
;
n_fds
=
1
;
}
else
if
((
r
=
service_collect_fds
(
s
,
&
fds
,
&
n_fds
))
<
0
)
goto
fail
;
}
else
{
if
((
r
=
service_collect_fds
(
s
,
&
fdsbuf
,
&
n_fds
))
<
0
)
goto
fail
;
fds
=
fdsbuf
;
}
}
if
(
timeout
&&
s
->
timeout_usec
)
{
...
...
@@ -1321,12 +1365,8 @@ static int service_spawn(
if
(
r
<
0
)
goto
fail
;
if
(
fds
)
{
if
(
s
->
socket_fd
>=
0
)
service_close_socket_fd
(
s
);
else
free
(
fds
);
}
if
(
fdsbuf
)
free
(
fdsbuf
);
if
((
r
=
unit_watch_pid
(
UNIT
(
s
),
pid
))
<
0
)
/* FIXME: we need to do something here */
...
...
@@ -1756,7 +1796,7 @@ static void service_run_next(Service *s, bool success) {
return
;
fail:
log_warning
(
"%s failed to run
spawn
next task: %s"
,
UNIT
(
s
)
->
meta
.
id
,
strerror
(
-
r
));
log_warning
(
"%s failed to run next task: %s"
,
UNIT
(
s
)
->
meta
.
id
,
strerror
(
-
r
));
if
(
s
->
state
==
SERVICE_START_PRE
)
service_enter_signal
(
s
,
SERVICE_FINAL_SIGTERM
,
false
);
...
...
@@ -2524,7 +2564,7 @@ static void service_bus_query_pid_done(
service_set_main_pid
(
s
,
pid
);
}
int
service_set_socket_fd
(
Service
*
s
,
int
fd
)
{
int
service_set_socket_fd
(
Service
*
s
,
int
fd
,
Socket
*
sock
)
{
assert
(
s
);
assert
(
fd
>=
0
);
...
...
@@ -2543,6 +2583,8 @@ int service_set_socket_fd(Service *s, int fd) {
s
->
socket_fd
=
fd
;
s
->
got_socket_fd
=
true
;
s
->
socket
=
sock
;
return
0
;
}
...
...
src/service.h
View file @
6cf6bbc2
...
...
@@ -137,13 +137,14 @@ struct Service {
RateLimit
ratelimit
;
int
socket_fd
;
struct
Socket
*
socket
;
Watch
timer_watch
;
};
extern
const
UnitVTable
service_vtable
;
int
service_set_socket_fd
(
Service
*
s
,
int
fd
);
int
service_set_socket_fd
(
Service
*
s
,
int
fd
,
struct
Socket
*
socket
);
const
char
*
service_state_to_string
(
ServiceState
i
);
ServiceState
service_state_from_string
(
const
char
*
s
);
...
...
src/socket.c
View file @
6cf6bbc2
...
...
@@ -63,6 +63,8 @@ static void socket_init(Unit *u) {
s
->
directory_mode
=
0755
;
s
->
socket_mode
=
0666
;
s
->
max_connections
=
64
;
exec_context_init
(
&
s
->
exec_context
);
s
->
control_command_id
=
_SOCKET_EXEC_COMMAND_INVALID
;
...
...
@@ -81,6 +83,7 @@ static void socket_unwatch_control_pid(Socket *s) {
static
void
socket_done
(
Unit
*
u
)
{
Socket
*
s
=
SOCKET
(
u
);
SocketPort
*
p
;
Meta
*
i
;
assert
(
s
);
...
...
@@ -108,6 +111,14 @@ static void socket_done(Unit *u) {
s
->
bind_to_device
=
NULL
;
unit_unwatch_timer
(
u
,
&
s
->
timer_watch
);
/* Make sure no service instance refers to us anymore. */
LIST_FOREACH
(
units_per_type
,
i
,
u
->
meta
.
manager
->
units_per_type
[
UNIT_SERVICE
])
{
Service
*
service
=
(
Service
*
)
i
;
if
(
service
->
socket
==
s
)
service
->
socket
=
NULL
;
}
}
static
bool
have_non_accept_socket
(
Socket
*
s
)
{
...
...
@@ -141,6 +152,11 @@ static int socket_verify(Socket *s) {
return
-
EINVAL
;
}
if
(
s
->
accept
&&
s
->
max_connections
<=
0
)
{
log_error
(
"%s's MaxConnection setting too small. Refusing."
,
UNIT
(
s
)
->
meta
.
id
);
return
-
EINVAL
;
}
return
0
;
}
...
...
@@ -307,8 +323,12 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) {
if
(
s
->
accept
)
fprintf
(
f
,
"%sAccepted: %u
\n
"
,
prefix
,
s
->
n_accepted
);
"%sAccepted: %u
\n
"
"%sNConnections: %u
\n
"
"%sMaxConnections: %u
\n
"
,
prefix
,
s
->
n_accepted
,
prefix
,
s
->
n_connections
,
prefix
,
s
->
max_connections
);
LIST_FOREACH
(
port
,
p
,
s
->
ports
)
{
...
...
@@ -734,7 +754,7 @@ static void socket_enter_stop_post(Socket *s, bool success) {
return
;
fail:
log_warning
(
"%s failed to run
stop-post executable
: %s"
,
s
->
meta
.
id
,
strerror
(
-
r
));
log_warning
(
"%s failed to run
'stop-post' task
: %s"
,
s
->
meta
.
id
,
strerror
(
-
r
));
socket_enter_signal
(
s
,
SOCKET_FINAL_SIGTERM
,
false
);
}
...
...
@@ -809,7 +829,7 @@ static void socket_enter_stop_pre(Socket *s, bool success) {
return
;
fail:
log_warning
(
"%s failed to run
stop-pre executable
: %s"
,
s
->
meta
.
id
,
strerror
(
-
r
));
log_warning
(
"%s failed to run
'stop-pre' task
: %s"
,
s
->
meta
.
id
,
strerror
(
-
r
));
socket_enter_stop_post
(
s
,
false
);
}
...
...
@@ -844,7 +864,7 @@ static void socket_enter_start_post(Socket *s) {
if
((
s
->
control_command
=
s
->
exec_command
[
SOCKET_EXEC_START_POST
]))
{
if
((
r
=
socket_spawn
(
s
,
s
->
control_command
,
&
s
->
control_pid
))
<
0
)
{
log_warning
(
"%s failed to run
start-post executable
: %s"
,
s
->
meta
.
id
,
strerror
(
-
r
));
log_warning
(
"%s failed to run
'start-post' task
: %s"
,
s
->
meta
.
id
,
strerror
(
-
r
));
goto
fail
;
}
...
...
@@ -877,7 +897,7 @@ static void socket_enter_start_pre(Socket *s) {
return
;
fail:
log_warning
(
"%s failed to run
start-pre exectuable
: %s"
,
s
->
meta
.
id
,
strerror
(
-
r
));
log_warning
(
"%s failed to run
'start-pre' task
: %s"
,
s
->
meta
.
id
,
strerror
(
-
r
));
socket_enter_dead
(
s
,
false
);
}
...
...
@@ -895,6 +915,12 @@ static void socket_enter_running(Socket *s, int cfd) {
Unit
*
u
;
char
*
prefix
,
*
instance
,
*
name
;
if
(
s
->
n_connections
>=
s
->
max_connections
)
{
log_warning
(
"Too many incoming connections (%u)"
,
s
->
n_connections
);
close_nointr_nofail
(
cfd
);
return
;
}
if
((
r
=
instance_from_socket
(
cfd
,
s
->
n_accepted
++
,
&
instance
))
<
0
)
goto
fail
;
...
...
@@ -919,11 +945,13 @@ static void socket_enter_running(Socket *s, int cfd) {
if
(
r
<
0
)
goto
fail
;
if
((
r
=
service_set_socket_fd
(
SERVICE
(
u
),
cfd
))
<
0
)
if
((
r
=
service_set_socket_fd
(
SERVICE
(
u
),
cfd
,
s
))
<
0
)
goto
fail
;
cfd
=
-
1
;
s
->
n_connections
++
;
if
((
r
=
manager_add_job
(
u
->
meta
.
manager
,
JOB_START
,
u
,
JOB_REPLACE
,
true
,
NULL
))
<
0
)
goto
fail
;
}
...
...
@@ -958,7 +986,7 @@ static void socket_run_next(Socket *s, bool success) {
return
;
fail:
log_warning
(
"%s failed to run
spawn next executable
: %s"
,
s
->
meta
.
id
,
strerror
(
-
r
));
log_warning
(
"%s failed to run
next task
: %s"
,
s
->
meta
.
id
,
strerror
(
-
r
));
if
(
s
->
state
==
SOCKET_START_POST
)
socket_enter_stop_pre
(
s
,
false
);
...
...
@@ -1181,6 +1209,14 @@ static const char *socket_sub_state_to_string(Unit *u) {
return
socket_state_to_string
(
SOCKET
(
u
)
->
state
);
}
static
bool
socket_check_gc
(
Unit
*
u
)
{
Socket
*
s
=
SOCKET
(
u
);
assert
(
u
);
return
s
->
n_connections
>
0
;
}
static
void
socket_fd_event
(
Unit
*
u
,
int
fd
,
uint32_t
events
,
Watch
*
w
)
{
Socket
*
s
=
SOCKET
(
u
);
int
cfd
=
-
1
;
...
...
@@ -1375,7 +1411,10 @@ int socket_collect_fds(Socket *s, int **fds, unsigned *n_fds) {
void
socket_notify_service_dead
(
Socket
*
s
)
{
assert
(
s
);
/* The service is dead. Dang. */
/* The service is dead. Dang!
*
* This is strictly for one-instance-for-all-connections
* services. */
if
(
s
->
state
==
SOCKET_RUNNING
)
{
log_debug
(
"%s got notified about service death."
,
s
->
meta
.
id
);
...
...
@@ -1383,6 +1422,20 @@ void socket_notify_service_dead(Socket *s) {
}
}
void
socket_connection_unref
(
Socket
*
s
)
{
assert
(
s
);
/* The service is dead. Yay!
*
* This is strictly for one-onstance-per-connection
* services. */
assert
(
s
->
n_connections
>
0
);
s
->
n_connections
--
;
log_debug
(
"%s: One connection closed, %u left."
,
s
->
meta
.
id
,
s
->
n_connections
);
}
static
const
char
*
const
socket_state_table
[
_SOCKET_STATE_MAX
]
=
{
[
SOCKET_DEAD
]
=
"dead"
,
[
SOCKET_START_PRE
]
=
"start-pre"
,
...
...
@@ -1429,6 +1482,8 @@ const UnitVTable socket_vtable = {
.
active_state
=
socket_active_state
,
.
sub_state_to_string
=
socket_sub_state_to_string
,
.
check_gc
=
socket_check_gc
,
.
fd_event
=
socket_fd_event
,
.
sigchld_event
=
socket_sigchld_event
,
.
timer_event
=
socket_timer_event
,
...
...
src/socket.h
View file @
6cf6bbc2
...
...
@@ -103,6 +103,8 @@ struct Socket {
bool
accept
;
unsigned
n_accepted
;
unsigned
n_connections
;
unsigned
max_connections
;
bool
failure
;
Watch
timer_watch
;
...
...
@@ -118,6 +120,9 @@ void socket_notify_service_dead(Socket *s);
* any of the sockets of this socket */
int
socket_add_one_mount_link
(
Socket
*
s
,
Mount
*
m
);
/* Called from the service code when a per-connection service ended */
void
socket_connection_unref
(
Socket
*
s
);
extern
const
UnitVTable
socket_vtable
;
const
char
*
socket_state_to_string
(
SocketState
i
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment