【转】iPhone推送功能的C语言实现

转自:http://blog.csdn.net/iw1210/article/details/18085225

iPhone推送功能的C语言实现。

直接上源代码:

  1. // ippush.c  
  2. // 在Linux下编译:gcc -o ippush ippush.c -lssl  
  3.   
  4. #ifdef _WIN32  
  5. # define WIN32_LEAN_AND_MEAN  
  6. # include <windows.h>  
  7. #else  
  8. # include <sys/types.h>  
  9. # include <sys/socket.h>  
  10. # include <netinet/in.h>  
  11. # include <netdb.h>  
  12. # include <arpa/inet.h>  
  13. # include <string.h>  
  14. # include <unistd.h>  
  15. # include <fcntl.h>  
  16. # include <errno.h>  
  17. #endif  
  18.   
  19. #include <stdlib.h>  
  20. #include <stdint.h>  
  21. #include <assert.h>  
  22.   
  23. #include <openssl/ssl.h>  
  24. #include <openssl/bio.h>  
  25. #include <openssl/err.h>  
  26.   
  27.   
  28. #define MAX_PAYLOAD_SIZE 256  
  29. #define TOKEN_SIZE 32  
  30.   
  31. void DeviceToken2Binary(const char* sz, const int len, unsigned charconst binary, const int size)   
  32. {  
  33.     int         i, val;  
  34.     const char*     pin;  
  35.     char        buf[3] = {0};  
  36.   
  37.     assert(size >= TOKEN_SIZE);  
  38.   
  39.     for (i = 0;i < len;i++)  
  40.     {  
  41.         pin = sz + i * 2;  
  42.         buf[0] = pin[0];  
  43.         buf[1] = pin[1];  
  44.   
  45.         val = 0;  
  46.         sscanf(buf, "%X", &val);  
  47.         binary[i] = val;  
  48.     }  
  49.   
  50.     return;  
  51. }  
  52.   
  53. void DeviceBinary2Token(const unsigned char* data, const int len, charconst token, const int size)   
  54. {  
  55.     int i;  
  56.   
  57.     assert(size > TOKEN_SIZE * 2);  
  58.   
  59.     for (i = 0;i < len;i++)  
  60.     {  
  61.         sprintf(token + i * 2, "%02x", data[i]);  
  62.     }  
  63.   
  64.     return;  
  65. }  
  66.   
  67. void Closesocket(int socket)  
  68. {  
  69. #ifdef _WIN32  
  70.     closesocket(socket);  
  71. #else  
  72.     close(socket);  
  73. #endif  
  74. }  
  75.   
  76. // 初始化ssl库,Windows下初始化WinSock  
  77. void init_openssl()  
  78. {  
  79. #ifdef _WIN32  
  80.     WSADATA wsaData;  
  81.     WSAStartup(MAKEWORD(2, 2), &wsaData);  
  82. #endif  
  83.   
  84.     SSL_library_init();  
  85.     ERR_load_BIO_strings();  
  86.     SSL_load_error_strings();  
  87.     OpenSSL_add_all_algorithms();  
  88. }  
  89.   
  90. SSL_CTX* init_ssl_context(  
  91.         const char* clientcert, /* 客户端的证书 */  
  92.         const char* clientkey, /* 客户端的Key */  
  93.         const char* keypwd, /* 客户端Key的密码, 如果有的话 */  
  94.         const char* cacert) /* 服务器CA证书 如果有的话 */  
  95. {  
  96.     // set up the ssl context  
  97.     SSL_CTX *ctx = SSL_CTX_new(SSLv23_client_method());  
  98.     if (!ctx) {  
  99.         return NULL;  
  100.     }  
  101.   
  102.     // certificate  
  103.     if (SSL_CTX_use_certificate_file(ctx, clientcert, SSL_FILETYPE_PEM) <= 0) {  
  104.         return NULL;  
  105.     }  
  106.   
  107.     // key  
  108.     if (SSL_CTX_use_PrivateKey_file(ctx, clientkey, SSL_FILETYPE_PEM) <= 0) {  
  109.         return NULL;  
  110.     }  
  111.   
  112.     // make sure the key and certificate file match  
  113.     if (SSL_CTX_check_private_key(ctx) == 0) {  
  114.         return NULL;  
  115.     }  
  116.   
  117.     // load ca if exist  
  118.     if (cacert) {  
  119.         if (!SSL_CTX_load_verify_locations(ctx, cacert, NULL)) {  
  120.             return NULL;  
  121.         }  
  122.     }  
  123.   
  124.     return ctx;  
  125. }  
  126.   
  127. // 建立TCP连接到服务器  
  128. int tcp_connect(const char* host, int port)  
  129. {  
  130.     struct hostent *hp;  
  131.     struct sockaddr_in addr;  
  132.     int sock = -1;  
  133.   
  134.     // 解析域名  
  135.     if (!(hp = gethostbyname(host))) {  
  136.         return -1;  
  137.     }  
  138.   
  139.     memset(&addr, 0, sizeof(addr));  
  140.     addr.sin_addr = *(struct in_addr*)hp->h_addr_list[0];  
  141.     addr.sin_family = AF_INET;  
  142.     addr.sin_port = htons(port);  
  143.   
  144.     if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0){  
  145.         return -1;  
  146.     }  
  147.   
  148.     if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) != 0) {  
  149.         return -1;  
  150.     }  
  151.   
  152.     return sock;  
  153. }  
  154.   
  155. // 实现SSL握手,建立SSL连接  
  156. SSL* ssl_connect(SSL_CTX* ctx, int socket)  
  157. {  
  158.     SSL *ssl = SSL_new(ctx);  
  159.     BIO *bio = BIO_new_socket(socket, BIO_NOCLOSE);  
  160.     SSL_set_bio(ssl, bio, bio);  
  161.   
  162.     if (SSL_connect(ssl) <= 0) {  
  163.         return NULL;  
  164.     }  
  165.   
  166.     return ssl;  
  167. }  
  168.   
  169. // 验证服务器证书  
  170. // 首先要验证服务器的证书有效,其次要验证服务器证书的CommonName(CN)与我们  
  171. // 实际要连接的服务器域名一致  
  172. int verify_connection(SSL* ssl, const char* peername)  
  173. {  
  174.     int result = SSL_get_verify_result(ssl);  
  175.     if (result != X509_V_OK) {  
  176.         fprintf(stderr, "WARNING! ssl verify failed: %d", result);  
  177.         return -1;  
  178.     }  
  179.   
  180.     X509 *peer;  
  181.     char peer_CN[256] = {0};  
  182.   
  183.     peer = SSL_get_peer_certificate(ssl);  
  184.     X509_NAME_get_text_by_NID(X509_get_subject_name(peer), NID_commonName, peer_CN, 255);  
  185.     if (strcmp(peer_CN, peername) != 0) {  
  186.         fprintf(stderr, "WARNING! Server Name Doesn't match, got: %s, required: %s", peer_CN,  
  187.                 peername);  
  188.     }  
  189.     return 0;  
  190. }  
  191.   
  192. void json_escape(char*  str)  
  193. {  
  194.     int     n;  
  195.     char    buf[1024];  
  196.   
  197.     n = strlen(str) * sizeof(char) + 100;  
  198.     assert(n < sizeof(buf));  
  199.   
  200.     strncpy(buf, str, n);  
  201.     buf[n] = '\0';  
  202.     char *found = buf;  
  203.     while (*found != '\0')  
  204.     {  
  205.         if('\\' == *found || '"' == *found || '\n' == *found || '/' == *found)  
  206.             *str++ = '\\';  
  207.   
  208.         if('\n' == *found)  
  209.             *found = 'n';  
  210.   
  211.         *str++ = *found++;         
  212.     }  
  213.   
  214.     *str='\0';  
  215.   
  216.     return;  
  217. }  
  218.   
  219. // Payload example  
  220.   
  221. // {"aps":{"alert" : "You got your emails.","badge" : 9,"sound" : "default"}}  
  222. int build_payload(char* buffer, int* plen, char* msg, int badage, const char * sound)  
  223. {  
  224.     int n;  
  225.     char buf[2048];  
  226.     char str[2048] = "{\"aps\":{\"alert\":\"";  
  227.   
  228.     n = strlen(str);  
  229.   
  230.     if (msg)   
  231.     {  
  232.         strcpy(buf, msg);  
  233.         json_escape(buf);  
  234.         n = n + sprintf(str+n, "%s", buf);  
  235.     }  
  236.   
  237.     n = n + sprintf(str+n, "%s%d""\",\"badge\":", badage);  
  238.   
  239.     if (sound)   
  240.     {  
  241.         n = n + sprintf(str+n, "%s"",\"sound\":\"");  
  242.         strcpy(buf, sound);  
  243.         json_escape(buf);  
  244.         n = n + sprintf(str+n, "%s%s", buf, "\"");  
  245.     }  
  246.   
  247.     strcat(str, "}}");  
  248.   
  249.     n = strlen(str);  
  250.   
  251.     if (n > *plen)   
  252.     {  
  253.         *plen = n;  
  254.         return -1;  
  255.     }  
  256.   
  257.   
  258.     if (n < *plen)   
  259.     {  
  260.         strcpy(buffer, str);  
  261.     } else   
  262.     {  
  263.         strncpy(buffer, str, *plen);  
  264.     }  
  265.   
  266.     *plen = n;  
  267.   
  268.     return *plen;  
  269. }  
  270.   
  271. // 第一种形式的包  
  272. int build_output_packet(char* buf, int buflen, /* 输出的缓冲区及长度 */  
  273.         const char* tokenbinary, /* 二进制的Token */  
  274.         char* msg, /* 要发送的消息 */  
  275.         int badage, /* 应用图标上显示的数字 */  
  276.         const char * sound) /* 设备收到时播放的声音,可以为空 */  
  277. {  
  278.     assert(buflen >= 1 + 2 + TOKEN_SIZE + 2 + MAX_PAYLOAD_SIZE);  
  279.   
  280.     char * pdata = buf;  
  281.     // command  
  282.     *pdata = 0;  
  283.   
  284.     // token length  
  285.     pdata++;  
  286.     *(uint16_t*)pdata = htons(TOKEN_SIZE);  
  287.   
  288.     // token binary  
  289.     pdata += 2;  
  290.     memcpy(pdata, tokenbinary, TOKEN_SIZE);  
  291.   
  292.     pdata += TOKEN_SIZE;  
  293.   
  294.     int payloadlen = MAX_PAYLOAD_SIZE;  
  295.     if (build_payload(pdata + 2, &payloadlen, msg, badage, sound) < 0)   
  296.     {  
  297.         msg[strlen(msg) - (payloadlen - MAX_PAYLOAD_SIZE)] = '\0';  
  298.         payloadlen = MAX_PAYLOAD_SIZE;  
  299.         if (build_payload(pdata + 2, &payloadlen, msg, badage, sound) <= 0)   
  300.         {  
  301.             return -1;  
  302.         }  
  303.     }  
  304.     *(uint16_t*)pdata = htons(payloadlen);  
  305.   
  306.     return 1 + 2 + TOKEN_SIZE + 2 + payloadlen;  
  307. }  
  308.   
  309. int send_message(SSL *ssl, const char* token, char* msg, int badage, const char* sound)  
  310. {  
  311.     int         n;  
  312.     char        buf[1 + 2 + TOKEN_SIZE + 2 + MAX_PAYLOAD_SIZE];  
  313.     unsigned char   binary[TOKEN_SIZE];  
  314.     int         buflen = sizeof(buf);  
  315.   
  316.     n = strlen(token);  
  317.     DeviceToken2Binary(token, n, binary, TOKEN_SIZE);  
  318.   
  319.     buflen = build_output_packet(buf, buflen, (const char*)binary, msg, badage, sound);  
  320.     if (buflen <= 0) {  
  321.         return -1;  
  322.     }  
  323.   
  324.     return SSL_write(ssl, buf, buflen);  
  325. }  
  326.   
  327. int build_output_packet_2(char* buf, int buflen, /* 缓冲区及长度 */  
  328.         uint32_t messageid, /* 消息编号 */  
  329.         uint32_t expiry, /* 过期时间 */  
  330.         const char* tokenbinary, /* 二进制Token */  
  331.         char* msg, /* message */  
  332.         int badage, /* badage */  
  333.         const char * sound) /* sound */  
  334. {  
  335.     assert(buflen >= 1 + 4 + 4 + 2 + TOKEN_SIZE + 2 + MAX_PAYLOAD_SIZE);  
  336.   
  337.     char * pdata = buf;  
  338.     // command  
  339.     *pdata = 1;  
  340.   
  341.     // messageid  
  342.     pdata++;  
  343.     *(uint32_t*)pdata = messageid;  
  344.   
  345.     // expiry time  
  346.     pdata += 4;  
  347.     *(uint32_t*)pdata = htonl(expiry);  
  348.   
  349.     // token length  
  350.     pdata += 4;  
  351.     *(uint16_t*)pdata = htons(TOKEN_SIZE);  
  352.   
  353.     // token binary  
  354.     pdata += 2;  
  355.     memcpy(pdata, tokenbinary, TOKEN_SIZE);  
  356.   
  357.     pdata += TOKEN_SIZE;  
  358.   
  359.     int payloadlen = MAX_PAYLOAD_SIZE;  
  360.     if (build_payload(pdata + 2, &payloadlen, msg, badage, sound) < 0)   
  361.     {  
  362.         msg[strlen(msg) - (payloadlen - MAX_PAYLOAD_SIZE)] = '\0';  
  363.         payloadlen = MAX_PAYLOAD_SIZE;  
  364.         if (build_payload(pdata + 2, &payloadlen, msg, badage, sound) <= 0)   
  365.         {  
  366.             return -1;  
  367.         }  
  368.     }  
  369.   
  370.     *(uint16_t*)pdata = htons(payloadlen);  
  371.   
  372.     return 1 + 4 + 4 + 2 + TOKEN_SIZE + 2 + payloadlen;  
  373. }  
  374.   
  375. int send_message_2(SSL *ssl, const char* token, uint32_t id, uint32_t expire, char* msg, int badage, const char* sound)  
  376. {  
  377.     int         i, n;  
  378.     char buf[1 + 4 + 4 + 2 + TOKEN_SIZE + 2 + MAX_PAYLOAD_SIZE];  
  379.     unsigned char   binary[TOKEN_SIZE];  
  380.     int buflen = sizeof(buf);  
  381.   
  382.     n = strlen(token);  
  383.     printf("token length : %d, TOKEN_SIZE = %d\n token = %s\n", n, TOKEN_SIZE, token);  
  384.     DeviceToken2Binary(token, n, binary, TOKEN_SIZE);  
  385.   
  386.     for (i = 0; i < TOKEN_SIZE; i++)  
  387.         printf("%d ", binary[i]);  
  388.     printf("\n");  
  389.   
  390.   
  391.     buflen = build_output_packet_2(buf, buflen, id, expire,(const char*)binary, msg, badage, sound);  
  392.   
  393.     if (buflen <= 0) {  
  394.         return -1;  
  395.     }  
  396.   
  397.     n = SSL_write(ssl, buf, buflen);  
  398.   
  399.     return  n;  
  400. }  
  401.   
  402. int main(int argc, char** argv)  
  403. {  
  404.     int  i, n;  
  405.     char buf[1024];  
  406.     char * msg = NULL;  
  407.     if (argc > 1) msg = argv[1];  
  408.   
  409.     init_openssl();  
  410.   
  411.     // 初始化Context  
  412.     // develop.pem是我们的证书和Key,为了方便使用,我们把证书和Key写到同一个文件中  
  413.     // 并取水了Key的密码保护  
  414.     // entrust_2048_ca.pem是苹果证书的CA,它并不在Openssl的根证书中,所以需要我们手动指定,不然会无法验证  
  415.     // 详细:http://www.entrust.net/developer/index.cfm  
  416.     SSL_CTX *ctx = init_ssl_context("develop.pem""develop.pem", NULL, "entrust_2048_ca.pem");  
  417.     if (!ctx) {  
  418.         fprintf(stderr, "init ssl context failed: %s\n",  
  419.                 ERR_reason_error_string(ERR_get_error()));  
  420.         return -1;  
  421.     }  
  422.   
  423.     // 连接到测试服务器  
  424.     const char* host = "gateway.sandbox.push.apple.com";  
  425.     const int port = 2195;  
  426.     int socket = tcp_connect(host, port);  
  427.     if (socket < 0) {  
  428.         fprintf(stderr, "failed to connect to host %s\n",  
  429.                 strerror(errno));  
  430.         return -1;  
  431.     }  
  432.   
  433.     // SSL连接  
  434.     SSL *ssl = ssl_connect(ctx, socket);  
  435.     if (!ssl) {  
  436.         fprintf(stderr, "ssl connect failed: %s\n",  
  437.                 ERR_reason_error_string(ERR_get_error()));  
  438.         Closesocket(socket);  
  439.         return -1;  
  440.     }  
  441.   
  442.     // 验证服务器证书  
  443.     if (verify_connection(ssl, host) != 0) {  
  444.         fprintf(stderr, "verify failed\n");  
  445.         Closesocket(socket);  
  446.         return 1;  
  447.     }  
  448.   
  449.     uint32_t msgid = 1;  
  450.     uint32_t expire = time(NULL) + 24 * 3600; // expire 1 day  
  451.   
  452.     printf("main, expire = %d\n", expire);  
  453.   
  454.     if (!msg) {  
  455.         msg = "hello\nThis is a test message";  
  456.     }  
  457.   
  458.     // 发送一条消息  
  459.     const char* token = "0a8b9e7cbe68616cd5470e4c8abb4c1a3f4ba2bee4ca113ff02ae2c325948b8a";  
  460.     n = send_message_2(ssl, token, msgid++, expire, msg, 1, "default");  
  461.     printf("after send_message_2, n = %d\n", n);  
  462.     if (n <= 0)   
  463.     {  
  464.         fprintf(stderr, "send failed: %s\n", ERR_reason_error_string(ERR_get_error()));  
  465.     }else  
  466.     {  
  467.         printf("send sucessfully.\n");  
  468.     }  
  469.   
  470.   
  471.     // 接收苹果推送服务器发来的数据:  
  472.     //n = recv(socket, buf, sizeof(buf), MSG_DONTWAIT); //非阻塞模式接收    
  473.     n = read(socket, buf, sizeof(buf)); //阻塞模式接收  
  474.     printf("from APNS, n = %d\n", n);  
  475.     for(i=0; i<n; i++)  
  476.         printf("%d ", buf[i]);  
  477.     printf("\n");  
  478.   
  479.   
  480.     // 关闭连接  
  481.     SSL_shutdown(ssl);  
  482.     Closesocket(socket);  
  483.   
  484.     printf("exit\n");  
  485.   
  486.     return 0;  
  487. }  
// ippush.c
// 在Linux下编译:gcc -o ippush ippush.c -lssl

#ifdef _WIN32
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
#else
# include <sys/types.h>
# include <sys/socket.h>
# include <netinet/in.h>
# include <netdb.h>
# include <arpa/inet.h>
# include <string.h>
# include <unistd.h>
# include <fcntl.h>
# include <errno.h>
#endif

#include <stdlib.h>
#include <stdint.h>
#include <assert.h>

#include <openssl/ssl.h>
#include <openssl/bio.h>
#include <openssl/err.h>


#define MAX_PAYLOAD_SIZE 256
#define TOKEN_SIZE 32

void DeviceToken2Binary(const char* sz, const int len, unsigned char* const binary, const int size) 
{
	int 		i, val;
	const char* 	pin;
	char 		buf[3] = {0};

	assert(size >= TOKEN_SIZE);

	for (i = 0;i < len;i++)
	{
		pin = sz + i * 2;
		buf[0] = pin[0];
		buf[1] = pin[1];

		val = 0;
		sscanf(buf, "%X", &val);
		binary[i] = val;
	}

	return;
}

void DeviceBinary2Token(const unsigned char* data, const int len, char* const token, const int size) 
{
	int i;

	assert(size > TOKEN_SIZE * 2);

	for (i = 0;i < len;i++)
	{
		sprintf(token + i * 2, "%02x", data[i]);
	}

	return;
}

void Closesocket(int socket)
{
#ifdef _WIN32
	closesocket(socket);
#else
	close(socket);
#endif
}

// 初始化ssl库,Windows下初始化WinSock
void init_openssl()
{
#ifdef _WIN32
	WSADATA wsaData;
	WSAStartup(MAKEWORD(2, 2), &wsaData);
#endif

	SSL_library_init();
	ERR_load_BIO_strings();
	SSL_load_error_strings();
	OpenSSL_add_all_algorithms();
}

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
	SSL_CTX *ctx = SSL_CTX_new(SSLv23_client_method());
	if (!ctx) {
		return NULL;
	}

	// certificate
	if (SSL_CTX_use_certificate_file(ctx, clientcert, SSL_FILETYPE_PEM) <= 0) {
		return NULL;
	}

	// key
	if (SSL_CTX_use_PrivateKey_file(ctx, clientkey, SSL_FILETYPE_PEM) <= 0) {
		return NULL;
	}

	// make sure the key and certificate file match
	if (SSL_CTX_check_private_key(ctx) == 0) {
		return NULL;
	}

	// load ca if exist
	if (cacert) {
		if (!SSL_CTX_load_verify_locations(ctx, cacert, NULL)) {
			return NULL;
		}
	}

	return ctx;
}

// 建立TCP连接到服务器
int tcp_connect(const char* host, int port)
{
	struct hostent *hp;
	struct sockaddr_in addr;
	int sock = -1;

	// 解析域名
	if (!(hp = gethostbyname(host))) {
		return -1;
	}

	memset(&addr, 0, sizeof(addr));
	addr.sin_addr = *(struct in_addr*)hp->h_addr_list[0];
	addr.sin_family = AF_INET;
	addr.sin_port = htons(port);

	if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0){
		return -1;
	}

	if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) != 0) {
		return -1;
	}

	return sock;
}

// 实现SSL握手,建立SSL连接
SSL* ssl_connect(SSL_CTX* ctx, int socket)
{
	SSL *ssl = SSL_new(ctx);
	BIO *bio = BIO_new_socket(socket, BIO_NOCLOSE);
	SSL_set_bio(ssl, bio, bio);

	if (SSL_connect(ssl) <= 0) {
		return NULL;
	}

	return ssl;
}

// 验证服务器证书
// 首先要验证服务器的证书有效,其次要验证服务器证书的CommonName(CN)与我们
// 实际要连接的服务器域名一致
int verify_connection(SSL* ssl, const char* peername)
{
	int result = SSL_get_verify_result(ssl);
	if (result != X509_V_OK) {
		fprintf(stderr, "WARNING! ssl verify failed: %d", result);
		return -1;
	}

	X509 *peer;
	char peer_CN[256] = {0};

	peer = SSL_get_peer_certificate(ssl);
	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 0;
}

void json_escape(char*  str)
{
	int 	n;
	char  	buf[1024];

	n = strlen(str) * sizeof(char) + 100;
	assert(n < sizeof(buf));

	strncpy(buf, str, n);
	buf[n] = '\0';
	char *found = buf;
	while (*found != '\0')
	{
		if('\\' == *found || '"' == *found || '\n' == *found || '/' == *found)
			*str++ = '\\';

		if('\n' == *found)
			*found = 'n';

		*str++ = *found++;       
	}

	*str='\0';

	return;
}

// Payload example

// {"aps":{"alert" : "You got your emails.","badge" : 9,"sound" : "default"}}
int build_payload(char* buffer, int* plen, char* msg, int badage, const char * sound)
{
	int n;
	char buf[2048];
	char str[2048] = "{\"aps\":{\"alert\":\"";

	n = strlen(str);

	if (msg) 
	{
		strcpy(buf, msg);
		json_escape(buf);
		n = n + sprintf(str+n, "%s", buf);
	}

	n = n + sprintf(str+n, "%s%d", "\",\"badge\":", badage);

	if (sound) 
	{
		n = n + sprintf(str+n, "%s", ",\"sound\":\"");
		strcpy(buf, sound);
		json_escape(buf);
		n = n + sprintf(str+n, "%s%s", buf, "\"");
	}

	strcat(str, "}}");

	n = strlen(str);

	if (n > *plen) 
	{
		*plen = n;
		return -1;
	}


	if (n < *plen) 
	{
		strcpy(buffer, str);
	} else 
	{
		strncpy(buffer, str, *plen);
	}

	*plen = n;

	return *plen;
}

// 第一种形式的包
int build_output_packet(char* buf, int buflen, /* 输出的缓冲区及长度 */
		const char* tokenbinary, /* 二进制的Token */
		char* msg, /* 要发送的消息 */
		int badage, /* 应用图标上显示的数字 */
		const char * sound) /* 设备收到时播放的声音,可以为空 */
{
	assert(buflen >= 1 + 2 + TOKEN_SIZE + 2 + MAX_PAYLOAD_SIZE);

	char * pdata = buf;
	// command
	*pdata = 0;

	// token length
	pdata++;
	*(uint16_t*)pdata = htons(TOKEN_SIZE);

	// token binary
	pdata += 2;
	memcpy(pdata, tokenbinary, TOKEN_SIZE);

	pdata += TOKEN_SIZE;

	int payloadlen = MAX_PAYLOAD_SIZE;
	if (build_payload(pdata + 2, &payloadlen, msg, badage, sound) < 0) 
	{
		msg[strlen(msg) - (payloadlen - MAX_PAYLOAD_SIZE)] = '\0';
		payloadlen = MAX_PAYLOAD_SIZE;
		if (build_payload(pdata + 2, &payloadlen, msg, badage, sound) <= 0) 
		{
			return -1;
		}
	}
	*(uint16_t*)pdata = htons(payloadlen);

	return 1 + 2 + TOKEN_SIZE + 2 + payloadlen;
}

int send_message(SSL *ssl, const char* token, char* msg, int badage, const char* sound)
{
	int 		n;
	char 		buf[1 + 2 + TOKEN_SIZE + 2 + MAX_PAYLOAD_SIZE];
	unsigned char 	binary[TOKEN_SIZE];
	int 		buflen = sizeof(buf);

	n = strlen(token);
	DeviceToken2Binary(token, n, binary, TOKEN_SIZE);

	buflen = build_output_packet(buf, buflen, (const char*)binary, msg, badage, sound);
	if (buflen <= 0) {
		return -1;
	}

	return SSL_write(ssl, buf, buflen);
}

int build_output_packet_2(char* buf, int buflen, /* 缓冲区及长度 */
		uint32_t messageid, /* 消息编号 */
		uint32_t expiry, /* 过期时间 */
		const char* tokenbinary, /* 二进制Token */
		char* msg, /* message */
		int badage, /* badage */
		const char * sound) /* sound */
{
	assert(buflen >= 1 + 4 + 4 + 2 + TOKEN_SIZE + 2 + MAX_PAYLOAD_SIZE);

	char * pdata = buf;
	// command
	*pdata = 1;

	// messageid
	pdata++;
	*(uint32_t*)pdata = messageid;

	// expiry time
	pdata += 4;
	*(uint32_t*)pdata = htonl(expiry);

	// token length
	pdata += 4;
	*(uint16_t*)pdata = htons(TOKEN_SIZE);

	// token binary
	pdata += 2;
	memcpy(pdata, tokenbinary, TOKEN_SIZE);

	pdata += TOKEN_SIZE;

	int payloadlen = MAX_PAYLOAD_SIZE;
	if (build_payload(pdata + 2, &payloadlen, msg, badage, sound) < 0) 
	{
		msg[strlen(msg) - (payloadlen - MAX_PAYLOAD_SIZE)] = '\0';
		payloadlen = MAX_PAYLOAD_SIZE;
		if (build_payload(pdata + 2, &payloadlen, msg, badage, sound) <= 0) 
		{
			return -1;
		}
	}

	*(uint16_t*)pdata = htons(payloadlen);

	return 1 + 4 + 4 + 2 + TOKEN_SIZE + 2 + payloadlen;
}

int send_message_2(SSL *ssl, const char* token, uint32_t id, uint32_t expire, char* msg, int badage, const char* sound)
{
	int 		i, n;
	char buf[1 + 4 + 4 + 2 + TOKEN_SIZE + 2 + MAX_PAYLOAD_SIZE];
	unsigned char 	binary[TOKEN_SIZE];
	int buflen = sizeof(buf);

	n = strlen(token);
	printf("token length : %d, TOKEN_SIZE = %d\n token = %s\n", n, TOKEN_SIZE, token);
	DeviceToken2Binary(token, n, binary, TOKEN_SIZE);

	for (i = 0; i < TOKEN_SIZE; i++)
		printf("%d ", binary[i]);
	printf("\n");


	buflen = build_output_packet_2(buf, buflen, id, expire,(const char*)binary, msg, badage, sound);

	if (buflen <= 0) {
		return -1;
	}

	n = SSL_write(ssl, buf, buflen);

	return  n;
}

int main(int argc, char** argv)
{
	int  i, n;
	char buf[1024];
	char * msg = NULL;
	if (argc > 1) msg = argv[1];

	init_openssl();

	// 初始化Context
	// develop.pem是我们的证书和Key,为了方便使用,我们把证书和Key写到同一个文件中
	// 并取水了Key的密码保护
	// entrust_2048_ca.pem是苹果证书的CA,它并不在Openssl的根证书中,所以需要我们手动指定,不然会无法验证
	// 详细:http://www.entrust.net/developer/index.cfm
	SSL_CTX *ctx = init_ssl_context("develop.pem", "develop.pem", NULL, "entrust_2048_ca.pem");
	if (!ctx) {
		fprintf(stderr, "init ssl context failed: %s\n",
				ERR_reason_error_string(ERR_get_error()));
		return -1;
	}

	// 连接到测试服务器
	const char* host = "gateway.sandbox.push.apple.com";
	const int port = 2195;
	int socket = tcp_connect(host, port);
	if (socket < 0) {
		fprintf(stderr, "failed to connect to host %s\n",
				strerror(errno));
		return -1;
	}

	// SSL连接
	SSL *ssl = ssl_connect(ctx, socket);
	if (!ssl) {
		fprintf(stderr, "ssl connect failed: %s\n",
				ERR_reason_error_string(ERR_get_error()));
		Closesocket(socket);
		return -1;
	}

	// 验证服务器证书
	if (verify_connection(ssl, host) != 0) {
		fprintf(stderr, "verify failed\n");
		Closesocket(socket);
		return 1;
	}

	uint32_t msgid = 1;
	uint32_t expire = time(NULL) + 24 * 3600; // expire 1 day

	printf("main, expire = %d\n", expire);

	if (!msg) {
		msg = "hello\nThis is a test message";
	}

	// 发送一条消息
	const char* token = "0a8b9e7cbe68616cd5470e4c8abb4c1a3f4ba2bee4ca113ff02ae2c325948b8a";
	n = send_message_2(ssl, token, msgid++, expire, msg, 1, "default");
	printf("after send_message_2, n = %d\n", n);
	if (n <= 0) 
	{
		fprintf(stderr, "send failed: %s\n", ERR_reason_error_string(ERR_get_error()));
	}else
	{
		printf("send sucessfully.\n");
	}


	// 接收苹果推送服务器发来的数据:
	//n = recv(socket, buf, sizeof(buf), MSG_DONTWAIT); //非阻塞模式接收  
	n = read(socket, buf, sizeof(buf)); //阻塞模式接收
	printf("from APNS, n = %d\n", n);
	for(i=0; i<n; i++)
		printf("%d ", buf[i]);
	printf("\n");


	// 关闭连接
	SSL_shutdown(ssl);
	Closesocket(socket);

	printf("exit\n");

	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值