Rob Crittenden wrote: > Nelson B wrote: >> Rob Crittenden wrote: >>> In an SSL client I want to force the SSL handshake to take place instead >>> of passively waiting for it to happen during the first write.
>> Here are a few (?) questions and comments: >> >> 1. Is this a blocking socket, or non-blocking? > > non-blocking, not my choice. > >> 2. If non-blocking, are you certain that the connection has completed? >> That is, are you certain that the TCP's "three phase connect" is >> completely done? This is tricky for non-blocking sockets, and trivial >> for blocking sockets. > > I'm not sure it has completed, hence the simplistic loop and my plea for > assistance. Despite empirical evidence that it "worked" in my 3 test > cases this code is obviously bogus. > >> 3. Is this the first handshake on the socket after the connect? or >> Is it a subsequent (e.g. second) handshake on the socket? > > First connection only. > >> 4. Is this a "server speaks first" application protocol? or >> is this a "client speaks first" protocol? > > Client speaks first, HTTPS. OK, well, I would not have (and obviously did not) guess that from the code you initially presented. That changes my answer, and makes me glad I asked all those questions. You're trying to do fairly typical non-blocking client behavior, with the added wrinkle that you want to do the handshake before doing the first write, for some reason I can't yet fathom. Since the socket is non-blocking, the client already must know how to handle PR_WOULD_BLOCK_ERROR. As long as the client does that correctly, it shouldn't need to force the handshake before the first write. The initial write attempts will simply return PR_WOULD_BLOCK_ERROR until the handshake is completed. Still, that's all very easy to do. There are 3 steps that need to be done, in order, each step completed before the next one is begun. They are a) initiate and complete the TCP connection b) do the handshake c) write the initial http request Notice that there's no need to do ANY recv calls in there, anywhere. The receive calls are completely unnecessary and actually complicate matters because of the timeouts. Just don't do 'em. NSS's test client program, tstclnt, already does everything you want to do except forcing the handshake before the first write. I'm going to point you to tstclnt and let you follow that example. It will show you how to initiate a non-blocking connection, and wait for it to complete and KNOW when it is completed. Look at lines 751-797 of http://landfill.mozilla.org/mxr-test/security/source/security/nss/cmd/tstclnt/tstclnt.c#751 The only additional piece you need to know is how to force the handshake, AFTER the TCP connection is completely established. > I guess at least the loop should be: > > do > ret = PR_Recv (ssl, handshake, 1, PR_MSG_PEEK, 100); > err = PR_GetError(); > while (ret < 0 && err == PR_IO_TIMEOUT_ERROR && handshake_done == 0); > > On slow connections I've seen the loop fire as many as 20 times. I can > increase the timeout, that is purely a goof. But again, I don't want a > noticable pause. On connections to a local machine even with an interval > of 1 sometimes the handshake completes in one run through the loop (and > who said SSL is slow?) >> 7. Why are you using such a short timeout on PR_Recv? > > So it doesn't cause a noticable pause in the connection. There will > never be any "data" to peek at so I am guaranteed to wait a certain > number of PRIntervals until PR_Recv returns. A larger value will almost > certainly negate the need for the icky loop but even if the handshake is > done, it'll hang around waiting for the timeout to end. Now I understand that you're using PR_Recv as a substitute for PR_Poll. Use PR_Poll instead. As far as "noticeable pause", you have to wait for the handshake to complete, however long that takes. You don't want to introduce any extra wait time, so don't use PR_Recv. Use PR_Poll. >> What trick are you trying to do? > > Force a handshake to complete on a non-blocking socket without doing I/O > with PR_Send/Write or PR_Read/Recv (in non-peek). To do that, you need SSL_ForceHandshake and PR_Poll. PR_Recv is actually the problem in this code. Given that you're the client doing the first handshake on a client-speaks- first application protocol, you don't need to worry about receiving any application data from the server before the handshake completes. That simplifies things a lot, AFTER you're sure the connection is completed (that is, fully established), you can simply do a loop, calling SSL_ForceHandshake, and if it returns PR_WOULD_BLOCK_ERROR, then calling PR_Poll on the socket until it is readable again. Repeat this until you get any other error or the handshake is completed, or too much time has elapsed. Don't make timeouts occur. You have to wait until the handshake is done anyway. You should only use timeout to detect that too much total time has elapsed. Set the socket's timeout to the upper bound of that time limit. -- Nelson B _______________________________________________ dev-tech-crypto mailing list dev-tech-crypto@lists.mozilla.org https://lists.mozilla.org/listinfo/dev-tech-crypto