static int qio_channel_websock_close(QIOChannel *ioc, Error **errp) { QIOChannelWebsock *wioc = QIO_CHANNEL_WEBSOCK(ioc); return qio_channel_close(wioc->master, errp); }
static int qio_channel_tls_close(QIOChannel *ioc, Error **errp) { QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc); return qio_channel_close(tioc->master, errp); }
static gboolean socket_accept_incoming_migration(QIOChannel *ioc, GIOCondition condition, gpointer opaque) { QIOChannelSocket *sioc; Error *err = NULL; sioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(ioc), &err); if (!sioc) { error_report("could not accept migration connection (%s)", error_get_pretty(err)); goto out; } trace_migration_socket_incoming_accepted(); qio_channel_set_name(QIO_CHANNEL(sioc), "migration-socket-incoming"); migration_channel_process_incoming(migrate_get_current(), QIO_CHANNEL(sioc)); object_unref(OBJECT(sioc)); out: /* Close listening socket as its no longer needed */ qio_channel_close(ioc, NULL); return FALSE; /* unregister */ }
static void test_io_channel(bool async, SocketAddress *listen_addr, SocketAddress *connect_addr, bool passFD) { QIOChannel *src, *dst, *srv; QIOChannelTest *test; if (async) { test_io_channel_setup_async(listen_addr, connect_addr, &srv, &src, &dst); g_assert(!passFD || qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_FD_PASS)); g_assert(!passFD || qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_FD_PASS)); g_assert(qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_SHUTDOWN)); g_assert(qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_SHUTDOWN)); test_io_channel_socket_path_exists(listen_addr, true); test = qio_channel_test_new(); qio_channel_test_run_threads(test, true, src, dst); qio_channel_test_validate(test); test_io_channel_socket_path_exists(listen_addr, true); /* unref without close, to ensure finalize() cleans up */ object_unref(OBJECT(src)); object_unref(OBJECT(dst)); test_io_channel_socket_path_exists(listen_addr, true); object_unref(OBJECT(srv)); test_io_channel_socket_path_exists(listen_addr, false); test_io_channel_setup_async(listen_addr, connect_addr, &srv, &src, &dst); g_assert(!passFD || qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_FD_PASS)); g_assert(!passFD || qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_FD_PASS)); g_assert(qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_SHUTDOWN)); g_assert(qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_SHUTDOWN)); test = qio_channel_test_new(); qio_channel_test_run_threads(test, false, src, dst); qio_channel_test_validate(test); /* close before unref, to ensure finalize copes with already closed */ qio_channel_close(src, &error_abort); qio_channel_close(dst, &error_abort); test_io_channel_socket_path_exists(listen_addr, true); object_unref(OBJECT(src)); object_unref(OBJECT(dst)); test_io_channel_socket_path_exists(listen_addr, true); qio_channel_close(srv, &error_abort); test_io_channel_socket_path_exists(listen_addr, false); object_unref(OBJECT(srv)); test_io_channel_socket_path_exists(listen_addr, false); } else { test_io_channel_setup_sync(listen_addr, connect_addr, &srv, &src, &dst); g_assert(!passFD || qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_FD_PASS)); g_assert(!passFD || qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_FD_PASS)); g_assert(qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_SHUTDOWN)); g_assert(qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_SHUTDOWN)); test_io_channel_socket_path_exists(listen_addr, true); test = qio_channel_test_new(); qio_channel_test_run_threads(test, true, src, dst); qio_channel_test_validate(test); test_io_channel_socket_path_exists(listen_addr, true); /* unref without close, to ensure finalize() cleans up */ object_unref(OBJECT(src)); object_unref(OBJECT(dst)); test_io_channel_socket_path_exists(listen_addr, true); object_unref(OBJECT(srv)); test_io_channel_socket_path_exists(listen_addr, false); test_io_channel_setup_sync(listen_addr, connect_addr, &srv, &src, &dst); g_assert(!passFD || qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_FD_PASS)); g_assert(!passFD || qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_FD_PASS)); g_assert(qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_SHUTDOWN)); g_assert(qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_SHUTDOWN)); test = qio_channel_test_new(); qio_channel_test_run_threads(test, false, src, dst); qio_channel_test_validate(test); test_io_channel_socket_path_exists(listen_addr, true); /* close before unref, to ensure finalize copes with already closed */ qio_channel_close(src, &error_abort); qio_channel_close(dst, &error_abort); test_io_channel_socket_path_exists(listen_addr, true); object_unref(OBJECT(src)); object_unref(OBJECT(dst)); test_io_channel_socket_path_exists(listen_addr, true); qio_channel_close(srv, &error_abort); test_io_channel_socket_path_exists(listen_addr, false); object_unref(OBJECT(srv)); test_io_channel_socket_path_exists(listen_addr, false); } }
// commit input, sending any data to the subprocess. // once input is sent, close input channel and file. // While sending that data, read output and error channels, // buffering up the read data. // once output/error reads EOF, close output/error file (not channel // since output channel has the buffered data). qioerr qio_proc_communicate( const int threadsafe, qio_channel_t* input, qio_channel_t* output, qio_channel_t* error) { qioerr err = 0; int rc = 0; bool do_input; bool do_output; bool do_error; bool input_ready; bool output_ready; bool error_ready; fd_set rfds, wfds, efds; int nfds = 1; int input_fd = -1; int output_fd = -1; int error_fd = -1; if( threadsafe ) { // lock all three channels. // but unlock them immediately and set them to NULL // if they are already closed. if( input ) { err = qio_lock(&input->lock); if( err ) return err; if( qio_channel_isclosed(false, input) ) { qio_unlock(&input->lock); input = NULL; } } if( output ) { err = qio_lock(&output->lock); if( err ) { if( input ) qio_unlock(&input->lock); return err; } if( qio_channel_isclosed(false, output) ) { qio_unlock(&output->lock); output = NULL; } } if( error ) { err = qio_lock(&error->lock); if( err ) { if( input ) qio_unlock(&input->lock); if( output ) qio_unlock(&output->lock); return err; } if( qio_channel_isclosed(false, error) ) { qio_unlock(&error->lock); error = NULL; } } } if( input ) { input_fd = input->file->fd; if( nfds <= input_fd ) nfds = input_fd + 1; } if( output ) { output_fd = output->file->fd; if( nfds <= output_fd ) nfds = output_fd + 1; } if( error ) { error_fd = error->file->fd; if( nfds <= error_fd ) nfds = error_fd + 1; } // Adjust all three pipes to be non-blocking. if( input_fd != -1 ) { rc = fcntl(input_fd, F_SETFL, O_NONBLOCK); if( rc == -1 ) { err = qio_int_to_err(errno); } } if( output_fd != -1 ) { rc = fcntl(output_fd, F_SETFL, O_NONBLOCK); if( rc == -1 ) { err = qio_int_to_err(errno); } } if( error_fd != -1 ) { rc = fcntl(error_fd, F_SETFL, O_NONBLOCK); if( rc == -1 ) { err = qio_int_to_err(errno); } } // mark the output and error channels so that we // can just keep advancing to read while buffering // up all data. Before returning, we'll revert them // so that this buffered data can be read again and // update end_pos so that the channel knows not to // call read again. Then, we can close the file // descriptor. if( output ) { qio_channel_mark(false, output); } if( error ) { qio_channel_mark(false, error); } do_input = (input != NULL); do_output = (output != NULL); do_error = (error != NULL); while( do_input || do_output || do_error ) { // Now call select to wait for one of the descriptors to // become ready. FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds); if( do_input && input_fd != -1 ) { FD_SET(input_fd, &wfds); FD_SET(input_fd, &efds); } if( do_output && output_fd != -1 ) { FD_SET(output_fd, &rfds); FD_SET(output_fd, &efds); } if( do_error && error_fd != -1 ) { FD_SET(error_fd, &rfds); FD_SET(error_fd, &efds); } input_ready = false; output_ready = false; error_ready = false; // Run select to wait for something if( do_input || do_output || do_error ) { // TODO -- use sys_select so threading can interact struct timeval t; t.tv_sec = 0; t.tv_usec = 10; rc = select(nfds, &rfds, &wfds, &efds, &t); if (rc > 0) { // read ready file descriptors input_ready = input_fd != -1 && FD_ISSET(input_fd, &wfds); output_ready = output_fd != -1 && FD_ISSET(output_fd, &rfds); error_ready = error_fd != -1 && FD_ISSET(error_fd, &rfds); } // Ignore EAGAIN and EINTR if (rc == EAGAIN || rc == EINTR) rc = 0; } if( rc == -1 ) { err = qio_int_to_err(errno); break; } if( do_input && input_ready ) { err = _qio_channel_flush_qio_unlocked(input); if( !err ) { do_input = false; // Close input channel. err = qio_channel_close(false, input); } if( qio_err_to_int(err) == EAGAIN ) err = 0; if( err ) break; } if( do_output && output_ready ) { // read some into our buffer. err = qio_channel_advance(false, output, qbytes_iobuf_size); if( qio_err_to_int(err) == EEOF ) { qio_file_t* output_file = qio_channel_get_file(output); do_output = false; // close the output file (not channel), in case closing output // causes the program to output on stderr, e.g. if( output_file ) err = qio_file_close(output_file); // Set the output channel maximum position // This prevents a read on output from trying to get // more data from the (now closed) file. output->end_pos = qio_channel_offset_unlocked(output); } if( qio_err_to_int(err) == EAGAIN ) err = 0; if( err ) break; } if( do_error && error_ready ) { // read some into our buffer. err = qio_channel_advance(false, error, qbytes_iobuf_size); if( qio_err_to_int(err) == EEOF ) { qio_file_t* error_file = qio_channel_get_file(error); do_error = false; // close the error file (not channel) if( error_file ) err = qio_file_close(error_file); // Set the error channel maximum position error->end_pos = qio_channel_offset_unlocked(error); } if( qio_err_to_int(err) == EAGAIN ) err = 0; if( err ) break; } chpl_task_yield(); } // we could close the file descriptors at this point, // but we don't because we don't want to modify // the file descriptor of the file since it's // constant (and not protected by file's lock). // The pipes will be closed when the channels are destroyed. // We marked the output and error channels so that we // can just keep advancing to read while buffering // up all data. Before returning, we'll revert them // so that this buffered data can be read again and // update end_pos so that the channel knows not to // call read again. Then, we can close the file // descriptor. // revert the output and error channels if( output) qio_channel_revert_unlocked(output); if( error ) qio_channel_revert_unlocked(error); if( threadsafe ) { // unlock all three channels. if( error ) qio_unlock(&error->lock); if( output ) qio_unlock(&output->lock); if( input ) qio_unlock(&input->lock); } return err; }