Socket APIs
Spectranext provides comprehensive socket APIs for network programming, supporting both TCP and UDP protocols. You can use these APIs from assembly language or C programs.
Overview
The socket API follows BSD-style socket programming patterns, making it familiar to developers experienced with Unix/Linux networking. The API supports:
- TCP Sockets: Reliable, connection-oriented communication
- UDP Sockets: Fast, connectionless datagram communication
- Socket Polling: Check socket status without blocking
- Hostname Resolution: DNS lookup for hostnames
Socket Types
TCP Sockets (SOCK_STREAM)
TCP sockets provide reliable, ordered, connection-oriented communication:
- Reliable: Data is guaranteed to arrive
- Ordered: Data arrives in the order sent
- Connection-oriented: Requires connection establishment
- Use for: HTTP, FTP, Telnet, custom protocols requiring reliability
UDP Sockets (SOCK_DGRAM)
UDP sockets provide fast, connectionless datagram communication:
- Fast: Lower overhead than TCP
- Connectionless: No connection required
- Unreliable: Packets may be lost or arrive out of order
- Use for: DNS queries, game protocols, real-time data
ROM Routines
Spectranext provides ROM routines for socket operations. These are accessed via call tables when the cartridge is paged in.
Socket Management
SOCKET equ 0x3E00 ; Allocate a socket
CLOSE equ 0x3E03 ; Close a socket
SOCKET: Allocates a new socket
- Input: Domain (AF_INET = 0), Type (SOCK_STREAM = 1 or SOCK_DGRAM = 2), Protocol (0)
- Output: Socket file descriptor in HL (carry clear) or error (carry set)
CLOSE: Closes a socket
- Input: Socket file descriptor in HL
- Output: Success (carry clear) or error (carry set)
TCP Operations
LISTEN equ 0x3E06 ; Listen for incoming connections
ACCEPT equ 0x3E09 ; Accept an incoming connection
CONNECT equ 0x3E0F ; Connect to a remote host
LISTEN: Start listening for connections
- Input: Socket fd in HL, Backlog in BC
- Output: Success or error
ACCEPT: Accept an incoming connection
- Input: Socket fd in HL, sockaddr_in pointer in DE
- Output: New socket fd in HL or error
CONNECT: Connect to a remote host
- Input: Socket fd in HL, sockaddr_in pointer in DE
- Output: Success or error
Data Transfer
SEND equ 0x3E12 ; Send data
RECV equ 0x3E15 ; Receive data
SENDTO equ 0x3E18 ; Send data to an address (UDP)
RECVFROM equ 0x3E1B ; Receive data from an address (UDP)
SEND: Send data on a TCP socket
- Input: Socket fd in HL, Buffer pointer in DE, Length in BC, Flags (0)
- Output: Bytes sent in HL or error
RECV: Receive data from a TCP socket
- Input: Socket fd in HL, Buffer pointer in DE, Length in BC, Flags (0)
- Output: Bytes received in HL or error
SENDTO: Send UDP datagram
- Input: Socket fd in HL, Buffer in DE, Length in BC, Flags (0), sockaddr_in in stack
- Output: Bytes sent or error
RECVFROM: Receive UDP datagram
- Input: Socket fd in HL, Buffer in DE, Length in BC, Flags (0), sockaddr_in pointer in stack
- Output: Bytes received or error
Socket Status
POLL equ 0x3E1E ; Poll a list of sockets
POLLALL equ 0x3E21 ; Poll all open sockets
POLLFD equ 0x3E24 ; Poll a single socket
POLL: Check status of multiple sockets
- Input: Array of pollfd structures
- Output: Number of ready sockets
POLLFD: Check status of a single socket
- Input: Socket fd in HL
- Output: Status bits (BIT_CONN, BIT_DISCON, BIT_RECV)
Network Configuration
GETHOSTBYNAME equ 0x3E27 ; Look up a hostname
IFCONFIG_INET equ 0x3E48 ; Set IPv4 address
IFCONFIG_NETMASK equ 0x3E4B ; Set netmask
IFCONFIG_GW equ 0x3E4E ; Set gateway
GETHOSTBYNAME: Resolve hostname to IP address
- Input: Hostname string pointer in HL
- Output: IP address in HL (4 bytes) or error
C API (z88dk)
If you're using C with z88dk, you can use the standard socket API:
#include <sys/socket.h>
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in addr;
// ... configure addr ...
connect(sockfd, (struct sockaddr*)&addr, sizeof(addr));
send(sockfd, buffer, length, 0);
recv(sockfd, buffer, length, 0);
close(sockfd);
Socket Address Structure
The sockaddr_in structure is used for addresses:
struct sockaddr_in {
int sin_family; // AF_INET (0)
unsigned int sin_port; // Port number (network byte order)
struct in_addr sin_addr; // IP address
char sin_zero[8]; // Padding
};
struct in_addr {
unsigned long s_addr; // 32-bit IP address
};
Example: TCP Client
; Connect to a server and send data
ld hl, hostname
call GETHOSTBYNAME
jr c, dns_error
; Create socket
ld hl, AF_INET
ld de, SOCK_STREAM
ld bc, 0
call SOCKET
jr c, socket_error
ld (sockfd), hl
; Set up address structure
ld hl, addr_struct
ld (hl), AF_INET
inc hl
ld (hl), 0x50 ; Port 80 (network byte order)
; ... set IP address ...
; Connect
ld hl, (sockfd)
ld de, addr_struct
call CONNECT
jr c, connect_error
; Send data
ld hl, (sockfd)
ld de, message_buffer
ld bc, message_length
call SEND
; Close socket
ld hl, (sockfd)
call CLOSE
Example: TCP Server
; Create socket
ld hl, AF_INET
ld de, SOCK_STREAM
ld bc, 0
call SOCKET
ld (listen_fd), hl
; Bind to port
ld hl, (listen_fd)
ld de, addr_struct
call BIND
; Listen
ld hl, (listen_fd)
ld bc, 5 ; Backlog
call LISTEN
; Accept connection
ld hl, (listen_fd)
ld de, client_addr
call ACCEPT
ld (client_fd), hl
; Receive data
ld hl, (client_fd)
ld de, buffer
ld bc, 1024
call RECV
; Close client socket
ld hl, (client_fd)
call CLOSE
Example: UDP Communication
; Create UDP socket
ld hl, AF_INET
ld de, SOCK_DGRAM
ld bc, 0
call SOCKET
ld (sockfd), hl
; Send datagram
ld hl, (sockfd)
ld de, data_buffer
ld bc, data_length
push de ; sockaddr_in pointer
call SENDTO
pop de
; Receive datagram
ld hl, (sockfd)
ld de, recv_buffer
ld bc, 1024
push de ; sockaddr_in pointer for source
call RECVFROM
pop de
Socket Polling
Polling allows you to check socket status without blocking:
; Poll a socket
ld hl, (sockfd)
call POLLFD
; Check status bits
bit BIT_RECV, a
jr nz, data_ready
bit BIT_CONN, a
jr nz, connected
bit BIT_DISCON, a
jr nz, disconnected
Error Handling
Socket operations can fail for various reasons:
- Network errors: Connection refused, timeout, network unreachable
- Resource errors: No sockets available, out of memory
- Protocol errors: Invalid address, socket not in correct state
Always check the carry flag after socket operations:
call CONNECT
jr c, handle_error
; Connection successful
Best Practices
Socket Lifecycle
- Allocate: Use
SOCKETto create a socket - Configure: Set up address structures
- Connect/Bind: Establish connection or bind to port
- Communicate: Send/receive data
- Close: Always close sockets when done
Resource Management
- Close sockets: Don't leak socket file descriptors
- Check errors: Always verify operations succeeded
- Handle timeouts: Network operations can take time
- Poll efficiently: Use polling to avoid blocking
Performance
- Reuse sockets: Keep connections open when possible
- Batch operations: Group sends/receives together
- Use UDP for speed: When reliability isn't critical
- Poll before blocking: Check status before waiting
Limitations
- Maximum sockets: Limited number of concurrent sockets
- Buffer sizes: Limited receive buffer sizes
- Blocking operations: Some operations may block
- Network speed: Limited by WiFi connection speed
Next Steps
- TLS/HTTPS Sockets - Secure connections
- Memory Management - Understanding memory for socket buffers
- Check ROM routine documentation for detailed API reference