Core: SSL support for Socket, finishing touches...

git-svn-id: svn://ultimatepp.org/upp/trunk@4785 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
cxl 2012-04-15 11:20:50 +00:00
parent 8aace300c4
commit eef7c20270
12 changed files with 476 additions and 394 deletions

View file

@ -4,8 +4,6 @@ NAMESPACE_UPP
#define LTIMING(x) // TIMING(x) #define LTIMING(x) // TIMING(x)
int msecs(int from) { return (int)GetTickCount() - from; }
#ifdef PLATFORM_WIN32 #ifdef PLATFORM_WIN32
#include <mmsystem.h> #include <mmsystem.h>
#endif #endif

View file

@ -73,8 +73,6 @@ void CloseStdLog();
void HexDump(Stream& s, const void *ptr, int size, int maxsize = INT_MAX); void HexDump(Stream& s, const void *ptr, int size, int maxsize = INT_MAX);
int msecs(int from = 0);
String GetTypeName(const char *type_name); String GetTypeName(const char *type_name);
inline String GetTypeName(const ::std::type_info& tinfo) { return GetTypeName(tinfo.name()); } inline String GetTypeName(const ::std::type_info& tinfo) { return GetTypeName(tinfo.name()); }

View file

@ -1,3 +1,4 @@
String WwwFormat(Time tm);
String FormatIP(dword _ip); String FormatIP(dword _ip);
String UrlEncode(const String& s); String UrlEncode(const String& s);
@ -81,7 +82,7 @@ class TcpSocket {
struct SSL { struct SSL {
virtual bool Start() = 0; virtual bool Start() = 0;
virtual bool Wait(dword flags) = 0; virtual bool Wait(dword flags, int end_time) = 0;
virtual int Send(const void *buffer, int maxlen) = 0; virtual int Send(const void *buffer, int maxlen) = 0;
virtual int Recv(void *buffer, int maxlen) = 0; virtual int Recv(void *buffer, int maxlen) = 0;
virtual void Close() = 0; virtual void Close() = 0;
@ -92,7 +93,9 @@ class TcpSocket {
One<SSL> ssl; One<SSL> ssl;
One<SSLInfo> sslinfo; One<SSLInfo> sslinfo;
String cert, pkey;
bool asn1;
struct SSLImp; struct SSLImp;
friend struct SSLImp; friend struct SSLImp;
@ -101,7 +104,9 @@ class TcpSocket {
friend void InitCreateSSL(); friend void InitCreateSSL();
bool RawWait(dword flags); int GetEndTime() const;
bool RawWait(dword flags, int end_time);
bool Wait(dword events, int end_time);
SOCKET AcceptRaw(dword *ipaddr, int timeout_msec); SOCKET AcceptRaw(dword *ipaddr, int timeout_msec);
bool Open(int family, int type, int protocol); bool Open(int family, int type, int protocol);
int RawRecv(void *buffer, int maxlen); int RawRecv(void *buffer, int maxlen);
@ -111,9 +116,11 @@ class TcpSocket {
bool RawConnect(addrinfo *info); bool RawConnect(addrinfo *info);
void RawClose(); void RawClose();
void ReadBuffer(); void ReadBuffer(int end_time);
int Get_(); int Get_();
int Peek_(); int Peek_();
int Peek_(int end_time);
int Peek(int end_time) { return ptr < end ? *ptr : Peek_(end_time); }
void Reset(); void Reset();
@ -170,18 +177,21 @@ public:
int Get() { return ptr < end ? *ptr++ : Get_(); } int Get() { return ptr < end ? *ptr++ : Get_(); }
int Get(void *buffer, int len); int Get(void *buffer, int len);
String Get(int len); String Get(int len);
int GetAll(void *buffer, int len) { return Get(buffer, len) == len; }
String GetAll(int len);
String GetLine(int maxlen = 2000000);
int Put(const char *s, int len); int Put(const char *s, int len);
int Put(const String& s) { return Put(s.Begin(), s.GetLength()); } int Put(const String& s) { return Put(s.Begin(), s.GetLength()); }
bool PutAll(const char *s, int len) { return Put(s, len) == len; }
bool PutAll(const String& s) { return Put(s) == s.GetCount(); } bool GetAll(void *buffer, int len);
String GetAll(int len);
String GetLine(int maxlen = 65536);
bool PutAll(const char *s, int len);
bool PutAll(const String& s);
bool StartSSL(); bool StartSSL();
bool IsSSL() const { return ssl; } bool IsSSL() const { return ssl; }
bool SSLHandshake(); bool SSLHandshake();
void SSLCertificate(const String& cert, const String& pkey, bool asn1);
const SSLInfo *GetSSLInfo() const { return ~sslinfo; } const SSLInfo *GetSSLInfo() const { return ~sslinfo; }
TcpSocket& Timeout(int ms) { timeout = ms; return *this; } TcpSocket& Timeout(int ms) { timeout = ms; return *this; }

View file

@ -2,6 +2,19 @@
NAMESPACE_UPP NAMESPACE_UPP
String WwwFormat(Time tm)
{
static const char *dayofweek[] =
{ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
static const char *month[] =
{ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
return String().Cat()
<< dayofweek[DayOfWeek(tm)] << ", "
<< (int)tm.day << ' ' << month[tm.month - 1]
<< ' ' << (int)tm.year
<< ' ' << Sprintf("%2d:%02d:%02d +0100", tm.hour, tm.minute, tm.second);
}
String FormatIP(dword _ip) String FormatIP(dword _ip)
{ {
byte ip[4]; byte ip[4];

View file

@ -1,136 +1,136 @@
#include <Core/Core.h> #include <Core/Core.h>
#include <openssl/ssl.h> #include <openssl/ssl.h>
#include <openssl/conf.h> #include <openssl/conf.h>
#include <openssl/err.h> #include <openssl/err.h>
#include <openssl/engine.h> #include <openssl/engine.h>
NAMESPACE_UPP NAMESPACE_UPP
void SslInitThread(); void SslInitThread();
class SslBuffer class SslBuffer
{ {
public: public:
SslBuffer(BUF_MEM *m = NULL) : buf_mem(m) {} SslBuffer(BUF_MEM *m = NULL) : buf_mem(m) {}
~SslBuffer() { Clear(); } ~SslBuffer() { Clear(); }
bool IsEmpty() const { return !buf_mem; } bool IsEmpty() const { return !buf_mem; }
bool Set(BUF_MEM *b) { Clear(); return !!(buf_mem = b); } bool Set(BUF_MEM *b) { Clear(); return !!(buf_mem = b); }
bool Create() { return Set(BUF_MEM_new()); } bool Create() { return Set(BUF_MEM_new()); }
void Clear() { if(buf_mem) { BUF_MEM_free(buf_mem); buf_mem = NULL; } } void Clear() { if(buf_mem) { BUF_MEM_free(buf_mem); buf_mem = NULL; } }
BUF_MEM *Detach() { BUF_MEM *b = buf_mem; buf_mem = NULL; return b; } BUF_MEM *Detach() { BUF_MEM *b = buf_mem; buf_mem = NULL; return b; }
bool Grow(int length); bool Grow(int length);
String Get() const; String Get() const;
bool Set(const String& d); bool Set(const String& d);
operator BUF_MEM * () const { return buf_mem; } operator BUF_MEM * () const { return buf_mem; }
private: private:
BUF_MEM *buf_mem; BUF_MEM *buf_mem;
}; };
class SslStream class SslStream
{ {
public: public:
SslStream(BIO *b = NULL) : bio(b) {} SslStream(BIO *b = NULL) : bio(b) {}
~SslStream() { Clear(); } ~SslStream() { Clear(); }
bool IsEmpty() const { return !bio; } bool IsEmpty() const { return !bio; }
bool Set(BIO *b) { Clear(); return !!(bio = b); } bool Set(BIO *b) { Clear(); return !!(bio = b); }
bool Create(BIO_METHOD *meth) { return Set(BIO_new(meth)); } bool Create(BIO_METHOD *meth) { return Set(BIO_new(meth)); }
void Clear() { if(bio) { BIO_free(bio); bio = NULL; } } void Clear() { if(bio) { BIO_free(bio); bio = NULL; } }
bool OpenBuffer(const char *data, int length); bool OpenBuffer(const char *data, int length);
bool CreateBuffer(); bool CreateBuffer();
String GetResult() const; String GetResult() const;
operator BIO * () const { return bio; } operator BIO * () const { return bio; }
private: private:
BIO *bio; BIO *bio;
}; };
class SslKey class SslKey
{ {
public: public:
SslKey(EVP_PKEY *k = NULL) : key(k) {} SslKey(EVP_PKEY *k = NULL) : key(k) {}
~SslKey() { Clear(); } ~SslKey() { Clear(); }
bool IsEmpty() const { return !key; } bool IsEmpty() const { return !key; }
bool Set(EVP_PKEY *k) { Clear(); return !!(key = k); } bool Set(EVP_PKEY *k) { Clear(); return !!(key = k); }
void Clear() { if(key) { EVP_PKEY_free(key); key = NULL; } } void Clear() { if(key) { EVP_PKEY_free(key); key = NULL; } }
EVP_PKEY *Detach() { EVP_PKEY *k = key; key = NULL; return k; } EVP_PKEY *Detach() { EVP_PKEY *k = key; key = NULL; return k; }
operator EVP_PKEY * () const { return key; } operator EVP_PKEY * () const { return key; }
bool Load(const String& data); bool Load(const String& data);
private: private:
EVP_PKEY *key; EVP_PKEY *key;
}; };
class SslCertificate class SslCertificate
{ {
public: public:
SslCertificate(X509 *c = NULL) : cert(c) {} SslCertificate(X509 *c = NULL) : cert(c) {}
~SslCertificate() { Clear(); } ~SslCertificate() { Clear(); }
bool IsEmpty() const { return !cert; } bool IsEmpty() const { return !cert; }
bool Set(X509 *c) { Clear(); return !!(cert = c); } bool Set(X509 *c) { Clear(); return !!(cert = c); }
bool Create() { return Set(X509_new()); } bool Create() { return Set(X509_new()); }
void Clear() { if(cert) { X509_free(cert); cert = NULL; } } void Clear() { if(cert) { X509_free(cert); cert = NULL; } }
X509 *Detach() { X509 *c = cert; cert = NULL; return c; } X509 *Detach() { X509 *c = cert; cert = NULL; return c; }
bool Load(const String& data, bool asn1 = false); bool Load(const String& data, bool asn1 = false);
String Save(bool asn1 = false) const; String Save(bool asn1 = false) const;
String GetSubjectName() const; String GetSubjectName() const;
String GetIssuerName() const; String GetIssuerName() const;
Date GetNotBefore() const; Date GetNotBefore() const;
Date GetNotAfter() const; Date GetNotAfter() const;
int GetVersion() const; int GetVersion() const;
String GetSerialNumber() const; String GetSerialNumber() const;
operator X509 * () const { return cert; } operator X509 * () const { return cert; }
private: private:
X509 *cert; X509 *cert;
}; };
class SslContext class SslContext
{ {
public: public:
SslContext(SSL_CTX *c = NULL); SslContext(SSL_CTX *c = NULL);
~SslContext() { Clear(); } ~SslContext() { Clear(); }
bool IsEmpty() const { return !ssl_ctx; } bool IsEmpty() const { return !ssl_ctx; }
bool Set(SSL_CTX *c) { Clear(); return !!(ssl_ctx = c); } bool Set(SSL_CTX *c) { Clear(); return !!(ssl_ctx = c); }
bool Create(SSL_METHOD *meth) { return Set(SSL_CTX_new(meth)); } bool Create(SSL_METHOD *meth) { return Set(SSL_CTX_new(meth)); }
void Clear() { if(ssl_ctx) { SSL_CTX_free(ssl_ctx); ssl_ctx = NULL; } } void Clear() { if(ssl_ctx) { SSL_CTX_free(ssl_ctx); ssl_ctx = NULL; } }
SSL_CTX *Detach() { SSL_CTX *c = ssl_ctx; ssl_ctx = NULL; return c; } SSL_CTX *Detach() { SSL_CTX *c = ssl_ctx; ssl_ctx = NULL; return c; }
operator SSL_CTX * () const { return ssl_ctx; } operator SSL_CTX * () const { return ssl_ctx; }
bool CipherList(const char *list); bool CipherList(const char *list);
bool UseCertificate(String certificate, String private_key, bool cert_asn1 = false); bool UseCertificate(String certificate, String private_key, bool cert_asn1 = false);
void VerifyPeer(bool verify = true, int depth = 2); void VerifyPeer(bool verify = true, int depth = 2);
private: private:
SSL_CTX *ssl_ctx; SSL_CTX *ssl_ctx;
}; };
String SslGetLastError(int& code); String SslGetLastError(int& code);
String SslGetLastError(); String SslGetLastError();
String SslToString(X509_NAME *name); String SslToString(X509_NAME *name);
Date ASN1ToDate(ASN1_STRING *time); Date Asn1ToDate(ASN1_STRING *time);
String ASN1ToString(ASN1_STRING *s); String Asn1ToString(ASN1_STRING *s);
END_UPP_NAMESPACE END_UPP_NAMESPACE

View file

@ -6,7 +6,7 @@ NAMESPACE_UPP
struct TcpSocket::SSLImp : TcpSocket::SSL { struct TcpSocket::SSLImp : TcpSocket::SSL {
virtual bool Start(); virtual bool Start();
virtual bool Wait(dword flags); virtual bool Wait(dword flags, int end_time);
virtual int Send(const void *buffer, int maxlen); virtual int Send(const void *buffer, int maxlen);
virtual int Recv(void *buffer, int maxlen); virtual int Recv(void *buffer, int maxlen);
virtual void Close(); virtual void Close();
@ -109,7 +109,8 @@ bool TcpSocket::SSLImp::Start()
SetSSLError("Start: SSL context."); SetSSLError("Start: SSL context.");
return false; return false;
} }
// context.VerifyPeer(); if(socket.cert.GetCount())
context.UseCertificate(socket.cert, socket.pkey, socket.asn1);
if(!(ssl = SSL_new(context))) { if(!(ssl = SSL_new(context))) {
SetSSLError("Start: SSL_new"); SetSSLError("Start: SSL_new");
return false; return false;
@ -157,12 +158,12 @@ dword TcpSocket::SSLImp::Handshake()
return 0; return 0;
} }
bool TcpSocket::SSLImp::Wait(dword flags) bool TcpSocket::SSLImp::Wait(dword flags, int end_time)
{ {
LLOG("SSL Wait"); LLOG("SSL Wait");
if((flags & WAIT_READ) && SSL_pending(ssl) > 0) if((flags & WAIT_READ) && SSL_pending(ssl) > 0)
return true; return true;
return socket.RawWait(flags); return socket.RawWait(flags, end_time);
} }
int TcpSocket::SSLImp::Send(const void *buffer, int maxlen) int TcpSocket::SSLImp::Send(const void *buffer, int maxlen)

View file

@ -1,208 +1,208 @@
#include "SSL.h" #include "SSL.h"
NAMESPACE_UPP NAMESPACE_UPP
String SslBuffer::Get() const String SslBuffer::Get() const
{ {
if(IsEmpty()) if(IsEmpty())
return String::GetVoid(); return String::GetVoid();
return String(buf_mem->data, buf_mem->length); return String(buf_mem->data, buf_mem->length);
} }
bool SslBuffer::Grow(int length) bool SslBuffer::Grow(int length)
{ {
return !IsEmpty() && BUF_MEM_grow(buf_mem, length); return !IsEmpty() && BUF_MEM_grow(buf_mem, length);
} }
bool SslBuffer::Set(const String& d) bool SslBuffer::Set(const String& d)
{ {
if(!buf_mem && !Create()) if(!buf_mem && !Create())
return false; return false;
int len = d.GetLength(); int len = d.GetLength();
if((int)buf_mem->max < len && !Grow(len)) if((int)buf_mem->max < len && !Grow(len))
return false; return false;
ASSERT((int)buf_mem->max >= len); ASSERT((int)buf_mem->max >= len);
buf_mem->length = len; buf_mem->length = len;
memcpy(buf_mem, d, len); memcpy(buf_mem, d, len);
return true; return true;
} }
bool SslStream::OpenBuffer(const char *data, int length) bool SslStream::OpenBuffer(const char *data, int length)
{ {
return Set(BIO_new_mem_buf(const_cast<char *>(data), length)); return Set(BIO_new_mem_buf(const_cast<char *>(data), length));
} }
bool SslStream::CreateBuffer() bool SslStream::CreateBuffer()
{ {
Clear(); Clear();
SslBuffer buf; SslBuffer buf;
if(!buf.Create() || !Create(BIO_s_mem())) if(!buf.Create() || !Create(BIO_s_mem()))
return false; return false;
BIO_set_mem_buf(bio, buf.Detach(), BIO_CLOSE); BIO_set_mem_buf(bio, buf.Detach(), BIO_CLOSE);
return true; return true;
} }
String SslStream::GetResult() const String SslStream::GetResult() const
{ {
if(IsEmpty()) if(IsEmpty())
return String::GetVoid(); return String::GetVoid();
BUF_MEM *bm = NULL; BUF_MEM *bm = NULL;
BIO_get_mem_ptr(bio, &bm); BIO_get_mem_ptr(bio, &bm);
if(!bm) if(!bm)
return String::GetVoid(); return String::GetVoid();
return String(bm->data, bm->length); return String(bm->data, bm->length);
} }
bool SslKey::Load(const String& data) bool SslKey::Load(const String& data)
{ {
Clear(); Clear();
SslStream strm; SslStream strm;
if(!strm.OpenBuffer(data.Begin(), data.GetLength())) if(!strm.OpenBuffer(data.Begin(), data.GetLength()))
return false; return false;
return Set(PEM_read_bio_PrivateKey(strm, NULL, NULL, NULL)); return Set(PEM_read_bio_PrivateKey(strm, NULL, NULL, NULL));
} }
bool SslCertificate::Load(const String& data, bool asn1) bool SslCertificate::Load(const String& data, bool asn1)
{ {
Clear(); Clear();
SslStream in, pem, *sio = &in; SslStream in, pem, *sio = &in;
if(!in.OpenBuffer(data, data.GetLength())) if(!in.OpenBuffer(data, data.GetLength()))
return false; return false;
if(!asn1) if(!asn1)
{ {
if(!pem.Create(BIO_f_base64())) if(!pem.Create(BIO_f_base64()))
return false; return false;
BIO_push(pem, in); BIO_push(pem, in);
sio = &pem; sio = &pem;
} }
return Set(d2i_X509_bio(*sio, NULL)); return Set(d2i_X509_bio(*sio, NULL));
} }
String SslCertificate::Save(bool asn1) const String SslCertificate::Save(bool asn1) const
{ {
if(IsEmpty()) if(IsEmpty())
return String::GetVoid(); return String::GetVoid();
SslStream out, pem, *sio = &out; SslStream out, pem, *sio = &out;
if(!out.CreateBuffer()) if(!out.CreateBuffer())
return String::GetVoid(); return String::GetVoid();
if(!asn1) if(!asn1)
{ {
if(!pem.Create(BIO_f_base64())) if(!pem.Create(BIO_f_base64()))
return String::GetVoid(); return String::GetVoid();
BIO_push(pem, out); BIO_push(pem, out);
sio = &pem; sio = &pem;
} }
i2d_X509_bio(*sio, cert); i2d_X509_bio(*sio, cert);
return out.GetResult(); return out.GetResult();
} }
String SslCertificate::GetSubjectName() const String SslCertificate::GetSubjectName() const
{ {
ASSERT(!IsEmpty()); ASSERT(!IsEmpty());
return SslToString(X509_get_subject_name(cert)); return SslToString(X509_get_subject_name(cert));
} }
String SslCertificate::GetIssuerName() const String SslCertificate::GetIssuerName() const
{ {
ASSERT(!IsEmpty()); ASSERT(!IsEmpty());
return SslToString(X509_get_issuer_name(cert)); return SslToString(X509_get_issuer_name(cert));
} }
Date SslCertificate::GetNotBefore() const Date SslCertificate::GetNotBefore() const
{ {
ASSERT(!IsEmpty()); ASSERT(!IsEmpty());
return ASN1ToDate(X509_get_notBefore(cert)); return Asn1ToDate(X509_get_notBefore(cert));
} }
Date SslCertificate::GetNotAfter() const Date SslCertificate::GetNotAfter() const
{ {
ASSERT(!IsEmpty()); ASSERT(!IsEmpty());
return ASN1ToDate(X509_get_notAfter(cert)); return Asn1ToDate(X509_get_notAfter(cert));
} }
int SslCertificate::GetVersion() const int SslCertificate::GetVersion() const
{ {
ASSERT(!IsEmpty()); ASSERT(!IsEmpty());
return X509_get_version(cert); return X509_get_version(cert);
} }
String SslCertificate::GetSerialNumber() const String SslCertificate::GetSerialNumber() const
{ {
ASSERT(!IsEmpty()); ASSERT(!IsEmpty());
return ASN1ToString(X509_get_serialNumber(cert)); return Asn1ToString(X509_get_serialNumber(cert));
} }
SslContext::SslContext(SSL_CTX *c) SslContext::SslContext(SSL_CTX *c)
: ssl_ctx(c) : ssl_ctx(c)
{ {
SslInitThread(); SslInitThread();
} }
bool SslContext::CipherList(const char *list) bool SslContext::CipherList(const char *list)
{ {
ASSERT(ssl_ctx); ASSERT(ssl_ctx);
return SSL_CTX_set_cipher_list(ssl_ctx, list); return SSL_CTX_set_cipher_list(ssl_ctx, list);
} }
bool SslContext::UseCertificate(String certdata, String pkeydata, bool cert_asn1) bool SslContext::UseCertificate(String certdata, String pkeydata, bool cert_asn1)
{ {
ASSERT(ssl_ctx); ASSERT(ssl_ctx);
if(IsNull(certdata) || IsNull(pkeydata)) if(IsNull(certdata) || IsNull(pkeydata))
return false; return false;
SslCertificate cert; SslCertificate cert;
SslKey pkey; SslKey pkey;
if(!cert.Load(certdata, cert_asn1) || !pkey.Load(pkeydata)) if(!cert.Load(certdata, cert_asn1) || !pkey.Load(pkeydata))
return false; return false;
if(!SSL_CTX_use_certificate(ssl_ctx, cert) || !SSL_CTX_use_PrivateKey(ssl_ctx, pkey)) if(!SSL_CTX_use_certificate(ssl_ctx, cert) || !SSL_CTX_use_PrivateKey(ssl_ctx, pkey))
return false; return false;
if(!SSL_CTX_check_private_key(ssl_ctx)) if(!SSL_CTX_check_private_key(ssl_ctx))
return false; return false;
return true; return true;
} }
void SslContext::VerifyPeer(bool verify, int depth) void SslContext::VerifyPeer(bool verify, int depth)
{ {
ASSERT(ssl_ctx); ASSERT(ssl_ctx);
SSL_CTX_set_verify(ssl_ctx, verify ? SSL_VERIFY_PEER : SSL_VERIFY_NONE, NULL); SSL_CTX_set_verify(ssl_ctx, verify ? SSL_VERIFY_PEER : SSL_VERIFY_NONE, NULL);
SSL_CTX_set_verify_depth(ssl_ctx, depth); SSL_CTX_set_verify_depth(ssl_ctx, depth);
} }
String SslGetLastError(int& code) String SslGetLastError(int& code)
{ {
char errbuf[150]; char errbuf[150];
ERR_error_string(code = ERR_get_error(), errbuf); ERR_error_string(code = ERR_get_error(), errbuf);
return errbuf; return errbuf;
} }
String SslGetLastError() String SslGetLastError()
{ {
int dummy; int dummy;
return SslGetLastError(dummy); return SslGetLastError(dummy);
} }
String SslToString(X509_NAME *name) String SslToString(X509_NAME *name)
{ {
char buffer[500]; char buffer[500];
return X509_NAME_oneline(name, buffer, sizeof(buffer)); return X509_NAME_oneline(name, buffer, sizeof(buffer));
} }
Date ASN1ToDate(ASN1_STRING *time) Date Asn1ToDate(ASN1_STRING *time)
{ {
if(!time) return Null; if(!time) return Null;
int digit = 0; int digit = 0;
while(digit < time->length && IsDigit(time->data[digit])) while(digit < time->length && IsDigit(time->data[digit]))
digit++; digit++;
if(digit < 6) if(digit < 6)
return Null; return Null;
int year2 = time->data[0] * 10 + time->data[1] - 11 * '0'; int year2 = time->data[0] * 10 + time->data[1] - 11 * '0';
int month = time->data[2] * 10 + time->data[3] - 11 * '0'; int month = time->data[2] * 10 + time->data[3] - 11 * '0';
int day = time->data[4] * 10 + time->data[5] - 11 * '0'; int day = time->data[4] * 10 + time->data[5] - 11 * '0';
return Date(year2 + (year2 < 90 ? 2000 : 1900), month, day); return Date(year2 + (year2 < 90 ? 2000 : 1900), month, day);
} }
String ASN1ToString(ASN1_STRING *s) String Asn1ToString(ASN1_STRING *s)
{ {
return String(s->data, s->length); return String(s->data, s->length);
} }
END_UPP_NAMESPACE END_UPP_NAMESPACE

View file

@ -272,6 +272,7 @@ TcpSocket::TcpSocket()
Reset(); Reset();
timeout = Null; timeout = Null;
waitstep = 20; waitstep = 20;
asn1 = false;
} }
bool TcpSocket::Open(int family, int type, int protocol) bool TcpSocket::Open(int family, int type, int protocol)
@ -343,9 +344,14 @@ bool TcpSocket::Accept(TcpSocket& ls)
Close(); Close();
Init(); Init();
Reset(); Reset();
ASSERT(ls.IsOpen());
if(timeout && !ls.WaitRead()) if(timeout) {
return false; int h = ls.GetTimeout();
bool b = ls.Timeout(timeout).Wait(WAIT_READ, GetEndTime());
ls.Timeout(h);
if(!b)
return false;
}
if(!Open(ls.ipv6 ? AF_INET6 : AF_INET, SOCK_STREAM, 0)) if(!Open(ls.ipv6 ? AF_INET6 : AF_INET, SOCK_STREAM, 0))
return false; return false;
socket = accept(ls.GetSOCKET(), NULL, NULL); socket = accept(ls.GetSOCKET(), NULL, NULL);
@ -519,12 +525,11 @@ String TcpSocket::GetHostName()
return buffer; return buffer;
} }
bool TcpSocket::RawWait(dword flags) bool TcpSocket::RawWait(dword flags, int end_time)
{ {
LLOG("Wait(" << timeout << ", " << flags << ")"); LLOG("Wait(" << msecs() << " - " << end_time << ", " << flags << ")");
if((flags & WAIT_READ) && ptr != end) if((flags & WAIT_READ) && ptr != end)
return true; return true;
int end_time = msecs() + timeout;
if(socket == INVALID_SOCKET) if(socket == INVALID_SOCKET)
return false; return false;
for(;;) { for(;;) {
@ -564,9 +569,19 @@ bool TcpSocket::RawWait(dword flags)
} }
} }
bool TcpSocket::Wait(dword flags, int end_time)
{
return ssl ? ssl->Wait(flags, end_time) : RawWait(flags, end_time);
}
int TcpSocket::GetEndTime() const
{
return IsNull(timeout) ? INT_MAX : msecs() + timeout;
}
bool TcpSocket::Wait(dword flags) bool TcpSocket::Wait(dword flags)
{ {
return ssl ? ssl->Wait(flags) : RawWait(flags); return Wait(flags, GetEndTime());
} }
int TcpSocket::Put(const char *s, int length) int TcpSocket::Put(const char *s, int length)
@ -579,8 +594,9 @@ int TcpSocket::Put(const char *s, int length)
return 0; return 0;
done = 0; done = 0;
bool peek = false; bool peek = false;
int end_time = GetEndTime();
while(done < length) { while(done < length) {
if(peek && !WaitWrite()) if(peek && !Wait(WAIT_WRITE, end_time))
return done; return done;
peek = false; peek = false;
int count = Send(s + done, length - done); int count = Send(s + done, length - done);
@ -595,6 +611,26 @@ int TcpSocket::Put(const char *s, int length)
return done; return done;
} }
bool TcpSocket::PutAll(const char *s, int len)
{
if(Put(s, len) != len) {
if(!IsError())
SetSockError("GePutAll", -1, "timeout");
return false;
}
return true;
}
bool TcpSocket::PutAll(const String& s)
{
if(Put(s) != s.GetCount()) {
if(!IsError())
SetSockError("GePutAll", -1, "timeout");
return false;
}
return true;
}
int TcpSocket::RawRecv(void *buf, int amount) int TcpSocket::RawRecv(void *buf, int amount)
{ {
int res = recv(socket, (char *)buf, amount, 0); int res = recv(socket, (char *)buf, amount, 0);
@ -619,10 +655,10 @@ int TcpSocket::Recv(void *buffer, int maxlen)
return ssl ? ssl->Recv(buffer, maxlen) : RawRecv(buffer, maxlen); return ssl ? ssl->Recv(buffer, maxlen) : RawRecv(buffer, maxlen);
} }
void TcpSocket::ReadBuffer() void TcpSocket::ReadBuffer(int end_time)
{ {
ptr = end = buffer; ptr = end = buffer;
if(WaitRead()) if(Wait(WAIT_READ, end_time))
end = buffer + Recv(buffer, BUFFERSIZE); end = buffer + Recv(buffer, BUFFERSIZE);
} }
@ -630,16 +666,21 @@ int TcpSocket::Get_()
{ {
if(!IsOpen() || IsError() || IsEof() || IsAbort()) if(!IsOpen() || IsError() || IsEof() || IsAbort())
return -1; return -1;
ReadBuffer(); ReadBuffer(GetEndTime());
return ptr < end ? *ptr++ : -1; return ptr < end ? *ptr++ : -1;
} }
int TcpSocket::Peek_(int end_time)
{
if(!IsOpen() || IsError() || IsEof() || IsAbort())
return -1;
ReadBuffer(end_time);
return ptr < end ? *ptr : -1;
}
int TcpSocket::Peek_() int TcpSocket::Peek_()
{ {
if(!IsOpen() || IsError() || IsEof() || IsAbort()) return Peek_(GetEndTime());
return -1;
ReadBuffer();
return ptr < end ? *ptr : -1;
} }
int TcpSocket::Get(void *buffer, int count) int TcpSocket::Get(void *buffer, int count)
@ -663,8 +704,9 @@ int TcpSocket::Get(void *buffer, int count)
ptr += count; ptr += count;
return count; return count;
} }
int end_time = GetEndTime();
while(done < count && !IsError() && !IsEof()) { while(done < count && !IsError() && !IsEof()) {
if(!WaitRead()) if(!Wait(WAIT_READ, end_time))
break; break;
int part = Recv((char *)buffer + done, count - done); int part = Recv((char *)buffer + done, count - done);
if(part > 0) if(part > 0)
@ -687,19 +729,41 @@ String TcpSocket::Get(int count)
return out; return out;
} }
bool TcpSocket::GetAll(void *buffer, int len)
{
if(Get(buffer, len) == len)
return true;
if(!IsError())
SetSockError("GetAll", -1, "timeout");
return false;
}
String TcpSocket::GetAll(int len) String TcpSocket::GetAll(int len)
{ {
String s = Get(len); String s = Get(len);
return s.GetCount() == len ? s : String::GetVoid(); if(s.GetCount() != len) {
if(IsEof())
return s;
if(!IsError())
SetSockError("GetAll", -1, "timeout");
return String::GetVoid();
}
return s;
} }
String TcpSocket::GetLine(int maxlen) String TcpSocket::GetLine(int maxlen)
{ {
String ln; String ln;
int end_time = GetEndTime();
for(;;) { for(;;) {
int c = Peek(); int c = Peek(end_time);
if(c < 0) if(c < 0) {
if(IsEof())
return ln;
if(!IsError())
SetSockError("GetLine", -1, "timeout");
return String::GetVoid(); return String::GetVoid();
}
Get(); Get();
if(c == '\n') if(c == '\n')
return ln; return ln;
@ -767,6 +831,13 @@ bool TcpSocket::SSLHandshake()
return false; return false;
} }
void TcpSocket::SSLCertificate(const String& cert_, const String& pkey_, bool asn1_)
{
cert = cert_;
pkey = pkey_;
asn1 = asn1_;
}
int SocketWaitEvent::Wait(int timeout) int SocketWaitEvent::Wait(int timeout)
{ {
FD_ZERO(read); FD_ZERO(read);

View file

@ -125,6 +125,9 @@ dword GetTickCount() {
gettimeofday(tv, tz); gettimeofday(tv, tz);
return (dword)tv->tv_sec * 1000 + tv->tv_usec / 1000; return (dword)tv->tv_sec * 1000 + tv->tv_usec / 1000;
} }
int msecs(int from) { return int((GetTickCount() - (dword)from) & 0x7fffffff); }
#endif #endif
void TimeStop::Reset() void TimeStop::Reset()

View file

@ -9,6 +9,8 @@ static const int _MAX_PATH = PATH_MAX;
dword GetTickCount(); dword GetTickCount();
#endif #endif
int msecs(int from = 0);
class TimeStop : Moveable<TimeStop> { class TimeStop : Moveable<TimeStop> {
dword starttime; dword starttime;

View file

@ -2,19 +2,6 @@
NAMESPACE_UPP NAMESPACE_UPP
String WwwFormat(Time tm)
{
static const char *dayofweek[] =
{ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
static const char *month[] =
{ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
return String().Cat()
<< dayofweek[DayOfWeek(tm)] << ", "
<< (int)tm.day << ' ' << month[tm.month - 1]
<< ' ' << (int)tm.year
<< ' ' << Sprintf("%2d:%02d:%02d +0100", tm.hour, tm.minute, tm.second);
}
bool IsSameTextFile(const char *p, const char *q) bool IsSameTextFile(const char *p, const char *q)
{ {
for(;;) for(;;)

View file

@ -1,7 +1,6 @@
#ifndef __tweb_util__ #ifndef __tweb_util__
#define __tweb_util__ #define __tweb_util__
String WwwFormat(Time tm);
bool IsSameTextFile(const char *p, const char *q); bool IsSameTextFile(const char *p, const char *q);
String StringSample(const char *s, int limit); String StringSample(const char *s, int limit);
String GetRandomIdent(int length); String GetRandomIdent(int length);