VOGONS

Common searches


First post, by veelstekel

User metadata
Rank Newbie
Rank
Newbie

Hi!

I was wondering, would it be possible to change SoftMPU to support RAW UDP support on top of Serial support.
I noticed that it is rather difficult to get USB to Serial adapters working due to different specific vendor implementation. (https://www.mail-archive.com/freedos-user@lis … t/msg21976.html)

However packet drivers seem quite universal and readily available for DOS for a lot of network cards.

Allowing UDP traffic would enable someone to link their laptop with a simple UTP cable directly to mt-32pi as this supports RAW UDP sockets: https://github.com/dwhinham/mt32-pi/wiki/Netw … ing%3A-UDP-MIDI. (Power could then be provided to the mt-32pi with USB)

This enables quite some netbooks with limited ports to still get the benefits for external MIDI devices and would also solve the different BAUD rates between Serial and Midi.

Any thoughts? 😉

Reply 1 of 19, by veelstekel

User metadata
Rank Newbie
Rank
Newbie

Ok, I am new to the entire C, ASM and C++ programming; but thought I would give it a go to see if would be able develop something like this.

So far I am successfully able to compile both SoftMPU and mTCP (http://brutmanlabs.org/mTCP/) from source.
However I have noticed:
- SoftMPU and mTCP both use different compilers;
- SoftMPU compiles with Microsoft C 6.0A & MASM 6.11
- mTCP uses Watcom 1.9
- SoftMPU is written in C, whereas mTCP sample applications are written in C++

Newbie question: Is it feasible to integrate these two projects or should I abandon this and will mTCP never work in C projects?

Reply 2 of 19, by mbbrutman

User metadata
Rank Member
Rank
Member

Have you read the mTCP developer documentation?

mTCP basically *is* a C project and it would be trivial to make it compile with a pure C compiler. While technically the mTCP code is mostly in C++, it closely resembles C code. The classes are mostly used to enforce some encapsulation so that you use the public functions to do things, which is a good practice. I can write objected oriented code in assembler or garbage in C++; look at the coding style, not the name of the compiler.

Also, for implementing UDP you could want to cut a significant portion of it out. (You don't need all of mTCP for what you are planning.)

Given that SoftMPU is what you are trying to enhance, start with that source code and developer environment and add UDP to it. Use/borrow whatever mTCP UDP code that you need, but think of it less as merging two projects and more of borrowing some code from mTCP or using it as a reference on how to do UDP.

Lastly, there is a mailing list for mTCP questions and discussions - check the home page for how to join it. I'll always answer questions here but the mailing list is probably a better resource for mTCP specific things long term.

Reply 3 of 19, by veelstekel

User metadata
Rank Newbie
Rank
Newbie

Thank you for your reply!

In the meanwhile I have taken a crashcourse C, and went further into the rabbit hole of TCP/IP in DOS based on your documentation references.
However C doesn't seem to be the issue; I am sure code-wise it would not be that difficult. The real challenge will come from compiling and linking code in DOS. (There seems to be very little documentation from the DOS era)

Based on your comments I am now doubting if mTCP is not overkill for what I am trying to accomplish 😉
At the moment two libraries come to mind:

mTCP
Pro:
- Well documented
- Maintained
- Many FreeDos utilities based on mTCP
Delta:
- Might be overkill for what I am trying to accomplish

WattTCP (Or Watt32)
Pro:
- Freedos applications are already making use of it (Arachne) etc. And is preconfigured
- Seems to be lightweight; comes with with 3 Libraries for 3 different memory models
- Comes with sample UDPSEND.C; which seems to be all the code I need to add to SOFTMPU
Delta:
- Poorly documented (there seems to be a guide available to buy, but cannot find the link. and others complaining that even with guide it is still challenging)
- Unsure if the WATTCP BC4.5 libraries can be used with Microsoft C 6.0A;
- Unable to find documentation on Microsoft C 6.0A (especially with commandline switches to CL.EXE etc.)

Analyzing the Source Code of SoftMPU my guess is I only need to modify slightly the orange part; and implement the green part.
But being new to DOS/C/C++/ASM programming I am open for suggestions 😉

Attachments

Reply 4 of 19, by mbbrutman

User metadata
Rank Member
Rank
Member

I'm not an expert on all of the different compilers and toolchains in DOS and I prefer to keep things simple by sticking to one toolchain at a time. However, there are a few calling conventions and most of the compilers can be made to choose between their default and others. For example, I know that the Watcom compiler that I use can generate code that can be linked with Microsoft tools. I think. ;-0 There are a lot of details though.

Rather than trying to mix and match toolchains it is easier to port the pieces of code that you need to the other compiler. mTCP initially started with Turbo C++ but after a few years I decided to move to Open Watcom. For a while I tried to keep things compiling under both compilers but that was a lot of work, especially when I was having to use inline assembler to speed things up. Most of the code is C++ that looks like C so if you "undo" my assembler optimizations and get back to the C++ or C code, it should be very portable to other compilers.

Some specific observations on your last reply:

  • FreeDOS ships mTCP but that is about it. The networking enabled FreeDOS package manager is actually using WATT32.
  • While I don't ship pre-compiled libraries with mTCP, that's actually a good thing. Mixing and matching compilers and toolchains is troublesome; I prefer the porting approach described above, especially for smaller amounts of code. And that also allows you to choose the memory model; mTCP programs can support all of the DOS memory models. I've never bothered with the HUGE model but I know that all of the others work.
  • I use a lot of #defines to allow you to add or strip out features that you don't need.

For your project you'll need some of my packet layer code to interface with the packet driver and the Ethernet, IP and UDP includes and code. A lot of it can be cut out:

  • You don't need any of the IP fragments code, and there is a lot of code there.
  • There are two UDP send functions, one that requires the caller to reserve space for the Ethernet and IP headers and one that does not but uses malloc instead. Use the first variant for space and performance reasons.
  • Anywhere you see a function call to the C runtime library try to get rid of it. Things like memcpy can easily be replaced with your own local function. The idea is to have pure C code that runs with a minimum amount of support from the C runtime library - just like assembler code.
  • Strip out the tracing code, the timer hook and management code, etc. Tracing is nice but it takes up space so remove it if you can. The timer management code was needed for TCP retry support and general time keeping, but you won't need it on something this small.

As a starter exercise, start with the mTCP code and the Netcat program. Convert Netcat to send UDP packets instead of opening an TCP/IP socket. Then start stripping *everything* you can. Once you get to the bare minimum that is enough to send a UDP packet with minimal calls to the C runtime library you are ready to port that code to the other compiler and integrate it with SoftMPU.

Reply 5 of 19, by veelstekel

User metadata
Rank Newbie
Rank
Newbie

Thanks for your suggestion! I am taking up the challenge for the starter exercise 😉

On the host I am running ncat -ul 4444

I am at least able to send "some" data to the UDP port with the first modified code; however the application hangs and on the host I get the error:
Ncat: A message sent on a datagram socket was larger than the internal message buffer or some other network limit, or the buffer used to receive a datagram into was smaller than the datagram itself.

On the client the Udp::sendUdp returns a value of 1; (thus it seems related to something with ARP resolution from the docs)

But this is only the first try, I'll keep on tinkering 😉

Reply 6 of 19, by digger

User metadata
Rank Oldbie
Rank
Oldbie

A while back, I was toying with a similar idea, but for digital sound playback. Having a sound driver (or SB emulator?) that outputs sound in a PCM (RTP?) stream through TCP/IP, preferably in a format that would be compatible with PulseAudio or Pipewire, allowing sound to be streamed to and played back on either another PC running Linux, or on an underlying hypervisor, if DOS were running as a VM guest.

Reply 7 of 19, by veelstekel

User metadata
Rank Newbie
Rank
Newbie

Interesting thought; in the past I remember we used to tunnel the sound through RS232; with 15k2 we could get audible sound. But it sounds doable; especially with UDP since it doesn't matter if you would lose some packets.
Might me something for the SBEMU project.

Btw I have received my UDP message from DOS (hooray!)
veelstekel@raspberrypi:~ $ nc -lu 4444
Test 123!

Now it's time to start stripping.
However this netcat listen only works with a Linux host; the ncat.exe provided with NMAP on windows still gives me this error: "Ncat: A message sent on a datagram socket was larger than the internal message buffer or some other network limit, or the buffer used to receive a datagram into was smaller than the datagram itself." - Anyone some clues on this? Safe to ignore and just move to a Linux host for listening on the UDP socket?

Reply 9 of 19, by veelstekel

User metadata
Rank Newbie
Rank
Newbie

Thanks for taking the time! Here is the butchered code 😉 / it's very rough.
I run it using nc -target 192.168.2.2000 4444 < test.txt

Line 392 is the actual code to send the packet: int16_t rc = Udp::sendUdp( serverAddr, LclPort, ServerPort, bytesToSend, fileReadBuffer, false);

I think that after I have sliced all the code I do not need (but please confirm; as I am no TCP expert):
- DHCP (I think I can use a random source IP address; as UDP is stateless and doesn't need to return data anyway)
- ARP (If I hardcode the destination MAC address I think I can skip this as well; a little like etherwake);
Also I do not need to respond to any ARP messages as well; as the target will send nothing back
- The entire handler hook (no incoming traffic, thus no hook required)

In the end only one prefab Ethernet packet is required to play a note I guess.

Attachments

Reply 10 of 19, by mbbrutman

User metadata
Rank Member
Rank
Member

I'm pretty sure you tried blasting a UDP packet out that was 8192 of data plus the IP and UDP headers. That's a no-no, as I don't know of any packet driver that handles jumbo frames.

The code that you commented out limits the number of bytes being sent to what can fit in a given Ethernet frame and MTU size. Try sending smaller, fixed chunks instead - 1400 bytes should work for your experiment.

Reply 11 of 19, by veelstekel

User metadata
Rank Newbie
Rank
Newbie

Thanks! That would explainthat it works listening on the PI; probably the switches / routers will reduce the message in transit. Whereas the Windows listen was on the host itself, and thus probably received the entire message.

Just to confirm though, I was under the impression that function Udp::sendUdp would only send payloadLen bytes.
What is the purpose of passing the payloadLen parameter? Is this only used to check if UDP fragmentation is required?

Reply 12 of 19, by mbbrutman

User metadata
Rank Member
Rank
Member

You need to tell it how many bytes you are sending because the UDP packet needs to have the length in it. It's not like sending an ASCIIZ string where you can compute it; it has to be explicitly set.

While switches and routers might fragment the packet that is not a guarantee and you want to avoid it. Fragmentation is a real pain to deal with and the fragmentation code in mTCP is very lightly tested and probably not used very often, so I wouldn't expect it to be bug free.

(I'm thinking my UDP code should have fragmented the packet, so sending a large packet should not have been a problem. Except for bugs ...)

Reply 13 of 19, by Jo22

User metadata
Rank l33t++
Rank
l33t++

That's why I liked X.25/AX.25, it's packet-oriented and ASCII friendly..

"Time, it seems, doesn't flow. For some it's fast, for some it's slow.
In what to one race is no time at all, another race can rise and fall..." - The Minstrel

//My video channel//

Reply 14 of 19, by mbbrutman

User metadata
Rank Member
Rank
Member

Picking up an old thread ...

In the time between my last reply on this thread and now I've figured out how to reliably send and receive UDP packets from device driver code through a packet driver. UDP wasn't easy, but it's much easier than TCP. The code is readily adaptable to a TSR.

For this project:

  • Besides working around the USB to serial problem, are there other advantages to UDP? Would it enable better sound because you can send more bytes? (Given that we are talking about MIDI I don't think that throughput is an issue here.
  • There might be some corner cases where this is not true, but in general it would require SoftMPU to have exclusive use of the network card. (i.e.: No sharing with the running program.) Is that going to cause different problems?

Reply 15 of 19, by veelstekel

User metadata
Rank Newbie
Rank
Newbie
mbbrutman wrote on 2024-01-01, 19:37:

Besides working around the USB to serial problem, are there other advantages to UDP? Would it enable better sound because you can send more bytes? (Given that we are talking about MIDI I don't think that throughput is an issue here.

A couple of advantages:
- USB To Serial is indeed one; there are a many different USB Serial hardware; and though some drivers exist (http://www.dosusb.net/dosusb.pdf) it is not standard (and these also do not work with SoftMPU).
- Ability to put the MIDI receiver anywhere in the network (wireless); thus perhaps even next to your Sonos Soundbar for instance.
- More bytes should not be an issue; most midi commands are general small (With some SysEx instrument uploads as an exception); but for MT32 I don't see any advantages here.
- I would like to have one DOS companion box (probably PI based) connected with one cable to the DOS machine providing:
PXE Booting (Allowing also for a uniform PXE packet driver)
Virtual Harddisk / Floppy (Based on your new UDP Disk software; or perhaps even RetroNAS)
MT32 / Midi Capabilities
Wireless Router / Firewall (Giving DOS wireless network card)
Dos browser proxy (Thus converting new websites to Arachna capable functions)

mbbrutman wrote on 2024-01-01, 19:37:

There might be some corner cases where this is not true, but in general it would require SoftMPU to have exclusive use of the network card. (i.e.: No sharing with the running program.) Is that going to cause different problems?

Hmmm, is this correct? I actually believe it could run side by side; as sending doesn't require passing a handle I believe.
Based on our previous discussion where mTCP would be overkill for this project; I dived into the etherdfs source code [https://sourceforge.net/projects/etherdfs/] ; I think I can get away with only sending one ethernet frame.

The packet driver specification doesn't require a handle for sending frames:
(http://crynwr.com/packet_driver.html)

6.6. send_pkt() int send_pkt(buffer, length) AH == 4 char far *buffer; DS:SI unsigned length; CX […]
Show full quote

6.6. send_pkt()
int send_pkt(buffer, length) AH == 4
char far *buffer; DS:SI
unsigned length; CX

error return:
carry flag set
error code DH
possible errors:
CANT_SEND

non-error return:
carry flag clear

Although getting the source mac-address does require a handle, I think a spoofed address can be fine; thus I am trying to create a simple ethernet packet with:
- Source MAC: MPU401 (Converted to HEX)
- Source IP: M401 (Converted to Ascii)
- Source Port: 1999
- Destination MAC: FF:FF:FF:FF:FF:FF (To allow for zero configuration and broadcast to all MT32pi devices on the network)
- Destination IP: 255.255.255.255
- Destination Port: 1999
In theory this should work; but probably not in VM's as it will only pass packets with the Real Source MAC.

Anyway currently this project is lower in priority; as I found out SoftMPU does not work in protected mode games; thus first to solve:
- use open tools to compile softmpu (https://github.com/bjt42/softmpu/issues/32)
- allow softmpu to work with protected mode games (https://github.com/bjt42/softmpu/issues/31)

And my C skills are too poorly; I tried copying the etherdfs send_query function and change SoftMPU; unfortunately the result crashed.
I cannot get debug messages as the TSR doesn't allow for the printf functions 😉

Thus currently I put it back on my backlog

Reply 16 of 19, by mbbrutman

User metadata
Rank Member
Rank
Member

That was the corner case I was referring to. The actual limitation has more to do with the packet driver can only be given one receiver function for a given set of EtherTypes. So while any code anywhere can send just by using the packet driver interrupt, only one receiver function can be called for an ARP or IP frame, and that's the real sharing limitation.

The way around not knowing the MAC address is to run a small utility program that connects to the packet driver first, grabs the MAC address, and puts it in a well known location that the later code can then find. I do this with the mTCP NetDrive code. (The device driver is in memory long before the packet driver; the utility program wires them together.)

Reply 17 of 19, by maxtherabbit

User metadata
Rank l33t
Rank
l33t
mbbrutman wrote on 2024-01-02, 17:29:

That was the corner case I was referring to. The actual limitation has more to do with the packet driver can only be given one receiver function for a given set of EtherTypes. So while any code anywhere can send just by using the packet driver interrupt, only one receiver function can be called for an ARP or IP frame, and that's the real sharing limitation.

The way around not knowing the MAC address is to run a small utility program that connects to the packet driver first, grabs the MAC address, and puts it in a well known location that the later code can then find. I do this with the mTCP NetDrive code. (The device driver is in memory long before the packet driver; the utility program wires them together.)

well since MIDI (in the gaming context anyway) is write-only, that shouldn't be a limitation at all

Reply 18 of 19, by veelstekel

User metadata
Rank Newbie
Rank
Newbie

Quick question though; from this thread: Simplest way to mount SAMBA share on DOS with packet driver and mTCP it seems that EtherDFS was used in combination with mTCP ftp at the same time... (Puzzled now...)

Reply 19 of 19, by mbbrutman

User metadata
Rank Member
Rank
Member

No need to be puzzled ...

The packet driver spec has you register a handler for each packet type you are interested in. EtherDFS does not conflict with IP or ARP, so you can have two different handlers. But if EtherDFS used IP that would not be possible.