Game Development Community

Code Assistance Please

by Ronald J Nelson · in Torque Game Engine · 09/25/2008 (4:42 am) · 15 replies

I have been updating some old file transfer code Sam Redfern gave me that he used for an auto-patching system several years ago. I have an issue though, for some reason it always stops around the third or second to last block of data before transfer completion. Can someone please give it a look over and tell me if they can see what would be causing this?

#1
09/25/2008 (5:42 am)
That's alot of code right there and I don't have time to read it trough.

* Does this happen on all files, large and small?
* If only on the latter, are you sure the code is subtracting the header size from the total file size?

Edit: Just realized it's not a typical HTTP transfer, so these two questions won't help - see post below.
#2
09/25/2008 (5:48 am)
However, there are some quite important mistakes in the code you posted. If you ever run into a situation where you have to repack a lost packet, you'll run into a wall because the code is incrementing and chosing the next file block in pack ().

fileBlock* temp = fb->next;
			delete fb;
			gconn->headFileBlock = temp;

All processing like that, should be done in process () as that's the function which is called once, and not on each send. If you drop a packet, you'll run pack () twice and the incremented value will be incorrect. Might or might not be your issue, especially not if you're running on LAN or localhost - but worth to consider.
#3
09/25/2008 (5:51 am)
Hi Stefan, yes and yes.

If I set the packet size to pretty small, while I get very slow transfers I can get enough of a file like a png file to tell that it is working because you can do a preview on it and see enough of it to tell that the transfer was stopped before completion.

I have tried this with several other files and have also added consolelog calls at a couple of points and it verified that it is usually stopping around the second or third to last block.

For the console method "prepareToSendFile" it will return the number of blocks necessary to transfer the file. I added calls that told me each cycle what block it was on and that is how I found that it was stopping short.
#4
09/25/2008 (5:54 am)
Well that is a very good point Stefan and something I will have to look at fixing. Now if that is a possible cause to the failure why would the number of packets lost be so consistent? It should be a random thing I would think.

One more thing, does the engine automatically ask for a lost packet again?
#5
09/25/2008 (7:02 am)
Quote:
Now if that is a possible cause to the failure why would the number of packets lost be so consistent? It should be a random thing I would think.

Should definatly be random enough that you can get a complete file trough with a few tries. If you're doing this across a loopback connection or across your LAN, packet loss should be very rare unless something goes seriously wonky in there.

Quote:
One more thing, does the engine automatically ask for a lost packet again?

It does if you set the correct type. There are three of them, Guaranteed, GuaranteedOrdered and Unguaranteed. The second one is the default one, and since you guys didn't set it anywhere that's the one which is being used.

You can catch the notify inside NetEvent::onNotifyDelivered () and even check (it passes a boolean value) if the packet went trough undamaged. Really nice.

Edit: Bah, Guaranteed was indeed set in the code. -_- Need some sleep. I would make it ordered so I could ignore that part of the file transfer myself, but again not sure it would help you in your current situation. If you're not trying this across loopback (localhost) yet, you should do that to see if your issues are minimized.
#6
09/25/2008 (7:37 am)
Thanks Stefan, I really appreciate the help.
#7
09/25/2008 (10:51 pm)
Stefan the more I look at it the more it looks like to do what you suggested would mean pretty much trying to design it the same way netDownload is. I have tried that and essentially killed the main functionality of this code which is to allow uploads. Perhaps you could give me a suggestion or two.

Thanks in advance.
#8
09/26/2008 (6:50 am)
Personally I would start off with a clean NetEvent class, because I find the NetDownload complicated to maintain. Your mileage may vary, of course.

If you do start over from scratch (as in, subclass from NetEvent) I would do this:

* Start by implementing RequestUpload, ApproveUpload, DenyUpload and SendChunk packet types.
* Use a small file, which is easy to follow if you have to check the stream later.
* Client creates a new NetEvent and sets the type to RequestUpload.
* Server receives and if it agrees, it creates a new NetEvent with type ApproveUpload.
* Client will receive this as part of a new NetEvent (not the old one which you used to request!) and will in return create a new NetEvent with SendChunk.
* In NetEvent::process () you need to open the file, create a buffer, store it in the actual NetEvent (so you can grab it in NetEvent::pack () and send it off. Increment the chunk counter.
* You can wait for the notify to arrive, and then send the next chunk.
* When that's working and you see that the files arrive as they should, you can implement more complicated stuff like keeping a queue of packets, where you send one packet + some number of packets, and increase this queue until you start to see packets drop and get resent by NetConnection. Waiting for an ack for each packet will be slow, so always keep a buffer and make sure you're using GuaranteedOrdered.
#9
09/26/2008 (3:29 pm)
Disconnecting with what message given? I can't read trough all that, but if you can be more specific I'll be happy to help you sort it out. These things (at least on the NetEvent level) are usually pretty simple to solve. :)

If you're getting disconnected you probably read out of bounds on your BitStream.
#10
09/26/2008 (4:48 pm)
Invalid file block transferred.
Client 3116 packet error: Invalid file block transferred..


That is in the function blockReceived when the condition if(blockLen + mCurrentBlockBufferOffset > mCurrentBlockBufferSize) is checked.

Now as far as I can tell because the server is performing client commands and the client is performing server commands, somewhere in the code the roles got reversed. The script side is still set to call prepareToSendFile on the client side using ServerConnection so the error must be within the code and therefore would likely be the source of the error.

Any ideas?
#11
10/03/2008 (4:38 am)
Well life got in the way for a couple days and I see no one has had any ideas or this has gone unnoticed.

So....
*BUMP*
#12
10/03/2008 (8:44 am)
To quote Stefan "I can't read through all that".
#13
10/03/2008 (9:40 am)
Well I drastically shortened it removing all script functions and consolemethod stuff and anything that I am positive cannot cause the issue I am seeing.
#14
10/03/2008 (10:51 am)
Put print's in there, and examine the output packet by packet until you start to get the wrong values. Use a basic file which is easy to recognize by looking at the content and you'll figure out where the length is getting screwed.
#15
10/04/2008 (6:26 pm)
BAH I just removed the blasted code and am doing a different post. Not getting mucfh help here and my constant editting the code is just screwwing things up.