1
0
mirror of https://github.com/stefanocasazza/ULib.git synced 2025-09-28 19:05:55 +08:00
ULib/include/ulib/net/client/client.h
stefanocasazza 2d1d846a7f MACOS fix
2016-02-29 18:00:26 +01:00

356 lines
9.0 KiB
C++

// ============================================================================
//
// = LIBRARY
// ULib - c++ library
//
// = FILENAME
// client.h - manages a client connection with a server
//
// = AUTHOR
// Stefano Casazza
//
// ============================================================================
#ifndef U_CLIENT_H
#define U_CLIENT_H 1
#include <ulib/url.h>
#include <ulib/net/rpc/rpc.h>
#include <ulib/utility/uhttp.h>
#ifdef USE_LIBSSL
# include <ulib/ssl/certificate.h>
# include <ulib/ssl/net/sslsocket.h>
#endif
/**
* @class UClient
*
* @brief Handles a connections with a server
*/
class ULog;
class USSLSocket;
class UHttpPlugIn;
class UFileConfig;
class UFCGIPlugIn;
class USCGIPlugIn;
class UProxyPlugIn;
class UNoCatPlugIn;
class UServer_Base;
class UHttpClient_Base;
class U_EXPORT UClient_Base {
public:
// Check for memory error
U_MEMORY_TEST
// Allocator e Deallocator
U_MEMORY_ALLOCATOR
U_MEMORY_DEALLOCATOR
// SERVICES
bool isOpen() const
{
U_TRACE_NO_PARAM(0, "UClient_Base::isOpen()")
if (socket->isOpen()) U_RETURN(true);
U_RETURN(false);
}
bool isClosed() const
{
U_TRACE_NO_PARAM(0, "UClient_Base::isClosed()")
if (socket->isClosed()) U_RETURN(true);
U_RETURN(false);
}
bool isConnected() const
{
U_TRACE_NO_PARAM(0, "UClient_Base::isConnected()")
if (socket->isOpen() &&
socket->isConnected())
{
U_RETURN(true);
}
U_RETURN(false);
}
void reserve(uint32_t n)
{
U_TRACE(0, "UClient_Base::reserve(%u)", n)
(void) response.reserve(n);
}
void close()
{
U_TRACE_NO_PARAM(0, "UClient_Base::close()")
U_INTERNAL_ASSERT_POINTER(socket)
if (isOpen()) socket->_closesocket();
}
bool shutdown(int how = SHUT_WR)
{
U_TRACE(0, "UClient_Base::shutdown(%d)", how)
U_INTERNAL_ASSERT_POINTER(socket)
if (socket->shutdown(how)) U_RETURN(true);
U_RETURN(false);
}
void setTimeOut(uint32_t t)
{
U_TRACE(0, "UClient_Base::setTimeOut()")
timeoutMS = t;
}
void adjustTimeOut()
{
U_TRACE_NO_PARAM(0, "UClient_Base::adjustTimeOut()")
if (timeoutMS < U_TIMEOUT_MS) timeoutMS = U_TIMEOUT_MS;
}
void reset()
{
U_TRACE_NO_PARAM(0, "UClient_Base::reset()")
# ifdef DEBUG
uri.clear(); // NB: to avoid DEAD OF SOURCE STRING WITH CHILD ALIVE... (uri can be a substr of url)
# endif
url.clear();
}
// LOG
static void closeLog();
static void setLogShared();
static bool isLogSharedWithServer()
{
U_TRACE_NO_PARAM(0, "UClient_Base::isLogSharedWithServer()")
U_RETURN(log_shared_with_server);
}
UString getUrl() const { return url.get(); }
UString getServer() const { return server; }
UString getBuffer() const { return buffer; }
UString getResponse() const { return response; }
int getFd() const { return socket->getFd(); }
const char* getResponseData() const { return response.data(); }
unsigned int getPort() const { return port; }
bool setUrl(const UString& url); // NB: return if it has modified host or port...
bool remoteIPAddress(UIPAddress& addr);
bool setHostPort(const UString& host, unsigned int port);
bool connect();
void clearData();
bool readResponse(uint32_t count = U_SINGLE_READ);
/**
* Establishes a TCP/IP socket connection with the host that will satisfy requests for the provided URL.
* This may connect to the host name contained within the URL, or to a proxy server if one has been set.
* This function does not send any information to the remote server after the connection is established
*
* @param url a fully-qualified http URL for the required resource
*/
bool connectServer(const UString& url);
// QUEUE MODE
static int queue_fd;
static const UString* queue_dir;
// -----------------------------------------------------------------------------------------------------------------------
// Very simple RPC-like layer
//
// Requests and responses are build of little packets each containing a 4-byte ascii token, an 8-byte hex value or length,
// and optionally data corresponding to the length
// -----------------------------------------------------------------------------------------------------------------------
// Transmit token name (4 characters) and value (32-bit int, as 8 hex characters)
bool sendTokenInt(const char* token, uint32_t value)
{ buffer.setEmpty(); return URPC::sendTokenInt(socket, token, value, buffer); }
// Write a token, and then the string data
bool sendTokenString(const char* token, const UString& data)
{ buffer.setEmpty(); return URPC::sendTokenString(socket, token, data, buffer); }
// Transmit an vector of string
bool sendTokenVector(const char* token, UVector<UString>& vec)
{ buffer.setEmpty(); return URPC::sendTokenVector(socket, token, vec, buffer); }
// DEBUG
#if defined(U_STDCPP_ENABLE) && defined(DEBUG)
const char* dump(bool reset) const;
#endif
USocket* socket;
protected:
UString server, // host name or ip address for server
cert_file, // locations for certificate of client
key_file, // locations for private key of client
password, // password for private key of client
ca_file, // locations of trusted CA certificates used in the verification
ca_path, // locations of trusted CA certificates used in the verification
uri,
request,
response,
buffer,
host_port;
Url url;
int iovcnt,
timeoutMS, // the time-out value in milliseconds
verify_mode; // mode of verification of connection
unsigned int port; // the port number to connect to
struct iovec iov[6];
static ULog* log;
static UFileConfig* cfg;
static bool log_shared_with_server, bIPv6;
bool readHTTPResponse();
void prepareRequest(const char* req, uint32_t len)
{
U_TRACE(0, "UClient_Base::prepareRequest(%.*S,%u)", len, req, len)
iovcnt = 1;
iov[0].iov_base = (caddr_t)req;
iov[0].iov_len = len;
(void) U_SYSCALL(memset, "%p,%d,%u", iov+1, 0, sizeof(struct iovec) * 5);
U_INTERNAL_ASSERT_EQUALS(iov[1].iov_len, 0)
U_INTERNAL_ASSERT_EQUALS(iov[2].iov_len, 0)
U_INTERNAL_ASSERT_EQUALS(iov[3].iov_len, 0)
U_INTERNAL_ASSERT_EQUALS(iov[4].iov_len, 0)
U_INTERNAL_ASSERT_EQUALS(iov[5].iov_len, 0)
}
void prepareRequest(const UString& req) { request = req; prepareRequest(U_STRING_TO_PARAM(req)); }
bool sendRequest(bool bread_response = false);
bool sendRequestAndReadResponse() { return sendRequest(true); }
#ifdef USE_LIBSSL
void setSSLContext();
void setActive(bool _flag)
{
U_TRACE(0, "UClient_Base::setActive(%b)", _flag)
((USSLSocket*)socket)->setSSLActive(_flag);
}
#endif
void loadConfigParam();
// COSTRUTTORI
UClient_Base(UFileConfig* pcfg);
~UClient_Base();
private:
UClient_Base(const UClient_Base&) {}
UClient_Base& operator=(const UClient_Base&) { return *this; }
friend class USSLSocket;
friend class UFCGIPlugIn;
friend class USCGIPlugIn;
friend class Application;
friend class UHttpPlugIn;
friend class UProxyPlugIn;
friend class UNoCatPlugIn;
friend class UServer_Base;
friend class UHttpClient_Base;
};
template <class Socket> class U_EXPORT UClient : public UClient_Base {
public:
// COSTRUTTORI
UClient(UFileConfig* pcfg) : UClient_Base(pcfg)
{
U_TRACE_REGISTER_OBJECT(0, UClient, "%p", pcfg)
socket = U_NEW(Socket(UClient_Base::bIPv6));
}
~UClient()
{
U_TRACE_UNREGISTER_OBJECT(0, UClient)
}
// DEBUG
#if defined(U_STDCPP_ENABLE) && defined(DEBUG)
const char* dump(bool _reset) const { return UClient_Base::dump(_reset); }
#endif
private:
UClient(const UClient&) : UClient_Base(0) {}
UClient& operator=(const UClient&) { return *this; }
};
#ifdef USE_LIBSSL // specializzazione con USSLSocket
template <> class U_EXPORT UClient<USSLSocket> : public UClient_Base {
public:
UClient(UFileConfig* pcfg) : UClient_Base(pcfg)
{
U_TRACE_REGISTER_OBJECT(0, UClient<USSLSocket>, "%p", pcfg)
UClient_Base::setSSLContext();
}
~UClient()
{
U_TRACE_UNREGISTER_OBJECT(0, UClient<USSLSocket>)
}
// DEBUG
#if defined(U_STDCPP_ENABLE) && defined(DEBUG)
const char* dump(bool _reset) const { return UClient_Base::dump(_reset); }
#endif
private:
#ifdef U_COMPILER_DELETE_MEMBERS
UClient<USSLSocket>(const UClient<USSLSocket>&) = delete;
UClient<USSLSocket>& operator=(const UClient<USSLSocket>&) = delete;
#else
UClient<USSLSocket>(const UClient<USSLSocket>&) : UClient_Base(0) {}
UClient<USSLSocket>& operator=(const UClient<USSLSocket>&) { return *this; }
#endif
};
#endif
#endif