/*************************************************************************** * Copyright (C) 2013 by gempa GmbH * * * * All Rights Reserved. * * * * NOTICE: All information contained herein is, and remains * * the property of gempa GmbH and its suppliers, if any. The intellectual * * and technical concepts contained herein are proprietary to gempa GmbH * * and its suppliers. * * Dissemination of this information or reproduction of this material * * is strictly forbidden unless prior written permission is obtained * * from gempa GmbH. * ***************************************************************************/ #ifndef GEMPA_CAPS_SOCKET_H #define GEMPA_CAPS_SOCKET_H #include #include #include #include #include #include #include namespace Gempa { namespace CAPS { class SC_GEMPA_CAPS_API Socket { public: typedef uint64_t count_t; enum Status { Success = 0, Error, AllocationError, ReuseAdressError, BindError, ListenError, AcceptError, ConnectError, AddrInfoError, Timeout, InvalidSocket, InvalidPort, InvalidAddressFamily, InvalidAddress, InvalidHostname }; struct Device { enum Status { Success = 0, Error, InvalidDevice, AllocationError }; }; public: Socket(); virtual ~Socket(); public: static const char *toString(Status); int fd() { return _fd; } bool isValid(); void shutdown(); void close(); int send(const char *data); virtual int write(const char *data, int len); virtual int read(char *data, int len); virtual int flush(); //! Sets the socket timeout. This utilizes setsockopt which does not //! work in non blocking sockets. Status setSocketTimeout(int secs, int usecs); Device::Status setNonBlocking(bool nb); virtual Status connect(const std::string &hostname, uint16_t port); count_t rx() const { return _bytesReceived; } count_t tx() const { return _bytesSent; } protected: Status applySocketTimeout(int secs, int usecs); protected: int _fd; count_t _bytesSent; count_t _bytesReceived; int _timeOutSecs; int _timeOutUsecs; }; typedef boost::shared_ptr SocketPtr; #if !defined(CAPS_FEATURES_SSL) || CAPS_FEATURES_SSL class SSLSocket : public Socket { public: SSLSocket(); SSLSocket(SSL_CTX *ctx); ~SSLSocket(); public: int write(const char *data, int len); int read(char *data, int len); Status connect(const std::string &hostname, uint16_t port); virtual const unsigned char *sessionID() const; virtual unsigned int sessionIDLength() const; X509 *peerCertificate(); private: void cleanUp(); private: SSL *_ssl; SSL_CTX *_ctx; }; typedef boost::shared_ptr SSLSocketPtr; #endif template class socketbuf : public std::streambuf { public: socketbuf() { setsocket(NULL); } socketbuf(T *sock) { setsocket(sock); } void setsocket(T *sock) { _allowed_reads = -1; _real_buffer_size = 0; _block_write = false; setg(_in, _in, _in); setp(_out, _out + N); _sock = sock; } void settimeout(const struct timeval &tv) { _timeout = tv; } void set_read_limit(int bytes) { _allowed_reads = bytes; if ( _allowed_reads >= 0 ) { if ( egptr() - gptr() > _allowed_reads ) setg(eback(), gptr(), gptr() + _allowed_reads); // Set the number of read bytes to the // remaining bytes in the buffer _allowed_reads -= egptr() - gptr(); } else setg(eback(), gptr(), eback() + _real_buffer_size); //std::cout << "[" << (void*)eback() << ", " << (void*)gptr() << ", " << (void*)egptr() << "]" << " = " << (egptr() - gptr()) << std::endl; } int read_limit() const { if ( _allowed_reads < 0 ) return -1; return egptr() - gptr() + _allowed_reads; } protected: virtual int underflow() { // No more reads allowed? if ( !_allowed_reads ) return traits_type::eof(); // Read available data from socket int res = _sock->read(_in, N); if ( res <= 0 ) { set_read_limit(0); return traits_type::eof(); } // Set input sequence pointers _real_buffer_size = res; setg(_in, _in, _in + _real_buffer_size); // clip to limit set_read_limit(_allowed_reads); return traits_type::to_int_type(*gptr()); } virtual int overflow(int c) { if ( _block_write ) return traits_type::eof(); if ( pptr() - pbase() == N ) { if ( sync() != 0 ) return traits_type::eof(); } if ( !traits_type::eq_int_type(traits_type::eof(), c)) { traits_type::assign(*pptr(), traits_type::to_char_type(c)); pbump(1); } return traits_type::not_eof(c); } virtual int sync() { if ( pbase() == pptr() ) return 0; int res = _sock->write(pbase(), pptr() - pbase()); if ( res == pptr() - pbase() ) { setp(_out, _out + N); return 0; } return 1; } // Only forward seeking is supported virtual std::streampos seekoff(std::streamoff off, std::ios_base::seekdir way, std::ios_base::openmode which = std::ios_base::in | std::ios_base::out) { if ( way != std::ios_base::cur || which != std::ios_base::in || off < 0 ) return -1; while ( off > 0 ) { int ch = sbumpc(); if ( ch == traits_type::eof() ) return -1; --off; } return 0; } private: T *_sock; timeval _timeout; char _in[N]; char _out[N]; bool _block_write; int _real_buffer_size; int _allowed_reads; }; } } #endif