From: Gunnar Beutner Date: Fri, 23 Nov 2012 10:02:34 +0000 (+0100) Subject: Implemented the StdioStream and UnixSocket classes. X-Git-Tag: v0.0.2~719 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=334bfe388ae2c70f616a283e33e89b2e04f92019;p=icinga2 Implemented the StdioStream and UnixSocket classes. --- diff --git a/lib/base/Makefile.am b/lib/base/Makefile.am index 8fc1cc23d..5df39cb42 100644 --- a/lib/base/Makefile.am +++ b/lib/base/Makefile.am @@ -41,6 +41,8 @@ libbase_la_SOURCES = \ scripttask.h \ socket.cpp \ socket.h \ + stdiostream.cpp \ + stdiostream.h \ stream.cpp \ stream.h \ stream_bio.cpp \ @@ -56,6 +58,8 @@ libbase_la_SOURCES = \ tlsstream.cpp \ tlsstream.h \ unix.h \ + unixsocket.cpp \ + unixsocket.h \ utility.cpp \ utility.h \ value.cpp \ diff --git a/lib/base/base.vcxproj b/lib/base/base.vcxproj index c877fbfa9..233c6bfeb 100644 --- a/lib/base/base.vcxproj +++ b/lib/base/base.vcxproj @@ -42,6 +42,7 @@ + @@ -49,6 +50,7 @@ + @@ -61,6 +63,7 @@ + @@ -80,6 +83,7 @@ + diff --git a/lib/base/base.vcxproj.filters b/lib/base/base.vcxproj.filters index 0845ca949..912b4fe92 100644 --- a/lib/base/base.vcxproj.filters +++ b/lib/base/base.vcxproj.filters @@ -82,6 +82,12 @@ Quelldateien + + Quelldateien + + + Quelldateien + @@ -174,6 +180,12 @@ Headerdateien + + Headerdateien + + + Headerdateien + diff --git a/lib/base/dynamicobject.cpp b/lib/base/dynamicobject.cpp index 734b9e93c..7be1d424f 100644 --- a/lib/base/dynamicobject.cpp +++ b/lib/base/dynamicobject.cpp @@ -361,14 +361,14 @@ void DynamicObject::DumpObjects(const String& filename) String tempFilename = filename + ".tmp"; - ofstream fp; - fp.open(tempFilename.CStr()); + fstream fp; + fp.open(tempFilename.CStr(), std::ios_base::out); if (!fp) throw_exception(runtime_error("Could not open '" + filename + "' file")); - FIFO::Ptr fifo = boost::make_shared(); - fifo->Start(); + StdioStream::Ptr sfp = boost::make_shared(&fp, false); + sfp->Start(); DynamicObject::TypeMap::iterator tt; for (tt = GetAllObjects().begin(); tt != GetAllObjects().end(); tt++) { @@ -402,22 +402,22 @@ void DynamicObject::DumpObjects(const String& filename) String json = value.Serialize(); /* This is quite ugly, unfortunatelly NetString requires an IOQueue object */ - NetString::WriteStringToStream(fifo, json); + NetString::WriteStringToStream(sfp, json); size_t count; - while ((count = fifo->GetAvailableBytes()) > 0) { + while ((count = sfp->GetAvailableBytes()) > 0) { char buffer[1024]; if (count > sizeof(buffer)) count = sizeof(buffer); - fifo->Read(buffer, count); + sfp->Read(buffer, count); fp.write(buffer, count); } } } - fifo->Close(); + sfp->Close(); fp.close(); @@ -433,23 +433,14 @@ void DynamicObject::RestoreObjects(const String& filename) { Logger::Write(LogInformation, "base", "Restoring program state from file '" + filename + "'"); - std::ifstream fp; - fp.open(filename.CStr()); + std::fstream fp; + fp.open(filename.CStr(), std::ios_base::in); - /* TODO: Fix this horrible mess by implementing a class that provides - * IOQueue functionality for files. */ - FIFO::Ptr fifo = boost::make_shared(); - fifo->Start(); - - while (fp) { - char buffer[1024]; - - fp.read(buffer, sizeof(buffer)); - fifo->Write(buffer, fp.gcount()); - } + StdioStream::Ptr sfp = boost::make_shared(&fp, false); + sfp->Start(); String message; - while (NetString::ReadStringFromStream(fifo, &message)) { + while (NetString::ReadStringFromStream(sfp, &message)) { Dictionary::Ptr persistentObject = Value::Deserialize(message); String type = persistentObject->Get("type"); @@ -468,7 +459,7 @@ void DynamicObject::RestoreObjects(const String& filename) } } - fifo->Close(); + sfp->Close(); } void DynamicObject::DeactivateObjects(void) diff --git a/lib/base/i2-base.h b/lib/base/i2-base.h index 25940b0b7..c529d2850 100644 --- a/lib/base/i2-base.h +++ b/lib/base/i2-base.h @@ -103,8 +103,10 @@ using std::make_pair; using std::stringstream; using std::istream; using std::ostream; +using std::fstream; using std::ifstream; using std::ofstream; +using std::iostream; using std::exception; using std::bad_alloc; @@ -180,8 +182,10 @@ namespace tuples = boost::tuples; #include "connection.h" #include "netstring.h" #include "fifo.h" +#include "stdiostream.h" #include "socket.h" #include "tcpsocket.h" +#include "unixsocket.h" #include "tlsstream.h" #include "asynctask.h" #include "process.h" diff --git a/lib/base/netstring.cpp b/lib/base/netstring.cpp index 546aa79c3..3522cad99 100644 --- a/lib/base/netstring.cpp +++ b/lib/base/netstring.cpp @@ -47,7 +47,12 @@ bool NetString::ReadStringFromStream(const Stream::Ptr& stream, String *str) if (buffer == NULL && buffer_length > 0) throw_exception(bad_alloc()); - stream->Peek(buffer, buffer_length); + buffer_length = stream->Peek(buffer, buffer_length); + + if (buffer_length < 3) { + free(buffer); + return false; + } /* no leading zeros allowed */ if (buffer[0] == '0' && isdigit(buffer[1])) { diff --git a/lib/base/socket.h b/lib/base/socket.h index 0dad5d507..7d495987e 100644 --- a/lib/base/socket.h +++ b/lib/base/socket.h @@ -44,10 +44,10 @@ public: bool IsConnected(void) const; - size_t GetAvailableBytes(void) const; - size_t Read(void *buffer, size_t size); - size_t Peek(void *buffer, size_t size); - void Write(const void *buffer, size_t size); + virtual size_t GetAvailableBytes(void) const; + virtual size_t Read(void *buffer, size_t size); + virtual size_t Peek(void *buffer, size_t size); + virtual void Write(const void *buffer, size_t size); void Listen(void); diff --git a/lib/base/stdiostream.cpp b/lib/base/stdiostream.cpp new file mode 100644 index 000000000..5cf4bd661 --- /dev/null +++ b/lib/base/stdiostream.cpp @@ -0,0 +1,89 @@ +/****************************************************************************** + * Icinga 2 * + * Copyright (C) 2012 Icinga Development Team (http://www.icinga.org/) * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software Foundation * + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * + ******************************************************************************/ + +#include "i2-base.h" + +using namespace icinga; + +StdioStream::StdioStream(iostream *innerStream, bool ownsStream) + : m_InnerStream(innerStream), m_OwnsStream(ownsStream), + m_ReadAheadBuffer(boost::make_shared()) +{ + m_ReadAheadBuffer->Start(); +} + +StdioStream::~StdioStream(void) +{ + m_ReadAheadBuffer->Close(); +} + +void StdioStream::Start(void) +{ + SetConnected(true); + + Stream::Start(); +} + +size_t StdioStream::GetAvailableBytes(void) const +{ + if (m_InnerStream->eof() && m_ReadAheadBuffer->GetAvailableBytes() == 0) + return 0; + else + return 1024; /* doesn't have to be accurate */ +} + +size_t StdioStream::Read(void *buffer, size_t size) +{ + size_t peek_len, read_len; + + peek_len = m_ReadAheadBuffer->GetAvailableBytes(); + peek_len = m_ReadAheadBuffer->Read(buffer, peek_len); + + m_InnerStream->read(static_cast(buffer) + peek_len, size - peek_len); + read_len = m_InnerStream->gcount(); + + return peek_len + read_len; +} + +size_t StdioStream::Peek(void *buffer, size_t size) +{ + size_t peek_len, read_len; + + peek_len = m_ReadAheadBuffer->GetAvailableBytes(); + peek_len = m_ReadAheadBuffer->Peek(buffer, peek_len); + + m_InnerStream->read(static_cast(buffer) + peek_len, size - peek_len); + read_len = m_InnerStream->gcount(); + + m_ReadAheadBuffer->Write(static_cast(buffer) + peek_len, read_len); + return peek_len + read_len; +} + +void StdioStream::Write(const void *buffer, size_t size) +{ + m_InnerStream->write(static_cast(buffer), size); +} + +void StdioStream::Close(void) +{ + if (m_OwnsStream) + delete *m_InnerStream; + + Stream::Close(); +} diff --git a/lib/base/stdiostream.h b/lib/base/stdiostream.h new file mode 100644 index 000000000..907073d1e --- /dev/null +++ b/lib/base/stdiostream.h @@ -0,0 +1,51 @@ +/****************************************************************************** + * Icinga 2 * + * Copyright (C) 2012 Icinga Development Team (http://www.icinga.org/) * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software Foundation * + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * + ******************************************************************************/ + +#ifndef STDIOSTREAM_H +#define STDIOSTREAM_H + +namespace icinga { + +class StdioStream : public Stream +{ +public: + typedef shared_ptr Ptr; + typedef weak_ptr WeakPtr; + + StdioStream(iostream *innerStream, bool ownsStream); + ~StdioStream(void); + + virtual void Start(void); + + virtual size_t GetAvailableBytes(void) const; + virtual size_t Read(void *buffer, size_t size); + virtual size_t Peek(void *buffer, size_t size); + virtual void Write(const void *buffer, size_t size); + + virtual void Close(void); + +private: + iostream *m_InnerStream; + bool m_OwnsStream; + FIFO::Ptr m_ReadAheadBuffer; +}; + +} + +#endif /* STDIOSTREAM_H */ \ No newline at end of file diff --git a/lib/base/streamlogger.cpp b/lib/base/streamlogger.cpp index 51266b0e4..f66e320a4 100644 --- a/lib/base/streamlogger.cpp +++ b/lib/base/streamlogger.cpp @@ -51,7 +51,7 @@ void StreamLogger::OpenFile(const String& filename) ofstream *stream = new ofstream(); try { - stream->open(filename.CStr(), ofstream::out | ofstream::trunc); + stream->open(filename.CStr(), fstream::out | fstream::trunc); if (!stream->good()) throw_exception(runtime_error("Could not open logfile '" + filename + "'")); diff --git a/lib/base/unixsocket.cpp b/lib/base/unixsocket.cpp new file mode 100644 index 000000000..58d491620 --- /dev/null +++ b/lib/base/unixsocket.cpp @@ -0,0 +1,58 @@ +/****************************************************************************** + * Icinga 2 * + * Copyright (C) 2012 Icinga Development Team (http://www.icinga.org/) * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software Foundation * + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * + ******************************************************************************/ + +#include "i2-base.h" + +#ifndef _WIN32 +using namespace icinga; + +UnixSocket::UnixSocket(void) +{ + int fd = socket(AF_UNIX, SOCK_STREAM, PF_UNIX); + + if (fd < 0) + throw_exception(PosixException("socket() failed", errno)); + + SetFD(fd); +} + +void UnixSocket::Bind(const String& path) +{ + unlink(path.CStr()); + + sockaddr_un sun = {}; + sun.sun_family = AF_UNIX; + strncpy(sun.sun_path, path.CStr(), sizeof(sun.sun_path)); + sun.sun_path[sizeof(sun.sun_path) - 1] = '\0'; + + if (bind(GetFD(), (sockaddr *)&sun, SUN_LEN(sun)) < 0) + throw_exception(PosixException("bind() failed", errno); +} + +void UnixSocket::Connect(const String& path) +{ + sockaddr_un sun = {}; + sun.sun_family = AF_UNIX; + strncpy(sun.sun_path, path.CStr(), sizeof(sun.sun_path)); + sun.sun_path[sizeof(sun.sun_path) - 1] = '\0'; + + if (connect(GetFD(), (sockaddr *)&sun, SUN_LEN(sun)) < 0 && errno != EINPROGRESS) + throw_exception(PosixException("connect() failed", errno); +} +#endif /* _WIN32 */ \ No newline at end of file diff --git a/lib/base/unixsocket.h b/lib/base/unixsocket.h new file mode 100644 index 000000000..5535d1001 --- /dev/null +++ b/lib/base/unixsocket.h @@ -0,0 +1,41 @@ +/****************************************************************************** + * Icinga 2 * + * Copyright (C) 2012 Icinga Development Team (http://www.icinga.org/) * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software Foundation * + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * + ******************************************************************************/ + +#ifndef UNIXSOCKET_H +#define UNIXSOCKET_H + +#ifndef _WIN32 +namespace icinga +{ + +class UnixSocket : public Socket +{ +public: + typedef shared_ptr Ptr; + typedef weak_ptr WeakPtr; + + void Bind(const String& path); + + void Connect(const String& path); +}; + +} +#endif /* _WIN32 */ + +#endif /* UNIXSOCKET_H */ \ No newline at end of file