This API provides a subset of the standard TCP/IP Berkeley Sockets API with just enough functionality to create functioning TCP/IP client applications for the TRS-80. We attempt to adhere to the conventions of the Unix standard sockets library found in <sys/types.h> and <sys/socket.h>. All API calls are sent to the Z80 I/O port 31 as a sequence of bytes where the socket function is represented by a single byte code. Other parameters are defined as bytes per the specification below. Responses for each function are read from the same port 31.
For a thorough course on socket programming, read the bible of TCP/IP Sockets Programming Unix Network Programming by W. Richard Stevens
For a quicker tutorial on using sockets, see https://www.tutorialspoint.com/unix_sockets/socket_core_functions.htm
Only TCP streaming sockets are supported at this time. UDP socket support will be in an upcoming release. TLS sockets will also be implemented at some time in the future.
Open a socket.
Unix: int socket (int family, int type, int protocol);
Family: AF_INET, AF_INET6 (not currently supported)
Types: SOCK_STREAM, SOCK_DGRAM (not currently supported)
Protocols: Defaults to TCP for SOCK_STREAM and UDP for SOCK_DGRAM (not currently supported)
This call consists of 4 bytes sent in sequence to the trsnic port:
<TCPIP><SOCKET><FAMILY><TYPE>
TCPIP = 0x1
SOCKET = 0x01
AF_INET = 0x01 or AF_INET6 = 0x02 (AF\INET6 not yet supported)
SOCK_STREAM = 0x1 or SOCK_DGRAM = 0x02 (SOCK_DGRAM not yet supported)
Example: To open a TCP streaming socket, you would send 4 bytes to port 31
<0x01><0x01><0x01><0x01>
Response: 2 bytes are returned. The first byte is status (1 for error, 0 for success). On success, the second byte is the socket file descriptor, aka sockfd. This sockfd should be saved as it will be used by the other socket API functions below. The second byte is set to errno only when there is an error.
Example Success returns <0x00><0x02> where byte 1 = success and byte 2 = sockfd (in this case the integer 2) Failure returns <0x01><0x01> where byte 1 = error and byte 2 = errno (in this case 1)
Connect to a server socket using an IP address. Only used for streaming sockets, ie. TCP SOCK_STREAM
Unix: int connect(int sockfd, struct sockaddr *serv_addr, int addrlen);
CONNECT with IP address consists of 10 bytes (for an IPv4 address) to send to the trsnic port. Use 1 byte for the protocol, 1 byte for the command code, 1 byte for the sockfd, 1 byte for the host format (0x00 for IP address), 4 bytes for IPv4 addresses (or 6 bytes for IPv6 addresses, not currently supported) and a 2 byte port sent in network order.
<TCPIP><CONNECT><SOCKFD><0x00><IP4><IP3><IP2><IP1><PORT LSB><PORT MSB>
where
TCPIP = 0x01
CONNECT = 0x02
SOCKFD = the socket descriptor returned from SOCKET
HOST FORMAT = 0x00 (0 indicates IP address)
IP4 = 0x00 to 0xFF
IP3 = 0x00 to 0xFF
IP2 = 0x00 to 0xFF
IP1 = 0x00 to 0xFF
PORT1 = 0x00 to 0xFF LSB of 16bit port number
PORT2 = 0x00 to 0xFF MSB of 16bit port number
Example: To connect to port 23 on a server listening on IP address 192.168.1.100
<0x01><0x02><SOCKFD><0xC0><0xA8><0x01><0x64><0x17><0x00>
CONNECT with a hostname consists of a series of bytes to send to the trsnic port. Use 1 byte for the protocol, 1 byte for the command code, 1 byte for the sockfd, 1 byte for the host format(0x01 for hostname), the hostname in ASCII bytes followed by a NULL (0x00) (to indicate the end of the hostname) and ends with a 2 byte port sent in network order.
<TCPIP><CONNECT><SOCKFD><0x01><HOSTNAME><NULL><PORT LSB><PORT MSB>
where
TCPIP = 0x01
CONNECT = 0x03
SOCKFD = the socket descriptor returned from SOCKET
HOSTNAME = a sequence of ASCII bytes representing any valid hostname resolvable by your network DNS (e.g. www.google.com)
NULL = 0x00 (marks the end of the hostname string)
PORT1 = 0x00 to 0xFF LSB of 16bit port number
PORT2 = 0x00 to 0xFF MSB of 16bit port number
Example: To connect to port 23 on a server with hostname pski.net
<0x01><0x03><SOCKFD><0x70><0x73><0x6B><0x69><0x2E><0x6E><0x65><0x74><0x00><0x17><0x00>
Response: 1 or 2 bytes are returned. The first byte is 1 for error, 0 for success. The second byte is set to errno only when there is an error.
Example: Success returns <0x00>
where byte 1 = success
Failure returns <0x01><0x01>
where byte 1 = error and byte 2 = errno
Sends data over the socket.
Unix: int send(int sockfd, const void *msg, int len, int flags);
SEND consists of a 7 byte header and L bytes of data.
<TCPIP><SEND><SOCKFD><L1><L2><L3><L4><DATA...>
SOCKFD = the socket descriptor returned from SOCKET
L1-L4 = the length of the data specified as 4 bytes. This is in little endian order where L1 is the LSB and L4 is the MSB. The theoretical maximum length of data in one send is 2,147,483,647 bytes.
DATA = a sequence of bytes of length len
Example:
<0x01><0x04><0x01><0x05><0xFF><0x00><0x00><0xFF><0xFF>....<0xFF>
where byte 1 = TCPIP, byte 2 = SEND, byte 3 = SOCKFD, bytes 4 to 7 = data length of 260 and bytes 8 to (data length+8) are the data bytes.
Response: a 1 byte success flag (1 for error, 0 for success), followed by 4 byte response with the length of data actually sent on success or single byte errno on error.
Example. <0x00><0x05><0xFF><0x00><0x00>
where byte 1 = success and bytes 2 to 5 = 32 bit data length of 260.
or
<0x01><0x06>
where byte 1 = error and byte 2 = errno
Sends a UDP datagram over the socket.
Unix: int send(int sockfd, const void *msg, int len, int flags);
Receive data from the socket. Use only for connection oriented sockets ie. TCP.
Unix: int recv(int s, void *buf, size_t len, int flags);
<TCPIP><RECV><SOCKFD><OPTION><L1><L2><L3><L4>
TCPIP = 0x01
RECV = 0x06
SOCKFD = the socket descriptor returned from SOCKET
OPTION (0 - blocking, 1 - nonblocking)
L1-L4 = the maximum length of the data to read specified as 4 bytes. The maximum length of data in one receive is 64K.
Example:
<0x01><0x06><0x01><0x01><0x05><0xFF><0x00><0x00>
where byte 1 = TCPIP, 2 = RECV, 3 = OPTION, byte 4 = SOCKFD, bytes 5 to 8 = max data length to received with this request in LE order.
Response: a 1 byte success flag (1 for error, 0 for success), followed by 4 byte response with the 32 bit length of data followed by the data bytes. On error only 2 bytes are returned. The first byte is 1 for error, 0 for success. The second byte is set to errno when there is an error.
Example: <0x00><L1><L2><L3><L4><DATA...>
or
<0x01><0x6>
where byte 1 = error and byte 2 = errno (in this case 6)
Receive a data gram from the socket. Use only for connection-less sockets (ie. UDP);
Unix: int recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen);
<RECVFROM><SOCKFD><IP4><IP3><IP2><IP1><PORT LSB><PORT MSB>
Returns a 1 byte success flag (1 for error, 0 for success), followed by 4 byte response with the length of data On error only 2 bytes are returned. The first byte is 1 for error, 0 for success. The second byte is set to errno when there is an error.
<0x00><DATA...> or <0x01>
Close a socket
Unix: int close(int sockfd);
Send 3 bytes to the trsnic port.
<TCPIP><CLOSE><SOCKFD>
TCPIP = 0x01
CLOSE = 0x08
SOCKFD = the socket descriptor returned from SOCKET
Response: 1 or 2 bytes are returned. The first byte is 1 for error, 0 for success. The second byte is set to errno only when there is an error.
Example:
<0x00>
or
<0x01><0x01>
Have questions? @pski