/* Copyright (C) 2009 Red Hat, Inc. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, see . */ #ifndef _H_REDPEER #define _H_REDPEER #include #include #include "common.h" #include #include "process_loop.h" #include "threads.h" #include "platform_utils.h" #include "marshaller.h" class RedPeer: protected EventSources::Socket { public: RedPeer(); virtual ~RedPeer(); class InMessage; class CompoundInMessage; class OutMessage; class DisconnectedException {}; class HostAuthOptions { public: enum Type { HOST_AUTH_OP_PUBKEY = 1, HOST_AUTH_OP_NAME = (1 << 1), HOST_AUTH_OP_SUBJECT = (1 << 2), }; typedef std::vector PublicKey; typedef std::pair CertFieldValuePair; typedef std::list CertFieldValueList; HostAuthOptions() : type_flags(0) {} public: int type_flags; PublicKey host_pubkey; CertFieldValueList host_subject; std::string CA_file; }; class ConnectionOptions { public: enum Type { CON_OP_INVALID, CON_OP_SECURE, CON_OP_UNSECURE, CON_OP_BOTH, }; ConnectionOptions(Type in_type, int in_port, int in_sport, int in_protocol, const HostAuthOptions& in_host_auth, const std::string& in_ciphers) : type (in_type) , unsecure_port (in_port) , secure_port (in_sport) , protocol (in_protocol) , host_auth (in_host_auth) , ciphers (in_ciphers) { } virtual ~ConnectionOptions() {} bool allow_secure() const { return (type == CON_OP_BOTH || type == CON_OP_SECURE) && secure_port != -1; } bool allow_unsecure() const { return (type == CON_OP_BOTH || type == CON_OP_UNSECURE) && unsecure_port != -1; } public: Type type; int unsecure_port; int secure_port; int protocol; // 0 == auto HostAuthOptions host_auth; // for secure connection std::string ciphers; }; void connect_unsecure(const char* host, int port); void connect_secure(const ConnectionOptions& options, const char* host); void disconnect(); void swap(RedPeer* other); void close(); void enable() { _shut = false;} virtual CompoundInMessage* recive(); uint32_t do_send(OutMessage& message, uint32_t skip_bytes); uint32_t send(OutMessage& message); uint32_t recive(uint8_t* buf, uint32_t size); uint32_t send(uint8_t* buf, uint32_t size); protected: virtual void on_event() {} virtual int get_socket() { return _peer;} static bool x509_cert_host_name_compare(const char *cert_name, int cert_name_size, const char *host_name); static bool verify_pubkey(X509* cert, const HostAuthOptions::PublicKey& key); static bool verify_host_name(X509* cert, const char* host_name); static bool verify_subject(X509* cert, const HostAuthOptions::CertFieldValueList& subject); static int ssl_verify_callback(int preverify_ok, X509_STORE_CTX *ctx); void cleanup(); private: void shutdown(); private: SOCKET _peer; Mutex _lock; bool _shut; uint64_t _serial; SSL_CTX *_ctx; SSL *_ssl; }; class RedPeer::InMessage { public: InMessage(uint16_t type, uint32_t size, uint8_t * data) : _type (type) , _size (size) , _data (data) { } virtual ~InMessage() {} uint16_t type() { return _type;} uint8_t* data() { return _data;} virtual uint32_t size() { return _size;} protected: uint16_t _type; uint32_t _size; uint8_t* _data; }; class RedPeer::CompoundInMessage: public RedPeer::InMessage { public: CompoundInMessage(uint64_t _serial, uint16_t type, uint32_t size, uint32_t sub_list) : InMessage(type, size, new uint8_t[size]) , _refs (1) , _serial (_serial) , _sub_list (sub_list) { } RedPeer::InMessage* ref() { _refs++; return this;} void unref() {if (!--_refs) delete this;} uint64_t serial() { return _serial;} uint32_t sub_list() { return _sub_list;} virtual uint32_t size() { return _sub_list ? _sub_list : _size;} uint32_t compound_size() {return _size;} protected: virtual ~CompoundInMessage() { delete[] _data;} private: int _refs; uint64_t _serial; uint32_t _sub_list; }; class RedPeer::OutMessage { public: OutMessage(uint32_t type); virtual ~OutMessage(); SpiceMarshaller *marshaller() { return _marshaller;} void reset(uint32_t type); private: uint32_t message_size() { return spice_marshaller_get_total_size(_marshaller);} uint8_t* base() { return spice_marshaller_get_ptr(_marshaller);} SpiceDataHeader& header() { return *(SpiceDataHeader *)base();} protected: SpiceMarshaller *_marshaller; friend class RedPeer; friend class RedChannel; }; #endif