1.该模块的用途C++ 和 Openssl 代码 它实现了一个简单的apns顾客

2.配套文件:基于boost 的苹果apns消息推送实现(1)

3.最初使用的sslv23/sslv2/sslv3仅仅能和apple 建立连接,但一直是handshake失败。

最后换tls连接,握手成功!

original_ssl_client.h

#ifndef original_ssl_client_h
#define original_ssl_client_h #pragma once
#include <iostream>
using namespace std; int myssl_verify_callback(int preverify_ok, X509_STORE_CTX *ctx); class original_ssl_client
{
public:
original_ssl_client()
{
m_pctx = NULL;
m_sockfd = -1;
m_phost_info = NULL;
m_pssl = NULL;
memset(m_recv_buffer,0,MAX_BUFFER_RECEIVE); }
~original_ssl_client()
{ } private:
//SSL_METHOD* m_pmeth;
SSL_CTX * m_pctx;
SOCKET m_sockfd;
sockaddr_in m_server_addr;
struct hostent* m_phost_info;
SSL* m_pssl;
enum
{
MAX_BUFFER_RECEIVE = 1024,
}; char m_recv_buffer[MAX_BUFFER_RECEIVE]; public:
//
void close()
{
// 关闭SSL套接字
SSL_shutdown(m_pssl); // 释放SSL套接字
SSL_free(m_pssl); // 释放SSL会话环境
SSL_CTX_free(m_pctx); // 关闭tcp 套接字
closesocket(m_sockfd); } // 初始化ssl库,Windows下初始化WinSock
void init_openssl()
{ #ifdef _WIN32 WSADATA wsaData;
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
#endif SSL_library_init();
ERR_load_BIO_strings();
SSL_load_error_strings();
OpenSSL_add_all_algorithms();
} //
bool init_tcp_connect(const char* host, int port)
{
if ( !host )
return false; struct hostent *hp;
//struct sockaddr_in m_server_addr;
if (!(hp = gethostbyname(host))) // 解析域名
return false; memset(&m_server_addr, 0, sizeof(m_server_addr));
m_server_addr.sin_addr = *(struct in_addr*)hp->h_addr_list[0];
m_server_addr.sin_family = AF_INET;
m_server_addr.sin_port = htons(port);
if ((m_sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
{
cout<<"Could not get Socket"<<endl;
return false;
} if (connect(m_sockfd, (struct sockaddr*)&m_server_addr, sizeof(m_server_addr)) != 0)
{
return false;
} return true;
} // 创建SSL Context
SSL_CTX* init_ssl_context( const char* clientcert, /* 客户端的证书 */ const char* clientkey, /* 客户端的Key */ const char* keypwd, /* 客户端Key的密码, 假设有的话 */ const char* cacert) /* 服务器CA证书 假设有的话 */
{
// set up the ssl context
m_pctx = SSL_CTX_new((SSL_METHOD*)TLSv1_client_method());
if (!m_pctx) { return NULL; } // 要求校验对方证书
//SSL_CTX_set_verify(m_pctx,SSL_VERIFY_PEER |SSL_VERIFY_CLIENT_ONCE , myssl_verify_callback); // certificate
if (clientcert && SSL_CTX_use_certificate_file(m_pctx, clientcert, SSL_FILETYPE_PEM) <= 0)
{ return NULL; } // key
if ( clientkey )
{
SSL_CTX_set_default_passwd_cb_userdata(m_pctx,(void*)keypwd); if (SSL_CTX_use_PrivateKey_file(m_pctx, clientkey, SSL_FILETYPE_PEM) <= 0)
{ return NULL; } // make sure the key and certificate file match
if (SSL_CTX_check_private_key(m_pctx) == 0)
{ return NULL; }
} // load ca if exist
if ( cacert )
{
if (!SSL_CTX_load_verify_locations(m_pctx, cacert, NULL))
{ return NULL; }
} return m_pctx;
} // 实现SSL握手,建立SSL连接
SSL* ssl_connect( )
{
m_pssl = SSL_new(m_pctx);
//BIO *bio = BIO_new_socket(m_sockfd, BIO_NOCLOSE);
//SSL_set_bio(m_pssl, bio, bio);
SSL_set_fd(m_pssl,m_sockfd);
int ret = SSL_connect(m_pssl);
if ( ret <= 0)
{
int nErr = SSL_get_error(m_pssl,ret); // SSL_ERROR_SSL 1, SSL_ERROR_SYSCALL 5 char err_msg[1024];
ERR_error_string_n(ERR_get_error(), err_msg, sizeof(err_msg));
printf("%s\n", err_msg); ERR_print_errors_fp(stderr);
std::cout<<ssl_error_string().c_str()<<endl;
return NULL;
} return m_pssl;
} // 验证服务器证书
// 首先要验证服务器的证书有效。其次要验证服务器证书的CommonName(CN)与我们
// 实际要连接的服务器域名一致
bool verify_connection(const char* peername)
{
// 获取校验结果
int result = SSL_get_verify_result(m_pssl);
if (result != X509_V_OK && result != X509_V_ERR_CERT_UNTRUSTED && result != X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY)
{
fprintf(stderr, "WARNING! ssl verify failed: %d \n", result);
std::cout<<ssl_error_string().c_str()<<endl;
return false;
} // X509 *peer;
// char peer_CN[256] = {0};
// peer = SSL_get_peer_certificate(m_pssl);
// X509_NAME_get_text_by_NID(X509_get_subject_name(peer), NID_commonName, peer_CN, 255);
// if (strcmp(peer_CN, peername) != 0)
// {
// fprintf(stderr, "WARNING! Server Name Doesn't match, got: %s, required: %s", peer_CN, peername);
// } return true;
} std::string ssl_error_string( )
{
//SSL_get_error();
unsigned long ulErr = ERR_get_error(); // 获取错误号
char szErrMsg[1024] = {0};
char *pTmp = NULL;
pTmp = ERR_error_string(ulErr,szErrMsg); // 格式:error:errId:库:函数:原因
return szErrMsg;
} void ssl_send_keyinput_msg( )
{
while ( true)
{
Sleep(100); if( false )
{
char szInput[100] = {};
cout<<"commond: "<<endl;
cin.getline(szInput,sizeof(szInput),'\n');
if ( strcmp(szInput,"exit") == 0 )
break; char token[] = "d2eb47674417c05c5a6f474bddef0391242e1c4d9ea3385e8f55c427d3c7d2ed";
char format[] = "{\"aps\":{\"alert\":\"%s\",\"badge\":1}}";
char payload[256] = {};
sprintf(payload,format,szInput);
int ret = pushMessage(token, payload);
cout<<"push ret["<<ret<<"]"<<endl;
} recv_message();
}
} int initializeSSL( )
{
/*/
char host[] = "gateway.sandbox.push.apple.com";
int port = 2195;
char password[] = "hc123";
#const char* CERTFILE_PATH = "boost/PushChatCert.pem";
#const char* CERTKEY_PATH = "boost/PushChatKey.pem";
#const char* CACERT_PATH = "boost/sandbox.pem";
/*/
const char* CERTFILE_PATH = NULL;
const char* CERTKEY_PATH = NULL;
const char* CACERT_PATH = "boost/ca.pem";
char host[] = "localhost";
int port = 13;
char password[] = "test";
//*/
char token[] = "adc97f91 fbd886bd cd052c3b 89c9bf95 1b5be2eb b31bdd56 16d3165c 9d0569c4";
char payload[] = "{\"aps\":{\"alert\":\"kkkkkkk\",\"badge\":1,\"sound\":\"default\"},}"; int err;
SSL_library_init();
SSL_load_error_strings();
OpenSSL_add_all_algorithms(); // 支持全部算法 m_pctx = SSL_CTX_new((SSL_METHOD*)SSLv3_client_method());
if( !m_pctx ) {
cout<<"Could not get SSL Context"<<endl;
return false;
}
// 要求校验对方证书
SSL_CTX_set_verify(m_pctx,SSL_VERIFY_PEER/*|SSL_VERIFY_CLIENT_ONCE*/, myssl_verify_callback); if(SSL_CTX_load_verify_locations(m_pctx, NULL, CACERT_PATH) <= 0)
{
cout<<"Failed to set CA location"<<endl;
ERR_print_errors_fp(stderr);
return false;
} if(CERTFILE_PATH && SSL_CTX_use_certificate_file(m_pctx,CERTFILE_PATH,SSL_FILETYPE_PEM) <= 0)
{
cout<<"Cannot use Certificate File"<<endl;
ERR_print_errors_fp(stderr);
return false;
} if ( CERTKEY_PATH )
{
SSL_CTX_set_default_passwd_cb_userdata(m_pctx,password); if (SSL_CTX_use_PrivateKey_file(m_pctx, CERTKEY_PATH, SSL_FILETYPE_PEM) <= 0)
{
cout<<"Cannot use Private Key"<<endl;
ERR_print_errors_fp(stderr);
return false;
} if (!SSL_CTX_check_private_key(m_pctx))
{
cout<<"Private key does not match the certificate public key"<<endl;
return false;
}
} WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
if ((m_sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
cout<<"Could not get Socket"<<endl;
return false;
} memset (&m_server_addr, '\0', sizeof(m_server_addr));
m_server_addr.sin_family = AF_INET;
m_server_addr.sin_port = htons(port);
m_phost_info = gethostbyname(host);
if( m_phost_info )
{
struct in_addr *address = (struct in_addr*)m_phost_info->h_addr_list[0];
m_server_addr.sin_addr.s_addr = inet_addr(inet_ntoa(*address));
}
else
{
cout<<"Could not resolve hostname = "<<host<<endl;
return false;
} err = connect(m_sockfd, (struct sockaddr*)&m_server_addr, sizeof(m_server_addr));
if(err == -1)
{
cout<<"Could not connect"<<endl;
return false;
} m_pssl = SSL_new(m_pctx);
if( !m_pssl ) {
cout<<"Could not get SSL Socket"<<endl;
return false;
} if( SSL_set_fd(m_pssl, m_sockfd) == -1 )
return false; err = SSL_connect(m_pssl);
if(err <= 0 ) {
//ERR_print_errors_fp(stderr);
cout<<ssl_error_string().c_str()<<endl;
cout<<"Could not connect to SSL Server"<<endl;
return false;
} // 获取证书验证结果
int result = SSL_get_verify_result(m_pssl);
if (result != X509_V_OK && result != X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN)
{
fprintf(stderr, "WARNING! ssl verify failed: %d \n", result);
std::cout<<ssl_error_string().c_str()<<endl;
return false;
} return true;
} int pushMessage(const char * token, const char * payload)
{
char tokenBytes[32];
char message[293];
unsigned long msgLength; token2bytes( token, tokenBytes );
unsigned short payloadLength = strlen( payload );
char * pointer = message;
unsigned short networkTokenLength = htons( (unsigned short)32 );
unsigned short networkPayloadLength = htons( (unsigned short)payloadLength );
// command
//*/
unsigned char command = 0;
memcpy(pointer, &command, sizeof(unsigned char));
pointer += sizeof(unsigned char);
/*/
unsigned char command = 1;
memcpy(pointer, &command, sizeof(unsigned char));
pointer += sizeof(unsigned char);
// identityfer
boost::uint32_t identityfer = 1;
memcpy(pointer, &identityfer, 4);
pointer += 4;
// expiry
boost::uint32_t tExpiry = time(NULL) + 24*3600;
memcpy(pointer, &tExpiry, 4);
pointer += 4;
//*/ // token len
memcpy(pointer, &networkTokenLength, sizeof(unsigned short));
pointer += sizeof(unsigned short);
// token
memcpy(pointer, tokenBytes, sizeof(tokenBytes));
pointer += 32;
// payload len
memcpy(pointer, &networkPayloadLength, sizeof(unsigned short));
pointer += sizeof(unsigned short);
// payload
memcpy(pointer, payload, payloadLength);
pointer += payloadLength;
// clac len
msgLength = pointer - message;
return SSL_write( m_pssl, message, (int)msgLength );
} void recv_message( )
{
int nRealRead = SSL_read(m_pssl,m_recv_buffer,MAX_BUFFER_RECEIVE);
if ( nRealRead <= 0 )
{
int nErr = SSL_get_error(m_pssl, nRealRead); // SSL_ERROR_SSL 1, SSL_ERROR_SYSCALL 5 char err_msg[1024];
ERR_error_string_n(ERR_get_error(), err_msg, sizeof(err_msg));
printf("%s\n", err_msg);
}
else
{
std::cout<<m_recv_buffer<<endl;
memset(m_recv_buffer,0,MAX_BUFFER_RECEIVE);
}
} void token2bytes(const char *token, char *bytes)
{
int val;
while (*token)
{
sscanf_s(token, "%2x", &val);
*(bytes++) = (char)val;
token += 2;
while (*token == ' ') {
++token; // skip space
}
}
} }; #endif

original_ssl_client.cpp

#include "stdafx.h"

#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp> #include "original_ssl_client.h" struct myssl_data
{
int verbose_mode;
int verify_depth;
int always_continue;
}; int myssl_verify_callback( int preverify_ok, X509_STORE_CTX *ctx )
{
char buf[256];
X509 *err_cert;
int err, depth;
SSL *ssl;
myssl_data *mydata;
int mydata_index = 0;
err_cert = X509_STORE_CTX_get_current_cert(ctx);
err = X509_STORE_CTX_get_error(ctx);
depth = X509_STORE_CTX_get_error_depth(ctx);
/*
* Retrieve the pointer to the SSL of the connection currently treated
* and the application specific data stored into the SSL object.
*/
ssl = (SSL*)X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
mydata = (myssl_data*)SSL_get_ex_data(ssl, mydata_index);
X509_NAME_oneline(X509_get_subject_name(err_cert), buf, 256);
/*
* Catch a too long certificate chain. The depth limit set using
* SSL_CTX_set_verify_depth() is by purpose set to "limit+1" so
* that whenever the "depth>verify_depth" condition is met, we
* have violated the limit and want to log this error condition.
* We must do it here, because the CHAIN_TOO_LONG error would not
* be found explicitly; only errors introduced by cutting off the
* additional certificates would be logged.
*/
if (mydata && depth > mydata->verify_depth) {
preverify_ok = 0;
err = X509_V_ERR_CERT_CHAIN_TOO_LONG;
X509_STORE_CTX_set_error(ctx, err);
}
if (!preverify_ok) {
printf("verify error:num=%d:%s:depth=%d:%s\n", err,
X509_verify_cert_error_string(err), depth, buf);
}
else if (mydata && mydata->verbose_mode)
{
printf("depth=%d:%s\n", depth, buf);
}
/*
* At this point, err contains the last verification error. We can use
* it for something special
*/
if (!preverify_ok && (err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT))
{
X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert), buf, 256);
printf("issuer= %s\n", buf);
}
if (mydata && mydata->always_continue)
return 1;
else if ( err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY || err == X509_V_ERR_CERT_UNTRUSTED )
return 1;
else
return preverify_ok;
}

使用:

int _tmain(int argc, _TCHAR* argv[])

{

original_ssl_client test_ssl_client;

test_ssl_client.init_openssl();

test_ssl_client.init_tcp_connect(“gateway.sandbox.push.apple.com”,2195);

test_ssl_client.init_ssl_context(“boost/PushChatCert.pem”,”boost/PushChatKey.pem”,”hc123”,”boost/sandbox.pem”);

test_ssl_client.ssl_connect();

test_ssl_client.verify_connection(NULL);

test_ssl_client.ssl_send_keyinput_msg();

test_ssl_client.close();

return 1;

}

版权声明:本文博主原创文章,博客,未经同意不得转载。

基于C++ 苹果apns消息推送实现(2)的更多相关文章

  1. oc学习之路----APNS消息推送从证书到代码(2015年4月26号亲试可用)

    前言:看这篇博客之前要准备:首先的有一个99刀的个人开发者账号或者199刀的企业开发者账号,其次你用的是apns消息推送,(本人之前四处打听有没有其他消息推送的方法:收获如下:首先如果想做到apns的 ...

  2. IOS 基于APNS消息推送原理与实现(JAVA后台)

    Push的原理: Push 的工作机制可以简单的概括为下图 图中,Provider是指某个iPhone软件的Push服务器,这篇文章我将使用.net作为Provider. APNS 是Apple Pu ...

  3. 转:IOS 基于APNS消息推送原理与实现(JAVA后台)

    Push的原理: Push 的工作机制可以简单的概括为下图   图中,Provider是指某个iPhone软件的Push服务器,这篇文章我将使用.net作为Provider. APNS 是Apple ...

  4. IOS 基于APNS消息推送原理与实现(JAVA后台)--转

    Push的原理: Push 的工作机制可以简单的概括为下图   图中,Provider是指某个iPhone软件的Push服务器,这篇文章我将使用.net作为Provider. APNS 是Apple ...

  5. iOS 基于APNS消息推送原理与实现(包括JAVA后台代码)

    Push的原理: Push 的工作机制可以简单的概括为下图   图中,Provider是指某个iPhone软件的Push服务器,这篇文章我将使用.net作为Provider. APNS 是Apple ...

  6. 【转】APNs消息推送完整讲解

    https://developer.apple.com/library/ios/#documentation/NetworkingInternet/Conceptual/RemoteNotificat ...

  7. APNs消息推送完整讲解

    在项目的AppDelegate中的didFinishLaunchingWithOptions方法中加入下面的代码: [[UIApplication sharedApplication] registe ...

  8. APNS消息推送实现

    转自:http://blog.csdn.net/biaobiaoqi/article/details/8058503 一.消息推送原理: 在实现消息推送之前先提及几个于推送相关概念,如下图1-1: 1 ...

  9. 基于APNs最新HTTP/2接口实现iOS的高性能消息推送(服务端篇)

    1.前言 本文要分享的消息推送指的是当iOS端APP被关闭或者处于后台时,还能收到消息/信息/指令的能力. 这种在APP处于后台或关闭情况下的消息推送能力,通常在以下场景下非常有用: 1)IM即时通讯 ...

随机推荐

  1. 又一次认识HTML,CSS,Javascript 之node-webkit 初探

    今天我们来系统的.全面的 了解一下前端的一些技术,将有助于我们写出 更优秀的 产品 出来. 什么是HTML? HTML 是用来描写叙述网页的一种语言. HTML 包括一些根节点.子节点,文本节点.属性 ...

  2. c++学籍管理系统v1.10

    //////////////新增添加学生和成绩录入系统 #include<iostream> #include <string> #include<conio.h> ...

  3. 二维码简单Demo

    二维码简单Demo 一.视图 @{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name=&qu ...

  4. 简单实现Android平台多语言

    这里,我们认识到两种语言.中国简体和繁体中国. 在res文件建议两个文件夹 values-zh-rCN values-zh-rTW 两个目录下都有一个strings.xml文件. 两个同名文件的字符串 ...

  5. 渲染优化 之fixed与返回顶部 以及开启GPU Hack

    fixed元素,常见网站右侧出现一个返回顶部的按钮,滚动的时候,会发现返回顶部这个区域在不停的进行重绘,而返回顶部是position:fixed定位的.这也解释了为什么fixed定位是最耗性能的属性之 ...

  6. uva 10817 - Headmaster's Headache ( 状态压缩dp)

    本文出自   http://blog.csdn.net/shuangde800 题目链接: 点击打开链接 题目大意 某校有n个教师和m个求职者,已知每人的工资和能教的课程集合,要求支付最少的工资使得每 ...

  7. 理解git经常使用命令原理

    git不同于类似SVN这样的版本号管理系统,尽管熟悉经常使用的操作就能够满足大部分需求,但为了在遇到麻烦时不至于靠蛮力去尝试,了解git的原理还是非常有必要. 文件 通过git管理的文件版本号信息所有 ...

  8. Net并行编程高级教程--Parallel

    Net并行编程高级教程--Parallel 一直觉得自己对并发了解不够深入,特别是看了<代码整洁之道>觉得自己有必要好好学学并发编程,因为性能也是衡量代码整洁的一大标准.而且在<失控 ...

  9. zoj 3659 并检查集合

    http://acm.zju.edu.cn/onlinejudge/showProblem.do? problemId=4882 现在在牡丹江,明天regional直播比赛,我会在一个月内退休.求祝福 ...

  10. DevExpress XtraReports 入门五 创建交叉表报表

    原文:DevExpress XtraReports 入门五 创建交叉表报表 本文只是为了帮助初次接触或是需要DevExpress XtraReports报表的人群使用的,为了帮助更多的人不会像我这样浪 ...