OpenSSL在苹果手机推送中的使用
来源:互联网 发布:二次元站源码 编辑:程序博客网 时间:2024/05/01 14:36
opensslshiy流程:
1.初始化; SSLv23_client_method();创建SSL上下文环境 SSL_CTX_new ()
2.创建socket,connect;校验证书;
3.socket绑定SSL:SSL_new,SSL_connect;
4.校验服务器证书;
5.SSL_write,SSL_read;
6.释放资源 SSL_shutdown等;
view source
print?
001 ////openssl
002 //author:jordan.sg QQ:87895224
003 //2012.7
004 //初始化部分
005 SSL_library_init();
006 SSL_load_error_strings();
007 SSLeay_add_ssl_algorithms();
008
009 //校验服务器
010 bool CWorker::verifyServer(APP_SERVER *ptserver)
011 {
012 /* Following two steps are optional and not required for
013 data exchange to be successful. */
014
015 /* Set for server verification*/
016 SSL_CTX_set_verify(ptserver->psslctx,SSL_VERIFY_PEER,NULL);
017
018 /* Get the cipher – opt */
019 #ifdef _DEBUG
020 LogExt(LOG_LOG_LEVEL,”SSL connection using %s\n”, SSL_get_cipher(ptserver->ssl));
021 #endif
022 /* Get server’s certificate (note: beware of dynamic allocation) – opt */
023
024 ptserver->server_cert = SSL_get_peer_certificate (ptserver->ssl);
025 if (!ptserver->server_cert)
026 {
027 writelogimmediatly(“[exception]SSL_get_peer_certificate \n”);
028 setallthreadexitflag();
029 return false;
030 }
031 #ifdef _DEBUG
032 LogExt(LOG_LOG_LEVEL,”Server certificate:\n”);
033 #endif
034 char* str = X509_NAME_oneline (X509_get_subject_name (ptserver->server_cert),0,0);
035 if (!str)
036 {
037 writelogimmediatly(“[exception]X509_NAME_oneline\n”);
038 setallthreadexitflag();
039 return false;
040 }
041
042 #ifdef _DEBUG
043 LogExt(LOG_LOG_LEVEL,”\t subject: %s\n”, str);
044 //subject: /C=US/ST=California/L=Cupertino/O=Apple Inc./OU=iTMS Engineering/CN=gateway.sandbox.push.apple.com
045 //issuer: /C=US/O=Entrust, Inc./OU=www.entrust.net/rpa is incorporated by reference/OU=(c) 2009 Entrust, Inc./CN=Entrust Certification Authority – L1C
046 #endif
047
048 OPENSSL_free (str);
049
050 str = X509_NAME_oneline (X509_get_issuer_name(ptserver->server_cert),0,0);
051 if (!str)
052 {
053 writelogimmediatly(“[exception]X509_NAME_oneline.\n”);
054 setallthreadexitflag();
055 return false;
056 }
057
058 #ifdef _DEBUG
059 LogExt(LOG_LOG_LEVEL,”\t issuer: %s\n”, str);
060 #endif
061
062 OPENSSL_free (str);
063
064 /* We could do all sorts of certificate verification stuff here before
065 deallocating the certificate. */
066
067 X509_free (ptserver->server_cert);
068
069 return true;
070 }
071 //本机校验
072 bool CWorker::caVerify(APP_SERVER *ptserver)
073 {
074 /* define HOME to be dir for key and certificate files… */
075 //#define HOME “/certs/”
076 /* Make these what you want for certificate & key files */
077 #define CERT_FILE ptserver->pemfile ///// HOME “1024ccert.pem”
078 #define KEY_FILE ptserver->pemfile
079
080 /*Cipher list to be used*/
081 #define CIPHER_LIST “AES128-SHA”
082
083 /*Trusted CAs location*/
084 #define CA_FILE ptserver->pemfile ////”/certs/1024ccert.pem”
085 #define CA_DIR NULL
086
087 /*Set cipher list*/
088 if (SSL_CTX_set_cipher_list(ptserver->psslctx,CIPHER_LIST) <= 0)
089 {
090 writelogimmediatly(“[exception][CWorker][SSL]Error setting the cipher list.\n”);
091 setallthreadexitflag();
092 return false ;
093 }
094
095 /*Indicate the certificate file to be used*/
096
097 string pathfile=getExePath();
098 pathfile+=”\\”;
099 pathfile+=ptserver->pemfile;
100 if (SSL_CTX_use_certificate_file(ptserver->psslctx, pathfile.c_str(), SSL_FILETYPE_PEM) <= 0)
101 {
102
103 string errstr(“[err][SSL]Error setting the certificate file”);
104 const char * pc=ERR_reason_error_string(ERR_get_error());
105 errstr.append(pc?pc:”!\n”);
106 errstr.append(“\n”);
107 writelogimmediatly(errstr.c_str() );
108
109 setallthreadexitflag();
110 return false;
111 }
112
113
114 /*Load the password for the Private Key*/
115 SSL_CTX_set_default_passwd_cb_userdata(ptserver->psslctx, (void*)g_cfg.pem_psw.c_str());
116
117 pathfile=getExePath();
118 pathfile+= “\\”;
119 pathfile+=KEY_FILE;
120 /*Indicate the key file to be used*/
121 if (SSL_CTX_use_PrivateKey_file(ptserver->psslctx, pathfile.c_str(), SSL_FILETYPE_PEM) <= 0)
122 {
123 writelogimmediatly(“[exception][CWorker][SSL]Error setting the key file.\n”);
124 setallthreadexitflag();
125 return false;
126 }
127
128 /*Make sure the key and certificate file match*/
129 if (SSL_CTX_check_private_key(ptserver->psslctx) == 0) {
130 writelogimmediatly(“[log][CWorker][SSL]Private key does not match the certificate public key\n”);
131 setallthreadexitflag();
132 return false;
133 }
134
135 /* Set the list of trusted CAs based on the file and/or directory provided*/
136 pathfile=getExePath();
137 pathfile+= “\\”;
138 pathfile+=CA_FILE;
139 if(SSL_CTX_load_verify_locations(ptserver->psslctx, pathfile.c_str(), CA_DIR)<1) {
140 writelogimmediatly(“[log][CWorker][SSL]Error setting verify location\n”);
141 setallthreadexitflag();
142 return false;
143 }
144
145 return true;
146
147 }
148 //连接到苹果的服务器
149 bool CWorker::connectToServer(const char *hostname,int port,APP_SERVER *ptserver)
150 {
151 #ifdef _DEBUG
152 writelogimmediatly(“connectToServer start\n”);
153 #endif
154
155 //set client using SSL version
156 ptserver->meth = (SSL_METHOD *)SSLv23_client_method();
157
158
159 //创建SSL上下文环境
160 ptserver->psslctx = SSL_CTX_new (ptserver->meth);
161 if(!ptserver->psslctx)
162 {
163 writelogimmediatly(“[err]SSL_CTX_new: NULL\n”);
164 //LogExt(LOG_LOG_LEVEL,”Error: %s\n”, ERR_reason_error_string(ERR_get_error()));
165 return false;
166 }
167
168 caVerify(ptserver);
169 /* ———————————————– */
170 /* Create a socket and connect to server using normal socket calls. */
171
172 ptserver->sd = socket (AF_INET, SOCK_STREAM, 0);
173 if(SOCKET_ERROR == ptserver->sd)
174 {
175 writelogimmediatly(“[err][connectToServer]socket\n”);
176 return false;
177 }
178
179 if(!nonblock_connect(ptserver->sd,ptserver->sa,hostname,port))
180 {
181 return false;
182 }
183
184 /* ———————————————– */
185 /* Now we have TCP conncetion. Start SSL negotiation. */
186 ptserver->ssl = SSL_new (ptserver->psslctx);
187 if(!ptserver->ssl)
188 {
189 string errstr(“[err][SSL_new]“);
190 const char * pc=ERR_reason_error_string(ERR_get_error());
191 errstr.append(pc?pc:”fail!\n”);
192 writelogimmediatly(errstr.c_str() );
193 return false;
194 }
195 SSL_set_fd (ptserver->ssl, ptserver->sd);
196 SSL_set_mode(ptserver->ssl, SSL_MODE_AUTO_RETRY);
197
198 #ifdef NONEBLOCK_SOCKET
199
200 CONN_RE:
201
202 ptserver->err = SSL_connect (ptserver->ssl);
203 if(1 == ptserver->err)
204 {
205 #ifdef _DEBUG
206 LogExt(LOG_LOG_LEVEL,”The TLS/SSL handshake was successfully completed, a TLS/SSL connection has been established.\n”);
207 #endif
208 }
209 else if(-1 == ptserver->err)
210 {
211 ptserver->err = SSL_get_error(ptserver->ssl,ptserver->err);
212 if (SSL_ERROR_WANT_READ==ptserver->err || SSL_ERROR_WANT_WRITE==ptserver->err)
213 {
214 goto CONN_RE;
215 }
216 string errstr(“[err][SSL_connect]fail!\n”);
217 writelogimmediatly(errstr.c_str() );
218 return false;
219 }
220
221 #else
222
223 ptserver->err = SSL_connect (ptserver->ssl);
224 if(1 == ptserver->err)
225 {
226 LogExt(LOG_LOG_LEVEL,”The TLS/SSL handshake was successfully completed, a TLS/SSL connection has been established.\n”);
227 }
228 else if(-1 == ptserver->err)
229 {
230 string errstr(“[err][SSL_connect]“);
231 const char * pc=ERR_reason_error_string(ERR_get_error());
232 errstr.append(pc?pc:”fail!\n”);
233 writelogimmediatly(errstr.c_str() );
234 return false;
235 }
236 #endif
237 // 检查证书是否有效
238 //20 X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: unable to get local issuer certificate
239 // the issuer certificate could not be found: this occurs if the issuer certificate of an untrusted certificate cannot be found.
240
241 int ret_ssl=0;
242 if(X509_V_OK != ( ret_ssl=SSL_get_verify_result(ptserver->ssl)))
243 {
244 LogExt(LOG_LOG_LEVEL,”SSL_get_verify_result =>%d\n”,ret_ssl);
245 }
246
247 return true;
248 }
249
250 //连接到Feedback沙盒测试服务器
251 bool CWorker::connectToFeedbackSandBoxServer()
252 {
253 bool ret = connectToServer(g_cfg.feedback_sandbox_www.c_str(),g_cfg.feedback_sandbox_port,&this->feed);
254 if (ret)
255 {
256 verifyServer(&this->feed);
257 }
258
259 return ret;
260 }
261
262 //读取Feedback
263 void CWorker::getFeedback()
264 {
265 bool ret = false;
266 if ( IsSandBox())
267 {
268 ret = connectToFeedbackSandBoxServer();
269 }
270 else
271 {
272 ret = connectToFeedbackServer();
273 }
274
275 //读feedback
276 if (ret)
277 {
278 readFeedbackSub();
279 }
280
281 stopSSLFeed();
282 }
283 //发送推送信息
284 void CWorker::sendtoAPNs()
285 {
286 bool ret = false;
287 if ( IsSandBox())
288 {
289 ret = connectToAPNsSandBox();
290 }
291 else
292 {
293 ret = connectToAPNs();
294 }
295
296 if (ret)
297 {
298 //找到开始的一条信息,开始的一个设备
299 string current_info_id(“”);//send_id char12
300 UINT current_device_id=0;
301 string current_device_token(“”);
302
303 StartSend(current_info_id,current_device_token,¤t_device_id);
304 if (!current_info_id.empty() && !current_device_token.empty() )
305 {
306 batchSendtoApns(current_info_id,current_device_token,current_device_id);
307 }
308
309 //
310
311 }
312 stopSSLApns();
313
314 }
315
316 void CWorker::stopSSLFeed()
317 {
318
319 if (feed.ssl)
320 {
321 SSL_shutdown (feed.ssl); /* send SSL/TLS close_notify */
322
323 close (feed.sd);
324 SSL_free (feed.ssl);
325 SSL_CTX_free (feed.psslctx);
326 }
327 feed.ssl=NULL;
328
329
330 }
001
////openssl
002
//author:jordan.sg QQ:87895224
003
//2012.7
004
//初始化部分
005
SSL_library_init();
006
SSL_load_error_strings();
007
SSLeay_add_ssl_algorithms();
008
009
//校验服务器
010
bool
CWorker::verifyServer(APP_SERVER *ptserver)
011
{
012
/* Following two steps are optional and not required for
013
data exchange to be successful. */
014
015
/* Set for server verification*/
016
SSL_CTX_set_verify(ptserver->psslctx,SSL_VERIFY_PEER,NULL);
017
018
/* Get the cipher - opt */
019
#ifdef _DEBUG
020
LogExt(LOG_LOG_LEVEL,
"SSL connection using %s\n"
, SSL_get_cipher(ptserver->ssl));
021
#endif
022
/* Get server's certificate (note: beware of dynamic allocation) - opt */
023
024
ptserver->server_cert = SSL_get_peer_certificate (ptserver->ssl);
025
if
(!ptserver->server_cert)
026
{
027
writelogimmediatly(
"[exception]SSL_get_peer_certificate \n"
);
028
setallthreadexitflag();
029
return
false
;
030
}
031
#ifdef _DEBUG
032
LogExt(LOG_LOG_LEVEL,
"Server certificate:\n"
);
033
#endif
034
char
* str = X509_NAME_oneline (X509_get_subject_name (ptserver->server_cert),0,0);
035
if
(!str)
036
{
037
writelogimmediatly(
"[exception]X509_NAME_oneline\n"
);
038
setallthreadexitflag();
039
return
false
;
040
}
041
042
#ifdef _DEBUG
043
LogExt(LOG_LOG_LEVEL,
"\t subject: %s\n"
, str);
044
//subject: /C=US/ST=California/L=Cupertino/O=Apple Inc./OU=iTMS Engineering/CN=gateway.sandbox.push.apple.com
045
//issuer: /C=US/O=Entrust, Inc./OU=www.entrust.net/rpa is incorporated by reference/OU=(c) 2009 Entrust, Inc./CN=Entrust Certification Authority - L1C
046
#endif
047
048
OPENSSL_free (str);
049
050
str = X509_NAME_oneline (X509_get_issuer_name(ptserver->server_cert),0,0);
051
if
(!str)
052
{
053
writelogimmediatly(
"[exception]X509_NAME_oneline.\n"
);
054
setallthreadexitflag();
055
return
false
;
056
}
057
058
#ifdef _DEBUG
059
LogExt(LOG_LOG_LEVEL,
"\t issuer: %s\n"
, str);
060
#endif
061
062
OPENSSL_free (str);
063
064
/* We could do all sorts of certificate verification stuff here before
065
deallocating the certificate. */
066
067
X509_free (ptserver->server_cert);
068
069
return
true
;
070
}
071
//本机校验
072
bool
CWorker::caVerify(APP_SERVER *ptserver)
073
{
074
/* define HOME to be dir for key and certificate files... */
075
//#define HOME "/certs/"
076
/* Make these what you want for certificate & key files */
077
#define CERT_FILE ptserver->pemfile ///// HOME "1024ccert.pem"
078
#define KEY_FILE ptserver->pemfile
079
080
/*Cipher list to be used*/
081
#define CIPHER_LIST "AES128-SHA"
082
083
/*Trusted CAs location*/
084
#define CA_FILE ptserver->pemfile ////"/certs/1024ccert.pem"
085
#define CA_DIR NULL
086
087
/*Set cipher list*/
088
if
(SSL_CTX_set_cipher_list(ptserver->psslctx,CIPHER_LIST) <= 0)
089
{
090
writelogimmediatly(
"[exception][CWorker][SSL]Error setting the cipher list.\n"
);
091
setallthreadexitflag();
092
return
false
;
093
}
094
095
/*Indicate the certificate file to be used*/
096
097
string pathfile=getExePath();
098
pathfile+=
"\\"
;
099
pathfile+=ptserver->pemfile;
100
if
(SSL_CTX_use_certificate_file(ptserver->psslctx, pathfile.c_str(), SSL_FILETYPE_PEM) <= 0)
101
{
102
103
string errstr(
"[err][SSL]Error setting the certificate file"
);
104
const
char
* pc=ERR_reason_error_string(ERR_get_error());
105
errstr.append(pc?pc:
"!\n"
);
106
errstr.append(
"\n"
);
107
writelogimmediatly(errstr.c_str() );
108
109
setallthreadexitflag();
110
return
false
;
111
}
112
113
114
/*Load the password for the Private Key*/
115
SSL_CTX_set_default_passwd_cb_userdata(ptserver->psslctx, (
void
*)g_cfg.pem_psw.c_str());
116
117
pathfile=getExePath();
118
pathfile+=
"\\"
;
119
pathfile+=KEY_FILE;
120
/*Indicate the key file to be used*/
121
if
(SSL_CTX_use_PrivateKey_file(ptserver->psslctx, pathfile.c_str(), SSL_FILETYPE_PEM) <= 0)
122
{
123
writelogimmediatly(
"[exception][CWorker][SSL]Error setting the key file.\n"
);
124
setallthreadexitflag();
125
return
false
;
126
}
127
128
/*Make sure the key and certificate file match*/
129
if
(SSL_CTX_check_private_key(ptserver->psslctx) == 0) {
130
writelogimmediatly(
"[log][CWorker][SSL]Private key does not match the certificate public key\n"
);
131
setallthreadexitflag();
132
return
false
;
133
}
134
135
/* Set the list of trusted CAs based on the file and/or directory provided*/
136
pathfile=getExePath();
137
pathfile+=
"\\"
;
138
pathfile+=CA_FILE;
139
if
(SSL_CTX_load_verify_locations(ptserver->psslctx, pathfile.c_str(), CA_DIR)<1) {
140
writelogimmediatly(
"[log][CWorker][SSL]Error setting verify location\n"
);
141
setallthreadexitflag();
142
return
false
;
143
}
144
145
return
true
;
146
147
}
148
//连接到苹果的服务器
149
bool
CWorker::connectToServer(
const
char
*hostname,
int
port,APP_SERVER *ptserver)
150
{
151
#ifdef _DEBUG
152
writelogimmediatly(
"connectToServer start\n"
);
153
#endif
154
155
//set client using SSL version
156
ptserver->meth = (SSL_METHOD *)SSLv23_client_method();
157
158
159
//创建SSL上下文环境
160
ptserver->psslctx = SSL_CTX_new (ptserver->meth);
161
if
(!ptserver->psslctx)
162
{
163
writelogimmediatly(
"[err]SSL_CTX_new: NULL\n"
);
164
//LogExt(LOG_LOG_LEVEL,"Error: %s\n", ERR_reason_error_string(ERR_get_error()));
165
return
false
;
166
}
167
168
caVerify(ptserver);
169
/* ----------------------------------------------- */
170
/* Create a socket and connect to server using normal socket calls. */
171
172
ptserver->sd = socket (AF_INET, SOCK_STREAM, 0);
173
if
(SOCKET_ERROR == ptserver->sd)
174
{
175
writelogimmediatly(
"[err][connectToServer]socket\n"
);
176
return
false
;
177
}
178
179
if
(!nonblock_connect(ptserver->sd,ptserver->sa,hostname,port))
180
{
181
return
false
;
182
}
183
184
/* ----------------------------------------------- */
185
/* Now we have TCP conncetion. Start SSL negotiation. */
186
ptserver->ssl = SSL_new (ptserver->psslctx);
187
if
(!ptserver->ssl)
188
{
189
string errstr(
"[err][SSL_new]"
);
190
const
char
* pc=ERR_reason_error_string(ERR_get_error());
191
errstr.append(pc?pc:
"fail!\n"
);
192
writelogimmediatly(errstr.c_str() );
193
return
false
;
194
}
195
SSL_set_fd (ptserver->ssl, ptserver->sd);
196
SSL_set_mode(ptserver->ssl, SSL_MODE_AUTO_RETRY);
197
198
#ifdef NONEBLOCK_SOCKET
199
200
CONN_RE:
201
202
ptserver->err = SSL_connect (ptserver->ssl);
203
if
(1 == ptserver->err)
204
{
205
#ifdef _DEBUG
206
LogExt(LOG_LOG_LEVEL,
"The TLS/SSL handshake was successfully completed, a TLS/SSL connection has been established.\n"
);
207
#endif
208
}
209
else
if
(-1 == ptserver->err)
210
{
211
ptserver->err = SSL_get_error(ptserver->ssl,ptserver->err);
212
if
(SSL_ERROR_WANT_READ==ptserver->err || SSL_ERROR_WANT_WRITE==ptserver->err)
213
{
214
goto
CONN_RE;
215
}
216
string errstr(
"[err][SSL_connect]fail!\n"
);
217
writelogimmediatly(errstr.c_str() );
218
return
false
;
219
}
220
221
#else
222
223
ptserver->err = SSL_connect (ptserver->ssl);
224
if
(1 == ptserver->err)
225
{
226
LogExt(LOG_LOG_LEVEL,
"The TLS/SSL handshake was successfully completed, a TLS/SSL connection has been established.\n"
);
227
}
228
else
if
(-1 == ptserver->err)
229
{
230
string errstr(
"[err][SSL_connect]"
);
231
const
char
* pc=ERR_reason_error_string(ERR_get_error());
232
errstr.append(pc?pc:
"fail!\n"
);
233
writelogimmediatly(errstr.c_str() );
234
return
false
;
235
}
236
#endif
237
// 检查证书是否有效
238
//20 X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: unable to get local issuer certificate
239
// the issuer certificate could not be found: this occurs if the issuer certificate of an untrusted certificate cannot be found.
240
241
int
ret_ssl=0;
242
if
(X509_V_OK != ( ret_ssl=SSL_get_verify_result(ptserver->ssl)))
243
{
244
LogExt(LOG_LOG_LEVEL,
"SSL_get_verify_result =>%d\n"
,ret_ssl);
245
}
246
247
return
true
;
248
}
249
250
//连接到Feedback沙盒测试服务器
251
bool
CWorker::connectToFeedbackSandBoxServer()
252
{
253
bool
ret = connectToServer(g_cfg.feedback_sandbox_www.c_str(),g_cfg.feedback_sandbox_port,&
this
->feed);
254
if
(ret)
255
{
256
verifyServer(&
this
->feed);
257
}
258
259
return
ret;
260
}
261
262
//读取Feedback
263
void
CWorker::getFeedback()
264
{
265
bool
ret =
false
;
266
if
( IsSandBox())
267
{
268
ret = connectToFeedbackSandBoxServer();
269
}
270
else
271
{
272
ret = connectToFeedbackServer();
273
}
274
275
//读feedback
276
if
(ret)
277
{
278
readFeedbackSub();
279
}
280
281
stopSSLFeed();
282
}
283
//发送推送信息
284
void
CWorker::sendtoAPNs()
285
{
286
bool
ret =
false
;
287
if
( IsSandBox())
288
{
289
ret = connectToAPNsSandBox();
290
}
291
else
292
{
293
ret = connectToAPNs();
294
}
295
296
if
(ret)
297
{
298
//找到开始的一条信息,开始的一个设备
299
string current_info_id(
""
);
//send_id char12
300
UINT
current_device_id=0;
301
string current_device_token(
""
);
302
303
StartSend(current_info_id,current_device_token,¤t_device_id);
304
if
(!current_info_id.empty() && !current_device_token.empty() )
305
{
306
batchSendtoApns(current_info_id,current_device_token,current_device_id);
307
}
308
309
//
310
311
}
312
stopSSLApns();
313
314
}
315
316
void
CWorker::stopSSLFeed()
317
{
318
319
if
(feed.ssl)
320
{
321
SSL_shutdown (feed.ssl);
/* send SSL/TLS close_notify */
322
323
close (feed.sd);
324
SSL_free (feed.ssl);
325
SSL_CTX_free (feed.psslctx);
326
}
327
feed.ssl=NULL;
328
329
330
}
- OpenSSL在苹果手机推送中的使用
- openssl编译及在VS2010中的使用
- 文件下载功能在苹果手机中的特殊处理
- Dmesg在手机中的使用
- 极光推送在java服务端推送消息到手机APP使用简单的demo
- 苹果推送通知服务中的iOS 教程
- openssl在高性能网络框架中的使用(自定义BIO)
- Windows下openssl安装与在vs中的使用
- 苹果手机怎么使用word
- 苹果证书 使用推送时报错
- Python使用HTTP2实现苹果原生推送
- 苹果推送
- 只要在苹果手机上使用软件(即使未经授权使用地理
- 在asio中使用OpenSSL
- 手机还是要在苹果下开发
- 如何在苹果手机上调试App
- js keyup事件 在安卓和苹果手机不同使用 input propertychange
- 使用OpenSSL发送IOS推送通知 Apple Push Notification
- iPhone开发中发送e-mail的3种方式
- 在 iOS 中使用 OpenSSL 库
- [ASP.NET MVC 小牛之路]04 - 依赖注入(DI)和Ninject
- warning: Signal <> missing in the sensitivity list is added for synthesis purposes
- ios获得通讯录中联系人的所有属性
- OpenSSL在苹果手机推送中的使用
- 黑马程序员_java注解
- iOS学习笔记–10 IOS之云端应用
- HDU 4278
- iOS学习笔记–11 IOS之地图和定位应用开发
- iOS学习笔记–12 IOS之多媒体API
- [ASP.NET MVC 小牛之路]07 - URL Routing
- iOS学习笔记–14 IOS之Quartz
- iOS学习笔记–15 IOS之动画