XMODEM is a simple file transfer protocol developed as a quick hack by Ward Christensen for use in his 1977 MODEM.ASM terminal program. It allowed users to transmit files between their computers when both sides used MODEM. Keith Petersen made a minor update to always turn on "quiet mode", and called the result XMODEM.
XMODEM, like most file transfer protocols, breaks up the original data into a series of "packets" that are sent to the receiver, along with additional information allowing the receiver to determine whether that packet was correctly received. If an error is detected, the receiver requests that the packet be re-sent. A string of bad packets causes the transfer to abort.
XMODEM became extremely popular in the early bulletin board system (BBS) market, largely because it was simple to implement. It was also fairly inefficient, and as modem speeds increased, this problem led to the development of a number of modified versions of XMODEM to improve performance or address other problems with the protocol. Christensen believed his original XMODEM to be "the single most modified program in computing history".
Chuck Forsberg collected a number of common modifications into his YMODEM protocol, but poor implementation led to a further fracturing before they were re-unified by his later ZMODEM protocol. ZMODEM became very popular, but never completely replaced XMODEM in the BBS market.
Packet structure
The original XMODEM used a 128-byte data packet, the basic block size used on CP/M floppy disks. The packet was prefixed by a simple 3-byte header containing a <SOH> character, a "block number" from 1-255, and the "inverse" block number—255 minus the block number. Block numbering starts with 1 for the first block sent, not 0. The header was followed by the 128 bytes of data, and then a single-byte checksum. The checksum was the sum of all 128 data bytes in the packet modulo 256. The complete packet was thus 132 bytes long, containing 128 bytes of payload data, for a total channel efficiency of about 97%.
The file was marked "complete" with a <EOT> character sent after the last block. This character was not in a packet, but sent alone as a single byte. Since the file length was not sent as part of the protocol, the last packet was padded out with a "known character" that could be dropped. In the original specification, this defaulted to <SUB> or 26 decimal, which CP/M used as the end-of-file marker inside its own disk format. The standard suggested any character could be used for padding, but there was no way for it to be changed within the protocol itself – if an implementation changed the padding character, only clients using the same implementation would correctly interpret the new padding character.
Transfer details
Files were transferred one packet at a time. When received, the packet's checksum was calculated by the receiver and compared to the one received from the sender at the end of the packet. If the two matched, the receiver sent an <ACK> message back to the sender, which then sent the next packet in sequence. If there was a problem with the checksum, the receiver instead sent a <NAK>. If a <NAK> was received, the sender would re-send the packet, and continued to try several times, normally ten, before aborting the transfer.
A <NAK> was also sent if the receiver did not receive a valid packet within ten seconds while still expecting data due to the lack of a <EOT> character. A seven-second timeout was also used within a packet, guarding against dropped connections in mid-packet.
The block numbers were also examined in a simple way to check for errors. After receiving a packet successfully, the next packet should have a one-higher number. If it instead received the same block number this was not considered serious, it was implied that the <ACK> had not been received by the sender, which had then re-sent the packet. Any other packet number signalled that packets had been lost.
Transfers were receiver-driven; the transmitter would not send any data until an initial <NAK> was sent by the receiver. This was a logical outcome of the way the user interacted with the sending machine, which would be remotely located. The user would navigate to the requested file on the sending machine, and then ask that machine to transfer it. Once this command was issued, the user would then execute a command in their local software to start receiving. Since the delay between asking the remote system for the file and issuing a local command to receive was unknown, XMODEM allowed up to 90 seconds for the receiver to begin issuing requests for data packets.