[← Home](../README.md) · [Networking](README.md) # Protocol Implementation — DNS, TCP, UDP, WaitSelect ## Overview Working code examples for common network protocols on AmigaOS using [bsdsocket.library](bsdsocket.md). See [TCP/IP Stacks](tcp_ip_stacks.md) 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 must `OpenLibrary("bsdsocket.library", ...)` before using any socket function. Use `CloseSocket()` instead of `close()`, and `Errno()` instead of `errno`. --- ## DNS Resolution ```c 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 ```c 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 ```c 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" "

Hello from Amiga!

\n"; send(clientSock, response, strlen(response), 0); CloseSocket(clientSock); } } CloseSocket(listenSock); ``` --- ## UDP Datagram ```c 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: ```c /* 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] > `WaitSelect` eliminates 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](tcp_ip_stacks.md) for configuration. The standard sequence is: 1. `DHCPDISCOVER` — stack broadcasts on port 67 2. `DHCPOFFER` — server responds with IP offer 3. `DHCPREQUEST` — stack accepts 4. `DHCPACK` — server confirms; interface is configured --- ## References - [bsdsocket.md](bsdsocket.md) — API reference and LVO table - [tcp_ip_stacks.md](tcp_ip_stacks.md) — stack architecture and configuration - [sana2.md](sana2.md) — SANA-II driver layer