• Welcome to Valhalla Legends Archive.
 

DLLs & messages for them

Started by tA-Kane, January 25, 2005, 03:08 AM

Previous topic - Next topic

tA-Kane

I'm trying to write a DLL (BCP actually, but that's not really important) which creates and uses sockets. I don't want it to hog the owning executable's processing time, so I of course would rather use asynchronous calls. But from the looks, they require a window to be passed to them in order to receive events such as data available.

I would rather not create a window (it's a DLL, it shouldn't need an interface!), so how might I go around this?
Macintosh programmer and enthusiast.
Battle.net Bot Programming: http://www.bash.org/?240059
I can write programs. Can you right them?

http://www.clan-mac.com
http://www.eve-online.com

Kp

Easy, don't use those functions!  In more detail: you could use overlapped I/O or completion ports (but OIO works poorly on Win9x and completion ports don't exist there).  You could create an extra thread and do blocking reads (though that's a somewhat inelegant solution).  IIRC, BCPs are guaranteed that the host process will periodically execute alertable sleeps, which have as a side effect that any completed overlapped operations are delivered to you.  So, I would recommend overlapped I/O for your case.  Look up ReadFile(Ex), WriteFile(Ex), WSASend, WSARecv.
[19:20:23] (BotNet) <[vL]Kp> Any idiot can make a bot with CSB, and many do!

tA-Kane

#2
hmmk thx

Edit:

With overlapped I/O, would I still need to use select() (or a variant thereof) to know that data is ready to be received with WSARecv()? If so, how would that *not* hog the owning processes' CPU time? If not, how am I informed that the socket has data available to be received?

Also with overlapped I/O, suppose I am using multiple sockets. From the looks of the completion routines, there is no way of telling which socket completed the WSARecv(). Except, it looks like if there *is* a completion routine specified, then the hEvent of the lpOverlapped which is passed to WSARecv is unused. Would using that to hold a pointer to the socket be a good idea?
Macintosh programmer and enthusiast.
Battle.net Bot Programming: http://www.bash.org/?240059
I can write programs. Can you right them?

http://www.clan-mac.com
http://www.eve-online.com

Kp

You don't need select, which is good.  Microsoft got the implementation of it all wrong anyway.

Yes, you can pass the socket in the hEvent of the OVERLAPPED structure.  Alternately, you could create your own structure which has OVERLAPPED as a member; the OS does not copy/move the structure you supply, which means you must ensure it stays valid (i.e. not on the stack of a routine that will return before I/O completes!).  Also, it grants you the ability to make assumptions about where your other data structures are in relation to the OVERLAPPED that the OS gives your callback.
[19:20:23] (BotNet) <[vL]Kp> Any idiot can make a bot with CSB, and many do!

tA-Kane

Quote from: tA-Kane on January 25, 2005, 03:35 PMWith overlapped I/O, would I still need to use select() (or a variant thereof) to know that data is ready to be received with WSARecv()? If not, how am I informed that the socket has data available to be received?
Quote from: Kp on January 25, 2005, 06:12 PMYou don't need select, which is good. Microsoft got the implementation of it all wrong anyway.
Could you answer my question a little more in depth? I'm still failing to understand how my DLL will be informed of when the socket is ready to call WSARecv().
Macintosh programmer and enthusiast.
Battle.net Bot Programming: http://www.bash.org/?240059
I can write programs. Can you right them?

http://www.clan-mac.com
http://www.eve-online.com

Kp

You call WSARecv as soon as the socket could possibly have data, thereby turning loose an overlapped read which will complete when the socket finally has data (which could be immediately or it could take hours).  When the receive completes, you'll be notified during the next alertable sleep.  If you need more data from the socket, your completion routine should call WSARecv again to start another asynchronous read to fetch more data.
[19:20:23] (BotNet) <[vL]Kp> Any idiot can make a bot with CSB, and many do!

Arta

("notified" == the system calls your completion routine)

tA-Kane

#7
Thanks Arta.

I have one more (possibly my last) question; can I reuse the WSAOVERLAPPED structure from the completion routine? That is, can I pass it in my initial call to WSARecv() or WSASend(), and then pass it again to another call to WSARecv() or WSASend() from within the completion routine of such?

If not, then what would strategy would you recommend to easily keep track of an arbitrary number of WSAOVERLAPPED structures?
Macintosh programmer and enthusiast.
Battle.net Bot Programming: http://www.bash.org/?240059
I can write programs. Can you right them?

http://www.clan-mac.com
http://www.eve-online.com

Kp

Yes, you can reuse it.  Once the OS calls your completion routine, it's done with that OVERLAPPED and you can have it back to be reused or deallocated as you see fit.  Just remember you need one OVERLAPPED per outstanding I/O operation (i.e. one per socket).
[19:20:23] (BotNet) <[vL]Kp> Any idiot can make a bot with CSB, and many do!

tA-Kane

#9
Actually, you'd need no less than two per socket; one to send data, another to simultaneously receive data, and possibly a third for other simultaneous miscellaneous overlapped I/O with the same socket.

That's excellent news, it'll simplify things greatly!  :)



Edit:
Hmm, I do have one more question:
QuoteThe array of WSABUF structures pointed to by the lpBuffers parameter is transient. If this operation is completed in an overlapped manner, it is the service provider's responsibility to capture these WSABUF structures before returning from this call. This enables applications to build stack-based WSABUF arrays.
Would that indicate that the data pointed to by buf is "captured" by the service provider as well?


Edit2:
It seems as the the answer to my question is yes... but it would still be nice to have someone else confirm (or deny) it.

As for your earlier statement:
Quote from: Kp on January 25, 2005, 03:30 PMIIRC, BCPs are guaranteed that the host process will periodically execute alertable sleeps, which have as a side effect that any completed overlapped operations are delivered to you.
It seems that is not so true in the case of SphtBotv3. I was not getting my callback routine called, so I installed a timer which executes every half of a second and calls SleepEx(0, TRUE), and suddenly ... my completion routine is called!

On a different (rather sad) note, it seems that if you load the DLL, call WSASend() with a completion routine installed, call WSACleanup(), unload and reload the DLL, and reinitialize WinSock with WSAStartup(), then the subsequent call to WSAConnect() results in the completion routine from the previous instance getting called. That's a major fuckup on Windows' part, I think.
Macintosh programmer and enthusiast.
Battle.net Bot Programming: http://www.bash.org/?240059
I can write programs. Can you right them?

http://www.clan-mac.com
http://www.eve-online.com

Kp

In order:

I don't use that family of calls, so I don't know.  I prefer to do the work with WriteFile / WriteFileEx.

That's an SphtBotv3 bug (unless I misremember the BCP spec., which is possible - atm, I can't find anything about whether it's guaranteed or not).

Re: previous completion routine: that's arguable.  Try canceling the overlapped operation before you unload your DLL (use CancelIo), which will cause your completion routine to be called with a notice that the operation was aborted.  After that, you can safely unload your DLL.  Of course, if SphtBot doesn't provide a way to let you refuse/defer an unload, you're still stuck. :)
[19:20:23] (BotNet) <[vL]Kp> Any idiot can make a bot with CSB, and many do!

tA-Kane

Do you use WriteFile(Ex) with sockets?

Even without calling CancelIo, called WSACleanup() should close all sockets and in doing so, cancel all operations on those sockets. If there's any pending completion routines, it should call them before returning, since it should basically be deinitializing the WinSock library, which should allow for zero WinSock use in that context's address space.
Macintosh programmer and enthusiast.
Battle.net Bot Programming: http://www.bash.org/?240059
I can write programs. Can you right them?

http://www.clan-mac.com
http://www.eve-online.com

Kp

Yes, I do.  It might be closing the handles (which would indeed interrupt/cancel the routine), but it might not be doing an alertable wait.  Try just adding a SleepEx(0, 1); after the WSACleanup.
[19:20:23] (BotNet) <[vL]Kp> Any idiot can make a bot with CSB, and many do!

Adron

Quote from: tA-Kane on January 28, 2005, 05:37 PM
Even without calling CancelIo, called WSACleanup() should close all sockets and in doing so, cancel all operations on those sockets. If there's any pending completion routines, it should call them before returning, since it should basically be deinitializing the WinSock library, which should allow for zero WinSock use in that context's address space.

Are you using this in an application you control entirely yourself or is it possible that the program loading your DLL, or some DLL that it has loaded for other reasons has also called WSAStartup? Multiple calls would mean that it's actually not uninitialized when you think it is.

tA-Kane

#14
Hmm... I am using this in a Battle.net client (are BCPs used anywhere else though?), so I assume it's already called WSAStartup().

I would think that being a DLL, I would get my own address space and as such, would also need to initialize WinSock before calling any WinSock functions.


...Unless WinSock only needs to be initialized for separate threads, in which case, I don't think my host application (SphtBotv3) creates separate threads for each plugin loaded.
Macintosh programmer and enthusiast.
Battle.net Bot Programming: http://www.bash.org/?240059
I can write programs. Can you right them?

http://www.clan-mac.com
http://www.eve-online.com