QDOS TCP/IP programming in Assembler

Anything QL Software or Programming Related.
Martin_Head
Aurora
Posts: 853
Joined: Tue Dec 17, 2013 1:17 pm

QDOS TCP/IP programming in Assembler

Post by Martin_Head »

Has anyone done any programming of the QDOS TCP/IP device driver in assembler, or know where I can get some sample assembly code that works, so I can try to figure out exactly how to call the system Traps.

I really don't know anything about programming TCP/IP ports, So I am learning as I go.

I've got some information written by Richard Zidlicky which gives the names of the system Traps and information on the register usage when calling them. But it is all very 'C' orientated (which I don't speak).

I can find lots on TCP/IP and socket programming on the Internet, but it's all in 'C' and nothing in assembler . I've managed to figure out what most of the QDOS Traps should do, but when I try to use them, they either don't do what I expect, give errors (but I don't know what went wrong, or what I did wrong), or they seem inconsistent in their operation.

Every time I think I'm starting to understand how the driver works, it all seems to fall apart. And at the moment all I seem to be doing is taking one step forward, and two steps back.

Thanks in advance
Martin


User avatar
tofro
Font of All Knowledge
Posts: 2702
Joined: Sun Feb 13, 2011 10:53 pm
Location: SW Germany

Re: QDOS TCP/IP programming in Assembler

Post by tofro »

Martin,

I've done a lot of TCP/IP socket programming in the past, both hobby and professional - But I have never even tried to do that in assembler. There's just too many data structures to tame in order to do even simple things......

I would propose you should acquire at least a minimum amount of C literacy before you start reading examples (not necessarily trying to write programs, but you should be able to read them. That shouldn't be too hard.

Once you're there I recommend a good book (for example W. Richard Stevens: Unix network programming - Prentic Hall - This is the TCPIP socket bible.) There's also some good, some bad and some ugly free C Socket programming tutorials on the internet - But a book is better, IMHO.

Then you could start translating C examples into assembler.

Or - you just come up with some hands-on examples and ask questions I could probably answer.

Tobias


ʎɐqǝ ɯoɹɟ ǝq oʇ ƃuᴉoƃ ʇou sᴉ pɹɐoqʎǝʞ ʇxǝu ʎɯ 'ɹɐǝp ɥO
User avatar
XorA
Site Admin
Posts: 1368
Joined: Thu Jun 02, 2011 11:31 am
Location: Shotts, North Lanarkshire, Scotland, UK

Re: QDOS TCP/IP programming in Assembler

Post by XorA »

I would just bite the bullet and learn C. Should only take about 20 minutes for any competent programmer, there are only 20 keywords :-D Also old school C compilers are pretty predictable about the assembler produced.

G


stevepoole
Super Gold Card
Posts: 716
Joined: Mon Nov 24, 2014 2:03 pm

Re: QDOS TCP/IP programming in Assembler

Post by stevepoole »

Are there any skilled 'C' programmers in the Ql Community?
How long does it take to learn the 'C' language enough to be able to transpose superbasic into 'C'?
EmmBee and I are looking for such a programmer too, as we need to submit a new 'Travelling Salesman Program' to the Clay Mathemeatics Institute, for consideration as a solution to the problem.
Of course we could always suggests that the Institute aquires QPC2, but that would eliminate all means of comparison with existing programs attempting to solve the problem...
Has anyone any ideas or suggestions please?
Regards,
Steve Poole.


Martin_Head
Aurora
Posts: 853
Joined: Tue Dec 17, 2013 1:17 pm

Re: QDOS TCP/IP programming in Assembler

Post by Martin_Head »

Thanks for the response, but I don't really want to go to the trouble of learning C and a compiler for it, just for playing with the IP driver in QDOS.

Besides at some point, would I not have to write something in C/Assembler to actually call the QDOS Trap routines. Say I wanted to use the sendto() function. Wouldn't I have to write the function (or whatever it's called in C) to set up the registers and call the IP_SENDTO Trap#3. Which kind of brings me back full circle at having to access the system Traps directly again.

Unless these routines have already been written? I did find something called, I think it was QLIP , a C program, which I had a quick look at, but I think it may be the code for the QDOS IP driver (or an earlier version of), which converts the QDOS system Trap call to a C system call for the QL emulators underlying operation system.

Martin


User avatar
tofro
Font of All Knowledge
Posts: 2702
Joined: Sun Feb 13, 2011 10:53 pm
Location: SW Germany

Re: QDOS TCP/IP programming in Assembler

Post by tofro »

Martin_Head wrote: Unless these routines have already been written?
They have. Jonathan Hudson has - More than 15 years ago ;) - written a C68 library that sits on top of the QDOS TCP/IP implementation in QPC2 and uqlx.
http://www.zen35309.zen.co.uk/qdos/qlsocket.zip

Using these, most of the UNIX TCP/IP code found on the internet can just be re-compiled with C68 and, normally, just runs.

Tobias


ʎɐqǝ ɯoɹɟ ǝq oʇ ƃuᴉoƃ ʇou sᴉ pɹɐoqʎǝʞ ʇxǝu ʎɯ 'ɹɐǝp ɥO
Martin_Head
Aurora
Posts: 853
Joined: Tue Dec 17, 2013 1:17 pm

Re: QDOS TCP/IP programming in Assembler

Post by Martin_Head »

tofro wrote:They have. Jonathan Hudson has - More than 15 years ago ;) - written a C68 library that sits on top of the QDOS TCP/IP implementation in QPC2 and uqlx.
http://www.zen35309.zen.co.uk/qdos/qlsocket.zip

Using these, most of the UNIX TCP/IP code found on the internet can just be re-compiled with C68 and, normally, just runs.

Tobias
I think this is the QLIP thing I was talking about. I will give it a deeper look at.

Could I ask a few a few basic questions about programming sockets?

I am trying to do a basic UDP peer to peer connection between two computers. On one I am using QPC2, and on the other a simple Visual basic program (a chat program from the help files), which just sends text to, or receives text from, a winsock control. I am using the Visual basic because I thought if I tried to use two QPC2's and they did not communicate, I would not know if it was a sending or a receiving problem.

I can get a two way connection working when using send() and recev(). But when I try to use sendto() and recevfrom(), sendto() seems to work Ok, but recevfrom() does not. It gives me a Bad Parameter error. I'm guessing it's to do with the sockaddr structure being wrong.

So first question, For recevfrom() does the sockaddr structure need to be set up with the details of the other computer before the function is called, so that you are telling it to receive a message from that computer specifically, or should it be set up empty so that the function fills in the information, so that you can tell where it has come from?

When opening a channel eg "UDP_172.16.0.5:1002" for send() and recev() you need the host and the port? But do you need the host and the port specified for sendto() and recevfrom()? this is kind of tied in with the question above.

Binding, When do you, and when don't you need to use it? Am I right that it's saying "this is the port number of this computer that I will be sending and receiving data on". The sockaddr structure for this command would contain the port number, but what about the IP address, is it the IP address of this computer?
When I have tried to use bind() and I get a Bad Parameter error, I think I am not constructing the sockaddr structure correctly.

Ports, What are a safe port numbers to use? maybe I am using the wrong ones? I have been using 1001 and 1002 because that's what the Visual basic program used. Some of the stuff I have seen on the Internet suggests using ports from about 50000 up to 65535.

The send(), recev() program I have which works, basically goes

open udp_IP address of other computer:port number
send() some text
which appears on the other computer

the other computer then sends some text
recv()
the text is received on this computer

The other computer has opened the IP address of this computer and a port number. But I have not told this computer what port to use, so how does it know to read from this port?

Sorry to have gone on a bit, and I'm sure I could find lots more question.

Martin


User avatar
XorA
Site Admin
Posts: 1368
Joined: Thu Jun 02, 2011 11:31 am
Location: Shotts, North Lanarkshire, Scotland, UK

Re: QDOS TCP/IP programming in Assembler

Post by XorA »

Martin_Head wrote: Ports, What are a safe port numbers to use? maybe I am using the wrong ones? I have been using 1001 and 1002 because that's what the Visual basic program used. Some of the stuff I have seen on the Internet suggests using ports from about 50000 up to 65535.
Ports below 1024 are reserved for administrator/root always use a port 1025+ for user applications, best for 5000+ as less likely to collide with other common services.

Get yourself a copy of wireshark to install on the PC, this will show you everything that is going on network wise. Its essential tool for debugging network issues.

G


User avatar
dilwyn
Mr QL
Posts: 2761
Joined: Wed Dec 01, 2010 10:39 pm

Re: QDOS TCP/IP programming in Assembler

Post by dilwyn »

Please keep us informed of progress with this project, Martin. It's a subject which doesn't get much attention in the QL scene and I'll follow it with interest.

I have dabbled a little with the tcp devices from BASIC and it's surprising what can be achieved just from BASIC in some cases. Here's a little program from Jon Dent which shows how to read email headers and the first few lines of a plain text email:

Code: Select all

100 OPEN_IN #8,"tcp_mail.isp.net:110": REM your account
110 inst$="": stage=0
120 crlf$= CHR$(13) & CHR$(10)
130 REPeat
140  a$= INKEY$(#8,100)
150  IF a$<>"":inst$= inst$ & a$
160  PRINT a$;
170  SELect ON stage
180     =0:
190         IF "OK" INSTR inst$ THEN
200           inst$= ""
210           PRINT #8, "USER user.name.here";crlf$; : REM your user name
220           stage= 1
230         END IF
240     =1:
250         IF "OK" INSTR inst$ THEN
260           inst$= ""
270           PRINT #8, "PASS password.here";crlf$; : REM your password
280           stage= 2
290         END IF
300     =2:
310         IF "OK" INSTR inst$ THEN
320           inst$= ""
330           PRINT #8, "LIST";crlf$;
340           stage= 3
350         END IF
360     =3:
370         IF "OK" INSTR inst$ THEN
380           PRINT #0,"view which mail number ? 0 to QUIT":
390           INPUT #0,number$
400           IF number$<>0
410             PRINT #8,"TOP ";number$;" 5";crlf$;
420           ELSE
430             PRINT #8,"QUIT";crlf$;
440           END IF
450           CLS:CLS #0
460           stage= 2
470         END IF
480   END SELect
490 END REPeat
For anyone who hasn't studied the tcp driver, you simply open a channel to the resource you want, preceded by tcp_ and ending with the port number after a colon (see line 100). You then talk to the server with normal BASIC commands like PRINT and INPUT. You need to study the official documents for exactly what commands are supported - there's plenty of documentation out there. What we're short of is examples for QL users to study. If anyone wishes to contribute examples I'll happily host them on my website, probably by starting a page like I did for the QL-SD in order to kick-start interest.


User avatar
tofro
Font of All Knowledge
Posts: 2702
Joined: Sun Feb 13, 2011 10:53 pm
Location: SW Germany

Re: QDOS TCP/IP programming in Assembler

Post by tofro »

@Dilwyn: There actually is quite a lot possible using SuperBASIC only - What you can't do, is writing a server, that is, you can only create the client side of a socket connection in S*BASIC and always need to rely on some other OS/language to implement the "other side" (Just because listen, bind and recvfrom have no implementation in S*BASIC - So implementing some new toolkit would actually solve this).

Martin,

when you use recvfrom (), you need to actually allocate some space for the call to store the address of the sender. It should be empty (it's about to be overwritten by the recvfrom() call anyhow), and have enough space for an IPv4 adress, that is, you must allocate memory for a struct sockaddr_in structure, even if the prototype only asks for a struct sockaddr. If there's not enough space, recvfrom() will complain.

The point is, in socket programming you have a lot of different cases handled by the same operating system calls. You need to know what case you're handling before you can actually fill in the proper data. Peer-to-peer communications between two UDP end-points is actually the simplest approach, so you have chosen the right thing to start with.

You need to
  • Open a socket at each end - The address you give to the endpoint actually doesn't really matter - It's going to be overridden by sendto()/recvfrom() anyhow later. For reasons of simplicity, just use "127.0.0.1" or your computer's "real" IP address. Note the socket type must be SOCKET_DGRAM - i.e, UDP.
  • Bind the socket to a port (should be otherwise un-used and above at least 1024, better above 5000)
    Note with some of the open() keys in combination with a properly formed device name, you can actually do both of the above steps in one
  • Sender does a sendto() . Needs a fully-specified IPv4 address of the receiver.
  • Receiver does a recvfrom(). Address needs to be supplied empty, but with enough space to hold a sockaddr_in, otherwise recvfrom() will fail.
Hope this helps,
Tobias


ʎɐqǝ ɯoɹɟ ǝq oʇ ƃuᴉoƃ ʇou sᴉ pɹɐoqʎǝʞ ʇxǝu ʎɯ 'ɹɐǝp ɥO
Post Reply