Am I missing data?
It's kind of weird the previous topic was on this subject as well.
Anyway, I wrote a SOCKS4 proxy which seems to be working well for the most part. It seems though I am having trouble with websites with quite a bit of content. If I open up one of these web pages, it is like it never quite finishes loading. By the way, I configured Firefox 3.5 to use my server.
An example of a web page that does this is msdn.microsoft.com
My code has virtually no comments, but I know the problem has to be in the main() block in the loop. I think that firefox may be firing off the connection requests so fast my program can't handle it.
It's about 200 lines, but I'll include the whole thing, but where I think the problem lies is where I referred to earlier, the loop in my main block.
Also any vulnerabilities you see I would love hear. I know of one already. It has to do with recv when the client first connects, packet fragmentation and stuff. But other than that I'm all ears. Thanks!
Edit: I used MinGW (gcc 4.4) to compile this. I am on Windows.
>> Am I missing data?
I really don't know much about the Sock4 specification, and I've just started to look at the code, but my first thought was maybe that the buffer is too small (1024 bytes)? Just an initial thought anyway.
>> By the way, I configured Firefox 3.5 to use my server.
Good idea. :)
I just thought of one more thing. CreateThread can have problems with memory leaks, which after awhile adds up to quite a bit of memory. I'd recommend _beginthreadex/_endthreadex, if possible.
1) Much error checking, keep this up.
2) You dynamically allocate proxy_s, but with your usage of it, you might as well put it on the stack.
3) Check the return value of both selects
4) You make the assumption that send() will send everything you pass it.
5) You make the assumption that recv() will do the same.
6) You make the above assumptions with nonblocking sockets, which is even more fatal.
7) You make the assumption that an error from send() / recv() is a bad thing -- you're using nonblocking sockets, you need to check for WSAEWOULDBLOCK.
Thanks a ton for looking at it. I know its a lot. I will be sure to fix everything you mentioned and let you know if it does better. I forgot about WSAEWOULDBLOCK... :P
Edit: Haha, the main problem was me not checking for WSAEWOULDBLOCK on recv. Thanks for spotting my oversight. I'll also be sure everything is being checked for errors.
OK. I have a lot more problems than I thought. Since both my in/out sockets are non-blocking, i need to wait until both of them can finish their operation. Here is where my confusion starts.
I think the constants WSAEINPROGRESS and WSAEWOULDBLOCK are needed at this point. So far I've figured this. I will check send() and recv(), and if they return WSAEWOULDBLOCK, don't fret, it just means there was no operation to perform.
Here is what I am ultimately getting to. Say I received a large amount of data. Since these are non-blocking sockets, do I need to make time for them to finish the send/recv operation, or is a function call enough? And how would I go about doing this? Because if recv throws a WSAEINPROGRESS, how can I get the total bytes received? Will it actually eventually change the value of the variable?
It seems my proxy works fine, but then I opened up the dreaded youtube, which in turn caused some mass confusion, lol.
You shouldn't be getting WSAEINPROGRESS. In fact, I'm not entirely sure how you get an EINPROGRESS, since the docs indicate this comes from calling two blocking socket functions in the same thread. Not exactly sure how they expect us to do that. That said, you're single threaded, you should be fine.
WSAEWOULDBLOCK, however, you should & will get. There's two places it can crop up:
If it crops up on a call to recv(), oh well. No bytes were recv()'d. (If they had, recv() would have returned a positive number.)
send() is a bit more of a stickler though. If send() returns EWOULDBLOCK, then no bytes were sent. (Careful though, send() might return less than what you ask it -- so it might send 50%, 25%, 100% or 0% of what you ask it to send!) This means you'll have to buffer the data somewhere until send() can actually send them. You can create another fd_set and pass it to select() to find out when the socket is writeable. Only include the socket in the fd_set if you actually have data you need to send though, otherwise, you'll end up waking up too often in a sort of "socket is writable! I don't have anything to send. socket is STILL writable! etc..." loop.
The most simplistic buffer could be a std::queue of
Keep a tag to the last one around, so you don't end up with 400 of them only 1% filled.
unsigned char data[SOME_MAGICAL_CONSTANT];
size_t used, size_t send;
Holy cow there's more to this than I thought lol. Oh well, a good learning experience. I guess at this point it would be much easier to combine some C++ because writing my own buffer handler in C might be tricky and dirty. But I do want to write a solid program that can handle anything so I will give it a shot.
Thanks again for your help.
Would this be an accurate way of handling the whole recv stuff:
r = recv(out, buff, 1048576, 0);
if (r == SOCKET_ERROR)
if (WSAGetLastError() != WSAEWOULDBLOCK)
if (r != SOCKET_ERROR)
if (r > 0)
send(in, buff, r, 0);
/* will add handler later */
Ok, I've narrowed it down pretty good. I still have the major bug I'm trying to pin down, when send returns less than what I want it to send.
Will send eventually finish this operation, or do I need to resend what it didn't send?
If I don't need to resend it and it is trying to finish the operation, what would I look for in its file descriptor so that I know it is complete, if that makes sense, lol.
If you pass send() M bytes and it returns N, then it only sent N bytes, and you are responsible for calling it again to send the remaining M-N bytes. It will not retry. (The TCP/IP layer actually DOES retry, but this is hidden under the covers -- by the time send() returns, all retry attempts have already been done)
Originally Posted by carrotcake1029
Ok, what I thought. When I get some time I'll see if I can write a good routine to get this working properly. Thank you.
My understanding was that send(), at least for non-blocking sockets, can merely buffer the data somewhere in the kernel (and perhaps, if the link is ready, send it out for the first try.) It's this buffer, however, that is of limited size, and once you exceed that, send() either blocks or returns EWOULDBLOCK (as it would have to wait for the buffer to empty, which takes time, and hence would block.)
Originally Posted by brewbuck