/server.c
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#define TEST_SSL_SERVER
#ifdef TEST_SSL_SERVER
#define Time_Out_Interval 10
SSL_CTX *ctx;
char sCaKeyDir[1024] = { 0 };
char *GetExePath(char *Buffer)
{
int count=0;
int MAXBUFSIZE = 1024;
Buffer[count] = '\0';
count = readlink("/proc/self/exe", Buffer, MAXBUFSIZE);
if (count < 0 || count >= MAXBUFSIZE)
{
return NULL;
}
Buffer[count] = '\0';
count = strrchr(Buffer,'/')-Buffer+1;
Buffer[count] = '\0';
return Buffer;
}
int MySSL_Init( )
{
char sCaPath[1024] = { 0 }, sKeyPath[1024] = { 0 };
SSL_library_init();
OpenSSL_add_all_algorithms();
SSL_load_error_strings();
ctx = SSL_CTX_new(SSLv23_server_method());
if (ctx == NULL)
{
printf("Error: new ctx error!\n");
return -1;
}
void tls_info_callback(const SSL *s, int where, int ret)
{
char *str;
int w;
/* Adapted from OpenSSL apps/s_cb.c. */
w = where & ~SSL_ST_MASK;
if (w & SSL_ST_CONNECT)
str = "SSL_connect";
else if (w & SSL_ST_ACCEPT)
str = "SSL_accept";
else
str = "unknown";
if (where & SSL_CB_LOOP)
{
printf("%s:%s\r\n", str, SSL_state_string_long((SSL *) s));
}
else if (where & SSL_CB_ALERT)
{
str = (where & SSL_CB_READ) ? "read" : "write";
if ((ret & 0xff) != SSL3_AD_CLOSE_NOTIFY)
printf("SSL3 alert %s:%s:%s\r\n", str,
SSL_alert_type_string_long(ret),
SSL_alert_desc_string_long(ret));
}
else if (where & SSL_CB_EXIT)
{
if (ret == 0)
printf("%s:failed in %s\r\n", str, SSL_state_string_long((SSL *) s));
else if (ret < 0)
{
#ifndef LOG_NON_ERROR_STATES
switch (SSL_get_error((SSL *) s, ret))
{
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE:break;
default:
#endif
printf("%s:error in %s\r\n", str, SSL_state_string_long((SSL *) s));
break;
#ifndef LOG_NON_ERROR_STATES
}
#endif
}
}
}
SSL_CTX_set_info_callback(ctx, tls_info_callback);
GetExePath(sCaKeyDir);
sprintf(sCaPath, "%s", sCaKeyDir);
strcat(sCaPath, "cacert.pem");
if (SSL_CTX_use_certificate_file(ctx, sCaPath, SSL_FILETYPE_PEM) <= 0)
{
ERR_print_errors_fp(stdout);
return -1;
}
sprintf(sKeyPath, "%s", sCaKeyDir);
strcat(sKeyPath, "privkey.pem");
if (SSL_CTX_use_PrivateKey_file(ctx, sKeyPath, SSL_FILETYPE_PEM) <= 0)
{
ERR_print_errors_fp(stdout);
return -1;
}
SSL_CTX_set_timeout(ctx, Time_Out_Interval);
return 0;
}
int MyFD_Timeout(int sock, unsigned secs, unsigned usecs)
{
struct timeval timeout;
fd_set fd;
FD_ZERO(&fd);
FD_SET(sock, &fd);
timeout.tv_sec = secs;
timeout.tv_usec = usecs;
return select(sock+1, NULL, &fd, NULL, &timeout);
}
size_t MySSL_Write(SSL *ssl, void *buf, size_t len)
{
int rc;
unsigned long err;
char errmsg[BUFSIZ];
rc = SSL_write(ssl, buf, len);
if(rc <= 0)
{
int fd;
int ret;
ret = SSL_get_error(ssl, rc);
rc = -1;
if((fd = SSL_get_fd(ssl)) < 0)
return -1;
switch(ret)
{
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE:
ret = MyFD_Timeout(fd, Time_Out_Interval, 0);
if(ret == 0)
return -1;
else if(ret > 0)
return MySSL_Write(ssl, buf, len);
else
return -1;
break;
default:
while((err = ERR_get_error()))
fputs(ERR_error_string(err, errmsg), stderr);
return -1;
break;
}
}
else
{
return rc;
}
return 0;
}
size_t MySSL_Read(SSL *ssl, void *buf, size_t len)
{
int rc;
unsigned long err;
char errmsg[BUFSIZ];
int ret = MyFD_Timeout(SSL_get_fd(ssl), Time_Out_Interval, 0);
if(ret <= 0)
return ret;
rc = SSL_read(ssl, buf, len);
if(rc <= 0)
{
int fd;
int ret;
ret = SSL_get_error(ssl, rc);
rc = -1;
if((fd = SSL_get_fd(ssl)) < 0)
return -1;
switch(ret)
{
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE:
ret = MyFD_Timeout(fd, Time_Out_Interval, 0);
if(ret <= 0)
return ret;
else
return MySSL_Read(ssl, buf, len);
break;
default:
if((err = ERR_get_error()) != 0)
{
ERR_error_string(err, errmsg);
printf("error:%s\n", errmsg);
}
return -1;
break;
}
}
else
{
return rc;
}
return 0;
}
size_t MySSL_ReadLine(SSL *s, char *vptr, size_t len)
{
int ret;
char c;
vptr[0]='\0';
do
{
ret = MySSL_Read(s, &c, 1);
if(ret == -1)
return -1;
else if (ret==0)
break;
vptr[strlen(vptr)+1]='\0';
vptr[strlen(vptr)]=c;
} while (c!='\n' && strlen(vptr)<len);
if (ret!=0)
vptr[strlen(vptr)]='\0';
return strlen(vptr);
}
#else
static int SocketSend(int nSocketFD, char *psMsg)
{
int ret_write;
while((ret_write = write(nSocketFD, psMsg, strlen(psMsg))) < 0 && errno == EINTR)
;
if(-1 == ret_write)
{
return -1;
}
return ret_write;
}
static int SocketRead(int nSocketFD, char *psBuffer, int nBufferLen)
{
int ret_read;
while((ret_read = read(nSocketFD, psBuffer, nBufferLen - 1)) < 0 && errno == EINTR)
;
if(-1 == ret_read)
{
return -1;
}
return ret_read;
}
#endif
static int AcceptSocket(char *psIp, int nPort)
{
if(psIp == NULL || nPort <= 0)
return -1;
long nIp = inet_addr(psIp);
int nReuseSoAddr = 1;
uint32_t nInterfaceIp = nIp;
uint16_t nInterfacePort = nPort;
struct in_addr tInterfaceInAddr;
struct sockaddr_in tServerAddrIn;
tInterfaceInAddr.s_addr = nInterfaceIp;
int sockTcp = socket(AF_INET, SOCK_STREAM, 0);
if (sockTcp < 0 )
{
printf("scoket error\n");
return -1;
}
if ( setsockopt(sockTcp, SOL_SOCKET, SO_REUSEADDR, &nReuseSoAddr, sizeof(nReuseSoAddr)) != 0 )
{
printf("Setsockopt error for service @ %s:%d", inet_ntoa(tInterfaceInAddr), nInterfacePort);
return -1;
}
memset(&tServerAddrIn, 0x0, sizeof(tServerAddrIn));
tServerAddrIn.sin_family = AF_INET;
tServerAddrIn.sin_addr.s_addr = nInterfaceIp;
tServerAddrIn.sin_port = htons(nInterfacePort);
if (bind(sockTcp, (struct sockaddr *)(&tServerAddrIn), sizeof(tServerAddrIn)) < 0 )
{
printf("Bind tcp error for service @ %s:%d", inet_ntoa(tInterfaceInAddr), nInterfacePort);
return -1;
}
if ( listen(sockTcp, 10) < 0 )
{
printf("Cannot listen on service @ %s:%d", inet_ntoa(tInterfaceInAddr), nInterfacePort);
return -1;
}
struct sockaddr_in tClientAddr;
socklen_t nSockAddrInLen = sizeof(struct sockaddr_in);
int sockClient = accept(sockTcp, (struct sockaddr *) (&tClientAddr), &nSockAddrInLen);
if ( -1 == sockClient )
{
}
return sockClient;
}
void MyStrTrim(char *psStr)
{
if(NULL == psStr)
return;
int nLen = strlen(psStr);
while(nLen > 0)
{
if(*(psStr + nLen - 1) == '\r' || *(psStr + nLen - 1) == '\n')
{
*(psStr + nLen - 1) = '\0';
nLen--;
}
else
break;
}
}
int main(int argc, char *argv[])
{
char *psIp = "127.0.0.1";
int nPort = 25;
if(argc == 3)
{
psIp = argv[1];
nPort = atoi(argv[2]);
}
#ifdef TEST_SSL_SERVER
if (MySSL_Init() != 0)
{
printf("Error: temp error");
return 0;
}
SSL *sockTlsChannel;
sockTlsChannel = SSL_new(ctx);
if (sockTlsChannel == NULL)
{
printf("Error: %s\n", ERR_reason_error_string(ERR_get_error()));
return 0;
}
#endif
printf("server listen %s:%d\n", psIp, nPort);
int sockSMTPClient = AcceptSocket(psIp, nPort);
if(sockSMTPClient <= 0)
{
printf("%s\n", "AcceptSocket fail");
return 0;
}
#ifdef TEST_SSL_SERVER
if (SSL_set_fd(sockTlsChannel, sockSMTPClient) != 1)
{
printf("SSL_set_fd Error: %s\n", ERR_reason_error_string(ERR_get_error()));
return 0;
}
if (SSL_accept(sockTlsChannel) != 1)
{
printf("SSL_accept Error: %s\n", ERR_reason_error_string(ERR_get_error()));
return 0;
}
printf("server ready to do...\n");
while(1)
{
char sBuffer[1024] = { 0 };
printf("put msg to send:\r\n");
fgets(sBuffer, sizeof(sBuffer), stdin);
int n = MySSL_Write(sockTlsChannel, sBuffer, strlen(sBuffer));
MyStrTrim(sBuffer);
printf("server send %d bytes [%d][%s]\n", n, (int)strlen(sBuffer), sBuffer);
memset(sBuffer, 0, sizeof(sBuffer));
n = MySSL_Read(sockTlsChannel, sBuffer, sizeof(sBuffer));
MyStrTrim(sBuffer);
printf("server read %d bytes [%d][%s]\n", n, (int)strlen(sBuffer), sBuffer);
}
#else
char sBuffer[512] = { 0 };
int n = SocketRead(sockSMTPClient, sBuffer, 512);
printf("server read %d bytes [%s]\n", n, sBuffer);
sprintf(sBuffer, "%s\n", "hello i'm server!");
n = SocketSend(sockSMTPClient, sBuffer);
printf("server send %d bytes\n", n);
#endif
return EXIT_SUCCESS;
}
/client.c
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <unistd.h>
#define TEST_SSL_CLIENT
#ifdef TEST_SSL_CLIENT
#define niTimeOutInterval 5
#define BUFFER_SIZE 1024
SSL_CTX *ctx;
int MySSL_Init( )
{
SSL_library_init();
OpenSSL_add_all_algorithms();
SSL_load_error_strings();
ctx = SSL_CTX_new(SSLv23_client_method());
if (ctx == NULL)
{
printf("Error: new ctx error!\n");
return -1;
}
void tls_info_callback(const SSL *s, int where, int ret)
{
char *str;
int w;
/* Adapted from OpenSSL apps/s_cb.c. */
w = where & ~SSL_ST_MASK;
if (w & SSL_ST_CONNECT)
str = "SSL_connect";
else if (w & SSL_ST_ACCEPT)
str = "SSL_accept";
else
str = "unknown";
if (where & SSL_CB_LOOP)
{
printf("%s:%s\r\n", str, SSL_state_string_long((SSL *) s));
}
else if (where & SSL_CB_ALERT)
{
str = (where & SSL_CB_READ) ? "read" : "write";
if ((ret & 0xff) != SSL3_AD_CLOSE_NOTIFY)
printf("SSL3 alert %s:%s:%s\r\n", str,
SSL_alert_type_string_long(ret),
SSL_alert_desc_string_long(ret));
}
else if (where & SSL_CB_EXIT)
{
if (ret == 0)
printf("%s:failed in %s\r\n", str, SSL_state_string_long((SSL *) s));
else if (ret < 0)
{
#ifndef LOG_NON_ERROR_STATES
switch (SSL_get_error((SSL *) s, ret))
{
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE: /* Don't log non-error states. */break;
default:
#endif
printf("%s:error in %s\r\n", str, SSL_state_string_long((SSL *) s));
break;
#ifndef LOG_NON_ERROR_STATES
}
#endif
}
}
}
SSL_CTX_set_timeout(ctx, 5);
return 0;
}
int MyFD_Timeout(int sock, unsigned secs, unsigned usecs)
{
struct timeval timeout;
fd_set fd;
FD_ZERO(&fd);
FD_SET(sock, &fd);
timeout.tv_sec = secs;
timeout.tv_usec = usecs;
return select(sock+1, NULL, &fd, NULL, &timeout);
}
size_t MySSL_Write(SSL *ssl, void *buf, size_t len)
{
int rc;
unsigned long err;
char errmsg[BUFSIZ];
rc = SSL_write(ssl, buf, len);
if(rc <= 0)
{
int fd;
int ret;
ret = SSL_get_error(ssl, rc);
rc = -1;
if((fd = SSL_get_fd(ssl)) < 0)
return -1;
switch(ret)
{
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE:
ret = MyFD_Timeout(fd, 5, 0);
if(ret == 0)
return -1;
else if(ret > 0)
return MySSL_Write(ssl, buf, len);
else
return -1;
break;
default:
while((err = ERR_get_error()))
fputs(ERR_error_string(err, errmsg), stderr);
return -1;
break;
}
}
else
{
return rc;
}
return 0;
}
size_t MySSL_Read(SSL *ssl, void *buf, size_t len)
{
int rc;
unsigned long err;
char errmsg[BUFSIZ];
int ret = MyFD_Timeout(SSL_get_fd(ssl), niTimeOutInterval, 0);
if(ret <= 0)
return ret;
rc = SSL_read(ssl, buf, len);
if(rc <= 0)
{
int fd;
int ret;
ret = SSL_get_error(ssl, rc);
rc = -1;
if((fd = SSL_get_fd(ssl)) < 0)
return -1;
switch(ret)
{
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE:
ret = MyFD_Timeout(fd, 5, 0);
if(ret <= 0)
return ret;
else
return MySSL_Read(ssl, buf, len);
break;
default:
if((err = ERR_get_error()) != 0)
{
ERR_error_string(err, errmsg);
printf("error:%s\n", errmsg);
}
return -1;
break;
}
}
else
{
return rc;
}
return 0;
}
size_t MySSL_ReadLine(SSL *s,char *vptr,size_t len)
{
int ret;
char c;
vptr[0]='\0';
do
{
ret = MySSL_Read(s, &c, 1);
if(ret == -1)
return -1;
else if (ret==0)
break;
vptr[strlen(vptr)+1]='\0';
vptr[strlen(vptr)]=c;
} while (c!='\n' && strlen(vptr)<len);
if (ret!=0)
vptr[strlen(vptr)]='\0';
return strlen(vptr);
}
#else
static int SocketSend(int nSocketFD, char *psMsg)
{
int ret_write;
while((ret_write = write(nSocketFD, psMsg, strlen(psMsg))) < 0 && errno == EINTR)
;
if(-1 == ret_write)
{
return -1;
}
return ret_write;
}
static int SocketRead(int nSocketFD, char *psBuffer, int nBufferLen)
{
int ret_read;
while((ret_read = read(nSocketFD, psBuffer, nBufferLen - 1)) < 0 && errno == EINTR)
;
if(-1 == ret_read)
{
return -1;
}
return ret_read;
}
#endif
static int SocketConnent(char *psIp, int nPort)
{
if(psIp == NULL || nPort <= 0)
return -1;
long nIp = inet_addr(psIp);
struct timeval tTimeOut;
tTimeOut.tv_sec = 5;
tTimeOut.tv_usec = 0;
struct linger lin;
lin.l_onoff=1;
lin.l_linger=0;
struct sockaddr_in inaddr;
inaddr.sin_family = AF_INET;
inaddr.sin_addr.s_addr = nIp;
inaddr.sin_port = htons(nPort);
int niSockFd = socket(AF_INET, SOCK_STREAM, 0);
if(niSockFd == -1)
return -1;
setsockopt(niSockFd, SOL_SOCKET, SO_LINGER, &lin, sizeof(struct linger));
int ulFlagBlock = 1;
ioctl(niSockFd, FIONBIO, &ulFlagBlock);
int rv = connect(niSockFd,(struct sockaddr *)&inaddr,sizeof(struct sockaddr_in));
if(-1 == rv && errno == EINPROGRESS)
{
fd_set fdSet;
FD_ZERO(&fdSet);
FD_SET(niSockFd, &fdSet);
if( select(niSockFd + 1, NULL, &fdSet, NULL, &tTimeOut) > 0)
{
int niError = 0;
int niLenth = sizeof(int);
getsockopt(niSockFd, SOL_SOCKET, SO_ERROR, &niError, (socklen_t *)&niLenth);
if(niError != 0)
{
close(niSockFd);
return -1;
}
}
}
else if(rv != 0 ){
close(niSockFd);
return -1;
}
//rv == 0 connect suc
ulFlagBlock=0;
ioctl(niSockFd, FIONBIO, &ulFlagBlock);
setsockopt(niSockFd,SOL_SOCKET,SO_SNDTIMEO,&tTimeOut,(socklen_t)sizeof(struct timeval));
setsockopt(niSockFd,SOL_SOCKET,SO_RCVTIMEO,&tTimeOut,(socklen_t)sizeof(struct timeval));
return niSockFd;
}
void MyStrTrim(char *psStr)
{
if(NULL == psStr)
return;
int nLen = strlen(psStr);
while(nLen > 0)
{
if(*(psStr + nLen - 1) == '\r' || *(psStr + nLen - 1) == '\n')
{
*(psStr + nLen - 1) = '\0';
nLen--;
}
else
break;
}
}
int main(int argc, char *argv[])
{
char *psIp = "127.0.0.1";
int nPort = 25;
if(argc == 3)
{
psIp = argv[1];
nPort = atoi(argv[2]);
}
#ifdef TEST_SSL_CLIENT
if (MySSL_Init() != 0)
{
printf("Error: temp error");
return 0;
}
SSL *sockTlsChannel;
sockTlsChannel = SSL_new(ctx);
if (sockTlsChannel == NULL)
{
printf("Error: %s\n", ERR_reason_error_string(ERR_get_error()));
return 0;
}
#endif
int sockSMTPClient = SocketConnent(psIp, nPort);
if(sockSMTPClient <= 0)
{
printf("Error: %s %s:%d\n", "scoket connent fail", psIp, nPort);
return 0;
}
printf("connect to %s:%d\n", psIp, nPort);
#ifdef TEST_SSL_CLIENT
if (SSL_set_fd(sockTlsChannel, sockSMTPClient) != 1)
{
printf("Error: %s\n", ERR_reason_error_string(ERR_get_error()));
return 0;
}
if(SSL_connect(sockTlsChannel) != 1)
{
printf("ssl connent fail\n");
return 0;
}
while(1)
{
char sBuffer[1024] = { 0 };
memset(sBuffer, 0, sizeof(sBuffer));
int n = MySSL_Read(sockTlsChannel, sBuffer, sizeof(sBuffer));
MyStrTrim(sBuffer);
printf("client read %d bytes [%d][%s]\n", n, (int)strlen(sBuffer), sBuffer);
printf("put msg to send:\r\n");
fgets(sBuffer, sizeof(sBuffer), stdin);
n = MySSL_Write(sockTlsChannel, sBuffer, strlen(sBuffer));
MyStrTrim(sBuffer);
printf("client send %d bytes [%d][%s]\n", n, (int)strlen(sBuffer), sBuffer);
}
#else
int n = SocketSend(sockSMTPClient, sBuffer);
printf("client send %d bytes\n", n);
memset(sBuffer, 0, BUFFER_SIZE);
n = SocketRead(sockSMTPClient, sBuffer, BUFFER_SIZE);
printf("client read %d bytes [%s]\n", n, sBuffer);
#endif
return EXIT_SUCCESS;
}
其他常用代码
///
SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);
///
SSL_CTX_set_cipher_list(ctx, "RC4-MD5");
///DH
/* Set up ephemeral DH stuff */
DH *dh_512 = NULL;
DH *dh_1024 = NULL;
FILE *paramfile;
/* "openssl dhparam -out dh_param_512.pem -2 512" */
paramfile = fopen("dh_param_512.pem", "r");
if (paramfile) {
dh_512 = PEM_read_DHparams(paramfile, NULL, NULL, NULL);
fclose(paramfile);
}
/* "openssl dhparam -out dh_param_1024.pem -2 1024" */
paramfile = fopen("dh_param_1024.pem", "r");
if (paramfile) {
dh_1024 = PEM_read_DHparams(paramfile, NULL, NULL, NULL);
fclose(paramfile);
}
SSL_CTX_set_tmp_dh(ctx, dh_512);
SSL_CTX_set_tmp_dh(ctx, dh_1024);