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,