You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
274 lines
5.9 KiB
C
274 lines
5.9 KiB
C
4 years ago
|
/***************************************************************************
|
||
|
* 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 <gempa/caps/packet.h>
|
||
|
|
||
|
#include <boost/shared_ptr.hpp>
|
||
|
|
||
|
#include <openssl/ssl.h>
|
||
|
|
||
|
#include <stdint.h>
|
||
|
#include <streambuf>
|
||
|
#include <iostream>
|
||
|
#include <fstream>
|
||
|
|
||
|
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<Socket> 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<SSLSocket> SSLSocketPtr;
|
||
|
|
||
|
#endif
|
||
|
|
||
|
template <typename T, int N>
|
||
|
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
|