@@ -30,7 +30,8 @@ void base_process_service::do_smooth_recovery() noexcept
3030
3131bool base_process_service::bring_up () noexcept
3232{
33- if (!open_socket ()) {
33+ if (!open_socket () || !open_ready_socket ()) {
34+ becoming_inactive ();
3435 return false ;
3536 }
3637
@@ -175,7 +176,7 @@ bool base_process_service::start_ps_process(const std::vector<const char *> &cmd
175176 }
176177 }
177178
178- if (have_notify) {
179+ if (have_notify && ready_socket_fd < 0 ) {
179180 // Create a notification pipe:
180181 if (bp_sys::pipe2 (notify_pipe, 0 ) != 0 ) {
181182 log (loglevel_t ::ERROR, get_name (), " : can't create notification pipe: " , strerror (errno));
@@ -185,10 +186,12 @@ bool base_process_service::start_ps_process(const std::vector<const char *> &cmd
185186 // Set the read side as close-on-exec:
186187 int fdflags = bp_sys::fcntl (notify_pipe[0 ], F_GETFD);
187188 bp_sys::fcntl (notify_pipe[0 ], F_SETFD, fdflags | FD_CLOEXEC);
189+ }
188190
191+ if (have_notify) {
189192 // add, but don't yet enable, readiness watcher:
190193 try {
191- rwatcher->add_watch (event_loop, notify_pipe[0 ], dasynq::IN_EVENTS, false );
194+ rwatcher->add_watch (event_loop, ready_socket_fd >= 0 ? ready_socket_fd : notify_pipe[0 ], dasynq::IN_EVENTS, false );
192195 ready_watcher_registered = true ;
193196 }
194197 catch (std::exception &exc) {
@@ -251,7 +254,7 @@ bool base_process_service::start_ps_process(const std::vector<const char *> &cmd
251254 run_params.unmask_sigint = onstart_flags.unmask_intr ;
252255 run_params.csfd = control_socket[1 ];
253256 run_params.socket_fd = socket_fd;
254- run_params.notify_fd = notify_pipe[1 ];
257+ run_params.notify_fd = ready_socket_fd >= 0 ? ready_socket_fd : notify_pipe[1 ];
255258 run_params.force_notify_fd = force_notification_fd;
256259 run_params.notify_var = notification_var.c_str ();
257260 run_params.env_file = env_file.c_str ();
@@ -469,86 +472,116 @@ void base_process_service::becoming_inactive() noexcept
469472 close (socket_fd);
470473 socket_fd = -1 ;
471474 }
472- }
473-
474- bool base_process_service::open_socket () noexcept
475- {
476- if (socket_path.empty () || socket_fd != -1 ) {
477- // No socket, or already open
478- return true ;
475+ if (ready_socket_fd != -1 ) {
476+ close (ready_socket_fd);
477+ ready_socket_fd = -1 ;
479478 }
479+ free (ready_socket_name);
480+ ready_socket_name = nullptr ;
481+ }
480482
481- const char * saddrname = socket_path. c_str ();
482-
483+ static int open_sock ( const char *path, const std::string &svcname, int type,
484+ uid_t uid, gid_t gid, int perms, struct sockaddr_un *&name) noexcept {
483485 // Check the specified socket path
484486 struct stat stat_buf;
485- if (stat (saddrname , &stat_buf) == 0 ) {
487+ if (stat (path , &stat_buf) == 0 ) {
486488 if ((stat_buf.st_mode & S_IFSOCK) == 0 ) {
487489 // Not a socket
488- log (loglevel_t ::ERROR, get_name () , " : activation socket file exists (and is not a socket)" );
489- return false ;
490+ log (loglevel_t ::ERROR, svcname , " : socket file exists (and is not a socket)" );
491+ return - 1 ;
490492 }
491493 }
492494 else if (errno != ENOENT) {
493495 // Other error
494- log (loglevel_t ::ERROR, get_name () , " : error checking activation socket: " , strerror (errno));
495- return false ;
496+ log (loglevel_t ::ERROR, svcname , " : error checking socket: " , strerror (errno));
497+ return - 1 ;
496498 }
497499
498500 // Remove stale socket file (if it exists).
499501 // We won't test the return from unlink - if it fails other than due to ENOENT, we should get an
500502 // error when we try to create the socket anyway.
501- unlink (saddrname );
503+ unlink (path );
502504
503- uint sockaddr_size = offsetof (struct sockaddr_un , sun_path) + socket_path. length ( ) + 1 ;
504- struct sockaddr_un * name = static_cast <sockaddr_un *>(malloc (sockaddr_size));
505+ uint sockaddr_size = offsetof (struct sockaddr_un , sun_path) + strlen (path ) + 1 ;
506+ name = static_cast <sockaddr_un *>(malloc (sockaddr_size));
505507 if (name == nullptr ) {
506- log (loglevel_t ::ERROR, get_name () , " : opening activation socket: out of memory" );
507- return false ;
508+ log (loglevel_t ::ERROR, svcname , " : opening socket: out of memory" );
509+ return - 1 ;
508510 }
509511
510512 name->sun_family = AF_UNIX;
511- strcpy (name->sun_path , saddrname );
513+ strcpy (name->sun_path , path );
512514
513- int sockfd = dinit_socket (AF_UNIX, SOCK_STREAM , 0 , SOCK_NONBLOCK | SOCK_CLOEXEC);
515+ int sockfd = dinit_socket (AF_UNIX, type , 0 , SOCK_NONBLOCK | SOCK_CLOEXEC);
514516 if (sockfd == -1 ) {
515- log (loglevel_t ::ERROR, get_name () , " : error creating activation socket: " , strerror (errno));
517+ log (loglevel_t ::ERROR, svcname , " : error creating socket: " , strerror (errno));
516518 free (name);
517- return false ;
519+ return - 1 ;
518520 }
519521
520522 if (bind (sockfd, (struct sockaddr *) name, sockaddr_size) == -1 ) {
521- log (loglevel_t ::ERROR, get_name () , " : error binding activation socket: " , strerror (errno));
523+ log (loglevel_t ::ERROR, svcname , " : error binding socket: " , strerror (errno));
522524 close (sockfd);
523525 free (name);
524- return false ;
526+ return - 1 ;
525527 }
526528
527- free (name);
528-
529529 // POSIX (1003.1, 2013) says that fchown and fchmod don't necessarily work on sockets. We have to
530530 // use chown and chmod instead.
531- if (chown (saddrname, socket_uid, socket_gid )) {
532- log (loglevel_t ::ERROR, get_name () , " : error setting activation socket owner/group: " ,
531+ if (chown (path, uid, gid )) {
532+ log (loglevel_t ::ERROR, svcname , " : error setting socket owner/group: " ,
533533 strerror (errno));
534534 close (sockfd);
535- return false ;
535+ return - 1 ;
536536 }
537537
538- if (chmod (saddrname, socket_perms ) == -1 ) {
539- log (loglevel_t ::ERROR, get_name () , " : Error setting activation socket permissions: " ,
538+ if (chmod (path, perms ) == -1 ) {
539+ log (loglevel_t ::ERROR, svcname , " : Error setting socket permissions: " ,
540540 strerror (errno));
541541 close (sockfd);
542- return false ;
542+ return - 1 ;
543543 }
544544
545- if (listen (sockfd, 128 ) == -1 ) { // 128 "seems reasonable".
546- log (loglevel_t ::ERROR, " : error listening on activation socket: " , strerror (errno));
545+ if (type != SOCK_DGRAM && listen (sockfd, 128 ) == -1 ) { // 128 "seems reasonable".
546+ log (loglevel_t ::ERROR, " : error listening on socket: " , strerror (errno));
547547 close (sockfd);
548+ return -1 ;
549+ }
550+
551+ return sockfd;
552+ }
553+
554+ bool base_process_service::open_socket () noexcept
555+ {
556+ if (socket_path.empty () || socket_fd != -1 ) {
557+ // No socket, or already open
558+ return true ;
559+ }
560+
561+ struct sockaddr_un *name = nullptr ;
562+ socket_fd = open_sock (socket_path.c_str (), get_name (), SOCK_STREAM, socket_uid,
563+ socket_gid, socket_perms, name);
564+ free (name);
565+
566+ return socket_fd >= 0 ;
567+ }
568+
569+ bool base_process_service::open_ready_socket () noexcept
570+ {
571+ if (ready_socket_path.empty () || ready_socket_fd != -1 ) {
572+ // No socket, or already open
573+ return true ;
574+ }
575+
576+ ready_socket_fd = open_sock (ready_socket_path.c_str (), get_name (), SOCK_DGRAM,
577+ ready_socket_uid, ready_socket_gid, ready_socket_perms, ready_socket_name);
578+
579+ if (ready_socket_fd < 0 ) {
580+ free (ready_socket_name);
581+ ready_socket_name = nullptr ;
548582 return false ;
549583 }
550584
551- socket_fd = sockfd;
552585 return true ;
553586}
554587
0 commit comments