uniform-io-0.1.0.0: src/System/IO/Uniform/ds.c
#include <malloc.h>
#include <unistd.h>
#include <string.h>
//#include <sys/select.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <errno.h>
#include <openssl/bio.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include "ds.h"
int openSslLoaded = 0;
void *clear(void *ptr){
int e = errno;
if(ptr){
free(ptr);
}
errno = e;
return NULL;
}
void loadOpenSSL(){
if(!openSslLoaded){
openSslLoaded = 1;
SSL_load_error_strings();
ERR_load_BIO_strings();
ERR_load_crypto_strings();
SSL_library_init();
OpenSSL_add_all_algorithms();
}
}
void copy6addr(unsigned char d[16], const unsigned char s[16]){
int i;
for(i = 0; i < 16; i++)
d[i] = s[i];
}
void zero6addr(unsigned char d[16]){
int i;
for(i = 0; i < 16; i++)
d[i] = 0;
}
nethandler getNethandler(const int ipv6, const int port){
nethandler h = (nethandler)malloc(sizeof(s_nethandler));
h->ipv6 = ipv6;
if(ipv6){
h->s = socket(AF_INET6, SOCK_STREAM, 0);
}else{
h->s = socket(AF_INET, SOCK_STREAM, 0);
}
int optval = 1;
setsockopt(h->s, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
int e, en;
if(ipv6){
struct sockaddr_in6 add;
add.sin6_family = AF_INET6;
zero6addr(add.sin6_addr.s6_addr);
add.sin6_port = htons(port);
e = bind(h->s, (struct sockaddr*) &add, sizeof(add));
}else{
struct sockaddr_in add;
add.sin_family = AF_INET;
add.sin_addr.s_addr = INADDR_ANY;
add.sin_port = htons(port);
e = bind(h->s, (struct sockaddr*) &add, sizeof(add));
}
if(e)
return clear(h);
e = listen(h->s, DEFAULT_LISTENNING_QUEUE);
if(e)
return clear(h);
return h;
}
nethandler getIPv4Port(const int port){
return getNethandler(0, port);
}
nethandler getPort(const int port){
return getNethandler(1, port);
}
fileDs createFromFile(int f){
fileDs d = (fileDs)malloc(sizeof(s_fileDs));
d->f = f;
return d;
}
fileDs createFromFileName(const char *f){
int fd = open(f, O_CREAT | O_RDWR);
if(fd == -1){
return NULL;
}
return createFromFile(fd);
}
sockDs createFromHandler(nethandler h){
sockDs d = (sockDs)malloc(sizeof(s_sockDs));
unsigned int s = sizeof(d->peer);
d->s = accept(h->s, (struct sockaddr*)&(d->peer), &s);
if(d->s <= 0)
return clear(d);
d->ipv6 = d->peer.ss_family == AF_INET6;
d->server = 1;
return d;
}
sockDs createToHost(struct sockaddr *add, const int add_size, const int ipv6){
sockDs d = (sockDs)malloc(sizeof(s_sockDs));
if(ipv6){
d->s = socket(AF_INET6, SOCK_STREAM, 0);
}else{
d->s = socket(AF_INET, SOCK_STREAM, 0);
}
if(connect(d->s, add, add_size) < 0){
int e = errno;
free(d);
errno = e;
return NULL;
}
d->server = 0;
return d;
}
sockDs createToIPv4Host(const unsigned long host, const int port){
struct sockaddr_in add;
add.sin_family = AF_INET;
add.sin_port = htons(port);
add.sin_addr.s_addr = host;
return createToHost((struct sockaddr*) &add, sizeof(add), 0);
}
sockDs createToIPv6Host(const unsigned char host[16], const int port){
struct sockaddr_in6 add;
add.sin6_family = AF_INET6;
add.sin6_port = htons(port);
add.sin6_flowinfo = 0;
copy6addr(add.sin6_addr.s6_addr, host);
add.sin6_scope_id = 0;
return createToHost((struct sockaddr*) &add, sizeof(add), 1);
}
int getPeer(sockDs d, unsigned long *ipv4peer, unsigned char ipv6peer[16], int *ipv6){
int port = 0;
struct sockaddr_storage peer;
int peer_size = sizeof(peer);
if(getpeername(d->s, (struct sockaddr*)&peer, &peer_size)){
return 0;
}
if(peer.ss_family == AF_INET){
struct sockaddr_in *a = (struct sockaddr_in*)&(peer);
zero6addr(ipv6peer);
*ipv6 = -1;
*ipv4peer = a->sin_addr.s_addr;
port = a->sin_port;
}else{
struct sockaddr_in6 *a = (struct sockaddr_in6*)&(peer);
*ipv4peer = 0;
*ipv6 = 1;
copy6addr(ipv6peer, a->sin6_addr.s6_addr);
port = a->sin6_port;
}
return port;
}
int fileDsSend(fileDs d, const char *b, const int s){
return write(d->f, b, s);
}
int sockDsSend(sockDs d, const char *b, const int s){
return write(d->s, b, s);
}
int tlsDsSend(tlsDs d, const char *b, const int s){
return SSL_write(d->s, b, s);
}
int stdDsSend(const char *b, const int s){
return write(1, b, s);
}
int fileDsRecv(fileDs d, char *b, const int s){
return read(d->f, b, s);
}
int sockDsRecv(sockDs d, char *b, const int s){
return read(d->s, b, s);
}
int tlsDsRecv(tlsDs d, char *b, const int s){
return SSL_read(d->s, b, s);
}
int stdDsRecv(char *b, const int s){
return read(0, b, s);
}
void closeFileDs(fileDs d){
close(d->f);
free(d);
}
void closeSockDs(sockDs d){
close(d->s);
free(d);
}
void closeTlsDs(tlsDs d){
SSL_shutdown(d->s);
SSL_shutdown(d->s);
SSL_free(d->s);
switch(d->tp){
case file:
closeFileDs(d->original);
break;
case sock:
closeSockDs(d->original);
break;
}
free(d);
}
void closeHandler(nethandler h){
close(h->s);
free(h);
}
tlsDs startSockTls(sockDs d, const char *cert, const char *key){
loadOpenSSL();
SSL_CTX * ctx = NULL;
if(d->server)
ctx = SSL_CTX_new(TLSv1_server_method());
else
ctx = SSL_CTX_new(TLSv1_client_method());
if(!ctx)
return NULL;
SSL_CTX_set_options(ctx, SSL_OP_SINGLE_DH_USE);
if(cert)
if(SSL_CTX_use_certificate_chain_file(ctx, cert) != 1){
closeSockDs(d);
return clear(ctx);
}
if(key)
if(SSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM) != 1){
closeSockDs(d);
return clear(ctx);
}
tlsDs t = (tlsDs)malloc(sizeof(s_tlsDs));
t->original = d;
if(!(t->s = SSL_new(ctx))){
closeSockDs(d);
clear(ctx);
return clear(t);
}
if(!SSL_set_fd(t->s, d->s)){
closeTlsDs(t);
return NULL;
}
printf("Starting handshake\n");
int retry = 1;
int e;
while(retry){
retry = 0;
if(d->server)
e = SSL_accept(t->s);
else
e = SSL_connect(t->s);
if(e <= 0){
retry = 1;
int erval = SSL_get_error(t->s, e);
if((erval == SSL_ERROR_WANT_READ) || (erval == SSL_ERROR_WANT_WRITE)){
}else{
printf("Error\n");
ERR_print_errors(t->s->bbio);
closeTlsDs(t);
return NULL;
}
}
}
printf("Success\n");
return t;
}