Graphics: text_fonts (bitmap layout, styles), sprites (DMA, multiplexing), gfx_base (chipset detection), rastport (draw modes, clipping), ham_ehb (mermaid fixes), display_modes (HAM palettes) Devices: scsi (per-model interfaces, Gayle limits, CD-ROM, native vs vendor drivers), console (ANSI sequences, CON:/RAW:), parallel (CIA registers, pinout), timer (resource exhaustion), gameport (quadrature, XOR state) Libraries: workbench (WBStartup, AppWindow/Icon/MenuItem), rexxsyslib (ARexx port hosting, command parsing), diskfont (font directory, colour fonts), keymap (rawkey codes, dead keys), locale (catalogue system, date formatting), layers (ClipRect, refresh types), utility (TagItem chains), icon (DiskObject, ToolTypes), iffparse (IFF structure, ByteRun1), expansion (Zorro AutoConfig) Networking: tcp_ip_stacks (major rewrite - Amiga vs Unix architecture, SANA-II pipeline, PPP/SLIP dial-up, Ethernet cards, MiSTer), bsdsocket (pure API ref), sana2 (buffer hooks, driver requirements), protocols (all code examples). Deduplicated overlap between the three files. Toolchain: debugging (Enforcer patterns, SnoopDOS, GDB remote, kprintf checklist), sasc (pragma encoding, __saveds idioms), stormc (NEW - StormC IDE, C++, PowerPC) References: error_codes (DOS, Exec, trackdisk, Intuition error tables) Driver development: rtg_driver (Native driver analysis, P96 tuning) All 22 README indexes updated. Root README synced with stormc.md entry.
6 KiB
Protocol Implementation — DNS, TCP, UDP, WaitSelect
Overview
Working code examples for common network protocols on AmigaOS using bsdsocket.library. See TCP/IP Stacks for the architecture that makes this possible and how it differs from Unix.
Note
Amiga socket functions are library calls (via
bsdsocket.library), not system calls. You mustOpenLibrary("bsdsocket.library", ...)before using any socket function. UseCloseSocket()instead ofclose(), andErrno()instead oferrno.
DNS Resolution
struct Library *SocketBase = OpenLibrary("bsdsocket.library", 4);
if (!SocketBase) return;
struct hostent *he = gethostbyname("www.amiga.org");
if (he)
{
struct in_addr addr;
CopyMem(he->h_addr, &addr, sizeof(addr));
Printf("Host: %s\n", he->h_name);
Printf("IP: %s\n", Inet_NtoA(addr.s_addr));
/* May have multiple addresses: */
char **p;
for (p = he->h_addr_list; *p; p++)
{
CopyMem(*p, &addr, sizeof(addr));
Printf(" Addr: %s\n", Inet_NtoA(addr.s_addr));
}
}
else
{
Printf("DNS lookup failed\n");
}
CloseLibrary(SocketBase);
TCP Client
struct Library *SocketBase = OpenLibrary("bsdsocket.library", 4);
if (!SocketBase) return;
LONG sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) { Printf("socket() failed\n"); goto out; }
struct hostent *he = gethostbyname("www.example.com");
if (!he) { Printf("DNS failed\n"); goto close; }
struct sockaddr_in sa;
sa.sin_family = AF_INET;
sa.sin_port = htons(80);
CopyMem(he->h_addr, &sa.sin_addr, he->h_length);
if (connect(sock, (struct sockaddr *)&sa, sizeof(sa)) < 0)
{
Printf("connect failed: %ld\n", Errno());
goto close;
}
/* Send HTTP request: */
char req[] = "GET / HTTP/1.0\r\nHost: www.example.com\r\n\r\n";
send(sock, req, strlen(req), 0);
/* Receive response: */
char buf[4096];
LONG n;
while ((n = recv(sock, buf, sizeof(buf) - 1, 0)) > 0)
{
buf[n] = 0;
Printf("%s", buf);
}
close:
CloseSocket(sock);
out:
CloseLibrary(SocketBase);
TCP Server
LONG listenSock = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in sa;
sa.sin_family = AF_INET;
sa.sin_port = htons(8080);
sa.sin_addr.s_addr = INADDR_ANY;
bind(listenSock, (struct sockaddr *)&sa, sizeof(sa));
listen(listenSock, 5);
Printf("Listening on port 8080...\n");
while (running)
{
struct sockaddr_in clientAddr;
LONG addrLen = sizeof(clientAddr);
LONG clientSock = accept(listenSock,
(struct sockaddr *)&clientAddr,
&addrLen);
if (clientSock >= 0)
{
Printf("Connection from %s\n",
Inet_NtoA(clientAddr.sin_addr.s_addr));
char response[] = "HTTP/1.0 200 OK\r\n"
"Content-Type: text/html\r\n\r\n"
"<h1>Hello from Amiga!</h1>\n";
send(clientSock, response, strlen(response), 0);
CloseSocket(clientSock);
}
}
CloseSocket(listenSock);
UDP Datagram
LONG udpSock = socket(AF_INET, SOCK_DGRAM, 0);
/* Send: */
struct sockaddr_in dest;
dest.sin_family = AF_INET;
dest.sin_port = htons(9999);
dest.sin_addr.s_addr = inet_addr("192.168.1.255");
char msg[] = "Hello UDP";
sendto(udpSock, msg, strlen(msg), 0,
(struct sockaddr *)&dest, sizeof(dest));
/* Receive: */
char buf[1024];
struct sockaddr_in from;
LONG fromLen = sizeof(from);
LONG n = recvfrom(udpSock, buf, sizeof(buf), 0,
(struct sockaddr *)&from, &fromLen);
buf[n] = 0;
Printf("From %s: %s\n", Inet_NtoA(from.sin_addr.s_addr), buf);
CloseSocket(udpSock);
WaitSelect — Combined Socket + GUI Event Loop
The key pattern for responsive Amiga network applications. WaitSelect simultaneously waits on sockets and Exec signals (windows, ARexx, timers) — no threads needed:
/* Set up signal masks: */
ULONG winSig = 1 << window->UserPort->mp_SigBit;
ULONG ctrlSig = SIGBREAKF_CTRL_C;
fd_set readFDs;
struct timeval tv;
BOOL running = TRUE;
while (running)
{
FD_ZERO(&readFDs);
FD_SET(sock, &readFDs);
tv.tv_secs = 1;
tv.tv_micro = 0;
ULONG sigmask = winSig | ctrlSig;
LONG result = WaitSelect(sock + 1, &readFDs, NULL, NULL,
&tv, &sigmask);
/* Socket data ready? */
if (result > 0 && FD_ISSET(sock, &readFDs))
{
LONG n = recv(sock, buffer, sizeof(buffer), 0);
if (n > 0)
{
/* process network data */
}
else
{
/* connection closed or error */
running = FALSE;
}
}
/* Window event? */
if (sigmask & winSig)
{
struct IntuiMessage *imsg;
while ((imsg = (struct IntuiMessage *)GetMsg(window->UserPort)))
{
switch (imsg->Class)
{
case IDCMP_CLOSEWINDOW:
running = FALSE;
break;
/* ... handle other IDCMP events ... */
}
ReplyMsg((struct Message *)imsg);
}
}
/* Ctrl-C? */
if (sigmask & ctrlSig)
{
Printf("*** Break\n");
running = FALSE;
}
}
Tip
WaitSelecteliminates the need for multi-threading in most Amiga network apps. A single event loop handles sockets, GUI, timers, and ARexx simultaneously — simpler and safer than threads in a non-protected memory environment.
DHCP
DHCP is handled by the TCP/IP stack, not by applications. See TCP/IP Stacks for configuration. The standard sequence is:
DHCPDISCOVER— stack broadcasts on port 67DHCPOFFER— server responds with IP offerDHCPREQUEST— stack acceptsDHCPACK— server confirms; interface is configured
References
- bsdsocket.md — API reference and LVO table
- tcp_ip_stacks.md — stack architecture and configuration
- sana2.md — SANA-II driver layer