基于C++ 的苹果apns消息推送实现(2)

1.本模块使用C++ 和 Openssl 代码 实现了一个简单的apns客户端 2.本文的姐妹篇:基于boost 的苹果apns消息推送实现(1) 3.最初使用的sslv23/sslv2/sslv3只能和apple 建立连接,但一直是handshake失败, 最后换tls连接,握手成功!

original_ssl_client.h

;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;SOCKETm_sockfd;sockaddr_inm_server_addr;struct hostent* m_phost_info;SSL*m_pssl;enum{MAX_BUFFER_RECEIVE = 1024,};charm_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下初始化WinSockvoid init_openssl(){#ifdef _WIN32 WSADATA wsaData;WSADATA wsaData;WSAStartup(MAKEWORD(2, 2), &wsaData);#endifSSL_library_init();ERR_load_BIO_strings();SSL_load_error_strings();OpenSSL_add_all_algorithms();}* host, int port){if ( !host )return false;struct hostent *hp;;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( * clientkey, * keypwd, * cacert) /* 服务器CA证书 如果有的话 */{// set up the ssl context m_pctx = SSL_CTX_new((SSL_METHOD*)TLSv1_client_method());if (!m_pctx) { return NULL; }(clientcert && SSL_CTX_use_certificate_file(m_pctx, clientcert, SSL_FILETYPE_PEM) <= 0){ return NULL; }// keyif ( 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 existif ( 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 5char 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;}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;} ;}std::string ssl_error_string( ){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;}* payload){char tokenBytes[32];char message[293];unsigned long msgLength;token2bytes( token, tokenBytes );unsigned short payloadLength = strlen( payload );char * pointer = message;)32 );)payloadLength );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);// identityferboost::uint32_t identityfer = 1;memcpy(pointer, &identityfer, 4);pointer += 4;// expiryboost::uint32_t tExpiry = time(NULL) + 24*3600;memcpy(pointer, &tExpiry, 4);pointer += 4;//*/));pointer += sizeof(unsigned short);// tokenmemcpy(pointer, tokenBytes, sizeof(tokenBytes));pointer += 32;));pointer += sizeof(unsigned short);// payloadmemcpy(pointer, payload, payloadLength);pointer += payloadLength;// clac lenmsgLength = 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 5char 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我们可以失望,但不能盲目。

基于C++ 的苹果apns消息推送实现(2)

相关文章:

你感兴趣的文章:

标签云: