S_Flash
Вот весь модуль ssl.cc
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <string>
#include "libstr.h"
#include "bill.hh"
#define TIMEOUT 30
#define SSL_PORT 443
SSL*
open_ssl_sock(string host, int timeout) {
SSL_METHOD *meth;
SSL* ssl;
SSL_CTX* ctx;
struct hostent* he;
struct sockaddr_in sa;
struct timeval tv;
unsigned char *addr;
char ip[128];
int sd;
if ((he = gethostbyname(host.c_str())) != NULL) {
addr = (unsigned char*)he->h_addr;
snprintf(ip, sizeof(ip), "%d.%d.%d.%d", addr[0], addr[1], addr[2], addr[3]);
}
else {
throw string("can't resolve ")+host+" : "+hstrerror(h_errno);
}
SSL_load_error_strings();
SSL_library_init();
//meth = (SSL_METHOD*)SSLv23_client_method();
meth = (SSL_METHOD*)TLSv1_2_client_method();
if((ctx = SSL_CTX_new(meth)) == NULL) {
throw "SSL: SSL_CTX_new() failed";
}
SSL_CTX_set_timeout(ctx, timeout);
sd = socket (AF_INET, SOCK_STREAM, 0);
tv.tv_sec = timeout;
tv.tv_usec = 0;
setsockopt(sd, SOL_SOCKET, SO_RCVTIMEO, (char*)&tv, sizeof(struct timeval));
setsockopt(sd, SOL_SOCKET, SO_SNDTIMEO, (char*)&tv, sizeof(struct timeval));
memset (&sa, '\0', sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_addr.s_addr = inet_addr(ip);
sa.sin_port = htons(SSL_PORT);
if (connect(sd, (struct sockaddr*)&sa, sizeof(sa)) == -1) {
SSL_CTX_free (ctx);
throw string("SSL: connect() failed : ") + strerror(errno);
}
tv.tv_sec = timeout;
setsockopt(sd, SOL_SOCKET, SO_RCVTIMEO, (char*)&tv, sizeof(struct timeval));
setsockopt(sd, SOL_SOCKET, SO_SNDTIMEO, (char*)&tv, sizeof(struct timeval));
if((ssl = SSL_new(ctx)) == NULL) {
SSL_CTX_free (ctx);
close(sd);
throw "SSL: SSL_new() failed";
}
SSL_set_fd(ssl, sd);
if (SSL_connect (ssl) == -1) {
SSL_CTX_free(ssl->ctx);
SSL_free(ssl);
close(sd);
throw "Can't connect to host via SSL";
}
return ssl;
};
void
close_ssl_sock(SSL *ssl)
{
SSL_shutdown(ssl);
SSL_CTX_free(ssl->ctx);
close(SSL_get_fd(ssl));
SSL_free(ssl);
}
string
read_responce(SSL *ssl, bool verbose)
{
char buff[1024*16];
string data;
int r;
unsigned long n;
// read response
while ((r = SSL_read(ssl, buff, sizeof(buff)-1))) {
if (verbose) cout << "read_responce() : " << r << " bytes" << endl;
if (r < 0) {
break;
}
buff[r] = 0;
data += buff;
}
if ((n = data.find("\r\n")) == string::npos) {
n = data.find("\n");
}
if (n == string::npos || n < 15) {
cout << "ssl_read_responce(): Read timeout or invalid HTTP response : "+data;
return "";
}
// if (data.substr(0, 15) != "HTTP/1.1 200 OK" && data.substr(0, 15) != "HTTP/1.0 200 OK") {
if (data.substr(0, 15) != "HTTP/1.1 200 OK" && data.substr(0, 15) != "HTTP/1.0 200 OK" && data.substr(0, 15) != "HTTP/1.0 302 Fo") {
cout << "ssl_read_responce(): bad HTTP code : "+data;
return "";
}
return data;
}
string
http_get_request(string host, string path, string query, bool verbose, string auth, string method)
{
int sock, bytes;
unsigned long n;
size_t sin_size;
struct sockaddr_in serv_addr;
struct timeval timeout;
struct hostent *he;
fd_set fds;
char buff[4096];
string xml;
string req = method+" "+path+(!query.empty() ? "?"+query : "")+" HTTP/1.1\r\nHost: "+host+"\r\n";
if (!auth.empty()) {
req += "Authorization: Basic "+auth+"\r\n";
}
req += "\r\n";
if (verbose) cout << "http_get_request(): " << req;
// resolve host
he = gethostbyname(host.c_str());
if (he == NULL) {
throw string("can't resolve hostname ")+host+" : "+hstrerror(h_errno);
}
// create socket
sock = socket(AF_INET, SOCK_STREAM, 0);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr = * ((struct in_addr *) he->h_addr); ;
serv_addr.sin_port = htons(80);
memset(&(serv_addr.sin_zero), '\0', 8);
sin_size = sizeof(struct sockaddr_in);
// connect
if (connect(sock, (struct sockaddr*)&serv_addr, sin_size) != 0) {
throw string("connect() failed : ")+strerror(errno);
}
// send request
write(sock, req.c_str(), req.length());
// read response
while (1) {
// timeout checking
FD_ZERO(&fds);
FD_SET(sock, &fds);
timeout.tv_sec = TIMEOUT;
timeout.tv_usec = 0;
if (select(sock+1, &fds, NULL, NULL, &timeout) == 0) {
break;
}
// read data
memset(buff, 0, sizeof(buff));
bytes = read(sock, buff, sizeof(buff)-1);
xml += buff;
if (bytes == 0) {
// no more data
break;
}
if (bytes == -1) {
throw "http_get_request(): read error - timeout";
}
}
// HEAD - return all response
if (method == "HEAD") {
return xml;
}
// GET - remove headers and decode
if ((n = xml.find("\r\n")) == string::npos) {
n = xml.find("\n");
}
if (n == string::npos || n < 15) {
cout << "http_get_request(): Read timeout or invalid HTTP response : '"+xml+"'";
return "";
}
string code = xml.substr(9, 3);
if (code != "200" && code != "302") {
cout << "http_get_request(): bad HTTP code : '"+xml.substr(0, 15)+"'";
return "";
}
xml = chunk_decode(xml);
return xml;
}
string
http_post_request(string host, string path, string query, bool verbose, string cookie)
{
string headers, req;
int sock, bytes;
unsigned long n;
size_t sin_size;
struct sockaddr_in serv_addr;
struct timeval timeout;
struct hostent *he;
fd_set fds;
char buff[4096];
string xml;
headers = "Content-Type: application/x-www-form-urlencoded\r\n";
headers += "Content-Length: "+itoa(query.size())+"\r\n";
headers += "Connection: close\r\n";
req = "POST "+path+" HTTP/1.1\r\n";
req += "Host: "+host+"\r\n";
if (!cookie.empty()) {
req += "Cookie: "+cookie+";\r\n";
}
req += headers;
req += "\r\n";
req += query;
if (verbose) cout << "http_post_request(): " << req << endl;
// resolve host
he = gethostbyname(host.c_str());
if (he == NULL) {
throw string("can't resolve hostname ")+host+" : "+hstrerror(h_errno);
}
// create socket
sock = socket(AF_INET, SOCK_STREAM, 0);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr = * ((struct in_addr *) he->h_addr); ;
serv_addr.sin_port = htons(80);
memset(&(serv_addr.sin_zero), '\0', 8);
sin_size = sizeof(struct sockaddr_in);
// connect
if (connect(sock, (struct sockaddr*)&serv_addr, sin_size) != 0) {
throw string("connect() failed : ")+strerror(errno);
}
// send request
write(sock, req.c_str(), req.length());
// read response
while (1) {
// timeout checking
FD_ZERO(&fds);
FD_SET(sock, &fds);
timeout.tv_sec = TIMEOUT;
timeout.tv_usec = 0;
if (select(sock+1, &fds, NULL, NULL, &timeout) == 0) {
break;
}
// read data
memset(buff, 0, sizeof(buff));
bytes = read(sock, buff, sizeof(buff)-1);
xml += buff;
if (bytes == 0) {
// no more data
break;
}
if (bytes == -1) {
throw "http_post_request(): read error - timeout";
}
}
if ((n = xml.find("\r\n")) == string::npos) {
n = xml.find("\n");
}
if (n == string::npos || n < 15) {
cout << "http_post_request(): Read timeout or invalid HTTP response : '"+xml+"'";
return "";
}
string code = xml.substr(9, 3);
if (code != "200" && code != "302") {
cout << "http_post_request(): bad HTTP code : '"+xml.substr(0, 15)+"'";
return "";
}
xml = chunk_decode(xml);
return xml;
}