cliloop.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. #include "putty.h"
  2. void cli_main_loop(cliloop_pre_t pre, cliloop_post_t post, void *ctx)
  3. {
  4. SOCKET *sklist = NULL;
  5. size_t skcount = 0, sksize = 0;
  6. unsigned long now, next, then;
  7. now = GETTICKCOUNT();
  8. while (true) {
  9. DWORD n;
  10. DWORD ticks;
  11. const HANDLE *extra_handles = NULL;
  12. size_t n_extra_handles = 0;
  13. if (!pre(ctx, &extra_handles, &n_extra_handles))
  14. break;
  15. if (toplevel_callback_pending()) {
  16. ticks = 0;
  17. next = now;
  18. } else if (run_timers(now, &next)) {
  19. then = now;
  20. now = GETTICKCOUNT();
  21. if (now - then > next - then)
  22. ticks = 0;
  23. else
  24. ticks = next - now;
  25. } else {
  26. ticks = INFINITE;
  27. /* no need to initialise next here because we can never
  28. * get WAIT_TIMEOUT */
  29. }
  30. HandleWaitList *hwl = get_handle_wait_list();
  31. size_t winselcli_index = -(size_t)1;
  32. size_t extra_base = hwl->nhandles;
  33. if (winselcli_event != INVALID_HANDLE_VALUE) {
  34. assert(extra_base < MAXIMUM_WAIT_OBJECTS);
  35. winselcli_index = extra_base++;
  36. hwl->handles[winselcli_index] = winselcli_event;
  37. }
  38. size_t total_handles = extra_base + n_extra_handles;
  39. assert(total_handles < MAXIMUM_WAIT_OBJECTS);
  40. for (size_t i = 0; i < n_extra_handles; i++)
  41. hwl->handles[extra_base + i] = extra_handles[i];
  42. n = WaitForMultipleObjects(total_handles, hwl->handles, false, ticks);
  43. size_t extra_handle_index = n_extra_handles;
  44. if ((unsigned)(n - WAIT_OBJECT_0) < (unsigned)hwl->nhandles) {
  45. handle_wait_activate(hwl, n - WAIT_OBJECT_0);
  46. } else if (winselcli_event != INVALID_HANDLE_VALUE &&
  47. n == WAIT_OBJECT_0 + winselcli_index) {
  48. WSANETWORKEVENTS things;
  49. SOCKET socket;
  50. int i, socketstate;
  51. /*
  52. * We must not call select_result() for any socket
  53. * until we have finished enumerating within the tree.
  54. * This is because select_result() may close the socket
  55. * and modify the tree.
  56. */
  57. /* Count the active sockets. */
  58. i = 0;
  59. for (socket = first_socket(&socketstate);
  60. socket != INVALID_SOCKET;
  61. socket = next_socket(&socketstate)) i++;
  62. /* Expand the buffer if necessary. */
  63. sgrowarray(sklist, sksize, i);
  64. /* Retrieve the sockets into sklist. */
  65. skcount = 0;
  66. for (socket = first_socket(&socketstate);
  67. socket != INVALID_SOCKET;
  68. socket = next_socket(&socketstate)) {
  69. sklist[skcount++] = socket;
  70. }
  71. /* Now we're done enumerating; go through the list. */
  72. for (i = 0; i < skcount; i++) {
  73. WPARAM wp;
  74. socket = sklist[i];
  75. wp = (WPARAM) socket;
  76. if (!p_WSAEnumNetworkEvents(socket, NULL, &things)) {
  77. static const struct { int bit, mask; } eventtypes[] = {
  78. {FD_CONNECT_BIT, FD_CONNECT},
  79. {FD_READ_BIT, FD_READ},
  80. {FD_CLOSE_BIT, FD_CLOSE},
  81. {FD_OOB_BIT, FD_OOB},
  82. {FD_WRITE_BIT, FD_WRITE},
  83. {FD_ACCEPT_BIT, FD_ACCEPT},
  84. };
  85. int e;
  86. noise_ultralight(NOISE_SOURCE_IOID, socket);
  87. for (e = 0; e < lenof(eventtypes); e++)
  88. if (things.lNetworkEvents & eventtypes[e].mask) {
  89. LPARAM lp;
  90. int err = things.iErrorCode[eventtypes[e].bit];
  91. lp = WSAMAKESELECTREPLY(eventtypes[e].mask, err);
  92. select_result(wp, lp);
  93. }
  94. }
  95. }
  96. } else if (n >= WAIT_OBJECT_0 + extra_base &&
  97. n < WAIT_OBJECT_0 + extra_base + n_extra_handles) {
  98. extra_handle_index = n - (WAIT_OBJECT_0 + extra_base);
  99. }
  100. run_toplevel_callbacks();
  101. if (n == WAIT_TIMEOUT) {
  102. now = next;
  103. } else {
  104. now = GETTICKCOUNT();
  105. }
  106. handle_wait_list_free(hwl);
  107. if (!post(ctx, extra_handle_index))
  108. break;
  109. }
  110. sfree(sklist);
  111. }
  112. bool cliloop_null_pre(void *vctx, const HANDLE **eh, size_t *neh)
  113. { return true; }
  114. bool cliloop_null_post(void *vctx, size_t ehi) { return true; }