SshStream ssh_stream_fd_file(const char *filename, Boolean readable, Boolean writable) { SshIOHandle fd; int mode; SshStream stream; SSH_ASSERT(readable || writable); if (readable && writable) mode = O_RDWR; else if (readable) mode = O_RDONLY; else mode = O_WRONLY; fd = open(filename, mode, 0); if (fd < 0) return NULL; /* Create the stream. */ stream = ssh_stream_fd_wrap(fd, TRUE); if (stream == NULL) close(fd); /* Return the stream or NULL if the wrap operation failed. */ return stream; }
void ssh_local_listen_callback(unsigned int events, void *context) { SshLocalListener listener = (SshLocalListener)context; int sock, addrlen; struct sockaddr_un sunaddr; if (events & SSH_IO_READ) { addrlen = sizeof(sunaddr); sock = accept(listener->sock, (struct sockaddr *)&sunaddr, &addrlen); if (sock < 0) { ssh_debug("ssh_local_listen_callback: accept failed"); return; } /* Re-enable requests on the listener. */ ssh_io_set_fd_request(listener->sock, SSH_IO_READ); /* Inform user callback of the new socket. Note that this might destroy the listener. */ (*listener->callback)(ssh_stream_fd_wrap(sock, TRUE), listener->context); } }
void ssh_local_connect_try(unsigned int events, void *context) { SshLocalConnect c = (SshLocalConnect)context; int ret; struct sockaddr_un sunaddr; /* Initialize the address to connect to. */ memset(&sunaddr, 0, sizeof(sunaddr)); sunaddr.sun_family = AF_UNIX; strncpy(sunaddr.sun_path, c->path, sizeof(sunaddr.sun_path)); /* Make a non-blocking connect attempt. */ ret = connect(c->sock, (struct sockaddr *)&sunaddr, AF_UNIX_SIZE(sunaddr)); if (ret >= 0 || errno == EISCONN) /* Connection is ready. */ { /* Successful connection. */ ssh_io_unregister_fd(c->sock, FALSE); (*c->callback)(ssh_stream_fd_wrap(c->sock, TRUE), c->context); ssh_xfree(c->path); ssh_xfree(c); return; } if (errno == EINPROGRESS || errno == EWOULDBLOCK || errno == EALREADY) { /* Connection still in progress. */ ssh_io_set_fd_request(c->sock, SSH_IO_WRITE); return; } /* Connection failed. */ ssh_io_unregister_fd(c->sock, FALSE); close(c->sock); (*c->callback)(NULL, c->context); ssh_xfree(c->path); ssh_xfree(c); }
SshPipeStatus ssh_pipe_create_and_fork(SshStream *stdio_return, SshStream *stderr_return) { int pin[2], pout[2], perr[2]; pid_t pid; SshPipeStream pipes; if (pipe(pin) < 0) return SSH_PIPE_ERROR; if (pipe(pout) < 0) { close(pin[0]); close(pin[1]); return SSH_PIPE_ERROR; } if (stderr_return != NULL && pipe(perr) < 0) { close(pin[0]); close(pin[1]); close(pout[0]); close(pout[1]); return SSH_PIPE_ERROR; } /* Initialize SIGCHLD handling. This will ensure the SIGCHLD won't get delivered until we register the handler for the new process below. */ ssh_sigchld_initialize(); /* Fork a child process. */ pid = fork(); if (pid < 0) { ssh_warning("Fork failed: %s", strerror(errno)); close(pin[0]); close(pin[1]); close(pout[0]); close(pout[1]); if (stderr_return != NULL) { close(perr[0]); close(perr[1]); } return SSH_PIPE_ERROR; } /* The remaining processing depends on whether we are the parent or the child. */ if (pid == 0) { /* Redirect stdin. */ close(pin[1]); if (dup2(pin[0], 0) < 0) perror("dup2 stdin"); close(pin[0]); /* Redirect stdout. */ close(pout[0]); if (dup2(pout[1], 1) < 0) perror("dup2 stdout"); close(pout[1]); if (stderr_return != NULL) { /* Redirect stderr. */ close(perr[0]); if (dup2(perr[1], 2) < 0) perror("dup2 stderr"); close(perr[1]); } *stdio_return = NULL; if (stderr_return != NULL) *stderr_return = NULL; return SSH_PIPE_CHILD_OK; } /* Parent */ pipes = ssh_xcalloc(sizeof(*pipes), 1); pipes->pid = pid; pipes->callback = NULL; pipes->callback_context = NULL; pipes->status_returned = FALSE; pipes->exit_status = -1; /* Close the child-side file descriptors. */ close(pin[0]); close(pout[1]); if (stderr_return != NULL) close(perr[1]); /* Register a handler for SIGCHLD for our new child. */ ssh_sigchld_register(pid, ssh_pipe_sigchld_handler, (void *)pipes); /* Wrap the master fd into a stream. */ pipes->stdio_stream = ssh_stream_fd_wrap2(pout[0], pin[1], TRUE); *stdio_return = ssh_stream_create(&ssh_pipe_methods, (void *) pipes); /* Create the stderr stream if requested. */ /* XXX should another context (errpipes?) be allocated for this, so that this, too, could be created as above?*/ if (stderr_return != NULL) *stderr_return = ssh_stream_fd_wrap(perr[0], TRUE); return SSH_PIPE_PARENT_OK; }