[esnacc-dev] [PATCH 1/2] cxx-lib/asn-buf: Add a filedescriptor streambuf

Aaron Conole aconole at bytheb.org
Fri Aug 26 19:32:08 UTC 2016


This commit adds a file-descriptor based streambuffer which can be used to
read/write directly to open file descriptors.  Such a buffer is useful when
dealing with sockets or pipes, which do not have a standardized C++ access
framework.

Signed-off-by: Aaron Conole <aconole at bytheb.org>
---
 cxx-lib/inc/asn-buf.h   |  49 ++++++++++++++--------
 cxx-lib/src/asn-buf.cpp | 108 +++++++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 135 insertions(+), 22 deletions(-)

diff --git a/cxx-lib/inc/asn-buf.h b/cxx-lib/inc/asn-buf.h
index c4baeda..d316ba9 100644
--- a/cxx-lib/inc/asn-buf.h
+++ b/cxx-lib/inc/asn-buf.h
@@ -2,34 +2,25 @@
 #define _ASN_BUF_H 1
 
 
-#if defined(WIN32)
 #if defined(_MSC_VER)
 #pragma warning(disable: 4100 4702 4710 4514 4786 4251 4018 4146 4284)
 #pragma warning(push,3)
 #endif
 
-#include <ostream>
-#include <streambuf>
 #include <deque>
-#include <list>
 #include <fstream>
+#include <list>
+#include <ostream>
 #include <sstream>
-//#include <strstream>
+#include <streambuf>
+#include <vector>
+
 #if defined(_MSC_VER)
 #pragma warning(pop)
 #endif
 
-#else // WIN32
-
-#include <ostream>
-#include <streambuf>
-#include <deque>
-#include <list>
-#include <fstream>
+#if !defined(WIN32)
 #include <utility>
-#include <sstream>
-//#include <strstream>
-
 #endif // WIN32
 
 
@@ -65,13 +56,37 @@ typedef unsigned long      AsnLen;
 
 typedef std::deque<Card *> Deck;
 
+class SNACCDLL_API AsnFDBuf : public std::streambuf
+{
+    int fd;
+    const bool sock;
+    const size_t putsz;
+    const bool close_on_fail;
+    std::vector<char> buffer;
+
+protected:
+    virtual void extra_reset();
+    std::streambuf::int_type underflow();
+    std::streambuf::int_type overflow(std::streambuf::int_type c);
+    std::streamsize xsputn (const char* s, std::streamsize num);
+
+public:
+    explicit AsnFDBuf(int descriptor, bool socket = false, bool failure = true,
+                      size_t buffersz = 256, size_t putsize = 8)
+        : fd(descriptor), sock(socket), putsz(std::max<int>(putsize,1)),
+        close_on_fail(failure), buffer(std::max<int>(buffersz,putsz) + putsz)
+    {
+        char *end = &buffer.front() + buffer.size();
+        setg(end, end, end);
+    }
+};
+
 struct SNACCDLL_API AsnBufLoc
 {
    Deck::iterator m_card;
    long           m_offset;
 };
-
-
+    
 class SNACCDLL_API AsnBuf
 {
 public:
diff --git a/cxx-lib/src/asn-buf.cpp b/cxx-lib/src/asn-buf.cpp
index 0441968..0d62824 100644
--- a/cxx-lib/src/asn-buf.cpp
+++ b/cxx-lib/src/asn-buf.cpp
@@ -1,11 +1,22 @@
+#include <config.h>
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+#ifndef WIN32
+#include <sys/socket.h>
+#include <unistd.h>
+#else
+#include "winsock2.h"
+#include "windows.h"
+#ifndef MSG_NOSIGNAL
+#define MSG_NOSIGNAL 0
+#endif
+#endif
 
 #include "asn-incl.h"
 
-
-#ifdef _MSC_VER
-	#pragma warning(disable: 4189)	// Disable local variable not referenced warning
-#endif
-
 using namespace SNACC;
 
 
@@ -781,6 +792,93 @@ const char * Card::bufTypeStr()
    }
    return NULL;
 }
+#endif
+
+std::streambuf::int_type
+AsnFDBuf::underflow()
+{
+    if (fd == -1)
+        return std::streambuf::traits_type::eof();
+
+    if (gptr() < egptr())
+        return std::streambuf::traits_type::to_int_type(*gptr());
+
+    char *base = &buffer.front();
+    char *start = base;
+
+    if (eback() == base) {
+        // Make arrangements for putback characters
+        ::memmove(base, egptr() - putsz, putsz);
+        start += putsz;
+    }
+
+    int n = 0;
+    if (sock)
+        n = recv(fd, start, buffer.size() - (start - base), 0);
+    else
+        n = ::read(fd, start, buffer.size() - (start - base));
+
+    if(n == 0 || n < 0) {
+        extra_reset();
+        return std::streambuf::traits_type::eof();
+    }
+
+    setg(base, start, start+n);
+    return std::streambuf::traits_type::to_int_type(*gptr());
+}
+
+std::streambuf::int_type
+AsnFDBuf::overflow(std::streambuf::int_type c)
+{
+    if( fd == -1 || c == std::streambuf::traits_type::eof() )
+        return std::streambuf::traits_type::eof();
+
+    char a = c;
+    int n = 0;
+    if (sock)
+        n = send(fd, &a, 1, MSG_NOSIGNAL);
+    else
+        n = ::write(fd, &a, 1);
+
+    if (n != 1) {
+        extra_reset();
+        return std::streambuf::traits_type::eof();
+    }
+    return n;
+}
+
+std::streamsize
+AsnFDBuf::xsputn(const char* s, std::streamsize num)
+{
+    if( fd == -1 )
+        return std::streambuf::traits_type::eof();
+
+    int result;
+    if (sock)
+        result = send(fd, s, num, MSG_NOSIGNAL);
+    else
+        result = ::write(fd, s, num);
 
+    if (result < 0) {
+        extra_reset();
+        return std::streambuf::traits_type::eof();
+    }
+    return result;
+}
 
+void
+AsnFDBuf::extra_reset()
+{
+    if (close_on_fail) {
+        if (!sock) {
+            close(fd);
+        } else {
+#ifndef WIN32
+            ::close(fd);
+#else
+            ::closesocket(fd);
 #endif
+        }
+        fd = -1;
+    }
+}
-- 
2.5.5




More information about the dev mailing list