This document implements TCP/IP as implemented in UQLX. The implementation is due to Jonathan Hudson and is free, the hope is that native QDOS implementations can be kept compatible with it.
The characteristics of the implementation:
The general design of the interface is chosen so that features more to be used from Assembler/Basic follow QDOS interfacing conventions, those used from C/unix like applications follow conventions that make it easier to interface for such programs.
Following new devices are available for the trap#2,open
call:
SCK_
TCP_host:port
UDP_host:port
host
and port
can be both given either by numerical value
or name.
Eg "129.69.1.59:119"
or "news.uni-stuttgart.de:nntp"
Supported keys
in D3
are:
D3=0
D3=1
TCP
and UDP
. host
and port
must be specified.
Opens a connection TCP
, or sets peer address for UDP
sockets
returns without error if connection can't be completed within 1-2/50s, internally the connection buildup continues. Every i/o operation will be blocked until the connection succeeds or fails.
D3=2
TCP
or UDP
socket to an address. Such sockets can be
used for accepting incoming connections
D3=channel_id
SCK
only. accpet connection for socket specified by channel_id
returns error if can't complete immediately.
Many operations typically not regarded as IO were provided by trap#3
calls
to gain flexibility.
Basic IO operations (D0=0..7
) are defined for connected TCP sockets. They may
work for UDP sockets when peer address is set, however this use is strongly discouraged.
Trap#3,[$48,$49] also work but it is not clear whether they are meaningful and thus
may not be supported.
Generally, TCP/IP aware software should probably use the socket specific IO functions - send,recv,sendto,recvfrom.
When a trap#3 returns with an error, an additional c68 conforming error code may be queried by IP_ERRNO, IP_H_ERRNO and IP_H_STRERROR operations. This code is valid unless -1.
These are compatible to QDOS. The only questionable issue here is whether io.fstrg
should always fill its buffer before returning as it does now, or rather mimic the
behaviour of recv/recvfrom. Since the number of received characters will be in D1
anyway, this should not disturb any QDOS applications.
Here only the most important constants that are defined, the rest is in socket library header files.
EQU IP_LISTEN $50 EQU IP_SEND $51 EQU IP_SENDTO $52 EQU IP_RECV $53 EQU IP_RECVFM $54 EQU IP_GETOPT $55 EQU IP_SETOPT $56 EQU IP_SHUTDWN $57 EQU IP_BIND $58 EQU IP_CONNECT $59 EQU IP_FCNTL $5a EQU IP_GETHOSTNAME $5b EQU IP_GETSOCKNAME $5c EQU IP_GETPEERNAME $5d EQU IP_GETHOSTBYNAME $5e EQU IP_GETHOSTBYADDR $5f EQU IP_SETHOSTENT $60 EQU IP_ENDHOSTENT $61 EQU IP_H_ERRNO $62 EQU IP_GETSERVENT $63 EQU IP_GETSERVBYNAME $64 EQU IP_GETSERVBYPORT $65 EQU IP_SETSERVENT $66 EQU IP_ENDSERVENT $67 EQU IP_GETNETENT $68 EQU IP_GETNETBYNAME $69 EQU IP_GETNETBYADDR $6a EQU IP_SETNETENT $6b EQU IP_ENDNETENT $6c EQU IP_GETPROTOENT $6d EQU IP_GETPROTOBYNAME $6e EQU IP_GETPROTOBYNUMBER $6f EQU IP_SETPROTOENT $70 EQU IP_ENDPROTOENT $71 EQU IP_INET_ATON $72 EQU IP_INET_ADDR $73 EQU IP_INET_NETWORK $74 EQU IP_INET_NTOA $75 EQU IP_INET_MAKEADDR $76 EQU IP_INET_LNAOF $77 EQU IP_INET_NETOF $78 EQU IP_IOCTL $79 EQU IP_GETDOMAIN $7a EQU IP_H_STRERROR $7b
Following constants and datatypes are a mix from AmiTCP/IP and Linux definitions. Not every of them is meaningful or supported on every implementation.
Next some definitions useful for socket(), bind() and connect() calls and their trap#2/#3 equivalents.
#define SOCK_STREAM 1 /* stream socket */ #define SOCK_DGRAM 2 /* datagram socket */ #define SOCK_RAW 3 /* raw-protocol interface */ #define SOCK_RDM 4 /* reliably-delivered message */ #define SOCK_SEQPACKET 5 /* sequenced packet stream */ #define AF_UNSPEC 0 /* unspecified address family */ #define AF_INET 2 /* internet: UDP, TCP, etc. */ #define PF_UNSPEC AF_UNSPEC /* aliases */ #define PF_INET AF_INET struct sockaddr { u_char sa_len; /* total length */ u_char sa_family; /* address family */ char sa_data[14]; /* actually longer; address value */ }; struct sockproto { u_short sp_family; /* address family */ u_short sp_protocol; /* protocol */ }; /* constants for getsockopt()/setsockopt() :*/ #define SOL_SOCKET 0x1 /* options for socket level */ /* other values conforming IP may be possible */ #define SO_DEBUG 1 #define SO_REUSEADDR 2 #define SO_TYPE 3 #define SO_ERROR 4 #define SO_DONTROUTE 5 #define SO_BROADCAST 6 #define SO_SNDBUF 7 #define SO_RCVBUF 8 #define SO_KEEPALIVE 9 #define SO_OOBINLINE 10 #define SO_NO_CHECK 11 #define SO_PRIORITY 12 #define SO_LINGER 13 /* ignored, doesn't seem practicable in QDOS */ #define SO_BSDCOMPAT 14
Next, some netdb definitions. This seems like a nigthmare for assembler programmers..
struct hostent { char *h_name; /* official name of host */ char **h_aliases; /* alias list */ int h_addrtype; /* host address type */ int h_length; /* length of address */ char **h_addr_list; /* list of addresses from name server */ #define h_addr h_addr_list[0] /* address, for backward compatiblity */ }; struct netent { char *n_name; /* official name of net */ char **n_aliases; /* alias list */ int n_addrtype; /* net address type */ unsigned long n_net; /* network # */ }; struct servent { char *s_name; /* official service name */ char **s_aliases; /* alias list */ int s_port; /* port number */ char *s_proto; /* protocol to use */ }; struct protoent { char *p_name; /* official protocol name */ char **p_aliases; /* alias list */ int p_proto; /* protocol # */ };
IP_LISTEN Provides listen(2) functionality. For a socket that has been bound during open or explicitly with bind() this will set the number of connect requests that are queued for accept(). Additional requests will not be handled and clients receive a protocol specific error or retry will be initiated. Input D0 = IP_LISTEN D1 = (int) backlog D3 = (short) timeout (should be -1) A0 = (chanid_t) channel ID Output D0 = result (0 if OK) IP_BIND Provides bind(2) functionality Input D0 = IP_BIND D1 = (int) namelen D3 = (short) timeout (-1) A0 = (chanid_t) Channel ID A2 = (struct sockaddr *) name; Output D0 = result IP_CONNECT Provides connect(2) functionality TCP: opens connection to host:prot UDP: (re)sets peer address to host:port Input D0 = IP_CONNECT D1 = (int) namelen D3 = (short) timeout (-1) A0 = (chanid_t) Channel ID A2 = (struct sockaddr *) name; Output D0 = result TCP: opens connection UDP: (re)sets peer address regardless of the timeout specified, the socket will remain blocked (any IO will timeout or be delayed) until the connection buildup succeeded or failed. IP_FCNTL Provides fcntl(2) functionality for IPDEV sockets only. An awful hack for now.. don't use it unless you have to. Input D0 = IP_FCNTL D1 = (int) cmd; D2 = (int) arg; D3 = (short) timeout -1; A0 = (chanid_t) channel ID Output D0 = result IP_GETOPT Provides (some) getsockopt functionality Input D0 = IP_GETOPT D1 = (int) optlen D2 = (int) level D3 = (short) timeout (-1) A0 = (chanid_t) channel ID A1 = (void *) optval address A2 = (int) optname Output D0 = result D1 = optlen IP_SETOPT Provides (some) setsockopt functionality Input D0 = IP_SETOPT D1 = (int) optlen D2 = (int) level D3 = (short) timeout (-1) A0 = (chanid_t) channel ID A1 = (void *) optval address A2 = (int) optname Output D0 = result IP_SHUTDWN Provides shutdown(2) functionality Input D0 = IP_SHUTDWN D1 = (int) how # how=0 disable receive ,1 send, # 2 send&receive D3 = (short) timeout (-1); A0 = (chanid_t) Channel ID Output D0 = result
send and recv differ from io.sstrg and io.fstrg in that they message oriented and allow chunks longer than 32k.
recv and recvfrom return immediately when data is available, or after the first message arrives.
send and recv can be (unlike sendto, recvfrom for UDP) applied only to sockets that have been connected previously.
IP_SEND Provides send(2) functionality Input D0 = IP_SEND; D1 = (uint) flag; D2 = (int) buffer size; D3 = (short) timeout (should be -1) A0 = (chanid_t) channel ID A1 = (void *) buffer address Output D0 = result D1 = (int) bytes written A1 = buffer address + bytes written IP_SENDTO Provides sendto(2) functionality Input D0 = IP_SENDTO; D1 = (uint) flag; D2 = (int) buffer size; D3 = (short) timeout (should be -1) A0 = (chanid_t) channel ID A1 = void *) buffer address A2 = parameter block (2 long words) params[0] = (struct sockaddr*) to params[1] = (int) tolen; Output D0 = result +ve => number of bytes sent -ve => error code IP_RECV Provides recv(2) functionality Input D0 = IP_RECV D1 = (uint) flag D2 = (int) buffer size D3 = (short) timeout (should be -1) A0 = (chanid_t) channel ID A1 = (void *) buffer address Output D0 = result code D1 = bytes written IP_RECVFM Provides recvfrom(2) functionality D0 = IP_RECVFM D1 = (uint) flag D2 = (int) buffer size D3 = (short) timeout (-1) A0 = (chanid_t) channel ID A1 = (void *) buffer address A2 = parameter block (2 long words) params[0] = (struct sockaddr*) from params[1] = (int) fromlen; Output D0 = result +ve => number of bytes sent -ve => error code D1 = size of returned struct sockaddr
IP_GETHOSTNAME Provides gethostname(2) functionality Input D0 = IP_GETHOSTNAME; D2 = (int) namebufferlen D3 = (short) timeout (-1) A0 = (chanid_t) channel ID A1 = (char *)namebuffer; Output D0 = result IP_GETSOCKNAME Provides getsockname(2) functionality Input D0 = IP_GETSOCKNAME D2 = (int) namelen D3 = (short) timeout (-1); A0 = (chanid_t) channel ID A1 = (struct sockaddr *) name Output D0 = result D1 = namelen IP_GETPEERNAME Provides getpeername(2) functionality Input D0 = IP_GETPEERNAME D2 = (int) addrlen D3 = (short) timeout (-1); A0 = (chanid_t) channel ID A1 = (struct sockaddr *) addr Output D0 = result D1 = addrlen IP_GETHOSTBYNAME Provides gethostbyname(2) functionality Input D0 = IP_GETHOSTBYNAME D3 = (short) timeout (-1) A0 = (chanid_t *) channel ID A1 = (char *) name // NULL terminated A2 = (struct hostent *)hostent buffer // minimum of 500 bytes The buffer pointed to by A2 must be at large enough to hold the largest struct hostent returned. D0 = result IP_GETHOSTBYADDR Provides gethostbyaddr(2) functionality Input D0 = IP_GETHOSTBYNAME D1 = (int) addrlen; D2 = (int) type; D3 = (short) timeout (-1) A0 = (chanid_t *) channel ID A1 = (char *) addr A2 = (struct hostent *)hostent buffer // minimum of 500 bytes The buffer pointed to by A2 must be at large enough to hold the largest struct hostent returned. D0 = result IP_SETHOSTENT IP_SETSERVENT IP_SETNETENT IP_SETPROTOENT Provides set*ent(2) functionality Input D0 = IP_SET*ENT D1 = (int) stayopen; D3 = (short) timeout (-1) A0 = (chanid_t *) channel ID Output D0 = result IP_ENDHOSTENT IP_ENDSERVENT IP_ENDNETENT IP_ENDPROTOENT Provides end*ent(2) functionality Input D0 = IP_END*ENT D3 = (short) timeout (-1) A0 = (chanid_t *) channel ID Output D0 = result IP_GETSERVBYNAME IP_GETSERVBYPORT IP_GETSERVENT Provides get*ent(2) functionality Input D0 = IP_GET*ENT D3 = (short) timeout (-1) A0 = (chanid_t *) channel ID A2 = (void *) buffer // cast as necessary Output D0 = result IP_GETNETBYNAME Provides getnetbyname(2) functionality Input D0 = IP_GETNETBYNAME D3 = (short) timeout (-1) A0 = (chanid_t)channel ID A1 = (char *)name A2 = (struct netent *)netent buffer Output D0 = result IP_GETNETBYADDR Provides getnetbyname(2) functionality Input D0 = IP_GETNETBYADDR; A0 = (chanid_t) channel ID A2 = (struct netent *)netent buffer D1 = (uint) net D2 = (int) type D3 = (short) timeout (-1) Output D0 = result IP_GETPROTOBYNAME Provides getprotobyname(2) functionality Input D0 = IP_GETPROTOBYNAME; D3 = (short) timeout (-1) A0 = (chanid_t) channel ID A1 = (char *)name; A2 = (struct protoent *)protoent buffer Output D0 = result IP_GETPROTOBYNUMBER Provides getprotobynumber(2) functionality Input D0 = IP_GETPROTOBYNUMBER; D1 = (int) proto number D3 = (short) timeout (-1) A0 = (chanid_t) channel ID A2 = (struct protoent *)protoent buffer Output D0 = result IP_INET_ATON Provides inet_aton(2) functionality Input D0 = IP_INET_ATON; D3 = (short) timeout (-1) A0 = (chanid_t) channel ID A1 = (char *) name A2 = ( struct in_addr *)inaddr buffer Output D0 = result IP_INET_ADDR Provides inet_addr(2) functionality Input D0 = IP_INET_ADDR D3 = (short) timeout (-1) A0 = (chanid_t) channel ID A1 = (char *) name Output D0 = result IP_INET_NETWORK Provides inet_network(2) functionality Input D0 = IP_INET_NETWORK D3 = (short) timeout (-1) A0 = (chanid_t) channel ID A1 = (char *) name Output D0 = result IP_INET_NTOA Provides (2) functionality Input D0 = IP_INET_NTOA D3 = (short) timeout (-1) A0 = (chanid_t) channel ID A1 = (struct in_addr *) net address buffer A2 = (char *) result buffer Output D0 = result IP_INET_MAKEADDR Provides (2) functionality Input D0 = IP_INET_MAKEADDR D1 = (int) network number D2 = (int) host address D3 = (short) timeout (-1) A0 = (chanid_t) channel ID A2 = (struct in_addr *) result buffer Output D0 = result IP_INET_LNAOF Provides inet_lnaof (2) functionality Input D0 = IP_INET_LNAOF; D3 = (short) timeout (-1) A0 = (chanid_t) channel ID A1 = (struct in_addr *) net address buffer Output D0 = result IP_INET_NETOF Provides inet_netof(2) functionality Input D0 = IP_INET_NETOF; D3 = (short) timeout (-1) A0 = (chanid_t) channel ID A1 = (struct in_addr *) net address buffer Output D0 = result IP_IOCTL Provides ioctl(2) functionality Input D0 = IP_IOCTL D1 = request D3 = (short) timeout (-1) A0 = (chanid_t) channel ID A1 = (char *) argp Output D0 = result IP_GETDOMAIN Provides getdomainname(2) functionality Input D0 = IP_GETDOMAIN; D2 = len; D3 = (short) timeout (-1) A0 = (chanid_t) channel ID A1 = name; Output D0 = result IP_H_ERRNO Provides h_errno (2) functionality Input D0 = IP_H_ERRNO D3 = (short) timeout (-1) A0 = (chanid_t) channel ID Output D0 = result D1 = h_errno IP_H_STRERROR Provides special functionality to return the text for h_errno Input D0 = IP_H_STRERROR D3 = (short) timeout (-1) A0 = (chanid_t) channel ID A1 = buffer for text Output D0 = result
int socket(int domain, int type, int protocol); int bind(int s, const struct sockaddr *name, int namelen); int listen(int s, int backlog); int accept(int s, struct sockaddr *addr, int *addrlen); int connect(int s, const struct sockaddr *name, int namelen); int sendto(int s, const void *msg, int len, unsigned int flags, struct sockaddr *to, int tolen); int send(int s, const void *msg, int len, unsigned int flags); int recvfrom(int s, void *buf, int len, unsigned int flags, struct sockaddr *from, int *fromlen); int recv(int s, void *buf, int len, unsigned int flags); int shutdown(int s, int how); int setsockopt(int s, int level, int optname, void *optval, int optlen); int getsockopt(int s, int level, int optname, void *optval, int *optlen); int getsockname(int s, struct sockaddr *name, int *namelen); int getpeername(int s, struct sockaddr *name, int *namelen); u_long inet_addr(const char *); u_long inet_network(const char *); struct hostent *gethostbyname(const char *name); struct hostent *gethostbyaddr(const char *addr, int len, int type); struct netent *getnetbyname(const char *name); struct netent *getnetbyaddr(int net, int type); struct servent *getservbyname(const char *name, const char *proto); struct servent *getservbyport(int port, const char *proto); struct protoent *getprotobyname(const char *name); struct protoent *getprotobynumber(int proto); char *inet_ntoa(struct in_addr); struct in_addr inet_makeaddr(int , int); unsigned long inet_lnaof(struct in_addr); unsigned long inet_netof(struct in_addr); int inet_aton(const char *cp, struct in_addr *inp); int gethostname(char *name, size_t len); int ioctl(int,int,void *); int sock_fcntl(int s, int action, int val);
This document was generated on 22 October 2002 using texi2html 1.56k.