static gboolean do_console_raw_console_write(GObject *stream, gpointer opaque) { GUnixOutputStream *consoleOutput = G_UNIX_OUTPUT_STREAM(stream); GVirSandboxConsoleRaw *console = GVIR_SANDBOX_CONSOLE_RAW(opaque); GVirSandboxConsoleRawPrivate *priv = console->priv; GError *err = NULL; gssize ret = g_pollable_output_stream_write_nonblocking (G_POLLABLE_OUTPUT_STREAM(consoleOutput), priv->consoleToLocal, priv->consoleToLocalOffset, NULL, &err); if (ret < 0) { g_debug("Error from console write %s", err ? err->message : ""); do_console_raw_close(console, err); g_error_free(err); goto cleanup; } if (priv->consoleToLocalOffset != ret) memmove(priv->consoleToLocal, priv->consoleToLocal + ret, priv->consoleToLocalOffset - ret); priv->consoleToLocalOffset -= ret; priv->consoleOutputSource = NULL; do_console_raw_update_events(console); cleanup: return FALSE; }
int SocketStreamHandle::platformSend(const char* data, int length) { GOwnPtr<GError> error; gssize written = g_pollable_output_stream_write_nonblocking(m_outputStream.get(), data, length, 0, &error.outPtr()); if (error) { if (g_error_matches(error.get(), G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) beginWaitingForSocketWritability(); else m_client->didFailSocketStream(this, SocketStreamError(error->code, error->message)); return 0; } // If we did not send all the bytes we were given, we know that // SocketStreamHandleBase will need to send more in the future. if (written < length) beginWaitingForSocketWritability(); return written; }
/** * g_pollable_stream_write: * @stream: a #GOutputStream. * @buffer: (array length=count) (element-type guint8): the buffer * containing the data to write. * @count: the number of bytes to write * @blocking: whether to do blocking I/O * @cancellable: (allow-none): optional #GCancellable object, %NULL to ignore. * @error: location to store the error occurring, or %NULL to ignore * * Tries to write to @stream, as with g_output_stream_write() (if * @blocking is %TRUE) or g_pollable_output_stream_write_nonblocking() * (if @blocking is %FALSE). This can be used to more easily share * code between blocking and non-blocking implementations of a method. * * If @blocking is %FALSE, then @stream must be a * #GPollableOutputStream for which * g_pollable_output_stream_can_poll() returns %TRUE or else the * behavior is undefined. If @blocking is %TRUE, then @stream does not * need to be a #GPollableOutputStream. * * Returns: the number of bytes written, or -1 on error. * * Since: 2.34 */ gssize g_pollable_stream_write (GOutputStream *stream, const void *buffer, gsize count, gboolean blocking, GCancellable *cancellable, GError **error) { if (blocking) { return g_output_stream_write (stream, buffer, count, cancellable, error); } else { return g_pollable_output_stream_write_nonblocking (G_POLLABLE_OUTPUT_STREAM (stream), buffer, count, cancellable, error); } }
static void test_zero_length_reads_writes (NiceAddress *addr) { NiceAgent *agent; guint stream_id; GIOStream *io_stream; GInputStream *input_stream; GOutputStream *output_stream; GPollableInputStream *pollable_input_stream; GPollableOutputStream *pollable_output_stream; GError *error = NULL; guint8 buf[1]; /* should never be accessed */ agent = nice_agent_new_reliable (NULL, NICE_COMPATIBILITY_RFC5245); nice_agent_add_local_address (agent, addr); /* Add a stream. */ stream_id = nice_agent_add_stream (agent, 1); /* Try building an I/O stream around it. */ io_stream = nice_agent_get_io_stream (agent, stream_id, 1); g_assert (G_IS_IO_STREAM (io_stream)); g_assert (NICE_IS_IO_STREAM (io_stream)); input_stream = g_io_stream_get_input_stream (G_IO_STREAM (io_stream)); output_stream = g_io_stream_get_output_stream (G_IO_STREAM (io_stream)); pollable_input_stream = G_POLLABLE_INPUT_STREAM (input_stream); pollable_output_stream = G_POLLABLE_OUTPUT_STREAM (output_stream); /* Check zero-length reads and writes complete immediately without error. */ g_assert (g_input_stream_read (input_stream, buf, 0, NULL, &error) == 0); g_assert_no_error (error); g_assert (g_output_stream_write (output_stream, buf, 0, NULL, &error) == 0); g_assert_no_error (error); g_assert ( g_pollable_input_stream_read_nonblocking (pollable_input_stream, buf, 0, NULL, &error) == 0); g_assert_no_error (error); g_assert ( g_pollable_output_stream_write_nonblocking (pollable_output_stream, buf, 0, NULL, &error) == 0); g_assert_no_error (error); /* Remove the component and check that zero-length reads and writes still * result in a 0 response, rather than any error. */ nice_agent_remove_stream (agent, stream_id); g_assert (g_io_stream_is_closed (G_IO_STREAM (io_stream))); g_assert (g_input_stream_read (input_stream, buf, 0, NULL, &error) == 0); g_assert_no_error (error); g_assert (g_output_stream_write (output_stream, buf, 0, NULL, &error) == 0); g_assert_no_error (error); g_assert ( g_pollable_input_stream_read_nonblocking (pollable_input_stream, buf, 0, NULL, &error) == 0); g_assert_no_error (error); g_assert ( g_pollable_output_stream_write_nonblocking (pollable_output_stream, buf, 0, NULL, &error) == 0); g_assert_no_error (error); g_object_unref (io_stream); g_object_unref (agent); }
static void test_pollable_cancellation (NiceAddress *addr) { NiceAgent *agent; guint stream_id; GIOStream *io_stream; GInputStream *input_stream; GOutputStream *output_stream; GPollableInputStream *pollable_input_stream; GPollableOutputStream *pollable_output_stream; guint8 buf[65536]; GError *error = NULL; GSource *stream_source; GCancellable *cancellable; agent = nice_agent_new_reliable (NULL, NICE_COMPATIBILITY_RFC5245); nice_agent_add_local_address (agent, addr); /* Add a stream. */ stream_id = nice_agent_add_stream (agent, 1); /* Try building an I/O stream around it. */ io_stream = nice_agent_get_io_stream (agent, stream_id, 1); g_assert (G_IS_IO_STREAM (io_stream)); g_assert (NICE_IS_IO_STREAM (io_stream)); /* Grab the input and output streams. */ input_stream = g_io_stream_get_input_stream (G_IO_STREAM (io_stream)); g_assert (G_IS_POLLABLE_INPUT_STREAM (input_stream)); pollable_input_stream = G_POLLABLE_INPUT_STREAM (input_stream); output_stream = g_io_stream_get_output_stream (G_IO_STREAM (io_stream)); g_assert (G_IS_POLLABLE_OUTPUT_STREAM (output_stream)); pollable_output_stream = G_POLLABLE_OUTPUT_STREAM (output_stream); /* Check the non-blocking read() and write() return immediately if called with * a cancelled cancellable. */ cancellable = g_cancellable_new (); g_cancellable_cancel (cancellable); g_assert ( g_pollable_input_stream_read_nonblocking (pollable_input_stream, buf, sizeof (buf), cancellable, &error) == -1); g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED); g_clear_error (&error); g_assert ( g_pollable_output_stream_write_nonblocking (pollable_output_stream, buf, sizeof (buf), cancellable, &error) == -1); g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED); g_clear_error (&error); g_object_unref (cancellable); /* Check the GSources invoke a callback when run with the cancellable * cancelled. */ cancellable = g_cancellable_new (); stream_source = g_pollable_input_stream_create_source (pollable_input_stream, cancellable); check_pollable_source_cancellation (stream_source, cancellable); g_source_unref (stream_source); g_object_unref (cancellable); /* And for the output stream. */ cancellable = g_cancellable_new (); stream_source = g_pollable_output_stream_create_source (pollable_output_stream, cancellable); check_pollable_source_cancellation (stream_source, cancellable); g_object_unref (io_stream); g_source_unref (stream_source); g_object_unref (cancellable); g_object_unref (agent); }
static void test_pollable_properties (NiceAddress *addr) { NiceAgent *agent; guint stream_id; GIOStream *io_stream; GInputStream *input_stream; GOutputStream *output_stream; GPollableInputStream *pollable_input_stream; GPollableOutputStream *pollable_output_stream; guint8 buf[65536]; GError *error = NULL; GSource *stream_source; agent = nice_agent_new_reliable (NULL, NICE_COMPATIBILITY_RFC5245); nice_agent_add_local_address (agent, addr); /* Add a stream. */ stream_id = nice_agent_add_stream (agent, 1); /* Try building an I/O stream around it. */ io_stream = nice_agent_get_io_stream (agent, stream_id, 1); g_assert (G_IS_IO_STREAM (io_stream)); g_assert (NICE_IS_IO_STREAM (io_stream)); /* Check the input stream’s properties. */ input_stream = g_io_stream_get_input_stream (G_IO_STREAM (io_stream)); g_assert (G_IS_POLLABLE_INPUT_STREAM (input_stream)); pollable_input_stream = G_POLLABLE_INPUT_STREAM (input_stream); g_assert (g_pollable_input_stream_can_poll (pollable_input_stream)); g_assert (!g_pollable_input_stream_is_readable (pollable_input_stream)); g_assert ( g_pollable_input_stream_read_nonblocking (pollable_input_stream, buf, sizeof (buf), NULL, &error) == -1); g_assert_error (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK); g_clear_error (&error); stream_source = g_pollable_input_stream_create_source (pollable_input_stream, NULL); g_assert (stream_source != NULL); g_source_unref (stream_source); /* Check the output stream’s properties. */ output_stream = g_io_stream_get_output_stream (G_IO_STREAM (io_stream)); g_assert (G_IS_POLLABLE_OUTPUT_STREAM (output_stream)); pollable_output_stream = G_POLLABLE_OUTPUT_STREAM (output_stream); g_assert (g_pollable_output_stream_can_poll (pollable_output_stream)); g_assert (!g_pollable_output_stream_is_writable (pollable_output_stream)); g_assert ( g_pollable_output_stream_write_nonblocking (pollable_output_stream, buf, sizeof (buf), NULL, &error) == -1); g_assert_error (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK); g_clear_error (&error); stream_source = g_pollable_output_stream_create_source (pollable_output_stream, NULL); g_assert (stream_source != NULL); g_source_unref (stream_source); /* Remove the component and check that the I/O streams close. */ nice_agent_remove_stream (agent, stream_id); g_assert (!g_pollable_input_stream_is_readable (pollable_input_stream)); g_assert (!g_pollable_output_stream_is_writable (pollable_output_stream)); g_assert ( g_pollable_input_stream_read_nonblocking (pollable_input_stream, buf, sizeof (buf), NULL, &error) == 0); g_assert_no_error (error); g_assert ( g_pollable_output_stream_write_nonblocking (pollable_output_stream, buf, sizeof (buf), NULL, &error) == -1); g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CLOSED); g_clear_error (&error); g_object_unref (io_stream); g_object_unref (agent); }
static gboolean dispatch_output (GPollableOutputStream *os, gpointer user_data) { CockpitStream *self = (CockpitStream *)user_data; GError *error = NULL; const gint8 *data; gsize len; gssize ret; g_return_val_if_fail (self->priv->out_source, FALSE); while (self->priv->out_queue->head) { data = g_bytes_get_data (self->priv->out_queue->head->data, &len); g_assert (self->priv->out_partial <= len); ret = g_pollable_output_stream_write_nonblocking (os, data + self->priv->out_partial, len - self->priv->out_partial, NULL, &error); if (ret < 0) { if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) { g_debug ("%s: output would block", self->priv->name); g_error_free (error); return TRUE; } else { set_problem_from_error (self, "couldn't write", error); g_error_free (error); close_immediately (self, NULL); return FALSE; } } self->priv->out_partial += ret; if (self->priv->out_partial >= len) { g_debug ("%s: wrote %d bytes", self->priv->name, (int)len); g_bytes_unref (g_queue_pop_head (self->priv->out_queue)); self->priv->out_partial = 0; } else { if (ret > 0) g_debug ("%s: partial write %d of %d bytes", self->priv->name, (int)ret, (int)len); return TRUE; } } g_debug ("%s: output queue empty", self->priv->name); /* If all messages are done, then stop polling out fd */ stop_output (self); if (self->priv->closing) close_output (self); else close_maybe (self); return TRUE; }
static gboolean on_response_output (GObject *pollable, gpointer user_data) { CockpitWebResponse *self = user_data; GError *error = NULL; const guint8 *data; GBytes *block; gssize count; gsize len; block = g_queue_peek_head (self->queue); if (block) { data = g_bytes_get_data (block, &len); g_assert (len == 0 || self->partial_offset < len); data += self->partial_offset; len -= self->partial_offset; if (len > 0) { count = g_pollable_output_stream_write_nonblocking (self->out, data, len, NULL, &error); } else { count = 0; } if (count < 0) { if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) { g_error_free (error); return TRUE; } if (!cockpit_web_should_suppress_output_error (self->logname, error)) g_message ("%s: couldn't write web output: %s", self->logname, error->message); self->failed = TRUE; cockpit_web_response_done (self); g_error_free (error); return FALSE; } if (count == len) { g_debug ("%s: sent %d bytes", self->logname, (int)len); self->partial_offset = 0; g_queue_pop_head (self->queue); g_bytes_unref (block); } else { g_debug ("%s: sent %d partial", self->logname, (int)count); g_assert (count < len); self->partial_offset += count; } return TRUE; } else { g_source_destroy (self->source); g_source_unref (self->source); self->source = NULL; if (self->complete) { g_debug ("%s: complete flushing output", self->logname); g_output_stream_flush_async (G_OUTPUT_STREAM (self->out), G_PRIORITY_DEFAULT, NULL, on_output_flushed, g_object_ref (self)); } return FALSE; } }