The emulator now (1 st
December 2004) emulates networking ability. Programs running on two instances of the emulator running on different real computers can communicate using the real internet. Programs running on two instances of the emulator running on the same real computer can communicate using an emulated internet. One program can communicate with itself using an emulated “loop-back” interface. All three cases work in exactly the same way, one program does not need to be aware of the real location on which the other is running.
Only the IP interface is emulated, if you want UDP or TCP or anything else, you will have to make it yourself. Allowing you to make it yourself is one of the reasons for having an emulator in the first place. The emulator uses SIX byte fake IP addresses. The first four bytes of the fake
IP address are normally the same as the real computer’s real IP address, the last two bytes of a fake IP address are unpredictable: each time you run the emulator they may (and probably will) be different. This is because a run of the emulator is supposed to represent a completely independent computer, so it would not make sense to repeat IP addresses.
If your computer has no real network access, even if it has no ethernet card, the emulated internet should still work within one instance of the emulator running. The fake IP address 127.0.0.1.10.1 is the “loop-back” address, and does not use real networking operations at all. An IP packet sent to IP address 127.0.0.1.10.1 will be put in the emulator’s own input queue without any processing.
As it is IP, not TCP that is emulated, there are no guarantees that a transmitted packet will ever be received, just like in real life. Each time a program is run, the received packet queue is emptied. This is primarily to prevent confusion caused by packets left over from a previous run, but it does mean that you can not run one program to send a packet to 127.0.0.1.10.1, then run another program to receive it. The same program would have to first send the packet, then go on to receive it.
To make experimentation realistic, there is a facility for introducing random transmission failures. Using an emulator command, you can set the error rate to a floating point number, which represents the probability of failure. For example, if you set the error rate to 0.25, then one packet in every four will not get through. This is an average of course, every packet is given an independent 0.25 probability of failing.
There is one new emulator command, with a few options:
NET
NET SE fff
Report IP address and other statistics
Set Sending Error rate to fff , (range 0.0 to 1.0)
NET RE fff
NET ERR fff
Set Receiving Error rate to fff , (range 0.0 to 1.0)
Set both sending and receiving ERRor rate to fff , (range 0.0 to 1.0)
When the error rate is 0.0, no artificial errors will be introduced, but of course the emulator is still subject to the vicissitudes of the real IP system underneath.
An artificial sending error is simply a decision not to send a given packet; the send function acts as though it did its job, but nothing is sent. An artificial receiving error is a decision to throw away a given packet once it has arrived; the receive function acts as though there was no packet.
There are only three new system functions required to support networking:
int sys$getip(int addr[]);
The parameter must be an array of at least 6 ints.
The emulated IP address is stored in the first 6 elements of the array.
Returns 1 on success, 0 on failure. I don’t think failure is possible. int sys$netsnd(int addr[], void *data, int len);
The first parameter must be an array of at least 6 ints, it contains the IP address of the emulator session to which the packet is to be sent.
The second parameter is simply a pointer to the address in memory containing the beginning of the data to be sent; it may be an array or a pointer to a struct or a pointer to a normal variable.
The third parameter is the size of the data object to be sent, in bytes. The system will never send more that 768 bytes.
Returns number of bytes actually sent on success, 0 or negative on failure.
Success does not imply that the data was or will be received, simply that it was sent. int sys$netrcv(int addr[], void *data, int maxlen);
The first parameter must be an array of at least 6 ints, it does not need to be given any initial content. When a packet is received, the sender’s IP address will be stored in this array.
The second parameter is simply a pointer to the address in memory where the incoming data should be stored; it may be an array or a pointer to a struct or a pointer to a normal variable.
The third parameter is the size of that memory area, in bytes. If a packet larger than this size is received, the end of it will be lost.
Returns number of bytes actually received and saved in the data area on success, 0 or negative on failure.
This is a Non-blocking function. If there is no packet already in the received queue, it will return 0 immediately, without any delay. In this case, addr and data will not usually be modified.
(this functionality is available just by typing the emulator command “NET”)
$ cat inetx.c
#include <stdsys.h>
#include <stdio.h> void main(void)
{ int ip[6];
sys$getip(ip);
printf("IP address is %d", ip[0]);
for (int i=1; i<6; i+=1)
printf(".%d", ip[i]);
printf("\n"); }
$ exe -q inetx
IP address is 129.171.33.6.10.97
$
This program will of course do no good unless there is another emulator program transmitting packets to it. This is what you should do:
Log in twice. That is, start Telnet or PowerTerm or CRT or secureCRT, or whatever it is you use, and log in as normal. Then start the same communications program again, and log in normally again. Position the windows so that you can see them both.
In one of your login sessions, compile and run the following program. It will tell you its own
IP address, then wait until some data arrives.
Then, in the other login session, compile and run Sample Three. It will ask you for the receiver’s IP address; type whatever the first program told you. The sender will then wait for you to type a string. Type one and it will be sent. You will see the receiver receiving it.
The receiver will not stop naturally. Type control-C to it when you’ve finished.
$ cat inetr.c
#include <stdsys.h>
#include <stdio.h> void main(void)
{ int ip[6];
char buff[100];
sys$getip(ip);
printf("Listening on IP address %d", ip[0]);
for (int i=1; i<6; i+=1)
printf(".%d", ip[i]);
printf(":\n");
while (1)
{ sys$smlslp();
int n=sys$netrcv(ip, buff, 99);
if (n<=0) continue;
buff[n]=0;
printf("Received %d bytes from %d", n, ip[0]);
for (int i=1; i<6; i+=1)
printf(".%d", ip[i]);
printf(": '%s'\n", buff); } }
$ exe -q inetr
Listening on IP address 129.171.33.6.8.134:
(sample run completed on next page...)
See sample two for explanation and instructions.
$ cat inett.c
#include <stdsys.h>
#include <stdio.h> int readint(void)
{ int r=0;
while (1)
{ int c=getchar();
if (c<'0' || c>'9') break;
r=r*10+c-'0'; }
return r; } int readstr(char *s)
{ int p=0;
while (1)
{ int c=getchar();
if (c=='\n') break;
s[p]=c;
p+=1; }
s[p]=0;
return p; } void main(void)
{ int ip[8];
printf("Enter destination IP address: ");
for (int i=0; i<6; i+=1)
ip[i]=readint();
char msg[100];
printf("Enter message: ");
int len=readstr(msg);
int n=sys$netsnd(ip, msg, len);
printf("sent %d bytes\n", n); }
You should first run sample two in a different terminal window...
$ exe -q inett
Enter destination IP address: 129.171.33.6.8.134
Enter message: Hello there!
sent 12 bytes
$ exe -q inett
Enter destination IP address: 129.171.33.6.8.134
Enter message: how are you doing then?
sent 23 bytes
What you see in the other terminal window... (continued from previous page)
$ exe -q inetr
Listening on IP address 129.171.33.6.8.134:
Received 12 bytes from 129.171.33.6.23.197: 'Hello there!'
Received 23 bytes from 129.171.33.6.29.2: 'how are you doing then?'
This program does not need to be told any IP address; it is communicating with itself, so it can use the loop-back interface, which always has the same IP address: 127.0.0.1.10.1.
It sends two separate packets through the loop-back interface, then enters an infinite loop to accepts any packets that arrive and print their contents.
Remember that the receiving function is non-blocking. The small sleep each time round the loop is only really needed if nothing is received (n<=0) after the attempt to receive, otherwise all your CPU time will be used up doing nothing.
Only a very limited number of packets will be safely kept in the receive queue. Normally you should not allow a lot of packets to arrive without accepting them.
$ cat inettr.c
#include <stdsys.h>
#include <stdio.h> void main(void)
{ int ip[8] = { 127, 0, 0, 1, 10, 1 };
int n=sys$netsnd(ip, "one two three four", 18);
printf("sent %d bytes\n", n);
n=sys$netsnd(ip, "test test test", 14);
printf("sent %d bytes\n", n);
while (1)
{ char buff[100];
sys$smlslp();
n=sys$netrcv(ip, buff, 99);
if (n<=0) continue;
buff[n]=0;
printf("Received %d bytes from %d", n, ip[0]);
for (int i=1; i<6; i+=1)
printf(".%d", ip[i]);
printf(": '%s'\n", buff); } }
$ exe -q inettr sent 18 bytes sent 14 bytes
Received 18 bytes from 127.0.0.1.10.1: 'one two three four'
Received 14 bytes from 127.0.0.1.10.1: 'test test test'
^C [ControlC]
Exception signalled: Control C (detail=00001088)
$
Program stopping
> > > > > > > > > > exit
$
I don’t know why all those > signs appeared after the control-C. I’d stop them if I could!