This is a file transfer protocol which works in a novel manner. The order of the transfer of the file's parts is irrelevant. This protocol works best on very noisy connections. THEORY: ------- Note: Section means any portion of a file, from the whole thing to a 1-byte piece of it. A section is denoted by a starting and ending byte offset in the file (starting with 0). The receiver works by holding a linked list of remaining sections in memory. Receiver builds table of missing section of file in memory. Initially this has one entry, the whole file starting at byte 0. As sections are received, the table is updated appropriately. If the next section of file expected was received, then the current section's linked list entry is modified appropriately. If some section of the file was skipped, then null bytes are written to it, and the current section's linked list entry will be split into two, to reflect the section remaining behind which needs to be resent. We may keep building the table in memory until file is done (in which case we ask for retransmissions of any remaining blocks) or until memory is full (in which case we do exactly the same thing!). THE PROGRAMMING: ---------------- For simplicity, a file will always be sent in each direction. This way the errorcodes can be restricted to just a set of four for file-transferring failure combinations. A "dummy" file can be sent for each side that doesn't need to send a file; it shouldn't be difficult for any calling software to arrange this. Each program has 2 variables, done_sending and done_receiving, which are set to 'Y' when their respective actions have been completed. The receiver should be in control of the transfer from start to finish, meaning that the only role of the transmitter is to supply those data sections which are requested of it. The receiver basically decides what sections it wants sent to it and sends out all the requests for those sections that it can. This also contributes to dissimilar-version-compatibility, since the transmitter's operation should be fairly unvarying from version to version. Since the outgoing (transmit) buffer gets full of these requests, even unto the end of the file, then one buffer's worth of time will be wasted at the end of each file; this is something to work on later to prevent wasting this amount of time for every transfer. Each program's state is held in a variable of one character. Usually it will be the packet type the program is waiting for (with a timeout?). The programs will progress from the 'i'nformation state, upon receipt of the requested 'i'nformation packet from the other end, to the 'd'ata state (waiting for requested data packets). When an entire file is received, the program sends 'e'of packets and goes into the 's'uccess state waiting for a 's'uccess acknowledgement from the other end (the file's transmitter). This is when the transmitter's done_sending variable should be updated (and both variables checked). At this point, if the other end is already done, we can start the exit procedure. If not, we go into an 'e'of wait, waiting for an 'e'of packet from the other side. This wait should time out, but the timeout should be reset each time a request from the other end is satisfied, because that means it's still busy doing _something_, and so the connection's still good. This means it's the responsibility of the receiver to quit a session if it thinks it's not productive! Each side will, whatever state it is in, alternate between checking and satisfying any requests from the other side and making its own requests. Nothing will stop either side, therefore, from filling up its transmit buffers with outgoing requests; we assume they'll most all have to be satisfied before it's all over with anyway. In fact, even when there's just one request outstanding, it should be repeated endlessly until satisfied. Remember that this entails at least a buffer's worth of time delay when each file is done. When one side is done (has gotten all of a file), it sets its done_receiving variable to 'Y' and starts sending 'e'of packets to the other side so that the other side will know to set its done_sending variable to 'Y'. The other side should respond with 's'uccess packets until the first side is happy. The fact that the other side might still be requesting and receiving file sections should not keep it from responding to the 'e'of packets with 's'uccess packets within a reasonable amount of time (the long timeout, actually). When each program starts, it begins to ask which file the other side wants to send with a packet type of 'b'. The incoming file name can, of course, be superseded from the command line. The other side should reply with a file 'i'nfo. packet containing information on the file it wants to send. Whenever an end sets an action variable, it should check the other variable to see if it is already 'Y'. If so, it starts the exit sync sequence: it sends a 'X'(0) packet (one per second, actually). It then waits for any 'X'(1) packets, which would indicate that the other end understands the exit sequence has started. During this time, it is also required to increment any 'X' packets it gets from the other end. It is in the 'X' state, sending out 'X'(0) packets and waiting for 'X'(x) packets. The other end, upon receiving any 'X'(0) packets, increments them to 'X'(1) packets and sends them back. The packets should go back and forth this way, originated by one side or the other (or both at the same time) until one side or the other receives an 'X'(2) packet. When any side receives a 'X'(2) packet, it sends back lots of 'X'(3) packets and then immediately exits. The other side should see one or more of the 'X'(3) packets and then exit. Even if it doesn't see any 'X'(3) packet(s) it should still exit with a success indication after the usual timeout. This approach guarantees that the modems will try to exit-sync for at least the long timeout amount of time. Look at the 'X'(3) packets as a way for one side to tell another side to exit _right away_. It may be processing some previously-sent packets or something, but it should finish and exit either because of a received 'X'(3) or a timeout. The 'X' state should only be tolerated for the long timeout. Something has _got_ to happen by then, or something's wrong. If the carrier should be lost or the transmission otherwise interrupted, the exit code should reflect appropriately: 1 for incoming file lost, 2 for out- going file lost, 3 for both files lost. If the transfer is successful both ways, then both programs exit with 0. Only in the unlikely event of communications loss during file acknowledgement will the different sides disagree as to file transfer successes. Bad arguments or configuration-type problems should return an errorlevel of 4. Aborting the transfer on either end should produce errorcode 5.