+struct smbd_open_socket;
+
+struct smbd_parent_context {
+ bool interactive;
+
+ /* the list of listening sockets */
+ struct smbd_open_socket *sockets;
+};
+
+struct smbd_open_socket {
+ struct smbd_open_socket *prev, *next;
+ struct smbd_parent_context *parent;
+ int fd;
+ struct tevent_fd *fde;
+};
+
+static void smbd_open_socket_close_fn(struct tevent_context *ev,
+ struct tevent_fd *fde,
+ int fd,
+ void *private_data)
+{
+ /* this might be the socket_wrapper swrap_close() */
+ close(fd);
+}
+
+static void smbd_accept_connection(struct tevent_context *ev,
+ struct tevent_fd *fde,
+ uint16_t flags,
+ void *private_data)
+{
+ struct smbd_open_socket *s = talloc_get_type_abort(private_data,
+ struct smbd_open_socket);
+ struct sockaddr_storage addr;
+ socklen_t in_addrlen = sizeof(addr);
+ pid_t pid = 0;
+
+ smbd_set_server_fd(accept(s->fd,(struct sockaddr *)&addr,&in_addrlen));
+
+ if (smbd_server_fd() == -1 && errno == EINTR)
+ return;
+
+ if (smbd_server_fd() == -1) {
+ DEBUG(0,("open_sockets_smbd: accept: %s\n",
+ strerror(errno)));
+ return;
+ }
+
+ if (s->parent->interactive) {
+ smbd_process();
+ exit_server_cleanly("end of interactive mode");
+ return;
+ }
+
+ if (!allowable_number_of_smbd_processes()) {
+ close(smbd_server_fd());
+ smbd_set_server_fd(-1);
+ return;
+ }
+
+ pid = sys_fork();
+ if (pid == 0) {
+ /* Child code ... */
+ am_parent = 0;
+
+ /* Stop zombies, the parent explicitly handles
+ * them, counting worker smbds. */
+ CatchChild();
+
+ /* close our standard file
+ descriptors */
+ close_low_fds(False);
+
+ TALLOC_FREE(s->parent);
+ s = NULL;
+
+ if (!reinit_after_fork(
+ smbd_messaging_context(),
+ smbd_event_context(),
+ true)) {
+ DEBUG(0,("reinit_after_fork() failed\n"));
+ smb_panic("reinit_after_fork() failed");
+ }
+
+ smbd_setup_sig_term_handler();
+ smbd_setup_sig_hup_handler();
+
+ smbd_process();
+ exit_server_cleanly("end of child");
+ return;
+ } else if (pid < 0) {
+ DEBUG(0,("smbd_accept_connection: sys_fork() failed: %s\n",
+ strerror(errno)));
+ }
+
+ /* The parent doesn't need this socket */
+ close(smbd_server_fd());
+
+ /* Sun May 6 18:56:14 2001 ackley@cs.unm.edu:
+ Clear the closed fd info out of server_fd --
+ and more importantly, out of client_fd in
+ util_sock.c, to avoid a possible
+ getpeername failure if we reopen the logs
+ and use %I in the filename.
+ */
+
+ smbd_set_server_fd(-1);
+
+ if (pid != 0) {
+ add_child_pid(pid);
+ }
+
+ /* Force parent to check log size after
+ * spawning child. Fix from
+ * klausr@ITAP.Physik.Uni-Stuttgart.De. The
+ * parent smbd will log to logserver.smb. It
+ * writes only two messages for each child
+ * started/finished. But each child writes,
+ * say, 50 messages also in logserver.smb,
+ * begining with the debug_count of the
+ * parent, before the child opens its own log
+ * file logserver.client. In a worst case
+ * scenario the size of logserver.smb would be
+ * checked after about 50*50=2500 messages
+ * (ca. 100kb).
+ * */
+ force_check_log_size();
+}
+
+bool smbd_open_one_socket(struct smbd_parent_context *parent,
+ const struct sockaddr_storage *ifss,
+ uint16_t port)
+{
+ struct smbd_open_socket *s;
+
+ s = talloc(parent, struct smbd_open_socket);
+ if (!s) {
+ return false;
+ }
+
+ s->parent = parent;
+ s->fd = open_socket_in(SOCK_STREAM,
+ port,
+ parent->sockets == NULL ? 0 : 2,
+ ifss,
+ true);
+ if (s->fd == -1) {
+ DEBUG(0,("smbd_open_once_socket: open_socket_in: "
+ "%s\n", strerror(errno)));
+ close(s->fd);
+ TALLOC_FREE(s);
+ return false;
+ }
+
+ /* ready to listen */
+ set_socket_options(s->fd, "SO_KEEPALIVE");
+ set_socket_options(s->fd, lp_socket_options());
+
+ /* Set server socket to
+ * non-blocking for the accept. */
+ set_blocking(s->fd, False);
+
+ if (listen(s->fd, SMBD_LISTEN_BACKLOG) == -1) {
+ DEBUG(0,("open_sockets_smbd: listen: "
+ "%s\n", strerror(errno)));
+ close(s->fd);
+ TALLOC_FREE(s);
+ return false;
+ }
+
+ s->fde = tevent_add_fd(smbd_event_context(),
+ s,
+ s->fd, TEVENT_FD_READ,
+ smbd_accept_connection,
+ s);
+ if (!s->fde) {
+ DEBUG(0,("open_sockets_smbd: "
+ "tevent_add_fd: %s\n",
+ strerror(errno)));
+ close(s->fd);
+ TALLOC_FREE(s);
+ return false;
+ }
+ tevent_fd_set_close_fn(s->fde, smbd_open_socket_close_fn);
+
+ DLIST_ADD_END(parent->sockets, s, struct smbd_open_socket *);
+
+ return true;
+}
+