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. IDEA内存异常问题

    设置工程运行Server  VM属性 VM options:   -Xms258m -Xmx1024m -XX:PermSize=128m -XX:MaxPermSize=256m    如图 :

  2. Eclipse建筑物SSH(struts-2.2.3 + spring-2.5.6 + hibernate-3.6.8)相框-随着源代码

    一直想自己搭建一个ssh框架,这次因为编写demo的须要,就亲手搭建了一下,并逐步測试!以下进入正题: 创建Struts项目 整合步骤: 1,在Eclipse中创建一个DynamicWeb Proje ...

  3. 在python正在使用mysql

    缘由 近期在折腾一个小东西须要抓取网上的页面.然后进行解析.将结果放到数据库中. 了解到Python在这方面有优势,便选用之. 由于我有台server上面安装有mysql,自然使用之.在进行数据库的这 ...

  4. Integer比较

    /** * @time 2014-06-25 * @author Cao HaiCheng * */ public class demo { public static void main(Strin ...

  5. Tuple

    Tuple(组元)是C# 4.0引入的一个新特性,编写的时候需要基于.NET Framework 4.0或者更高版本. 在以前编程中,当需要返回多个值得方法中,常常需要将这些值放置到一个结构体或者对象 ...

  6. Cocos2d-x3.2游戏的核心循环在Application,怎样处理FPS不稳

    今天天气非常阴,立即要下雨了,陈吃早点功夫写点东西, 一场秋雨一场寒,十场秋雨要穿棉,各位从今往后多穿点 int Application::run() { if(!applicationDidFini ...

  7. 看你的门-攻击服务器(4)-HTTP参数注入攻击

    首先需要声明.这纯粹是没有远见和有点真才实学开发一个愚蠢的观点,只为web参考系统安全. 1.HTTP参数注入攻击 參数,被用做后端HTTP请求中的參数,这个时候就有可能会导致HTTP參数注入. 一个 ...

  8. SQL Server 2008性能故障排查(一)——概论

    原文:SQL Server 2008性能故障排查(一)--概论 备注:本人花了大量下班时间翻译,绝无抄袭,允许转载,但请注明出处.由于篇幅长,无法一篇博文全部说完,同时也没那么快全部翻译完,所以按章节 ...

  9. Cocos2d-x 3.0 Lua编程 之 响应物理引擎的Contact事件回调不运行的问题

    在较早的版本号如3.0beta使用例如以下代码的话: -- add ground local groudNode = cc.Node:create() groudNode:setPhysicsBody ...

  10. AndroidSlidingUpPanel 使用控制和简单的分析方法

    滑 - 向上的时间可以飞起来控件的显示区域.分类似至play music有效. 该控件在主界面中有一个例如以下图红色箭头所指的底部触发区域: 该区域点击的时候被隐藏在下方的内容将网上漂移到顶部,直到被 ...