> From: owner-openssl-us...@openssl.org On Behalf Of Sam Jantz > Sent: Wednesday, 01 September, 2010 12:25 > My proxy behaves like number two in the previous email. > It is purely a bidirectional proxy with no clear tracking of the > protocol [after CONNECT] It's multi threaded with non-blocking I/O. > I'm not sure exactly what you mean by socket discovery, but I think > you are asking how my program determines when something is ready? > If that's the case then my program uses a select statement to watch > the file descriptor to see if it's ready for read or write > [with callbacks] based on which fd_set was ready.
Okay, sounds fine. > It looks like the issue with a SSL_read call from the perspective > of the program as the client is returning zero during the upload > (which makes sense) but the way my proxy is handling connections > the only reason it could have read is if there was a > SSL_get_error() that returned a SSL_ERROR_WANT_READ code. <snipped most code> We need to distinguish SSL_read/write and socket level. You should, and it looks like your code does, call SSL_read when you want (app-level) data and either _WANT_READ was previously returned and select says readable (normal case) or _WANT_WRITE was returned and select says writable (only renegotiation, which I doubt gmail does, but others might). Similarly for write. It appears to me your psc->ssl_read should be called once at connection start; it might get data which you process, and schedule another read when select says; or it returns -1 and SSL_get_error returns _WANT_READ and you schedule the next read when select says. In either case 'scheduled' reads should normally return data and schedule again, although it is possible there is socket level data that does not constitute a complete app-level record, so SSL_read=-1/get_error=_WANT_READ, and you re-schedule. Or you could schedule_read(&psc::ssl_read) at startup, so the first ssl_read is attempted when select says but without _WANT_READ having cause that scheduling. For a HTTP-unaware proxy, you must try to SSL_read from each side (and forward to the other) 'always', but can't when you don't have buffer space available. I don't see any checking, so I guess buf->len_avail() returns 0 and you call SSL_read with max 0, and it looks to me that will return 0 but NOT meaning disconnect/EOF, and I'm not sure what SSL_get_error does in this state; it may well 'default' to _SYSCALL. If the client=browser is 'nearby' in network terms e.g. on same LAN and gmail is 'distant', then it is quite plausible receiving is faster than sending and you do get buffer (temporarily) full unless it's big enough. > void ProxySSLConnection::handle_ssl_error(int ret, > handler_function handler, const char * caller) > { > int error = SSL_get_error(_ssl, ret); > switch (error) > { > case SSL_ERROR_WANT_READ: > schedule_read(handler); > break; > case SSL_ERROR_WANT_WRITE: > schedule_write(handler); > break; > case SSL_ERROR_ZERO_RETURN: > _proxy_thread->shutdown(); > break; > default: > unsigned long err = ERR_get_error(); > while (err != 0) > { > char* err_string = ERR_error_string(err, NULL); > cout << err_string << endl; > err = ERR_get_error(); > } > close_connection(); > _proxy_thread->shutdown(); > break; > } > } I suggest for ERROR_SYSCALL and probably ERROR_SSL it would often help to know what was going on when you encountered the "error". Your (added, below) caller gives the operation; do you have info conveniently in (or possibly mappable from) your ProxySSLConnection that says which side this is, and if you handle multiple connections concurrently (which from your structure I guess is a goal/feature) which connection? Alternatively can you get a debugger on this (state)? Then you can look around at whatever you need (in memory). > If the following case is added to the switch then the > upload is fixed, but the threads never exit: > case SSL_ERROR_SYSCALL: //This case is where the uploads fail. > schedule_write(handler); > break; > The caller variable is just for debug purposes. As per > Dave Thompson's request I was using it to determine which call > was causing the error, and was then calling perror(caller) since > I was getting a SSL_ERROR_SYSCALL with a ret of 0, and the perror > printed "read: Success". Did you do perror() before cout<<err_string could clobber errno? Assuming so, that's either disconnect-without-shutdown (because shutdown would have given _ZERO_RETURN) but neither peer should be deciding to disconnect with or without shutdown during request; or as above read-zero-did-nothing. (disconnect isn't considered an error at socket level so errno=0=Success; and read-zero isn't an error at all, just an abnormal use of the API.) Assuming this was read-from-client, schedule_write shouldn't accomplish anything directly -- socket is immediately writable and you just come back to this->ssl_read -- but perhaps this lets write-to-server callback progress and free up buffer space. Does your 'proxythread' select-dispatching stop after the first found, or after readables before writables? > <snip fd_set/select/callback within thread> sounds okay > void ProxySSLConnection::handle_callback(handler_function *handler) > { > if (*handler) > { > handler_function the_handler = *handler; > *handler = NULL; > (this->*the_handler)(); > schedule_send_buffer(); > } > } I don't see any need for a schedule_send_buffer there; your read-here-got-something=>send-there should be sufficient. OTOH if this tries to send when you have nothing to send it probably just does nothing, so no harm done? In fact you really need read-got=>other.schedule_send only when the buffer was empty; if the buffer was already nonempty, the other side is already writing, and will continue while its buffer is nonempty, including this. The symmetric way to handle buffer full is: read-side (re)schedule_read only if the buffer is not full, and write-side other.schedule_read when it has written and (thus) removed data from a buffer that was full. > If you need anything else to help you understand how > my proxy works please let me know and I will be happy to > provide what I can. I know that this can be confusing, > but I tried to lay it out in as logical of an order as possible. > It's hard to type english descriptions of code. I found this quite clear. > Thank you for any help you can give. Hope this helps. ______________________________________________________________________ OpenSSL Project http://www.openssl.org User Support Mailing List openssl-users@openssl.org Automated List Manager majord...@openssl.org