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