前言
关于TCP/IP和OPENSSL相关的描述我想很多人都知道,这里也不做什么陈述,如果刚接触的话可以去搜搜相关的文章,有很多写的不错的例子让你来更充分地了解他们。
这里的示例是由于要用到TLS1.2协议中的AEAD模式。
话不多说,直接上代码。。。
TCP封装
int setup_tcp_connect(char *ip, char *port)
{
struct sockaddr_in sin;
int sockfd;
int res;
struct timeval timeout = {60,0};
int buflen = DEVICE_INFO_ARRAY_MAX_SIZE*240; //这里我设置了240K的发送缓冲区大小
sockfd = socket(AF_INET, SOCK_STREAM, 0);
memset(&sin, 0, sizeof(struct sockaddr_in));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = inet_addr(ip);
sin.sin_port = htons(atoi(port));
if(connect(sockfd, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
printf("[%s:%d] Socket connect error!error msg == %s\n", __FUNCTION__, __LINE__, strerror(errno));
close(sockfd);
return -1;
}
if(setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, (const char *)&timeout, sizeof(timeout)) < 0) {
printf("[%s:%d] Setsockopt send timeout fail\n", __FUNCTION__, __LINE__);
return -1;
}
if(setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (const char *)&buflen, 4) < 0) {
printf("[%s:%d] Setsockopt sendbuffer fail\n", __FUNCTION__, __LINE__);
return -1;
}
if(setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char *)&timeout, sizeof(timeout)) < 0) {
printf("[%s:%d] Setsockopt rcv fail\n", __FUNCTION__, __LINE__);
return -1;
}
printf("[%s:%d] TCP connect success\n", __FUNCTION__, __LINE__);
return sockfd;
}
SSL封装
SSL *setup_ssl_connect(int sockfd, SSL_CTX *pssl_ctx)
{
const char *cipher_list = "ECDHE-ECDSA-AES128-GCM-SHA256"; //这里的cipher_list是与服务器协商好的加密套件,这里以其中一个为例
SSL_METHOD *meth = NULL;
SSL *pssl = NULL;
int len = 0;
int seed_init[DEVICE_INFO_ARRAY_SIZE] = {0};
OpenSSL_add_ssl_algorithms();
SSL_load_error_strings();
meth = (SSL_METHOD *)TLSv1_2_client_method();
pssl_ctx = SSL_CTX_new(meth);
if(pssl_ctx == NULL) {
printf("[%s:%d] SSL CTX NEW error!\n", __FUNCTION__, __LINE__);
ERR_print_errors_fp(stderr);
return NULL;
}
srand((unsigned)time(NULL));
for(len = 0; len < 100; len++) {
seed_init[len] = rand();
}
RAND_seed(seed_init, sizeof(seed_init));
SSL_CTX_set_cipher_list(pssl_ctx, cipher_list);
SSL_CTX_set_mode(pssl_ctx, SSL_MODE_AUTO_RETRY);
//setup ssl
pssl = SSL_new(pssl_ctx);
if(SSL_set_fd(pssl, sockfd) <= 0) {
printf("[%s:%d] SSL set fd error\n", __FUNCTION__, __LINE__);
goto error;
}
SSL_set_mode(pssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
if(SSL_connect(pssl) <= 0) {
printf("[%s:%d] SSL connect error\n", __FUNCTION__, __LINE__);
ERR_print_errors_fp(stderr);
goto error;
}
printf("[%s:%d] SSL connect success\n", __FUNCTION__, __LINE__);
return pssl;
error:
if(SSL_shutdown(pssl) != 1) {
SSL_shutdown(pssl);
}
SSL_free(pssl);
SSL_CTX_free(pssl_ctx);
return NULL;
}
int send_requset(char *request_data, long int len, SSL *pssl)
{
int ret,res;
long int count = 0;
if(pssl != NULL && request_data != NULL && len > 0) {
pthread_mutex_lock(&write_lock);
while(1) {
res = SSL_write(pssl, (void *)request_data + count, len - count);
ret = SSL_get_error(pssl, res);
if(ret == SSL_ERROR_NONE) {
if(res > 0) {
count += res;
if(count >= len) {
break;
}
continue;
} else {
printf("[%s:%d] SSL write error\n", __FUNCTION__, __LINE__);
ERR_print_errors_fp(stderr);
}
} else if(ret == SSL_ERROR_WANT_READ) {
continue;
} else if(ret == SSL_ERROR_WANT_WRITE) {
continue;
} else {
printf("[%s:%d] SSL write error, error code == %d\n", __FUNCTION__, __LINE__, ret);
ERR_print_errors_fp(stderr);
break;
}
}
pthread_mutex_unlock(&write_lock);
return count;
} else {
printf("[%s:%d] Send request pssl/request_data/len is NULL\n", __FUNCTION__, __LINE__);
return -1;
}
}
备注:按道理这里的ssl_write是不需要加锁的,不过这个是按照自己这边的项目情况而定,没有什么特殊的设定的话不需要加锁
之前在网上也有搜到ssl_write的返回值代表什么意思,这里推荐给大家:
点击这里查看
关于这两个的代码就是这些,下一篇再说ssl_read的相关实现。