commit 373303723b12dadb32eea2473c0d79db4aa87aae Author: John Bintz Date: Wed Dec 28 11:34:14 2022 -0500 add server diff --git a/server.c b/server.c new file mode 100644 index 0000000..b3c721e --- /dev/null +++ b/server.c @@ -0,0 +1,210 @@ +/** + * 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; +}