/** * Simple bsdsocket.library server for AmigaOS * Copyright 2022 John Bintz * Released under the MIT License * Visit theindustriousrabbit.com for more fun! * * You would not believe how sparse the documentation for * bsdsocket.library is on the Amiga. All this required * digging through documentation on multiple sites, in * multiple forum threads to describe the Amiga quirks * (Amiga code has quirks? who knew!), and required a bunch of * experimentation and resetting the Minimig MiSTer core * and PPP connection to get this working. I tested it * with CodeWatcher and nothing is leaking, so this should * be a (hopefully) good bsdsocket example in C for the Amiga. * * This code is built for SAS/C. Be sure to disable ChkAbort * in the Linker options, otherwise the SAS/C Ctrl-c * handler will take over and screw up server teardown. * * You can use netcat/ncat on another machine to send data * to the running server: * * echo "whoa computers" | netcat 192.168.50.100 8090 * */ #include #include #include #include #include #include #include // socket stuff struct Library *SocketBase; int serverSocket = -1; struct sockaddr_in serverAddress; #define PORT (8090) #define MAX_CONNECTIONS (2) // data handling #define BUFFER_LENGTH (256) char buffer [BUFFER_LENGTH]; int msgSize; // set up all the global stuff we need, allowing for early exits // on failures. int setup(void) { const int enable = 1; // this works with the most modern MiamiDX if (!(SocketBase = OpenLibrary("bsdsocket.library", 4))) { printf("Can't open socket library\n"); return 1; } serverSocket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if (serverSocket < 0) { printf("can't get a socket\n"); return 1; } // AmiTCP 4.3 SDK does not have SO_REUSEPORT, this is all you get if (setsockopt( serverSocket, SOL_SOCKET, SO_REUSEADDR, // oh c... &enable, sizeof(int) ) < 0) { printf("can't set socket options\n"); return 1; } return 0; } void teardown(void) { if (serverSocket != -1) { shutdown( serverSocket, // SHUT_RDWR, stop all communication both ways 2 ); // double close it to stop the listen as well CloseSocket(serverSocket); CloseSocket(serverSocket); } if (SocketBase) { CloseLibrary(SocketBase); } } int startServer(void) { // bind to all addresses on our defined port memset(&serverAddress, 0, sizeof(serverAddress)); serverAddress.sin_family = AF_INET; serverAddress.sin_port = htons(PORT); serverAddress.sin_addr.s_addr = htonl(INADDR_ANY); if (bind( serverSocket, (struct sockaddr *) &serverAddress, sizeof(serverAddress) ) < 0) { printf("can't bind\n"); return 1; } if (listen(serverSocket, MAX_CONNECTIONS) < 0) { printf("can't listen\n"); return 1; } return 0; } void readData(int clientSocket) { do { // keep stomping over the same buffer // ideally we'd take the data out of the buffer and // do something with it. msgSize = recv(clientSocket, buffer, BUFFER_LENGTH, 0); if (msgSize <= 0) { printf("End of data\n"); } else { printf("Got stuff: %i\n", msgSize); printf("%s\n", buffer); } } while (msgSize == 256); printf("Data received: %s\n", buffer); } int main(void) { // The incoming netcat client int clientSocket; struct sockaddr_in clientAddress; LONG clientLength = sizeof(clientAddress); // be able to use WaitSelect int waitSelectResult; fd_set readFDs; if (setup() != 0) { teardown(); return 1; } printf("got socket number %d\n", serverSocket); if (startServer() != 0) { teardown(); return 1; } printf("listening on port %d\n", PORT); // just enough to get WaitSelect working // this macro also wants strings.h included FD_ZERO(&readFDs); (( FD_SET(serverSocket, &readFDs); waitSelectResult = WaitSelect( serverSocket + 1, &readFDs, NULL, NULL, NULL, // other Exec Signals would go here as ORed mp_SigBits NULL ); // WaitSelect will trap on Ctrl-C for us, and returns -1 if that happens if (waitSelectResult == -1) { printf("ctrl-c\n"); teardown(); return 1; } if ( ( clientSocket = accept( serverSocket, (struct sockaddr *) &clientAddress, &clientLength ) ) < 0 ) { printf("can't accept\n"); return 1; } // note the capitalization difference on Inet_NtoA. the Amiga does // that a lot... printf("connection from %s\n", Inet_NtoA(clientAddress.sin_addr.s_addr)); readData(clientSocket); printf("all done\n"); teardown(); return 0; }