blob: 7eafa05ee167c93ed4841e59012dbdfbd735f3e0 [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
Julius Werner22e244a2012-11-13 18:25:19 -08007#include <errno.h>
Paul Stewart25379f12011-05-26 06:41:38 -07008#include <stdio.h>
Julius Werner22e244a2012-11-13 18:25:19 -08009#include <string.h>
Paul Stewart25379f12011-05-26 06:41:38 -070010#include <glib.h>
11
Ben Chanb6a75532012-09-07 20:30:49 -070012#include "shill/logging.h"
13
Eric Shienbrood3e20a232012-02-16 11:35:56 -050014using base::Callback;
15
Paul Stewart25379f12011-05-26 06:41:38 -070016namespace shill {
17
18static gboolean DispatchIOHandler(GIOChannel *chan,
19 GIOCondition cond,
Paul Stewart25379f12011-05-26 06:41:38 -070020 gpointer data) {
Eric Shienbrood3e20a232012-02-16 11:35:56 -050021 GlibIOInputHandler *handler = reinterpret_cast<GlibIOInputHandler *>(data);
Paul Stewart25379f12011-05-26 06:41:38 -070022 unsigned char buf[4096];
Ben Chanb6a75532012-09-07 20:30:49 -070023 gsize len = 0;
Julius Werner22e244a2012-11-13 18:25:19 -080024 gint fd = g_io_channel_unix_get_fd(chan);
25 GError *err = 0;
Paul Stewart25379f12011-05-26 06:41:38 -070026
27 if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR))
Julius Werner22e244a2012-11-13 18:25:19 -080028 LOG(FATAL) << "Unexpected GLib error condition " << cond << " on poll("
29 << fd << "): " << strerror(errno);
Paul Stewart25379f12011-05-26 06:41:38 -070030
Ben Chanb6a75532012-09-07 20:30:49 -070031 GIOStatus status = g_io_channel_read_chars(
Julius Werner22e244a2012-11-13 18:25:19 -080032 chan, reinterpret_cast<gchar *>(buf), sizeof(buf), &len, &err);
33 if (err) {
34 LOG(WARNING) << "GLib error code " << err->domain << "/" << err->code
35 << " (" << err->message << ") on read(" << fd << "):"
36 << strerror(errno);
37 g_error_free(err);
Paul Stewart25379f12011-05-26 06:41:38 -070038 }
Julius Werner22e244a2012-11-13 18:25:19 -080039 if (status == G_IO_STATUS_AGAIN)
40 return TRUE;
41 if (status != G_IO_STATUS_NORMAL)
42 LOG(FATAL) << "Unexpected GLib return status " << status;
Paul Stewart25379f12011-05-26 06:41:38 -070043
Darin Petkov633ac6f2011-07-08 13:56:13 -070044 InputData input_data(buf, len);
Eric Shienbrood3e20a232012-02-16 11:35:56 -050045 handler->callback().Run(&input_data);
Paul Stewart25379f12011-05-26 06:41:38 -070046
Julius Werner22e244a2012-11-13 18:25:19 -080047 return TRUE;
Paul Stewart25379f12011-05-26 06:41:38 -070048}
49
Eric Shienbrood3e20a232012-02-16 11:35:56 -050050GlibIOInputHandler::GlibIOInputHandler(
51 int fd, const Callback<void(InputData *)> &callback)
Paul Stewartf0aae102011-10-19 12:11:44 -070052 : channel_(g_io_channel_unix_new(fd)),
53 callback_(callback),
54 source_id_(G_MAXUINT) {
Ben Chanb6a75532012-09-07 20:30:49 -070055 // To avoid blocking in g_io_channel_read_chars() due to its internal buffer,
56 // set the channel to unbuffered, which in turns requires encoding to be NULL.
57 // This assumes raw binary data are read from |fd| via the channel.
58 CHECK_EQ(G_IO_STATUS_NORMAL, g_io_channel_set_encoding(channel_, NULL, NULL));
59 g_io_channel_set_buffered(channel_, FALSE);
Paul Stewartf0aae102011-10-19 12:11:44 -070060 g_io_channel_set_close_on_unref(channel_, TRUE);
61}
62
63GlibIOInputHandler::~GlibIOInputHandler() {
64 g_source_remove(source_id_);
65 g_io_channel_shutdown(channel_, TRUE, NULL);
66 g_io_channel_unref(channel_);
67}
68
69void GlibIOInputHandler::Start() {
70 if (source_id_ == G_MAXUINT) {
71 source_id_ = g_io_add_watch(channel_,
72 static_cast<GIOCondition>(
73 G_IO_IN | G_IO_NVAL | G_IO_HUP | G_IO_ERR),
Eric Shienbrood3e20a232012-02-16 11:35:56 -050074 DispatchIOHandler, this);
Paul Stewartf0aae102011-10-19 12:11:44 -070075 }
76}
77
78void GlibIOInputHandler::Stop() {
79 if (source_id_ != G_MAXUINT) {
80 g_source_remove(source_id_);
81 source_id_ = G_MAXUINT;
82 }
83}
84
Paul Stewart25379f12011-05-26 06:41:38 -070085} // namespace shill