git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@902 e7ae566f-a301-0410-adde-c780ea21d3b5
| ... | ... |
@@ -133,7 +133,7 @@ |
| 133 | 133 |
#define D_ALIGN_DEBUG LOGLEV(7, 70, M_DEBUG) /* show verbose struct alignment info */ |
| 134 | 134 |
#define D_PACKET_TRUNC_DEBUG LOGLEV(7, 70, M_DEBUG) /* PACKET_TRUNCATION_CHECK verbose */ |
| 135 | 135 |
#define D_PING LOGLEV(7, 70, M_DEBUG) /* PING send/receive messages */ |
| 136 |
-#define D_PS_PROXY_DEBUG LOGLEV(7, 70, M_DEBUG) /* port share proxy debug */ |
|
| 136 |
+#define D_PS_PROXY_DEBUG LOGLEV(4, 70, M_DEBUG) /* JYFIXME port share proxy debug */ |
|
| 137 | 137 |
|
| 138 | 138 |
#define D_HANDSHAKE_VERBOSE LOGLEV(8, 70, M_DEBUG) /* show detailed description of each handshake */ |
| 139 | 139 |
#define D_TLS_DEBUG_MED LOGLEV(8, 70, M_DEBUG) /* limited info from tls_session routines */ |
| ... | ... |
@@ -238,6 +238,19 @@ pc_list_len (struct proxy_connection *pc) |
| 238 | 238 |
return count; |
| 239 | 239 |
} |
| 240 | 240 |
|
| 241 |
+static void |
|
| 242 |
+proxy_entry_close_sd (struct proxy_connection *pc, struct event_set *es) |
|
| 243 |
+{
|
|
| 244 |
+ if (pc->defined && socket_defined (pc->sd)) |
|
| 245 |
+ {
|
|
| 246 |
+ dmsg (D_PS_PROXY_DEBUG, "PORT SHARE PROXY: delete sd=%d", pc->sd); |
|
| 247 |
+ if (es) |
|
| 248 |
+ event_del (es, pc->sd); |
|
| 249 |
+ openvpn_close_socket (pc->sd); |
|
| 250 |
+ pc->sd = SOCKET_UNDEFINED; |
|
| 251 |
+ } |
|
| 252 |
+} |
|
| 253 |
+ |
|
| 241 | 254 |
/* |
| 242 | 255 |
* Mark a proxy entry and its counterpart for close. |
| 243 | 256 |
*/ |
| ... | ... |
@@ -247,18 +260,10 @@ proxy_entry_mark_for_close (struct proxy_connection *pc, struct event_set *es) |
| 247 | 247 |
if (pc->defined) |
| 248 | 248 |
{
|
| 249 | 249 |
struct proxy_connection *cp = pc->counterpart; |
| 250 |
- dmsg (D_PS_PROXY_DEBUG, "PORT SHARE PROXY: delete sd=%d", pc->sd); |
|
| 251 |
- if (socket_defined (pc->sd)) |
|
| 252 |
- {
|
|
| 253 |
- if (es) |
|
| 254 |
- event_del (es, pc->sd); |
|
| 255 |
- openvpn_close_socket (pc->sd); |
|
| 256 |
- pc->sd = SOCKET_UNDEFINED; |
|
| 257 |
- } |
|
| 250 |
+ proxy_entry_close_sd (pc, es); |
|
| 258 | 251 |
free_buf (&pc->buf); |
| 259 | 252 |
pc->buffer_initial = false; |
| 260 | 253 |
pc->rwflags = 0; |
| 261 |
- pc->counterpart = NULL; |
|
| 262 | 254 |
pc->defined = false; |
| 263 | 255 |
if (cp && cp->defined && cp->counterpart == pc) |
| 264 | 256 |
proxy_entry_mark_for_close (cp, es); |
| ... | ... |
@@ -327,7 +332,7 @@ sock_addr_set (struct openvpn_sockaddr *osaddr, |
| 327 | 327 |
static inline void |
| 328 | 328 |
proxy_connection_io_requeue (struct proxy_connection *pc, const int rwflags_new, struct event_set *es) |
| 329 | 329 |
{
|
| 330 |
- if (pc->rwflags != rwflags_new) |
|
| 330 |
+ if (socket_defined (pc->sd) && pc->rwflags != rwflags_new) |
|
| 331 | 331 |
{
|
| 332 | 332 |
event_ctl (es, pc->sd, rwflags_new, (void*)pc); |
| 333 | 333 |
pc->rwflags = rwflags_new; |
| ... | ... |
@@ -489,67 +494,120 @@ control_message_from_parent (const socket_descriptor_t sd_control, |
| 489 | 489 |
return ret; |
| 490 | 490 |
} |
| 491 | 491 |
|
| 492 |
-/* proxy_connection_io_xfer return values */ |
|
| 492 |
+/* |
|
| 493 |
+ * Return values for proxy_connection_io functions |
|
| 494 |
+ */ |
|
| 495 |
+ |
|
| 496 |
+#define IOSTAT_UNDEF 0 |
|
| 497 |
+#define IOSTAT_EAGAIN_ON_READ 1 /* recv returned EAGAIN */ |
|
| 498 |
+#define IOSTAT_EAGAIN_ON_WRITE 2 /* send returned EAGAIN */ |
|
| 499 |
+#define IOSTAT_READ_ERROR 3 /* the other end of our read socket (pc) was closed */ |
|
| 500 |
+#define IOSTAT_WRITE_ERROR 4 /* the other end of our write socket (pc->counterpart) was closed */ |
|
| 501 |
+#define IOSTAT_BOTH_CLOSED 5 /* both sockets are closed, preventing action */ |
|
| 502 |
+#define IOSTAT_HALF_CLOSED_1 6 /* one socket is closed, preventing action */ |
|
| 503 |
+#define IOSTAT_HALF_CLOSED_2 7 /* one socket is closed, preventing action */ |
|
| 504 |
+#define IOSTAT_GOOD 8 /* nothing to report */ |
|
| 505 |
+#define IOSTAT_ASYMFLUSH 9 /* pc socket is closed, flushed send data to pc->counterpart socket */ |
|
| 506 |
+ |
|
| 507 |
+static int |
|
| 508 |
+proxy_connection_io_recv (struct proxy_connection *pc) |
|
| 509 |
+{
|
|
| 510 |
+ /* recv data from socket */ |
|
| 511 |
+ ssize_t status = recv (pc->sd, BPTR(&pc->buf), BCAP(&pc->buf), MSG_NOSIGNAL); |
|
| 512 |
+ if (status == -1) |
|
| 513 |
+ {
|
|
| 514 |
+ return (errno == EAGAIN) ? IOSTAT_EAGAIN_ON_READ : IOSTAT_READ_ERROR; |
|
| 515 |
+ } |
|
| 516 |
+ else |
|
| 517 |
+ {
|
|
| 518 |
+ if (!status) |
|
| 519 |
+ return IOSTAT_READ_ERROR; |
|
| 520 |
+ pc->buf.len = status; |
|
| 521 |
+ } |
|
| 522 |
+ return IOSTAT_GOOD; |
|
| 523 |
+} |
|
| 524 |
+ |
|
| 525 |
+static int |
|
| 526 |
+proxy_connection_io_send (struct proxy_connection *pc) |
|
| 527 |
+{
|
|
| 528 |
+ if ((get_random() % 4096) == 0) // JYFIXME |
|
| 529 |
+ {
|
|
| 530 |
+ /* send data to counterpart socket */ |
|
| 531 |
+ ssize_t status = send (pc->counterpart->sd, BPTR(&pc->buf), BLEN(&pc->buf), MSG_NOSIGNAL); |
|
| 532 |
+ if (status == -1) |
|
| 533 |
+ {
|
|
| 534 |
+ const int e = errno; |
|
| 535 |
+ return (e == EAGAIN) ? IOSTAT_EAGAIN_ON_WRITE : IOSTAT_WRITE_ERROR; |
|
| 536 |
+ } |
|
| 537 |
+ else |
|
| 538 |
+ {
|
|
| 539 |
+ if (status != pc->buf.len) |
|
| 540 |
+ return IOSTAT_WRITE_ERROR; |
|
| 541 |
+ pc->buf.len = 0; |
|
| 542 |
+ } |
|
| 493 | 543 |
|
| 494 |
-#define IOSTAT_EAGAIN_ON_READ 0 |
|
| 495 |
-#define IOSTAT_EAGAIN_ON_WRITE 1 |
|
| 496 |
-#define IOSTAT_ERROR 2 |
|
| 544 |
+ /* realloc send buffer after initial send */ |
|
| 545 |
+ if (pc->buffer_initial) |
|
| 546 |
+ {
|
|
| 547 |
+ free_buf (&pc->buf); |
|
| 548 |
+ pc->buf = alloc_buf (PROXY_CONNECTION_BUFFER_SIZE); |
|
| 549 |
+ pc->buffer_initial = false; |
|
| 550 |
+ } |
|
| 551 |
+ return IOSTAT_GOOD; |
|
| 552 |
+ } |
|
| 553 |
+ return IOSTAT_EAGAIN_ON_WRITE; |
|
| 554 |
+} |
|
| 497 | 555 |
|
| 498 | 556 |
/* |
| 499 | 557 |
* Forward data from pc to pc->counterpart. |
| 500 |
- * Return values: |
|
| 501 |
- * |
|
| 502 |
- * IOSTAT_EAGAIN_ON_READ -- recv returned EAGAIN |
|
| 503 |
- * IOSTAT_EAGAIN_ON_WRITE -- send return EAGAIN |
|
| 504 |
- * IOSTAT_ERROR -- the other end of one of our sockets was closed |
|
| 505 | 558 |
*/ |
| 559 |
+ |
|
| 506 | 560 |
static int |
| 507 | 561 |
proxy_connection_io_xfer (struct proxy_connection *pc) |
| 508 | 562 |
{
|
| 509 |
- while (true) |
|
| 563 |
+ const bool sd_defined = (pc->defined && socket_defined (pc->sd)); |
|
| 564 |
+ const bool sd_counterpart_defined = (pc->counterpart->defined && socket_defined (pc->counterpart->sd)); |
|
| 565 |
+ |
|
| 566 |
+ if (sd_defined && sd_counterpart_defined) |
|
| 510 | 567 |
{
|
| 511 |
- if (!BLEN (&pc->buf)) |
|
| 568 |
+ while (true) |
|
| 512 | 569 |
{
|
| 513 |
- /* recv data from socket */ |
|
| 514 |
- ssize_t status = recv (pc->sd, BPTR(&pc->buf), BCAP(&pc->buf), MSG_NOSIGNAL); |
|
| 515 |
- if (status == -1) |
|
| 570 |
+ if (!BLEN (&pc->buf)) |
|
| 516 | 571 |
{
|
| 517 |
- return (errno == EAGAIN) ? IOSTAT_EAGAIN_ON_READ : IOSTAT_ERROR; |
|
| 572 |
+ const int status = proxy_connection_io_recv (pc); |
|
| 573 |
+ if (status != IOSTAT_GOOD) |
|
| 574 |
+ return status; |
|
| 518 | 575 |
} |
| 519 |
- else |
|
| 576 |
+ |
|
| 577 |
+ if (BLEN (&pc->buf)) |
|
| 520 | 578 |
{
|
| 521 |
- if (!status) |
|
| 522 |
- return IOSTAT_ERROR; |
|
| 523 |
- pc->buf.len = status; |
|
| 579 |
+ const int status = proxy_connection_io_send (pc); |
|
| 580 |
+ if (status != IOSTAT_GOOD) |
|
| 581 |
+ return status; |
|
| 524 | 582 |
} |
| 525 | 583 |
} |
| 526 |
- |
|
| 584 |
+ } |
|
| 585 |
+ else if (!sd_defined && sd_counterpart_defined) |
|
| 586 |
+ {
|
|
| 527 | 587 |
if (BLEN (&pc->buf)) |
| 528 | 588 |
{
|
| 529 |
- /* send data to counterpart socket */ |
|
| 530 |
- ssize_t status = send (pc->counterpart->sd, BPTR(&pc->buf), BLEN(&pc->buf), MSG_NOSIGNAL); |
|
| 531 |
- if (status == -1) |
|
| 532 |
- {
|
|
| 533 |
- const int e = errno; |
|
| 534 |
- return (e == EAGAIN) ? IOSTAT_EAGAIN_ON_WRITE : IOSTAT_ERROR; |
|
| 535 |
- } |
|
| 536 |
- else |
|
| 537 |
- {
|
|
| 538 |
- if (status != pc->buf.len) |
|
| 539 |
- return IOSTAT_ERROR; |
|
| 540 |
- pc->buf.len = 0; |
|
| 541 |
- } |
|
| 542 |
- |
|
| 543 |
- /* successful send */ |
|
| 544 |
- if (pc->buffer_initial) |
|
| 545 |
- {
|
|
| 546 |
- free_buf (&pc->buf); |
|
| 547 |
- pc->buf = alloc_buf (PROXY_CONNECTION_BUFFER_SIZE); |
|
| 548 |
- pc->buffer_initial = false; |
|
| 549 |
- } |
|
| 589 |
+ /* |
|
| 590 |
+ * One side of the connection has been closed, but the other side is open |
|
| 591 |
+ * and still has pending output which must be sent before closure. |
|
| 592 |
+ */ |
|
| 593 |
+ const int status = proxy_connection_io_send (pc); |
|
| 594 |
+ dmsg (D_PS_PROXY_DEBUG, "PORT SHARE PROXY: asymmetric flush on sd=%d status=%d", |
|
| 595 |
+ pc->counterpart->sd, status); |
|
| 596 |
+ return (status == IOSTAT_EAGAIN_ON_WRITE) ? IOSTAT_EAGAIN_ON_WRITE : IOSTAT_ASYMFLUSH; |
|
| 550 | 597 |
} |
| 598 |
+ else |
|
| 599 |
+ return IOSTAT_HALF_CLOSED_1; |
|
| 600 |
+ } |
|
| 601 |
+ else if (sd_defined && !sd_counterpart_defined) |
|
| 602 |
+ {
|
|
| 603 |
+ return IOSTAT_HALF_CLOSED_2; |
|
| 551 | 604 |
} |
| 552 |
- return IOSTAT_ERROR; |
|
| 605 |
+ return IOSTAT_BOTH_CLOSED; |
|
| 553 | 606 |
} |
| 554 | 607 |
|
| 555 | 608 |
/* |
| ... | ... |
@@ -560,16 +618,45 @@ proxy_connection_io_status (const int status, int *rwflags_pc, int *rwflags_cp) |
| 560 | 560 |
{
|
| 561 | 561 |
switch (status) |
| 562 | 562 |
{
|
| 563 |
- case IOSTAT_EAGAIN_ON_READ: |
|
| 564 |
- *rwflags_pc |= EVENT_READ; |
|
| 565 |
- *rwflags_cp &= ~EVENT_WRITE; |
|
| 566 |
- return true; |
|
| 567 |
- case IOSTAT_EAGAIN_ON_WRITE: |
|
| 568 |
- *rwflags_pc &= ~EVENT_READ; |
|
| 569 |
- *rwflags_cp |= EVENT_WRITE; |
|
| 570 |
- return true; |
|
| 571 |
- default: |
|
| 572 |
- return false; |
|
| 563 |
+ case IOSTAT_EAGAIN_ON_READ: |
|
| 564 |
+ *rwflags_pc |= EVENT_READ; |
|
| 565 |
+ *rwflags_cp &= ~EVENT_WRITE; |
|
| 566 |
+ return true; |
|
| 567 |
+ case IOSTAT_EAGAIN_ON_WRITE: |
|
| 568 |
+ *rwflags_pc &= ~EVENT_READ; |
|
| 569 |
+ *rwflags_cp |= EVENT_WRITE; |
|
| 570 |
+ return true; |
|
| 571 |
+ default: |
|
| 572 |
+ return false; |
|
| 573 |
+ } |
|
| 574 |
+} |
|
| 575 |
+ |
|
| 576 |
+static void |
|
| 577 |
+proxy_connection_close (struct proxy_connection *pc, struct event_set *es) |
|
| 578 |
+{
|
|
| 579 |
+ if (BLEN (&pc->buf) && pc->counterpart && socket_defined (pc->counterpart->sd)) |
|
| 580 |
+ proxy_entry_close_sd (pc, es); /* close one side of the connection (pc) */ |
|
| 581 |
+ else |
|
| 582 |
+ proxy_entry_mark_for_close (pc, es); /* close both sides of the connection */ |
|
| 583 |
+} |
|
| 584 |
+ |
|
| 585 |
+static void |
|
| 586 |
+proxy_connection_exception (struct proxy_connection *pc, const int status, struct event_set *es) |
|
| 587 |
+{
|
|
| 588 |
+ dmsg (D_PS_PROXY_DEBUG, "PORT SHARE PROXY: proxy_connection_exception, status=%d", status); |
|
| 589 |
+ switch (status) |
|
| 590 |
+ {
|
|
| 591 |
+ case IOSTAT_READ_ERROR: |
|
| 592 |
+ proxy_connection_close (pc, es); |
|
| 593 |
+ break; |
|
| 594 |
+ case IOSTAT_WRITE_ERROR: |
|
| 595 |
+ proxy_connection_close (pc->counterpart, es); |
|
| 596 |
+ break; |
|
| 597 |
+ case IOSTAT_ASYMFLUSH: |
|
| 598 |
+ proxy_entry_mark_for_close (pc, es); /* close both sides of the connection */ |
|
| 599 |
+ break; |
|
| 600 |
+ default: |
|
| 601 |
+ break; |
|
| 573 | 602 |
} |
| 574 | 603 |
} |
| 575 | 604 |
|
| ... | ... |
@@ -577,36 +664,29 @@ proxy_connection_io_status (const int status, int *rwflags_pc, int *rwflags_cp) |
| 577 | 577 |
* Dispatch function for forwarding data between the two socket fds involved |
| 578 | 578 |
* in the proxied connection. |
| 579 | 579 |
*/ |
| 580 |
-static bool |
|
| 580 |
+static void |
|
| 581 | 581 |
proxy_connection_io_dispatch (struct proxy_connection *pc, |
| 582 | 582 |
const int rwflags, |
| 583 | 583 |
struct event_set *es) |
| 584 | 584 |
{
|
| 585 | 585 |
struct proxy_connection *cp = pc->counterpart; |
| 586 |
- int status; |
|
| 587 | 586 |
int rwflags_pc = pc->rwflags; |
| 588 | 587 |
int rwflags_cp = cp->rwflags; |
| 589 | 588 |
|
| 590 | 589 |
if (rwflags & EVENT_READ) |
| 591 | 590 |
{
|
| 592 |
- status = proxy_connection_io_xfer (pc); |
|
| 591 |
+ const int status = proxy_connection_io_xfer (pc); |
|
| 593 | 592 |
if (!proxy_connection_io_status (status, &rwflags_pc, &rwflags_cp)) |
| 594 |
- goto bad; |
|
| 593 |
+ proxy_connection_exception (pc, status, es); |
|
| 595 | 594 |
} |
| 596 | 595 |
if (rwflags & EVENT_WRITE) |
| 597 | 596 |
{
|
| 598 |
- status = proxy_connection_io_xfer (cp); |
|
| 597 |
+ const int status = proxy_connection_io_xfer (cp); |
|
| 599 | 598 |
if (!proxy_connection_io_status (status, &rwflags_cp, &rwflags_pc)) |
| 600 |
- goto bad; |
|
| 599 |
+ proxy_connection_exception (pc, status, es); |
|
| 601 | 600 |
} |
| 602 | 601 |
proxy_connection_io_requeue (pc, rwflags_pc, es); |
| 603 | 602 |
proxy_connection_io_requeue (cp, rwflags_cp, es); |
| 604 |
- |
|
| 605 |
- return true; |
|
| 606 |
- |
|
| 607 |
- bad: |
|
| 608 |
- proxy_entry_mark_for_close (pc, es); |
|
| 609 |
- return false; |
|
| 610 | 603 |
} |
| 611 | 604 |
|
| 612 | 605 |
/* |