You really need to do file setup and memory allocation outside your SocketGetfile in case you're responding to a FD_READ event - otherwise you're going to keep overwriting the file data.

Try starting with a simple blocking socket and no events, and try the following code snippet. If that works, we can move on to some proper program structure and event-based handling. Written off top of my head, not tested btw :)

SocketGetFile PROC
MessageBox, 0, addr szErr1, addr szErr1, MB_OK
mov esi, eax

invoke GetProcessHeap
invoke HeapAlloc, eax, 0, MEMSIZE
mov edi, eax

invoke recv, , edi, MEMSIZE, 0

.if sdword ptr eax < 0
; note: memory + file handle leak
MessageBox, 0, addr szErr2, addr szErr2, MB_OK
.if eax > 0
invoke WriteFile, esi, edi, eax, addr fwritten, NULL
jmp @@doTheFunkyLoop

invoke GetProcessHeap
invoke HeapFree, eax, 0, edi
invoke CloseHandle, esi
SocketGetFile ENDP
Posted on 2008-12-18 13:27:12 by f0dder
Thank you for your reply! Your code works wonders on a blocking socket (apart from some missing "invoke"s)

What's the main difference between using GlobalAlloc and GetProcessHeap?

According to MSDN GlobalAlloc "Allocates the specified number of bytes from the heap." while GetProcessHeap "Retrieves a handle to the heap of the calling process. This handle can then be used in subsequent calls to the heap functions."

Pardon my minor knowledge of english and/or my tired brain. But I did not understand the wizzy wizzy tech talk. Or at least not what the difference is.

I really appreciate your help guys, you are champs!
Posted on 2008-12-18 14:15:38 by n1mda
Local* and Global* functions are deprecated leftovers from the 16-bit days of Win3.x - new code should be written using the Heap* functions instead. On NT, Local* and Global* point to the same functions, and end up calling Heap* anyway.

GetProcessHeap() returns the current process heap (which is a "pseudo-handle" on all windows versions I know of, but you should still call the function for future compatibility - it's not like it costs a lot of time anyway). This handle is required for the rest of the Heap* functions.

Now, as for event-based async sockets, I'm going for a little explanation and pseudo-code, since writing a proper example takes too much time :)

First off, you will want a per-connection struct with the info you need. This would be State (not connected, connected, error - perhaps more, depending on your needs), probably a BufferPtr, probably a hFile, a Socket, perhaps a Type indicator.

You'll want to allocate an array of these, with MAXIMUM_WAIT_OBJECTS entries. If you want to handle a lot of sockets, make each entry a linked-list or other dynamically growing data structure (and keep track of each pool size, distributing connections evenly across this pool).

Depending on your needs, either reserve slot 0 as a "program shutdown" even, or specify a timeout on your WaitForMultipleObjects() and check a global "shuttingDown" flag.

Create your sockets in async mode, set up Connection structure (with "unconnected" state), allocate buffers, hFile and whatever other state you need, and use WSAEventSelect() to associate the socket with the EVENT for the slot you assign the connection to.

When WaitForMultipleObjects() returns >= WAIT_OBJECT_0, loop through all the sockets for the givent event slot and call WSAEnumNetworkEvents() for each socket, to check whether to process this socket or not.

When calling recv() on a (nonblocking) socket, remember that 0 means "connection closed gracefully", and that you need processing for SOCKET_ERROR - even if WSAEnumNetworkEvents() signalled that the socket has an event. Call WSAGetLastError() and check for WSAEWOULDBLOCK and WSAEALREADY which are non-fatal, and mean you should retry operation next time you get the event.

And umm... that's basically it. Try implementing the above pseudo-code and I'll try finding the time to give you a hand with problems. Remember that memory allocation, file creation etc. happens outside the connection-handler.
Posted on 2008-12-18 14:47:19 by f0dder
I see. It seems that the guides that I've been using for memory allocation is a bit outdated.

I will try to implement your pseudo-code, though it'd probably take a while. I've so far only been working with events, not objects. I've been googling a bit but havn't found what the difference is between the two. I know that events is obviously events and objects is objects. But what's the better one to use.

My needs are quite simple. The program needs to be notified if the socket is closed (in any way) so it can reconnect.

I'll go back to the drawing board and figure out if I need multiple sockets. Perhaps for multiple files and other socket functions while files are transfering.
Posted on 2008-12-19 13:20:16 by n1mda
Event is an object. If you're refering to the "WaitForMultipleObjects" name, then -for the purpose of your application- I can tell you that it could as well be named "WaitForMultipleEvents". Whole Windows OS is event-driven. Everything just waits for something and acts when particular event occurs. Try to see it this way ^^
Posted on 2008-12-19 17:32:30 by ti_mo_n
Not to beat a dead horse, but I would assume the reason your early versions were not working was because you were leaving out the ADDR directive for each instance of 'buff_sock' (except the one you commented out, RtlZeroMemory).

Calling NULL - Zero tends to be one of my pet pieves. Reason being that 0xBFFF4332 could very well be NULL. NULL isn't a value or an indentifier as much a description of a common occurance in programming. A NULL is properly defined as a "void pointer to zero", which means that any value that dereferences to zero is NULL. I get so annoyed when I see Assembly programmers using the equate NULL all over the place as a substitute for zero when they should know better. (you should know better) O o . :p

But that's just my two cents.
Posted on 2008-12-22 20:59:30 by Synfire