SshStream ssh_stream_fd_wrap2(SshIOHandle readfd, SshIOHandle writefd, Boolean close_on_destroy) { SshFdStream sdata; SshStream str; sdata = ssh_malloc(sizeof(*sdata)); if (sdata == NULL) return NULL; memset(sdata, 0, sizeof(*sdata)); sdata->readfd = readfd; sdata->writefd = writefd; sdata->close_on_destroy = close_on_destroy; sdata->read_has_failed = FALSE; sdata->write_has_failed = FALSE; sdata->destroyed = FALSE; sdata->keep_nonblocking = FALSE; sdata->callback = NULL_FNPTR; if (readfd >= 0) { if (ssh_io_register_fd(readfd, ssh_stream_fd_callback, (void *)sdata) == FALSE ) { ssh_free(sdata); return NULL; } } if (readfd != writefd && writefd >= 0) { if (ssh_io_register_fd(writefd, ssh_stream_fd_callback, (void *)sdata) == FALSE ) { if (readfd >= 0) ssh_io_unregister_fd(readfd,TRUE); ssh_free(sdata); return NULL; } } str = ssh_stream_create(&ssh_stream_fd_methods, (void *)sdata); if (str == NULL) { ssh_free(sdata); if (readfd >= 0) ssh_io_unregister_fd(readfd, TRUE); if (readfd != writefd && writefd >= 0) ssh_io_unregister_fd(writefd, TRUE); return NULL; } return str; }
SshStream ssh_packet_impl_create(SshPacketReceiveProc received_packet, SshPacketEofProc received_eof, SshPacketCanSendProc can_send, SshPacketImplDestroyProc destroy, void *context) { SshPacketImpl up; SshStream stream; /* Allocate and initialize the context. */ if ((up = ssh_calloc(1, sizeof(*up))) == NULL) return NULL; ssh_buffer_init(&up->incoming); ssh_buffer_init(&up->outgoing); ssh_buffer_init(&up->outgoing_packet); up->can_receive = FALSE; up->incoming_eof = FALSE; up->outgoing_eof = FALSE; up->up_write_blocked = FALSE; up->up_read_blocked = FALSE; up->send_blocked = TRUE; /* Cause a callback immediately. */ /* Save the callback functions. */ up->received_packet = received_packet; up->received_eof = received_eof; up->can_send = can_send; up->destroy = destroy; up->context = context; up->up_callback = NULL_FNPTR; up->up_context = NULL; /* Cause the send callback to be called if non-NULL. Note that it isn't called until from the bottom of the event loop. */ ssh_packet_impl_restart_send(up); /* Wrap it into a stream. */ stream = ssh_stream_create(&ssh_packet_impl_methods, (void *)up); if (stream == NULL) ssh_fatal("Insufficient memory to create packet stream object!"); /* Enable receives. */ ssh_packet_impl_can_receive(stream, TRUE); return stream; }
SshStream ssh_stream_fd_wrap2(int readfd, int writefd, Boolean close_on_destroy) { SshFdStream sdata; sdata = ssh_xmalloc(sizeof(*sdata)); memset(sdata, 0, sizeof(*sdata)); sdata->readfd = readfd; sdata->writefd = writefd; sdata->close_on_destroy = close_on_destroy; sdata->read_has_failed = FALSE; sdata->write_has_failed = FALSE; sdata->destroyed = FALSE; sdata->in_callback = FALSE; sdata->keep_nonblocking = FALSE; sdata->callback = NULL; if (readfd >= 0) ssh_io_register_fd(readfd, ssh_stream_fd_callback, (void *)sdata); if (readfd != writefd && writefd >= 0) ssh_io_register_fd(writefd, ssh_stream_fd_callback, (void *)sdata); return ssh_stream_create(&ssh_stream_fd_methods, (void *)sdata); }
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; }