blob: e63fc67cc3d065aa3827421211c9bf11dd997d1c [file] [log] [blame]
Ben Chanb6a75532012-09-07 20:30:49 -07001// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
Paul Stewart25379f12011-05-26 06:41:38 -07002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Paul Stewartf0aae102011-10-19 12:11:44 -07005#include "shill/glib_io_input_handler.h"
Paul Stewart26b327e2011-10-19 11:38:09 -07006
Paul Stewart25379f12011-05-26 06:41:38 -07007#include <stdio.h>
8#include <glib.h>
9
Ben Chanb6a75532012-09-07 20:30:49 -070010#include "shill/logging.h"
11
Eric Shienbrood3e20a232012-02-16 11:35:56 -050012using base::Callback;
13
Paul Stewart25379f12011-05-26 06:41:38 -070014namespace shill {
15
16static gboolean DispatchIOHandler(GIOChannel *chan,
17 GIOCondition cond,
Paul Stewart25379f12011-05-26 06:41:38 -070018 gpointer data) {
Eric Shienbrood3e20a232012-02-16 11:35:56 -050019 GlibIOInputHandler *handler = reinterpret_cast<GlibIOInputHandler *>(data);
Paul Stewart25379f12011-05-26 06:41:38 -070020 unsigned char buf[4096];
Ben Chanb6a75532012-09-07 20:30:49 -070021 gsize len = 0;
Paul Stewartf65320c2011-10-13 14:34:52 -070022 gboolean ret = TRUE;
Paul Stewart25379f12011-05-26 06:41:38 -070023
24 if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR))
25 return FALSE;
26
Ben Chanb6a75532012-09-07 20:30:49 -070027 GIOStatus status = g_io_channel_read_chars(
28 chan, reinterpret_cast<gchar *>(buf), sizeof(buf), &len, NULL);
29 if (status != G_IO_STATUS_NORMAL) {
30 if (status == G_IO_STATUS_AGAIN)
Paul Stewart25379f12011-05-26 06:41:38 -070031 return TRUE;
Paul Stewartf65320c2011-10-13 14:34:52 -070032 len = 0;
33 ret = FALSE;
Paul Stewart25379f12011-05-26 06:41:38 -070034 }
35
Darin Petkov633ac6f2011-07-08 13:56:13 -070036 InputData input_data(buf, len);
Eric Shienbrood3e20a232012-02-16 11:35:56 -050037 handler->callback().Run(&input_data);
Paul Stewart25379f12011-05-26 06:41:38 -070038
Paul Stewartf65320c2011-10-13 14:34:52 -070039 return ret;
Paul Stewart25379f12011-05-26 06:41:38 -070040}
41
Eric Shienbrood3e20a232012-02-16 11:35:56 -050042GlibIOInputHandler::GlibIOInputHandler(
43 int fd, const Callback<void(InputData *)> &callback)
Paul Stewartf0aae102011-10-19 12:11:44 -070044 : channel_(g_io_channel_unix_new(fd)),
45 callback_(callback),
46 source_id_(G_MAXUINT) {
Ben Chanb6a75532012-09-07 20:30:49 -070047 // To avoid blocking in g_io_channel_read_chars() due to its internal buffer,
48 // set the channel to unbuffered, which in turns requires encoding to be NULL.
49 // This assumes raw binary data are read from |fd| via the channel.
50 CHECK_EQ(G_IO_STATUS_NORMAL, g_io_channel_set_encoding(channel_, NULL, NULL));
51 g_io_channel_set_buffered(channel_, FALSE);
Paul Stewartf0aae102011-10-19 12:11:44 -070052 g_io_channel_set_close_on_unref(channel_, TRUE);
53}
54
55GlibIOInputHandler::~GlibIOInputHandler() {
56 g_source_remove(source_id_);
57 g_io_channel_shutdown(channel_, TRUE, NULL);
58 g_io_channel_unref(channel_);
59}
60
61void GlibIOInputHandler::Start() {
62 if (source_id_ == G_MAXUINT) {
63 source_id_ = g_io_add_watch(channel_,
64 static_cast<GIOCondition>(
65 G_IO_IN | G_IO_NVAL | G_IO_HUP | G_IO_ERR),
Eric Shienbrood3e20a232012-02-16 11:35:56 -050066 DispatchIOHandler, this);
Paul Stewartf0aae102011-10-19 12:11:44 -070067 }
68}
69
70void GlibIOInputHandler::Stop() {
71 if (source_id_ != G_MAXUINT) {
72 g_source_remove(source_id_);
73 source_id_ = G_MAXUINT;
74 }
75}
76
Paul Stewart25379f12011-05-26 06:41:38 -070077} // namespace shill