Mercurial > pidgin.yaz
comparison plugins/ssl/ssl-nss.c @ 13200:33bef17125c2
[gaim-migrate @ 15563]
This is the soon-to-be-infamous nonblocking network activity patch that I've been working on. Feel free to yell at me if this makes you unhappy.
committer: Tailor Script <tailor@pidgin.im>
author | Daniel Atallah <daniel.atallah@gmail.com> |
---|---|
date | Thu, 09 Feb 2006 04:17:56 +0000 |
parents | 8f8087bc9732 |
children | a587a6c6149c |
comparison
equal
deleted
inserted
replaced
13199:d8f238864c88 | 13200:33bef17125c2 |
---|---|
44 | 44 |
45 typedef struct | 45 typedef struct |
46 { | 46 { |
47 PRFileDesc *fd; | 47 PRFileDesc *fd; |
48 PRFileDesc *in; | 48 PRFileDesc *in; |
49 guint handshake_handler; | |
49 | 50 |
50 } GaimSslNssData; | 51 } GaimSslNssData; |
51 | 52 |
52 #define GAIM_SSL_NSS_DATA(gsc) ((GaimSslNssData *)gsc->private_data) | 53 #define GAIM_SSL_NSS_DATA(gsc) ((GaimSslNssData *)gsc->private_data) |
53 | 54 |
54 static const PRIOMethods *_nss_methods = NULL; | 55 static const PRIOMethods *_nss_methods = NULL; |
55 static PRDescIdentity _identity; | 56 static PRDescIdentity _identity; |
57 | |
58 /* Thank you, Evolution */ | |
59 static void | |
60 set_errno(int code) | |
61 { | |
62 /* FIXME: this should handle more. */ | |
63 switch (code) { | |
64 case PR_INVALID_ARGUMENT_ERROR: | |
65 errno = EINVAL; | |
66 break; | |
67 case PR_PENDING_INTERRUPT_ERROR: | |
68 errno = EINTR; | |
69 break; | |
70 case PR_IO_PENDING_ERROR: | |
71 errno = EAGAIN; | |
72 break; | |
73 case PR_WOULD_BLOCK_ERROR: | |
74 errno = EAGAIN; | |
75 /*errno = EWOULDBLOCK; */ | |
76 break; | |
77 case PR_IN_PROGRESS_ERROR: | |
78 errno = EINPROGRESS; | |
79 break; | |
80 case PR_ALREADY_INITIATED_ERROR: | |
81 errno = EALREADY; | |
82 break; | |
83 case PR_NETWORK_UNREACHABLE_ERROR: | |
84 errno = EHOSTUNREACH; | |
85 break; | |
86 case PR_CONNECT_REFUSED_ERROR: | |
87 errno = ECONNREFUSED; | |
88 break; | |
89 case PR_CONNECT_TIMEOUT_ERROR: | |
90 case PR_IO_TIMEOUT_ERROR: | |
91 errno = ETIMEDOUT; | |
92 break; | |
93 case PR_NOT_CONNECTED_ERROR: | |
94 errno = ENOTCONN; | |
95 break; | |
96 case PR_CONNECT_RESET_ERROR: | |
97 errno = ECONNRESET; | |
98 break; | |
99 case PR_IO_ERROR: | |
100 default: | |
101 errno = EIO; | |
102 break; | |
103 } | |
104 } | |
56 | 105 |
57 static void | 106 static void |
58 ssl_nss_init_nss(void) | 107 ssl_nss_init_nss(void) |
59 { | 108 { |
60 char *lib; | 109 char *lib; |
156 | 205 |
157 _nss_methods = NULL; | 206 _nss_methods = NULL; |
158 } | 207 } |
159 | 208 |
160 static void | 209 static void |
210 ssl_nss_handshake_cb(gpointer data, int fd, GaimInputCondition cond) | |
211 { | |
212 GaimSslConnection *gsc = (GaimSslConnection *)data; | |
213 GaimSslNssData *nss_data = gsc->private_data; | |
214 | |
215 /* I don't think this the best way to do this... | |
216 * It seems to work because it'll eventually use the cached value | |
217 */ | |
218 if(SSL_ForceHandshake(nss_data->in) != SECSuccess) { | |
219 set_errno(PR_GetError()); | |
220 if (errno == EAGAIN || errno == EWOULDBLOCK) | |
221 return; | |
222 | |
223 gaim_debug_error("nss", "Handshake failed %u\n", PR_GetError()); | |
224 | |
225 if (gsc->error_cb != NULL) | |
226 gsc->error_cb(gsc, GAIM_SSL_HANDSHAKE_FAILED, gsc->connect_cb_data); | |
227 | |
228 gaim_ssl_close(gsc); | |
229 | |
230 return; | |
231 } | |
232 | |
233 gaim_input_remove(nss_data->handshake_handler); | |
234 nss_data->handshake_handler = 0; | |
235 | |
236 gsc->connect_cb(gsc->connect_cb_data, gsc, cond); | |
237 } | |
238 | |
239 static void | |
161 ssl_nss_connect_cb(gpointer data, gint source, GaimInputCondition cond) | 240 ssl_nss_connect_cb(gpointer data, gint source, GaimInputCondition cond) |
162 { | 241 { |
163 GaimSslConnection *gsc = (GaimSslConnection *)data; | 242 GaimSslConnection *gsc = (GaimSslConnection *)data; |
164 GaimSslNssData *nss_data = g_new0(GaimSslNssData, 1); | 243 GaimSslNssData *nss_data = g_new0(GaimSslNssData, 1); |
165 PRSocketOptionData socket_opt; | 244 PRSocketOptionData socket_opt; |
181 | 260 |
182 return; | 261 return; |
183 } | 262 } |
184 | 263 |
185 socket_opt.option = PR_SockOpt_Nonblocking; | 264 socket_opt.option = PR_SockOpt_Nonblocking; |
186 socket_opt.value.non_blocking = PR_FALSE; | 265 socket_opt.value.non_blocking = PR_TRUE; |
187 | 266 |
188 PR_SetSocketOption(nss_data->fd, &socket_opt); | 267 if (PR_SetSocketOption(nss_data->fd, &socket_opt) != PR_SUCCESS) |
268 gaim_debug_warning("nss", "unable to set socket into non-blocking mode: %u\n", PR_GetError()); | |
189 | 269 |
190 nss_data->in = SSL_ImportFD(NULL, nss_data->fd); | 270 nss_data->in = SSL_ImportFD(NULL, nss_data->fd); |
191 | 271 |
192 if (nss_data->in == NULL) | 272 if (nss_data->in == NULL) |
193 { | 273 { |
210 SSL_BadCertHook(nss_data->in, (SSLBadCertHandler)ssl_bad_cert, NULL); | 290 SSL_BadCertHook(nss_data->in, (SSLBadCertHandler)ssl_bad_cert, NULL); |
211 | 291 |
212 if(gsc->host) | 292 if(gsc->host) |
213 SSL_SetURL(nss_data->in, gsc->host); | 293 SSL_SetURL(nss_data->in, gsc->host); |
214 | 294 |
295 #if 0 /* This seems like it'd the be the correct way to implement the nonblocking stuff, | |
296 but it doesn't seem to work */ | |
297 SSL_HandshakeCallback(nss_data->in, | |
298 (SSLHandshakeCallback) ssl_nss_handshake_cb, gsc); | |
299 #endif | |
215 SSL_ResetHandshake(nss_data->in, PR_FALSE); | 300 SSL_ResetHandshake(nss_data->in, PR_FALSE); |
216 | 301 |
217 if (SSL_ForceHandshake(nss_data->in)) | 302 nss_data->handshake_handler = gaim_input_add(gsc->fd, |
218 { | 303 GAIM_INPUT_READ, ssl_nss_handshake_cb, gsc); |
219 gaim_debug_error("nss", "Handshake failed\n"); | 304 |
220 | 305 ssl_nss_handshake_cb(gsc, gsc->fd, GAIM_INPUT_READ); |
221 if (gsc->error_cb != NULL) | |
222 gsc->error_cb(gsc, GAIM_SSL_HANDSHAKE_FAILED, gsc->connect_cb_data); | |
223 | |
224 gaim_ssl_close(gsc); | |
225 | |
226 return; | |
227 } | |
228 | |
229 gsc->connect_cb(gsc->connect_cb_data, gsc, cond); | |
230 } | 306 } |
231 | 307 |
232 static void | 308 static void |
233 ssl_nss_close(GaimSslConnection *gsc) | 309 ssl_nss_close(GaimSslConnection *gsc) |
234 { | 310 { |
238 return; | 314 return; |
239 | 315 |
240 if (nss_data->in) PR_Close(nss_data->in); | 316 if (nss_data->in) PR_Close(nss_data->in); |
241 /* if (nss_data->fd) PR_Close(nss_data->fd); */ | 317 /* if (nss_data->fd) PR_Close(nss_data->fd); */ |
242 | 318 |
319 if (nss_data->handshake_handler) | |
320 gaim_input_remove(nss_data->handshake_handler); | |
321 | |
243 g_free(nss_data); | 322 g_free(nss_data); |
323 gsc->private_data = NULL; | |
244 } | 324 } |
245 | 325 |
246 static size_t | 326 static size_t |
247 ssl_nss_read(GaimSslConnection *gsc, void *data, size_t len) | 327 ssl_nss_read(GaimSslConnection *gsc, void *data, size_t len) |
248 { | 328 { |
329 ssize_t ret; | |
249 GaimSslNssData *nss_data = GAIM_SSL_NSS_DATA(gsc); | 330 GaimSslNssData *nss_data = GAIM_SSL_NSS_DATA(gsc); |
250 | 331 |
251 return PR_Read(nss_data->in, data, len); | 332 ret = PR_Read(nss_data->in, data, len); |
333 | |
334 if (ret == -1) | |
335 set_errno(PR_GetError()); | |
336 | |
337 return ret; | |
252 } | 338 } |
253 | 339 |
254 static size_t | 340 static size_t |
255 ssl_nss_write(GaimSslConnection *gsc, const void *data, size_t len) | 341 ssl_nss_write(GaimSslConnection *gsc, const void *data, size_t len) |
256 { | 342 { |
343 ssize_t ret; | |
257 GaimSslNssData *nss_data = GAIM_SSL_NSS_DATA(gsc); | 344 GaimSslNssData *nss_data = GAIM_SSL_NSS_DATA(gsc); |
258 | 345 |
259 if(!nss_data) | 346 if(!nss_data) |
260 return 0; | 347 return 0; |
261 | 348 |
262 return PR_Write(nss_data->in, data, len); | 349 ret = PR_Write(nss_data->in, data, len); |
350 | |
351 if (ret == -1) | |
352 set_errno(PR_GetError()); | |
353 | |
354 return ret; | |
263 } | 355 } |
264 | 356 |
265 static GaimSslOps ssl_ops = | 357 static GaimSslOps ssl_ops = |
266 { | 358 { |
267 ssl_nss_init, | 359 ssl_nss_init, |