DOSBox modem emulation

From Vogons Wiki
Revision as of 13:46, 10 October 2024 by Hornpipe2 (Talk | contribs) (Note on listenport:0 behavior)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Quick Overview

DOSBox supports a (roughly) Hayes-compatible modem emulation, connected over serial port(s) COM1-COM4. Modem traffic is routed over a TCP/IP connection, managed by the host. In this way one DOSBox can "call" another, and traffic sent from one "modem" is passed over TCP/IP internet to be received by the "modem" in the second emulator.

To attach a modem to a serial port, edit dosbox.ini and within the [serial] section, set one (or more) lines as serialN=modem where N is the COM port number. There is only one configuration option, listenport:XYZ where XYZ is the TCP port number to listen for incoming connections. (It also defines the default destination port when making calls). So for example serial1=modem listenport:5000 adds a virtual modem on COM port 1, listening for connections to port 5000.

When a modem is attached, DOSBox will open a TCP port to "listen" for calls on the listenport (default 23, i.e. "telnet"), unless listenport is set to 0 (disabled). It also enables dialing out to other machines.

To "dial" another computer, enter the IP address as a 12-digit phone number. By default the destination port is the same as the listen port. You can change this by adding the port after the 12 IP address digits. For example, calling 192.168.10.99 port 2323 uses the phone number 1921680100992323. DOSBox also supports "dialing" hostnames, but most UIs for diallers don't let you put non-digits in.

The modem code is found in src/hardware/serialport/softmodem.cpp.

Details

A Brief History of Modems

Physical modem-to-modem connection

A "modem" is a device for translating binary data (say, from a serial port on a computer) into sound waves and sending these noises over the public telephone system - where another modem can reverse this translation i.e. turn sound back into binary data. When the two modems had a circuit established between them, they could do this communication, but the phone setup portion (dialing numbers, answering calls, negotiating speeds etc) was a manual process for some time. For example the human operator would call a number on a regular phone, then set the handset on the "acoustic coupler", and let the modem start "talking". To hang up, the user physically took the phone away and placed it back on the hook.

All this changed in 1981 with the release of the Hayes SmartModem. This was a device that connected to a microcomputer via RS-232 standard serial port, and the phone line at the other end. The computer could send commands to the modem to control things ("dial this number", "set the speed", "hang up", "answer the call" etc) and the modem handled the interface to the phone line by itself. There were a few innovations at work here but one was digital control of the modem via normal serial comms using a semi-standard set of predefined commands. And because it was an external serial device, it was computer-agnostic: no drivers needed, the same modem worked for Apple II, IBM PC, etc.

In fact this system was so popular, and so successful, that a number of clone modems using the same Hayes command set were developed. The idea was, you could swap the modem plugged into your serial port for a faster one (or cheaper, or w/e) and the same commands would still work to dial BBSes or whatever.

Later as Windows and the PC platform became dominant, modems became internal devices, and much of the functionality they previously provided was intergrated into drivers running on the host CPU. Many early Linux users remember well the pain of being stuck with a "WinModem", a virtually useless device without the manufacturer's proprietary Windows-only device driver.

DOSBox emulates (some sort of) Hayes-compatible modem, attached to COM port(s). MS-DOS talks to this modem as any other RS-232 character device: open the port, send commands for the modem, tell the modem to dial someone, then drop into "data" mode and everything you send to the modem goes out the phone line. Again, remember there's two modes to the modem - "command mode" (whatever you send instructs the modem) and "data mode" (whatever you send goes out the phone line).

A complete list of supported Hayes commands is in a table, below.

Look ma, no Bell!

DOSBox virtual modem-to-modem connection

Great, so, how does one emulate a "phone modem" without a phone line? DOSbox does this by routing all "data mode" traffic (i.e. anything, digital, that the modem is supposed to send) over the TCP/IP network (ethernet, etc) protocol instead.

When DOSBox starts with a virtual modem attached, it attempts to open a TCP server on the listen port, anticipating commands from a remote server. By default, the listen port is 23 (Telnet). This might cause problems on Unix-based systems as opening a port below 1024 normally requires root access. 2323 is a suitable alternative port number. Also, setting listenport to 0 prevents opening a listen socket at all, but you can still make "calls" out.

When the modem wishes to make a call, DOSBox opens a new connection to a remote TCP IP and port, as specified in the ATDT dial string. As mentioned above, you can "dial" a hostname, but if the program accepts only numbers then you dial a 12-digit IP address (no dots). Extra digits beyond the 12 are read as a destination port: this lets you connect to something other than the default listenport.

When receiving a call (TCP connection request) the virtual "ring indicator" goes off, and if the program is looking for this signal one of two things happens:

  • The game / program may automatically "answer" on the first call, and establish connection immediately.
  • Or, the game may tell you a call is coming, and you must choose to "answer" it yourself.

Now you're connected and both in "data" mode, allowing the programs to communicate with each other.

Getting Online

Physical modem-to-Internet connection

A modem that calls another modem is enough for things like a 1v1 game of Warcraft or DOOM, or the ability to call a BBS. Indeed, with all four COM ports set to a modem on a different listen port, one could emulate a 4-line BBS server and accept "calls" from up to four users simultaneously.

But getting connected to the global Internet requires dialing into an ISP. The ISP has banks of modems and a network connection to the wider Internet. Your modem dials one of the ISP modems, then your computer needs to speak a special protocol to the ISP so that its packets can be routed to the IP-based internet. This is generally SLIP (for permanent / dedicated lines) or more often PPP (for pooled lines like AOL or whatever). Once your computer has logged into the ISP then they bridge you to the Internet and the packets may flow.

MS-DOS and Windows 3.1 mostly pre-dated the dial-up Internet age, but not quite: there was a brief window of time between users wanting to call ISPs, and the release of Windows 95 which included built-in support for TCP/IP stack, and a modem dialler program with PPP support.

So to make it work in this old environment, you need certain things:

  • Winsock (Windows sockets), the API for network programming in Windows. Windows for Workgroups ships with winsock libraries but only IPX/SPX and Netbios, not helpful for the internet. So you must add...
  • A TCP/IP stack. There is an optional addon available from Microsoft "TCP32b". But note that WfW expects network cards instead of modems....
  • so you need a dialler too, which can command modems to connect to things, as well as handle PPP / SLIP. There is a dialler for Windows 3.1 that comes with early Internet Explorer versions... but it is incompatible with network cards too. I think.

Given the messy state of all this, what people did instead is use a third-party Winsock system to provide all the components to get online. By far the most popular was Trumpet Winsock, latest version 3.0d. It's shareware but it has TCP dial-up support.

The last piece of the puzzle is: you can now "dial" an ISP, but where do you find one for your virtual modem? If you're a *nix user, you provide it yourself, using something like pppd or slattach to route your incoming virtual phonecall through the host machine's network stack and onto the Internet. Windows users, tbd :)

The Emulated Modem

Some details on the modem emulation follows.

The modem supports signals for Carrier Detect, Ring Indicator, and also DSR (Data Set Ready) and CTS (Clear To Send). This means you can / should set your app to use "hardware flow control".

The modem always claims 57600 baud on CONNECT, but there is really no rate limiting applied to the virtual connection. Data is sent at the speed the host can process it.

Real Hayes modems allowed multiple commands issued in a single AT command, but DOSBox's modem is inconsistent in handling these (some commands like ATD and ATNET stop processing). Recommend to issue an AT command for each change you want to make.

This set of Hayes AT modem is understood by the modem:

Modem command
Command Meaning
NET0 / NET1 Disable or enable "telnet mode". When enabled, the modem will interpret Telnet commands read on the serial port. This may help when using the modem to call a BBS or Unix machine directly, but generally interferes with other games and applications.
DT / DP Dial a host or IP. The function accepts hostname:port, IP:Port with dots, or 12-digits for IP (plus 5 more for port). ATDT means "tone dialing" and ATDP "pulse", but there is obviously no difference for a virtual modem.
I3 / I4 Get modem info. The ATI command should have a number indicating which info you want. Only types 3 (get firmware version) and 4 (get DOSBox version) do anything.
E0 / E1 Disable or enable local echo. When enabled, the modem prints the commands back to the user as they're read in.
V0 / V1 Set "numeric" or "verbose" result codes. When in numeric mode, number codes are returned after each command to indicate success / error. In Verbose mode, English words and phrases are returned instead ("CONNECT", "NO CARRIER" etc)
Q0 / Q1 Disable or enable "quiet mode". When enabled, no result codes are returned at all.
H Hang up the phone (disconnect TCP connection)
O Return to "data mode" - if you've gone back to "command mode" with +++ mid-session, ATO will resume the data session again.
T / P Specify "tone" or "pulse" dialing. These have no effect on the virtual modem.
M / L Set "monitor" or "volume" of the speaker (needs a number parameter e.g. ATL3) Hayes modems had a speaker that played the phone audio, which users could monitor their connection by. DOSBox does not emulate modem sounds; these have no effect.
A Answer an incoming call.
Z Hard reset the modem to initial state. This disconnects any call. The command may have a number following, which would specify a "profile", but DOSBox modem does not have multiple profiles.
S Modify register. The modem has several numbered "S registers" that control behavior. The user may query a register with S?12 ("return the value of register 12"), and SET a register with S12=5 ("SET register 12 to value 5"). A list of supported S-registers is below.
&K Set flow control (values 0-5 accepted). Only type 3 really does anything (enable CTS/RTS flow control).
\N Set error correction. Values 0-5 are accepted, but DOSBox does not emulate error-control, so these do nothing.
Modem S-registers
Register Description Range Default value
S0 Number of rings before Auto-Answer 0–255 (0 = never) 0
S1 Ring Counter 0–255 rings 0
S2 Escape character 0–255, ASCII decimal 43 ("+")
S3 Carriage Return Character 0–127, ASCII decimal 13 (Carriage Return)
S4 Line Feed Character 0–127, ASCII decimal 10 (Line Feed)
S5 Backspace Character 0–32, ASCII decimal 8 (Backspace)
S12 Escape Code Guard Time 0–255 fiftieths of a second 50 (1 second)