[openssl-users] Application and TCP buffers with OpenSSL
Dipak Gaigole
dipakgaigole at rediffmail.com
Tue Jun 16 08:00:01 UTC 2015
Hello,
I am writing a Client Server program. In order to achieve the Network
Throughput I was playing around with the Application buffer size and TCP
Buffer size (SO_SNDBUF/SO_RCVBUF) to find the best values for a specific
client-server pair. I am transferring a file of size 748MB from Client to
Server which are in LAN.
I had tested this with Basic TCP and OpenSSL enabled Client Server program
and have measured the time it takes to transfer the file.
1) In Basic TCP Client Server program I could see the gain at the
different combinations of those 2 buffer values.
2) In OpenSSL enabled Client Server I couldn’t see such gain and the
values are too high as compared to Basic TCP Client Server.
Here are few results:
####### TCP Client #######
[root at vl-blg-dv10 dipak]# zsh
[root at vl-blg-dv10]~/dipak# ./tcp-client_1
usage: ./tcp-client_1 <IPAddress> <port> <filename> <bufferSize>
<tcpbufsize>
[root at vl-blg-dv10]~/dipak# time ./tcp-client_1 10.129.85.242 32000 /tmp/748M
16384 65536 >/dev/null
./tcp-client_1 10.129.85.242 32000 /tmp/748M 16384 65536 > /dev/null 0.06s
user 1.47s system 4% cpu 33.930 total
[root at vl-blg-dv10]~/dipak# time ./tcp-client_1 10.129.85.242 32000 /tmp/748M
65536 131072 >/dev/null
./tcp-client_1 10.129.85.242 32000 /tmp/748M 65536 131072 > /dev/null 0.02s
user 1.20s system 14% cpu 8.503 total
[root at vl-blg-dv10]~/dipak# time ./tcp-client_1 10.129.85.242 32000 /tmp/748M
131072 524288 >/dev/null
./tcp-client_1 10.129.85.242 32000 /tmp/748M 131072 524288 > /dev/null
0.01s user 1.06s system 20% cpu 5.154 total
[root at vl-blg-dv10]~/dipak#
####### OpenSSL Enabled Client #######
[root at vl-blg-dv10]~/dipak# ./SSL_Client_3
usage: ./SSL_Client_3 <hostname> <portnum> <FileName> <AppBufferSize>
<TCPBufferSize>
[root at vl-blg-dv10]~/dipak# time ./SSL_Client_3 10.129.85.242 32000 /tmp/748M
16384 65536 > /dev/null
./SSL_Client_3 10.129.85.242 32000 /tmp/748M 16384 65536 > /dev/null 68.20s
user 3.68s system 86% cpu 1:23.19 total
[root at vl-blg-dv10]~/dipak# time ./SSL_Client_3 10.129.85.242 32000 /tmp/748M
65536 131072 > /dev/null
./SSL_Client_3 10.129.85.242 32000 /tmp/748M 65536 131072 > /dev/null
59.22s user 2.20s system 86% cpu 1:11.06 total
[root at vl-blg-dv10]~/dipak# time ./SSL_Client_3 10.129.85.242 32000 /tmp/748M
131072 524288 > /dev/null
./SSL_Client_3 10.129.85.242 32000 /tmp/748M 131072 524288 > /dev/null
62.15s user 2.45s system 88% cpu 1:12.92 total
[root at vl-blg-dv10]~/dipak#
####### SCP #######
With SCP it is taking around 22 Seconds.
[root at vl-blg-dv10]~/dipak# time scp /tmp/748M root at 10.129.85.242:/tmp/
root at 10.129.85.242's password:
748M
100% 748MB 34.0MB/s 00:22
scp /tmp/748M root at 10.129.85.242:/tmp/ 13.66s user 6.42s system 69% cpu
28.784 total
[root at vl-blg-dv10]~/dipak#
I noticed that in case of OpenSSL Enabled Client the time spend in the “User
Space” is high (around 60 seconds). So I guess this is mostly because of the
encryption activity.
Please find the source code below for reference. Has anyone faced/noticed
such issue? Is there anything wrong I am doing with my OpenSSL code or
anything needs to be tweaked?
Any pointers, suggestions are always welcome....
Thanks,
Dipak
//################SSL-Client.c #######################
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <malloc.h>
#include <string.h>
#include <sys/socket.h>
#include <resolv.h>
#include <netdb.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include <netinet/tcp.h>
#include <netinet/ip.h>
#define FAIL -1
void LoadCertificates(SSL_CTX* ctx, char* CertFile, char* KeyFile)
{
/* set the local certificate from CertFile */
if (SSL_CTX_use_certificate_file(ctx, CertFile, SSL_FILETYPE_PEM) <= 0)
{
ERR_print_errors_fp(stderr);
abort();
}
/* set the private key from KeyFile (may be the same as CertFile) */
if ( SSL_CTX_use_PrivateKey_file(ctx, KeyFile, SSL_FILETYPE_PEM) <= 0 )
{
ERR_print_errors_fp(stderr);
abort();
}
/* verify private key */
if ( !SSL_CTX_check_private_key(ctx) )
{
fprintf(stderr, "Private key does not match the public
certificate\n");
abort();
}
}
int OpenConnection(const char *hostname, int port, int tbuf_size)
{ int sd, val;
struct hostent *host;
struct sockaddr_in addr;
if ((host = gethostbyname(hostname)) == NULL)
{
perror(hostname);
abort();
}
sd = socket(PF_INET, SOCK_STREAM, 0);
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = *(long*)(host->h_addr);
val = tbuf_size;
printf ("Using TCP buffer size (SO_SNDBUF/SO_RCVBUF) = <%d>\n", val);
setsockopt (sd, SOL_SOCKET, SO_RCVBUF, (char *)&val, sizeof (val));
setsockopt (sd, SOL_SOCKET, SO_SNDBUF, (char *)&val, sizeof (val));
val = 1;
setsockopt (sd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val));
val = IPTOS_THROUGHPUT | IPTOS_LOWDELAY;
setsockopt (sd, IPPROTO_IP, IP_TOS, (char *)&val, sizeof(val));
if (connect(sd, (struct sockaddr*)&addr, sizeof(addr)) != 0)
{
close(sd);
perror(hostname);
abort();
}
return sd;
}
SSL_CTX* InitCTX(void)
{ SSL_METHOD *method;
SSL_CTX *ctx;
OpenSSL_add_all_algorithms(); /* Load cryptos, et.al. */
SSL_load_error_strings(); /* Bring in and register error messages
*/
method = SSLv2_client_method(); /* Create new client-method instance */
ctx = SSL_CTX_new(method); /* Create new context */
if (ctx == NULL)
{
ERR_print_errors_fp(stderr);
abort();
}
LoadCertificates(ctx, "client_cert.pem", "client_key.pem"); /* load
certs */
return ctx;
}
int main(int count, char *argv[])
{
SSL_CTX *ctx;
int server;
SSL *ssl;
char *hostname, *portnum;
char *recvBuff1;
int fd=0;
int rlen;
long sz=0;
struct stat st;
int read_cnt;
int data_cnt;
int tobe_read_cnt;
int ok;
int app_buf_size = 0;
int tcp_buf_size = 0;
if (count != 6)
{
fprintf(stderr, "usage: %s <hostname> <portnum> <FileName>
<AppBufferSize> <TCPBufferSize>\n", argv[0]);
exit(0);
}
SSL_library_init();
OpenSSL_add_all_algorithms();
hostname=argv[1];
portnum=argv[2];
app_buf_size = atoi (argv[4]);
tcp_buf_size = atoi (argv[5]);
if (stat(argv[3], &st) < 0)
{
fprintf (stderr, "stat() failed. Error = %s\n", strerror(errno));
return -1;
}
printf ("Using Application buffer size = <%d>\n", app_buf_size);
recvBuff1 = malloc (app_buf_size);
data_cnt = st.st_size;
ctx = InitCTX();
server = OpenConnection(hostname, atoi(portnum), tcp_buf_size);
ssl = SSL_new(ctx); /* create new SSL connection state */
SSL_set_fd(ssl, server); /* attach the socket descriptor */
//SSL_CTX_set_cipher_list(ctx, "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH");
if (SSL_connect(ssl) == FAIL) /* perform the connection */
{
ERR_print_errors_fp(stderr);
close(server); /* close socket */
SSL_CTX_free(ctx); /* release context */
return -1;
}
printf ("Connected to %s:%s\n", hostname, portnum);
printf ("SSL_get_cipher_name returned <%s>\n",
SSL_get_cipher_name(ssl));
fd = open (argv[3], O_RDONLY);
if (fd == 0)
{
fprintf (stderr, "Failed to open the file <%s>\n", argv[3]);
return 0;
}
read_cnt = 0;
ok = 1;
tobe_read_cnt = app_buf_size;
//Send the Application buffer size to be used for read
SSL_write(ssl, &app_buf_size, sizeof(app_buf_size)); /* encrypt & send
message */
while (1)
{
if (data_cnt < read_cnt + tobe_read_cnt)
tobe_read_cnt = data_cnt - read_cnt;
if((rlen = read(fd, recvBuff1, tobe_read_cnt)) > 0)
{
read_cnt += rlen;
}
else
break;
sz = SSL_write (ssl, recvBuff1,rlen ); /* encrypt & send message
*/
if (sz != rlen)
{
fprintf (stderr, "Write data length <%ld> doesn't match input
data length <%d>\n", sz, rlen);
}
if (data_cnt == read_cnt)
{
printf ("Sucessfully sent data of length %d\n", read_cnt);
ok = 0;
break;
}
}
SSL_free(ssl); /* release connection state */
close(server); /* close socket */
SSL_CTX_free(ctx); /* release context */
return 0;
}
//######################## SSL-Server.c #########################
#include <errno.h>
#include <unistd.h>
#include <malloc.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <resolv.h>
#include "openssl/ssl.h"
#include "openssl/err.h"
#include <sys/stat.h>
#include <fcntl.h>
#include <netinet/tcp.h>
#include <netinet/ip.h>
#include <sys/types.h>
#include <sys/wait.h>
#define FAIL -1
int non_ssl;
int OpenListener(int port, int tbuf_size)
{ int sd, val;
struct sockaddr_in addr;
sd = socket(PF_INET, SOCK_STREAM, 0);
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = INADDR_ANY;
val = tbuf_size;
printf ("Using TCP buffer size (SO_SNDBUF/SO_RCVBUF) = <%d>\n", val);
setsockopt (sd, SOL_SOCKET, SO_RCVBUF, (char *)&val, sizeof (val));
setsockopt (sd, SOL_SOCKET, SO_SNDBUF, (char *)&val, sizeof (val));
val = 1;
setsockopt (sd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val));
val = IPTOS_THROUGHPUT | IPTOS_LOWDELAY;
setsockopt (sd, IPPROTO_IP, IP_TOS, (char *)&val, sizeof(val));
if (bind(sd, (struct sockaddr*)&addr, sizeof(addr)) != 0)
{
perror("can't bind port");
abort();
}
if (listen(sd, 64) != 0)
{
perror("Can't configure listening port");
abort();
}
return sd;
}
SSL_CTX* InitServerCTX(void)
{ SSL_METHOD *method;
SSL_CTX *ctx;
OpenSSL_add_all_algorithms(); /* load & register all cryptos, etc. */
SSL_load_error_strings(); /* load all error messages */
method = SSLv2_server_method(); /* create new server-method instance */
ctx = SSL_CTX_new(method); /* create new context from method */
if ( ctx == NULL )
{
ERR_print_errors_fp(stderr);
abort();
}
return ctx;
}
void LoadCertificates(SSL_CTX* ctx, char* CertFile, char* KeyFile)
{
/* set the local certificate from CertFile */
if ( SSL_CTX_use_certificate_file(ctx, CertFile, SSL_FILETYPE_PEM) <= 0
)
{
ERR_print_errors_fp(stderr);
abort();
}
/* set the private key from KeyFile (may be the same as CertFile) */
if ( SSL_CTX_use_PrivateKey_file(ctx, KeyFile, SSL_FILETYPE_PEM) <= 0 )
{
ERR_print_errors_fp(stderr);
abort();
}
/* verify private key */
if ( !SSL_CTX_check_private_key(ctx) )
{
fprintf(stderr, "Private key does not match the public
certificate\n");
abort();
}
}
void Servlet(SSL* ssl) /* Serve the connection request*/
{ char *buf;
int sd, bytes;
int fd=0;
int len;
char filename [32];
int app_buf_size = 0;
if (SSL_accept(ssl) == FAIL) /* do SSL-protocol accept */
{
ERR_print_errors_fp(stderr);
sd = SSL_get_fd(ssl); /* get socket connection */
SSL_free(ssl); /* release SSL state */
close(sd); /* close connection */
return;
}
sprintf (filename, "/tmp/test1");
fd = open (filename, O_WRONLY|O_CREAT, 0666);
if (fd < 0)
{
fprintf (stderr, "Failed to open the file %s, error = %s", filename,
strerror(errno));
return;
}
//Get Application buffer size to be used.
SSL_read(ssl, &app_buf_size, sizeof(app_buf_size));
printf ("Using Application buffer size as <%d>\n", app_buf_size);
buf = malloc (app_buf_size);
while(1)
{
bytes = SSL_read(ssl, buf, app_buf_size); /* get request */
//bytes = read(non_ssl, buf, sizeof(buf)); /* get request */
if (bytes <= 0)
{
ERR_print_errors_fp (stderr);
break;
}
len=write(fd,buf,bytes);
}
sd = SSL_get_fd(ssl); /* get socket connection */
SSL_free(ssl); /* release SSL state */
close(sd); /* close connection */
close(fd);
free(buf);
unlink(filename);
}
int main(int count, char *argv[])
{ SSL_CTX *ctx;
int server;
int portnum;
int pid;
int tcp_buf_size = 0;
if (count != 3)
{
printf("Usage: %s <portnum> <tcpbufsize>\n", argv[0]);
exit(0);
}
SSL_library_init();
portnum = atoi (argv[1]);
tcp_buf_size = atoi (argv[2]);
server = OpenListener(portnum, tcp_buf_size); /* create server socket
*/
ctx = InitServerCTX(); /* initialize SSL */
LoadCertificates(ctx, "server_cert.pem", "server_key.pem"); /* load
certs */
while (1)
{ struct sockaddr_in addr;
socklen_t len = sizeof(addr);
SSL *ssl;
int client = accept(server, (struct sockaddr*)&addr, &len); /*
accept connection as usual */
if (client < 0)
break;
printf("Accepted Connection: %s:%d\n",inet_ntoa(addr.sin_addr),
ntohs(addr.sin_port));
pid = fork();
if (pid == 0)
{
ssl = SSL_new(ctx); /* get new SSL state with
context */
SSL_set_fd(ssl, client); /* set connection socket to SSL
state */
OpenSSL_add_all_ciphers();
non_ssl=client;
Servlet(ssl); /* service connection */
printf("Done.\n\n");
_exit (0);
}
else
{
//Parent wait for next client
continue;
}
}
SSL_CTX_free(ctx); /* release context */
close(server); /* close server socket */
return 0;
}
--
View this message in context: http://openssl.6102.n7.nabble.com/Application-and-TCP-buffers-with-OpenSSL-tp58723.html
Sent from the OpenSSL - User mailing list archive at Nabble.com.
More information about the openssl-users
mailing list