eventmachine 1.0.3-x86-mingw32 → 1.2.0.dev.2-x86-mingw32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +84 -1
- data/README.md +6 -7
- data/ext/binder.cpp +10 -10
- data/ext/binder.h +5 -5
- data/ext/cmain.cpp +173 -61
- data/ext/ed.cpp +262 -127
- data/ext/ed.h +50 -30
- data/ext/em.cpp +491 -445
- data/ext/em.h +101 -36
- data/ext/eventmachine.h +67 -51
- data/ext/extconf.rb +124 -31
- data/ext/fastfilereader/extconf.rb +9 -2
- data/ext/fastfilereader/mapper.cpp +3 -1
- data/ext/fastfilereader/rubymain.cpp +7 -7
- data/ext/kb.cpp +1 -1
- data/ext/pipe.cpp +11 -4
- data/ext/project.h +26 -6
- data/ext/rubymain.cpp +408 -201
- data/ext/ssl.cpp +167 -20
- data/ext/ssl.h +11 -2
- data/java/src/com/rubyeventmachine/EmReactor.java +16 -0
- data/java/src/com/rubyeventmachine/EventableChannel.java +2 -0
- data/java/src/com/rubyeventmachine/EventableDatagramChannel.java +6 -0
- data/java/src/com/rubyeventmachine/EventableSocketChannel.java +55 -10
- data/lib/1.9/fastfilereaderext.so +0 -0
- data/lib/1.9/rubyeventmachine.so +0 -0
- data/lib/2.0/fastfilereaderext.so +0 -0
- data/lib/2.0/rubyeventmachine.so +0 -0
- data/lib/2.1/fastfilereaderext.so +0 -0
- data/lib/2.1/rubyeventmachine.so +0 -0
- data/lib/2.2/fastfilereaderext.so +0 -0
- data/lib/2.2/rubyeventmachine.so +0 -0
- data/lib/2.3/fastfilereaderext.so +0 -0
- data/lib/2.3/rubyeventmachine.so +0 -0
- data/lib/em/buftok.rb +34 -85
- data/lib/em/channel.rb +5 -0
- data/lib/em/completion.rb +2 -2
- data/lib/em/connection.rb +62 -4
- data/lib/em/iterator.rb +30 -48
- data/lib/em/pool.rb +1 -1
- data/lib/em/protocols/httpclient.rb +31 -11
- data/lib/em/protocols/line_and_text.rb +4 -4
- data/lib/em/protocols/linetext2.rb +44 -39
- data/lib/em/protocols/smtpclient.rb +60 -31
- data/lib/em/protocols/smtpserver.rb +32 -9
- data/lib/em/pure_ruby.rb +8 -3
- data/lib/em/queue.rb +16 -7
- data/lib/em/resolver.rb +64 -24
- data/lib/em/threaded_resource.rb +2 -2
- data/lib/em/tick_loop.rb +19 -19
- data/lib/em/version.rb +1 -1
- data/lib/eventmachine.rb +96 -49
- data/lib/jeventmachine.rb +17 -0
- data/rakelib/package.rake +31 -4
- data/tests/dhparam.pem +13 -0
- data/tests/em_test_helper.rb +87 -0
- data/tests/test_attach.rb +25 -0
- data/tests/test_basic.rb +27 -38
- data/tests/test_channel.rb +14 -1
- data/tests/test_completion.rb +1 -0
- data/tests/test_connection_count.rb +22 -1
- data/tests/test_connection_write.rb +35 -0
- data/tests/test_defer.rb +17 -0
- data/tests/test_epoll.rb +26 -14
- data/tests/test_file_watch.rb +1 -0
- data/tests/test_fork.rb +75 -0
- data/tests/test_httpclient.rb +43 -0
- data/tests/test_idle_connection.rb +6 -4
- data/tests/test_ipv4.rb +125 -0
- data/tests/test_ipv6.rb +131 -0
- data/tests/test_iterator.rb +115 -0
- data/tests/test_kb.rb +19 -25
- data/tests/test_ltp2.rb +20 -0
- data/tests/test_many_fds.rb +22 -0
- data/tests/test_pause.rb +29 -0
- data/tests/test_pool.rb +2 -0
- data/tests/test_process_watch.rb +2 -0
- data/tests/test_processes.rb +7 -7
- data/tests/test_queue.rb +14 -0
- data/tests/test_resolver.rb +56 -7
- data/tests/test_set_sock_opt.rb +2 -0
- data/tests/test_smtpclient.rb +20 -0
- data/tests/test_ssl_args.rb +2 -2
- data/tests/test_ssl_dhparam.rb +83 -0
- data/tests/test_ssl_ecdh_curve.rb +79 -0
- data/tests/test_ssl_extensions.rb +49 -0
- data/tests/test_ssl_methods.rb +22 -5
- data/tests/test_ssl_protocols.rb +246 -0
- data/tests/test_ssl_verify.rb +103 -59
- data/tests/test_system.rb +4 -0
- data/tests/test_threaded_resource.rb +8 -0
- data/tests/test_unbind_reason.rb +5 -1
- metadata +173 -107
- data/.gitignore +0 -21
- data/.travis.yml +0 -12
- data/.yardopts +0 -7
- data/Gemfile +0 -2
- data/Rakefile +0 -20
- data/eventmachine.gemspec +0 -36
- data/rakelib/cpp.rake_example +0 -77
data/ext/ssl.cpp
CHANGED
@@ -82,7 +82,7 @@ static char PrivateMaterials[] = {
|
|
82
82
|
builtin_passwd_cb
|
83
83
|
*****************/
|
84
84
|
|
85
|
-
extern "C" int builtin_passwd_cb (char *buf, int bufsize, int rwflag, void *userdata)
|
85
|
+
extern "C" int builtin_passwd_cb (char *buf UNUSED, int bufsize UNUSED, int rwflag UNUSED, void *userdata UNUSED)
|
86
86
|
{
|
87
87
|
strcpy (buf, "kittycat");
|
88
88
|
return 8;
|
@@ -120,7 +120,8 @@ static void InitializeDefaultCredentials()
|
|
120
120
|
SslContext_t::SslContext_t
|
121
121
|
**************************/
|
122
122
|
|
123
|
-
SslContext_t::SslContext_t (bool is_server, const string &privkeyfile, const string &certchainfile):
|
123
|
+
SslContext_t::SslContext_t (bool is_server, const string &privkeyfile, const string &certchainfile, const string &cipherlist, const string &ecdh_curve, const string &dhparam, int ssl_version) :
|
124
|
+
bIsServer (is_server),
|
124
125
|
pCtx (NULL),
|
125
126
|
PrivateKey (NULL),
|
126
127
|
Certificate (NULL)
|
@@ -144,18 +145,47 @@ SslContext_t::SslContext_t (bool is_server, const string &privkeyfile, const str
|
|
144
145
|
InitializeDefaultCredentials();
|
145
146
|
}
|
146
147
|
|
147
|
-
|
148
|
-
pCtx = SSL_CTX_new (is_server ? SSLv23_server_method() : SSLv23_client_method());
|
148
|
+
pCtx = SSL_CTX_new (bIsServer ? SSLv23_server_method() : SSLv23_client_method());
|
149
149
|
if (!pCtx)
|
150
150
|
throw std::runtime_error ("no SSL context");
|
151
151
|
|
152
152
|
SSL_CTX_set_options (pCtx, SSL_OP_ALL);
|
153
|
-
|
154
|
-
#ifdef
|
153
|
+
|
154
|
+
#ifdef SSL_CTRL_CLEAR_OPTIONS
|
155
|
+
SSL_CTX_clear_options (pCtx, SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_NO_TLSv1);
|
156
|
+
# ifdef SSL_OP_NO_TLSv1_1
|
157
|
+
SSL_CTX_clear_options (pCtx, SSL_OP_NO_TLSv1_1);
|
158
|
+
# endif
|
159
|
+
# ifdef SSL_OP_NO_TLSv1_2
|
160
|
+
SSL_CTX_clear_options (pCtx, SSL_OP_NO_TLSv1_2);
|
161
|
+
# endif
|
162
|
+
#endif
|
163
|
+
|
164
|
+
if (!(ssl_version & EM_PROTO_SSLv2))
|
165
|
+
SSL_CTX_set_options (pCtx, SSL_OP_NO_SSLv2);
|
166
|
+
|
167
|
+
if (!(ssl_version & EM_PROTO_SSLv3))
|
168
|
+
SSL_CTX_set_options (pCtx, SSL_OP_NO_SSLv3);
|
169
|
+
|
170
|
+
if (!(ssl_version & EM_PROTO_TLSv1))
|
171
|
+
SSL_CTX_set_options (pCtx, SSL_OP_NO_TLSv1);
|
172
|
+
|
173
|
+
#ifdef SSL_OP_NO_TLSv1_1
|
174
|
+
if (!(ssl_version & EM_PROTO_TLSv1_1))
|
175
|
+
SSL_CTX_set_options (pCtx, SSL_OP_NO_TLSv1_1);
|
176
|
+
#endif
|
177
|
+
|
178
|
+
#ifdef SSL_OP_NO_TLSv1_2
|
179
|
+
if (!(ssl_version & EM_PROTO_TLSv1_2))
|
180
|
+
SSL_CTX_set_options (pCtx, SSL_OP_NO_TLSv1_2);
|
181
|
+
#endif
|
182
|
+
|
183
|
+
#ifdef SSL_MODE_RELEASE_BUFFERS
|
155
184
|
SSL_CTX_set_mode (pCtx, SSL_MODE_RELEASE_BUFFERS);
|
156
|
-
#endif
|
185
|
+
#endif
|
186
|
+
|
187
|
+
if (bIsServer) {
|
157
188
|
|
158
|
-
if (is_server) {
|
159
189
|
// The SSL_CTX calls here do NOT allocate memory.
|
160
190
|
int e;
|
161
191
|
if (privkeyfile.length() > 0)
|
@@ -171,11 +201,69 @@ SslContext_t::SslContext_t (bool is_server, const string &privkeyfile, const str
|
|
171
201
|
e = SSL_CTX_use_certificate (pCtx, DefaultCertificate);
|
172
202
|
if (e <= 0) ERR_print_errors_fp(stderr);
|
173
203
|
assert (e > 0);
|
204
|
+
|
205
|
+
if (dhparam.length() > 0) {
|
206
|
+
DH *dh;
|
207
|
+
BIO *bio;
|
208
|
+
|
209
|
+
bio = BIO_new_file(dhparam.c_str(), "r");
|
210
|
+
if (bio == NULL) {
|
211
|
+
char buf [500];
|
212
|
+
snprintf (buf, sizeof(buf)-1, "dhparam: BIO_new_file(%s) failed", dhparam.c_str());
|
213
|
+
throw std::runtime_error (buf);
|
214
|
+
}
|
215
|
+
|
216
|
+
dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
|
217
|
+
|
218
|
+
if (dh == NULL) {
|
219
|
+
BIO_free(bio);
|
220
|
+
char buf [500];
|
221
|
+
snprintf (buf, sizeof(buf)-1, "dhparam: PEM_read_bio_DHparams(%s) failed", dhparam.c_str());
|
222
|
+
throw new std::runtime_error(buf);
|
223
|
+
}
|
224
|
+
|
225
|
+
SSL_CTX_set_tmp_dh(pCtx, dh);
|
226
|
+
|
227
|
+
DH_free(dh);
|
228
|
+
BIO_free(bio);
|
229
|
+
}
|
230
|
+
|
231
|
+
if (ecdh_curve.length() > 0) {
|
232
|
+
#if OPENSSL_VERSION_NUMBER >= 0x0090800fL && !defined(OPENSSL_NO_ECDH)
|
233
|
+
int nid;
|
234
|
+
EC_KEY *ecdh;
|
235
|
+
|
236
|
+
nid = OBJ_sn2nid((const char *) ecdh_curve.c_str());
|
237
|
+
if (nid == 0) {
|
238
|
+
char buf [200];
|
239
|
+
snprintf (buf, sizeof(buf)-1, "ecdh_curve: Unknown curve name: %s", ecdh_curve.c_str());
|
240
|
+
throw std::runtime_error (buf);
|
241
|
+
}
|
242
|
+
|
243
|
+
ecdh = EC_KEY_new_by_curve_name(nid);
|
244
|
+
if (ecdh == NULL) {
|
245
|
+
char buf [200];
|
246
|
+
snprintf (buf, sizeof(buf)-1, "ecdh_curve: Unable to create: %s", ecdh_curve.c_str());
|
247
|
+
throw std::runtime_error (buf);
|
248
|
+
}
|
249
|
+
|
250
|
+
SSL_CTX_set_options(pCtx, SSL_OP_SINGLE_ECDH_USE);
|
251
|
+
|
252
|
+
SSL_CTX_set_tmp_ecdh(pCtx, ecdh);
|
253
|
+
|
254
|
+
EC_KEY_free(ecdh);
|
255
|
+
#else
|
256
|
+
throw std::runtime_error ("No openssl ECDH support");
|
257
|
+
#endif
|
258
|
+
}
|
174
259
|
}
|
175
260
|
|
176
|
-
|
261
|
+
if (cipherlist.length() > 0)
|
262
|
+
SSL_CTX_set_cipher_list (pCtx, cipherlist.c_str());
|
263
|
+
else
|
264
|
+
SSL_CTX_set_cipher_list (pCtx, "ALL:!ADH:!LOW:!EXP:!DES-CBC3-SHA:@STRENGTH");
|
177
265
|
|
178
|
-
if (
|
266
|
+
if (bIsServer) {
|
179
267
|
SSL_CTX_sess_set_cache_size (pCtx, 128);
|
180
268
|
SSL_CTX_set_session_id_context (pCtx, (unsigned char*)"eventmachine", 12);
|
181
269
|
}
|
@@ -216,10 +304,11 @@ SslContext_t::~SslContext_t()
|
|
216
304
|
SslBox_t::SslBox_t
|
217
305
|
******************/
|
218
306
|
|
219
|
-
SslBox_t::SslBox_t (bool is_server, const string &privkeyfile, const string &certchainfile, bool verify_peer, const
|
307
|
+
SslBox_t::SslBox_t (bool is_server, const string &privkeyfile, const string &certchainfile, bool verify_peer, bool fail_if_no_peer_cert, const string &snihostname, const string &cipherlist, const string &ecdh_curve, const string &dhparam, int ssl_version, const uintptr_t binding):
|
220
308
|
bIsServer (is_server),
|
221
309
|
bHandshakeCompleted (false),
|
222
310
|
bVerifyPeer (verify_peer),
|
311
|
+
bFailIfNoPeerCert (fail_if_no_peer_cert),
|
223
312
|
pSSL (NULL),
|
224
313
|
pbioRead (NULL),
|
225
314
|
pbioWrite (NULL)
|
@@ -228,7 +317,7 @@ SslBox_t::SslBox_t (bool is_server, const string &privkeyfile, const string &cer
|
|
228
317
|
* a new one every time we come here.
|
229
318
|
*/
|
230
319
|
|
231
|
-
Context = new SslContext_t (bIsServer, privkeyfile, certchainfile);
|
320
|
+
Context = new SslContext_t (bIsServer, privkeyfile, certchainfile, cipherlist, ecdh_curve, dhparam, ssl_version);
|
232
321
|
assert (Context);
|
233
322
|
|
234
323
|
pbioRead = BIO_new (BIO_s_mem());
|
@@ -239,13 +328,22 @@ SslBox_t::SslBox_t (bool is_server, const string &privkeyfile, const string &cer
|
|
239
328
|
|
240
329
|
pSSL = SSL_new (Context->pCtx);
|
241
330
|
assert (pSSL);
|
331
|
+
|
332
|
+
if (snihostname.length() > 0) {
|
333
|
+
SSL_set_tlsext_host_name (pSSL, snihostname.c_str());
|
334
|
+
}
|
335
|
+
|
242
336
|
SSL_set_bio (pSSL, pbioRead, pbioWrite);
|
243
337
|
|
244
338
|
// Store a pointer to the binding signature in the SSL object so we can retrieve it later
|
245
339
|
SSL_set_ex_data(pSSL, 0, (void*) binding);
|
246
340
|
|
247
|
-
if (bVerifyPeer)
|
248
|
-
|
341
|
+
if (bVerifyPeer) {
|
342
|
+
int mode = SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE;
|
343
|
+
if (bFailIfNoPeerCert)
|
344
|
+
mode = mode | SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
|
345
|
+
SSL_set_verify(pSSL, mode, ssl_verify_wrapper);
|
346
|
+
}
|
249
347
|
|
250
348
|
if (!bIsServer)
|
251
349
|
SSL_connect (pSSL);
|
@@ -296,7 +394,7 @@ int SslBox_t::GetPlaintext (char *buf, int bufsize)
|
|
296
394
|
{
|
297
395
|
if (!SSL_is_init_finished (pSSL)) {
|
298
396
|
int e = bIsServer ? SSL_accept (pSSL) : SSL_connect (pSSL);
|
299
|
-
if (e
|
397
|
+
if (e != 1) {
|
300
398
|
int er = SSL_get_error (pSSL, e);
|
301
399
|
if (er != SSL_ERROR_WANT_READ) {
|
302
400
|
// Return -1 for a nonfatal error, -2 for an error that should force the connection down.
|
@@ -312,7 +410,7 @@ int SslBox_t::GetPlaintext (char *buf, int bufsize)
|
|
312
410
|
if (!SSL_is_init_finished (pSSL)) {
|
313
411
|
// We can get here if a browser abandons a handshake.
|
314
412
|
// The user can see a warning dialog and abort the connection.
|
315
|
-
cerr << "<SSL_incomp>";
|
413
|
+
//cerr << "<SSL_incomp>";
|
316
414
|
return 0;
|
317
415
|
}
|
318
416
|
|
@@ -392,13 +490,16 @@ int SslBox_t::PutPlaintext (const char *buf, int bufsize)
|
|
392
490
|
|
393
491
|
bool fatal = false;
|
394
492
|
bool did_work = false;
|
493
|
+
int pending = BIO_pending(pbioWrite);
|
395
494
|
|
396
|
-
while (OutboundQ.HasPages()) {
|
495
|
+
while (OutboundQ.HasPages() && pending < SSLBOX_WRITE_BUFFER_SIZE) {
|
397
496
|
const char *page;
|
398
497
|
int length;
|
399
498
|
OutboundQ.Front (&page, &length);
|
400
499
|
assert (page && (length > 0));
|
401
500
|
int n = SSL_write (pSSL, page, length);
|
501
|
+
pending = BIO_pending(pbioWrite);
|
502
|
+
|
402
503
|
if (n > 0) {
|
403
504
|
did_work = true;
|
404
505
|
OutboundQ.PopFront();
|
@@ -434,14 +535,60 @@ X509 *SslBox_t::GetPeerCert()
|
|
434
535
|
return cert;
|
435
536
|
}
|
436
537
|
|
538
|
+
/**********************
|
539
|
+
SslBox_t::GetCipherBits
|
540
|
+
**********************/
|
541
|
+
|
542
|
+
int SslBox_t::GetCipherBits()
|
543
|
+
{
|
544
|
+
int bits = -1;
|
545
|
+
if (pSSL)
|
546
|
+
SSL_get_cipher_bits(pSSL, &bits);
|
547
|
+
return bits;
|
548
|
+
}
|
549
|
+
|
550
|
+
/**********************
|
551
|
+
SslBox_t::GetCipherName
|
552
|
+
**********************/
|
553
|
+
|
554
|
+
const char *SslBox_t::GetCipherName()
|
555
|
+
{
|
556
|
+
if (pSSL)
|
557
|
+
return SSL_get_cipher_name(pSSL);
|
558
|
+
return NULL;
|
559
|
+
}
|
560
|
+
|
561
|
+
/**********************
|
562
|
+
SslBox_t::GetCipherProtocol
|
563
|
+
**********************/
|
564
|
+
|
565
|
+
const char *SslBox_t::GetCipherProtocol()
|
566
|
+
{
|
567
|
+
if (pSSL)
|
568
|
+
return SSL_get_cipher_version(pSSL);
|
569
|
+
return NULL;
|
570
|
+
}
|
571
|
+
|
572
|
+
/**********************
|
573
|
+
SslBox_t::GetSNIHostname
|
574
|
+
**********************/
|
575
|
+
|
576
|
+
const char *SslBox_t::GetSNIHostname()
|
577
|
+
{
|
578
|
+
#ifdef TLSEXT_NAMETYPE_host_name
|
579
|
+
if (pSSL)
|
580
|
+
return SSL_get_servername (pSSL, TLSEXT_NAMETYPE_host_name);
|
581
|
+
#endif
|
582
|
+
return NULL;
|
583
|
+
}
|
437
584
|
|
438
585
|
/******************
|
439
586
|
ssl_verify_wrapper
|
440
587
|
*******************/
|
441
588
|
|
442
|
-
extern "C" int ssl_verify_wrapper(int preverify_ok, X509_STORE_CTX *ctx)
|
589
|
+
extern "C" int ssl_verify_wrapper(int preverify_ok UNUSED, X509_STORE_CTX *ctx)
|
443
590
|
{
|
444
|
-
|
591
|
+
uintptr_t binding;
|
445
592
|
X509 *cert;
|
446
593
|
SSL *ssl;
|
447
594
|
BUF_MEM *buf;
|
@@ -450,7 +597,7 @@ extern "C" int ssl_verify_wrapper(int preverify_ok, X509_STORE_CTX *ctx)
|
|
450
597
|
|
451
598
|
cert = X509_STORE_CTX_get_current_cert(ctx);
|
452
599
|
ssl = (SSL*) X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
|
453
|
-
binding = (
|
600
|
+
binding = (uintptr_t) SSL_get_ex_data(ssl, 0);
|
454
601
|
|
455
602
|
out = BIO_new(BIO_s_mem());
|
456
603
|
PEM_write_bio_X509(out, cert);
|
data/ext/ssl.h
CHANGED
@@ -33,7 +33,7 @@ class SslContext_t
|
|
33
33
|
class SslContext_t
|
34
34
|
{
|
35
35
|
public:
|
36
|
-
SslContext_t (bool is_server, const string &privkeyfile, const string &certchainfile);
|
36
|
+
SslContext_t (bool is_server, const string &privkeyfile, const string &certchainfile, const string &cipherlist, const string &ecdh_curve, const string &dhparam, int ssl_version);
|
37
37
|
virtual ~SslContext_t();
|
38
38
|
|
39
39
|
private:
|
@@ -54,10 +54,14 @@ class SslContext_t
|
|
54
54
|
class SslBox_t
|
55
55
|
**************/
|
56
56
|
|
57
|
+
#define SSLBOX_INPUT_CHUNKSIZE 2019
|
58
|
+
#define SSLBOX_OUTPUT_CHUNKSIZE 2048
|
59
|
+
#define SSLBOX_WRITE_BUFFER_SIZE 8192 // (SSLBOX_OUTPUT_CHUNKSIZE * 4)
|
60
|
+
|
57
61
|
class SslBox_t
|
58
62
|
{
|
59
63
|
public:
|
60
|
-
SslBox_t (bool is_server, const string &privkeyfile, const string &certchainfile, bool verify_peer, const
|
64
|
+
SslBox_t (bool is_server, const string &privkeyfile, const string &certchainfile, bool verify_peer, bool fail_if_no_peer_cert, const string &snihostname, const string &cipherlist, const string &ecdh_curve, const string &dhparam, int ssl_version, const uintptr_t binding);
|
61
65
|
virtual ~SslBox_t();
|
62
66
|
|
63
67
|
int PutPlaintext (const char*, int);
|
@@ -69,6 +73,10 @@ class SslBox_t
|
|
69
73
|
bool IsHandshakeCompleted() {return bHandshakeCompleted;}
|
70
74
|
|
71
75
|
X509 *GetPeerCert();
|
76
|
+
int GetCipherBits();
|
77
|
+
const char *GetCipherName();
|
78
|
+
const char *GetCipherProtocol();
|
79
|
+
const char *GetSNIHostname();
|
72
80
|
|
73
81
|
void Shutdown();
|
74
82
|
|
@@ -78,6 +86,7 @@ class SslBox_t
|
|
78
86
|
bool bIsServer;
|
79
87
|
bool bHandshakeCompleted;
|
80
88
|
bool bVerifyPeer;
|
89
|
+
bool bFailIfNoPeerCert;
|
81
90
|
SSL *pSSL;
|
82
91
|
BIO *pbioRead;
|
83
92
|
BIO *pbioWrite;
|
@@ -569,6 +569,22 @@ public class EmReactor {
|
|
569
569
|
return Connections.get(sig).isNotifyWritable();
|
570
570
|
}
|
571
571
|
|
572
|
+
public boolean pauseConnection (long sig) {
|
573
|
+
return ((EventableSocketChannel) Connections.get(sig)).pause();
|
574
|
+
}
|
575
|
+
|
576
|
+
public boolean resumeConnection (long sig) {
|
577
|
+
return ((EventableSocketChannel) Connections.get(sig)).resume();
|
578
|
+
}
|
579
|
+
|
580
|
+
public boolean isConnectionPaused (long sig) {
|
581
|
+
return ((EventableSocketChannel) Connections.get(sig)).isPaused();
|
582
|
+
}
|
583
|
+
|
584
|
+
public long getOutboundDataSize (long sig) {
|
585
|
+
return Connections.get(sig).getOutboundDataSize();
|
586
|
+
}
|
587
|
+
|
572
588
|
public int getConnectionCount() {
|
573
589
|
return Connections.size() + Acceptors.size();
|
574
590
|
}
|
@@ -54,6 +54,7 @@ public class EventableDatagramChannel implements EventableChannel {
|
|
54
54
|
Selector selector;
|
55
55
|
boolean bCloseScheduled;
|
56
56
|
LinkedList<Packet> outboundQ;
|
57
|
+
long outboundS;
|
57
58
|
SocketAddress returnAddress;
|
58
59
|
|
59
60
|
|
@@ -63,6 +64,7 @@ public class EventableDatagramChannel implements EventableChannel {
|
|
63
64
|
selector = sel;
|
64
65
|
bCloseScheduled = false;
|
65
66
|
outboundQ = new LinkedList<Packet>();
|
67
|
+
outboundS = 0;
|
66
68
|
|
67
69
|
dc.register(selector, SelectionKey.OP_READ, this);
|
68
70
|
}
|
@@ -71,6 +73,7 @@ public class EventableDatagramChannel implements EventableChannel {
|
|
71
73
|
try {
|
72
74
|
if ((!bCloseScheduled) && (bb.remaining() > 0)) {
|
73
75
|
outboundQ.addLast(new Packet(bb, returnAddress));
|
76
|
+
outboundS += bb.remaining();
|
74
77
|
channel.register(selector, SelectionKey.OP_WRITE | SelectionKey.OP_READ, this);
|
75
78
|
}
|
76
79
|
} catch (ClosedChannelException e) {
|
@@ -82,6 +85,7 @@ public class EventableDatagramChannel implements EventableChannel {
|
|
82
85
|
try {
|
83
86
|
if ((!bCloseScheduled) && (bb.remaining() > 0)) {
|
84
87
|
outboundQ.addLast(new Packet (bb, new InetSocketAddress (recipAddress, recipPort)));
|
88
|
+
outboundS += bb.remaining();
|
85
89
|
channel.register(selector, SelectionKey.OP_WRITE | SelectionKey.OP_READ, this);
|
86
90
|
}
|
87
91
|
} catch (ClosedChannelException e) {
|
@@ -136,6 +140,7 @@ public class EventableDatagramChannel implements EventableChannel {
|
|
136
140
|
try {
|
137
141
|
// With a datagram socket, it's ok to send an empty buffer.
|
138
142
|
written = channel.send(p.bb, p.recipient);
|
143
|
+
outboundS -= written;
|
139
144
|
}
|
140
145
|
catch (IOException e) {
|
141
146
|
return false;
|
@@ -192,4 +197,5 @@ public class EventableDatagramChannel implements EventableChannel {
|
|
192
197
|
public boolean isWatchOnly() { return false; }
|
193
198
|
public boolean isNotifyReadable() { return false; }
|
194
199
|
public boolean isNotifyWritable() { return false; }
|
200
|
+
public long getOutboundDataSize() { return outboundS; }
|
195
201
|
}
|
@@ -54,6 +54,7 @@ public class EventableSocketChannel implements EventableChannel {
|
|
54
54
|
|
55
55
|
long binding;
|
56
56
|
LinkedList<ByteBuffer> outboundQ;
|
57
|
+
long outboundS;
|
57
58
|
|
58
59
|
boolean bCloseScheduled;
|
59
60
|
boolean bConnectPending;
|
@@ -61,6 +62,7 @@ public class EventableSocketChannel implements EventableChannel {
|
|
61
62
|
boolean bAttached;
|
62
63
|
boolean bNotifyReadable;
|
63
64
|
boolean bNotifyWritable;
|
65
|
+
boolean bPaused;
|
64
66
|
|
65
67
|
SSLEngine sslEngine;
|
66
68
|
SSLContext sslContext;
|
@@ -76,6 +78,7 @@ public class EventableSocketChannel implements EventableChannel {
|
|
76
78
|
bNotifyReadable = false;
|
77
79
|
bNotifyWritable = false;
|
78
80
|
outboundQ = new LinkedList<ByteBuffer>();
|
81
|
+
outboundS = 0;
|
79
82
|
}
|
80
83
|
|
81
84
|
public long getBinding() {
|
@@ -164,12 +167,14 @@ public class EventableSocketChannel implements EventableChannel {
|
|
164
167
|
sslEngine.wrap(bb, b);
|
165
168
|
b.flip();
|
166
169
|
outboundQ.addLast(b);
|
170
|
+
outboundS += b.remaining();
|
167
171
|
} catch (SSLException e) {
|
168
172
|
throw new RuntimeException ("ssl error");
|
169
173
|
}
|
170
174
|
}
|
171
175
|
else {
|
172
176
|
outboundQ.addLast(bb);
|
177
|
+
outboundS += bb.remaining();
|
173
178
|
}
|
174
179
|
|
175
180
|
updateEvents();
|
@@ -188,6 +193,8 @@ public class EventableSocketChannel implements EventableChannel {
|
|
188
193
|
throw new IOException ("eof");
|
189
194
|
}
|
190
195
|
|
196
|
+
public long getOutboundDataSize() { return outboundS; }
|
197
|
+
|
191
198
|
/**
|
192
199
|
* Called by the reactor when we have selected writable.
|
193
200
|
* Return false to indicate an error that should cause the connection to close.
|
@@ -196,23 +203,35 @@ public class EventableSocketChannel implements EventableChannel {
|
|
196
203
|
* this code is written, we're depending on a nonblocking write NOT TO CONSUME
|
197
204
|
* the whole outbound buffer in this case, rather than firing an exception.
|
198
205
|
* We should somehow verify that this is indeed Java's defined behavior.
|
199
|
-
* Also TODO, see if we can use gather I/O rather than one write at a time.
|
200
|
-
* Ought to be a big performance enhancer.
|
201
206
|
* @return
|
202
207
|
*/
|
203
208
|
public boolean writeOutboundData() throws IOException {
|
209
|
+
ByteBuffer[] bufs = new ByteBuffer[64];
|
210
|
+
int i;
|
211
|
+
long written, toWrite;
|
204
212
|
while (!outboundQ.isEmpty()) {
|
205
|
-
|
206
|
-
|
207
|
-
|
213
|
+
i = 0;
|
214
|
+
toWrite = 0;
|
215
|
+
written = 0;
|
216
|
+
while (i < 64 && !outboundQ.isEmpty()) {
|
217
|
+
bufs[i] = outboundQ.removeFirst();
|
218
|
+
toWrite += bufs[i].remaining();
|
219
|
+
i++;
|
220
|
+
}
|
221
|
+
if (toWrite > 0)
|
222
|
+
written = channel.write(bufs, 0, i);
|
208
223
|
|
224
|
+
outboundS -= written;
|
209
225
|
// Did we consume the whole outbound buffer? If yes,
|
210
226
|
// pop it off and keep looping. If no, the outbound network
|
211
227
|
// buffers are full, so break out of here.
|
212
|
-
if (
|
213
|
-
|
214
|
-
|
228
|
+
if (written < toWrite) {
|
229
|
+
while (i > 0 && bufs[i-1].remaining() > 0) {
|
230
|
+
outboundQ.addFirst(bufs[i-1]);
|
231
|
+
i--;
|
232
|
+
}
|
215
233
|
break;
|
234
|
+
}
|
216
235
|
}
|
217
236
|
|
218
237
|
if (outboundQ.isEmpty() && !bCloseScheduled) {
|
@@ -244,8 +263,10 @@ public class EventableSocketChannel implements EventableChannel {
|
|
244
263
|
|
245
264
|
public boolean scheduleClose (boolean afterWriting) {
|
246
265
|
// TODO: What the hell happens here if bConnectPending is set?
|
247
|
-
if (!afterWriting)
|
266
|
+
if (!afterWriting) {
|
248
267
|
outboundQ.clear();
|
268
|
+
outboundS = 0;
|
269
|
+
}
|
249
270
|
|
250
271
|
if (outboundQ.isEmpty())
|
251
272
|
return true;
|
@@ -331,6 +352,30 @@ public class EventableSocketChannel implements EventableChannel {
|
|
331
352
|
}
|
332
353
|
public boolean isNotifyWritable() { return bNotifyWritable; }
|
333
354
|
|
355
|
+
public boolean pause() {
|
356
|
+
if (bWatchOnly) {
|
357
|
+
throw new RuntimeException ("cannot pause/resume 'watch only' connections, set notify readable/writable instead");
|
358
|
+
}
|
359
|
+
boolean old = bPaused;
|
360
|
+
bPaused = true;
|
361
|
+
updateEvents();
|
362
|
+
return !old;
|
363
|
+
}
|
364
|
+
|
365
|
+
public boolean resume() {
|
366
|
+
if (bWatchOnly) {
|
367
|
+
throw new RuntimeException ("cannot pause/resume 'watch only' connections, set notify readable/writable instead");
|
368
|
+
}
|
369
|
+
boolean old = bPaused;
|
370
|
+
bPaused = false;
|
371
|
+
updateEvents();
|
372
|
+
return old;
|
373
|
+
}
|
374
|
+
|
375
|
+
public boolean isPaused() {
|
376
|
+
return bPaused;
|
377
|
+
}
|
378
|
+
|
334
379
|
private void updateEvents() {
|
335
380
|
if (channelKey == null)
|
336
381
|
return;
|
@@ -353,7 +398,7 @@ public class EventableSocketChannel implements EventableChannel {
|
|
353
398
|
if (bNotifyWritable)
|
354
399
|
events |= SelectionKey.OP_WRITE;
|
355
400
|
}
|
356
|
-
else
|
401
|
+
else if (!bPaused)
|
357
402
|
{
|
358
403
|
if (bConnectPending)
|
359
404
|
events |= SelectionKey.OP_CONNECT;
|