2
0

sm.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. #include "tunala.h"
  2. #ifndef NO_TUNALA
  3. void state_machine_init(state_machine_t *machine)
  4. {
  5. machine->ssl = NULL;
  6. machine->bio_intossl = machine->bio_fromssl = NULL;
  7. buffer_init(&machine->clean_in);
  8. buffer_init(&machine->clean_out);
  9. buffer_init(&machine->dirty_in);
  10. buffer_init(&machine->dirty_out);
  11. }
  12. void state_machine_close(state_machine_t *machine)
  13. {
  14. if(machine->ssl)
  15. SSL_free(machine->ssl);
  16. /* SSL_free seems to decrement the reference counts already so doing this goes
  17. * kaboom. */
  18. #if 0
  19. if(machine->bio_intossl)
  20. BIO_free(machine->bio_intossl);
  21. if(machine->bio_fromssl)
  22. BIO_free(machine->bio_fromssl);
  23. #endif
  24. buffer_close(&machine->clean_in);
  25. buffer_close(&machine->clean_out);
  26. buffer_close(&machine->dirty_in);
  27. buffer_close(&machine->dirty_out);
  28. state_machine_init(machine);
  29. }
  30. buffer_t *state_machine_get_buffer(state_machine_t *machine, sm_buffer_t type)
  31. {
  32. switch(type) {
  33. case SM_CLEAN_IN:
  34. return &machine->clean_in;
  35. case SM_CLEAN_OUT:
  36. return &machine->clean_out;
  37. case SM_DIRTY_IN:
  38. return &machine->dirty_in;
  39. case SM_DIRTY_OUT:
  40. return &machine->dirty_out;
  41. default:
  42. break;
  43. }
  44. /* Should never get here */
  45. abort();
  46. return NULL;
  47. }
  48. SSL *state_machine_get_SSL(state_machine_t *machine)
  49. {
  50. return machine->ssl;
  51. }
  52. int state_machine_set_SSL(state_machine_t *machine, SSL *ssl, int is_server)
  53. {
  54. if(machine->ssl)
  55. /* Shouldn't ever be set twice */
  56. abort();
  57. machine->ssl = ssl;
  58. /* Create the BIOs to handle the dirty side of the SSL */
  59. if((machine->bio_intossl = BIO_new(BIO_s_mem())) == NULL)
  60. abort();
  61. if((machine->bio_fromssl = BIO_new(BIO_s_mem())) == NULL)
  62. abort();
  63. /* Hook up the BIOs on the dirty side of the SSL */
  64. SSL_set_bio(machine->ssl, machine->bio_intossl, machine->bio_fromssl);
  65. if(is_server)
  66. SSL_set_accept_state(machine->ssl);
  67. else
  68. SSL_set_connect_state(machine->ssl);
  69. /* If we're the first one to generate traffic - do it now otherwise we
  70. * go into the next select empty-handed and our peer will not send data
  71. * but will similarly wait for us. */
  72. return state_machine_churn(machine);
  73. }
  74. /* Performs the data-IO loop and returns zero if the machine should close */
  75. int state_machine_churn(state_machine_t *machine)
  76. {
  77. unsigned int loop;
  78. if(machine->ssl == NULL) {
  79. if(buffer_empty(&machine->clean_out))
  80. /* Time to close this state-machine altogether */
  81. return 0;
  82. else
  83. /* Still buffered data on the clean side to go out */
  84. return 1;
  85. }
  86. /* Do this loop twice to cover any dependencies about which precise
  87. * order of reads and writes is required. */
  88. for(loop = 0; loop < 2; loop++) {
  89. buffer_to_SSL(&machine->clean_in, machine->ssl);
  90. buffer_to_BIO(&machine->dirty_in, machine->bio_intossl);
  91. buffer_from_SSL(&machine->clean_out, machine->ssl);
  92. buffer_from_BIO(&machine->dirty_out, machine->bio_fromssl);
  93. }
  94. /* We close on the SSL side if the info callback noticed some problems
  95. * or an SSL shutdown was underway and shutdown traffic had all been
  96. * sent. */
  97. if(SSL_get_app_data(machine->ssl) || (SSL_get_shutdown(machine->ssl) &&
  98. buffer_empty(&machine->dirty_out))) {
  99. /* Great, we can seal off the dirty side completely */
  100. if(!state_machine_close_dirty(machine))
  101. return 0;
  102. }
  103. /* Either the SSL is alive and well, or the closing process still has
  104. * outgoing data waiting to be sent */
  105. return 1;
  106. }
  107. /* Called when the clean side of the SSL has lost its connection */
  108. int state_machine_close_clean(state_machine_t *machine)
  109. {
  110. /* Well, first thing to do is null out the clean-side buffers - they're
  111. * no use any more. */
  112. buffer_close(&machine->clean_in);
  113. buffer_close(&machine->clean_out);
  114. /* And start an SSL shutdown */
  115. if(machine->ssl)
  116. SSL_shutdown(machine->ssl);
  117. /* This is an "event", so flush the SSL of any generated traffic */
  118. state_machine_churn(machine);
  119. if(buffer_empty(&machine->dirty_in) &&
  120. buffer_empty(&machine->dirty_out))
  121. return 0;
  122. return 1;
  123. }
  124. /* Called when the dirty side of the SSL has lost its connection. This is pretty
  125. * terminal as all that can be left to do is send any buffered output on the
  126. * clean side - after that, we're done. */
  127. int state_machine_close_dirty(state_machine_t *machine)
  128. {
  129. buffer_close(&machine->dirty_in);
  130. buffer_close(&machine->dirty_out);
  131. buffer_close(&machine->clean_in);
  132. if(machine->ssl)
  133. SSL_free(machine->ssl);
  134. machine->ssl = NULL;
  135. machine->bio_intossl = machine->bio_fromssl = NULL;
  136. if(buffer_empty(&machine->clean_out))
  137. return 0;
  138. return 1;
  139. }
  140. #endif /* !defined(NO_TUNALA) */