123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130 |
- /* shared library frontend for qwixx
- * create the so or dll with:
- gcc -shared -o libfester.dll -fPIC fester.c .\http-server.o .\server.o -lws2_32
- compile the example
- gcc .\example.c -L . -lfester -lws2_32
- */
- #include "server.h"
- #include "fester.h"
- #include "http-server/http-server.h"
- /* Handles the setup of a socket for the use by the server. The steps to
- * get and configure a socket on an Operating System are:
- * 1. request a socket file descriptor from the OS
- * 2. optionally set the reuse flag for this socket
- * 3. set the non-blocking flag for this socket
- * 4. request that the socket has a reserved port exclusive for our use
- * 5. set socket passive, incoming connections are queued by the OS
- *
- * The system calls for steps 1-5 are: socket, setsockopt, fcntl, bind, listen
- *
- * The setup process will step through each of these system calls and return
- * the file descriptor. Any error will result in the system error printed
- * to standard error and a zero returned to the caller, the program should
- * exit. To improve on this, just use the same system calls in a new function
- * that can handle the various errors.
- *
- * setup makes use of the getaddrinfo helper function which when using Msft
- * products only exists in their Winsock2 API. There is not that big of a
- * difference not using getaddrinfo, but it does make it easier for the user
- * to switch to either a IPV4 or IPV6 address scheme easier.
- *
- * [?] The pre-processor macro, MYPORT is used to set the listening port
- *
- * [!] If using Msft, you are required to run their proprietary code before
- * calling this routine. This is important enough to Msft that they make
- * it impossible to use sockets without doing so. Doing this aids Msft in
- * maintaining a monopoly by generating applications and code that only
- * work on Msft platforms. It is pretty easy, albeit annoying, to sidestep
- * this by keeping track of Msft's shenanigans (see WSAStartup).
- */
- int setup() {
- int c, sock;
- struct addrinfo hints, *form;
- #ifndef _WIN32
- /* install a signal handler so that when send attempts to write to a
- * broken pipe and the OS sends the SIGPIPE error we can keep running
- * instead of having our process killed off
- */
- signal(SIGPIPE, handle_sigpipe);
- #endif
- // setup the helper structure for getaddrinfo() routine
- { memset(&hints, 0, sizeof(hints));
- hints.ai_family = AF_INET;
- hints.ai_socktype = SOCK_STREAM;
- hints.ai_flags = AI_PASSIVE;
- }
- // fill out request form using a port, and previously defined hints
- if(0 != (c = getaddrinfo(NULL, MYPORT, &hints, &form))) {
- fprintf(stderr, "FATAL getaddrinfo: %s\n", gai_strerror(c)); return 0;
- }
- // request socket from operating system (OS) using completed form
- if(0 > (sock = socket(form->ai_family, form->ai_socktype, form->ai_protocol))) {
- fprintf(stderr, "FATAL socket: %s\n", strerror(errno)); return 0;
- }
- /* [!] Deal with a minor annoyance, OSes prevent applications from using
- * an address that was recently used and subsequently returned. This
- * feature is not desired - turn it off before we lock in the port portion
- * of the address (currently the socket only has IP, no Port).
- */
- { optType okay = 1;
- if(0 > setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &okay, sizeof(okay))) {
- fprintf(stderr, "FATAL reuse: %s\n", strerror(errno)); return 0;
- }
- }
-
- // ask OS to set the non-blocking flag on the socket
- if(0 > setNonBlocking(sock)) {
- fprintf(stderr, "FATAL non-blocking flag request: %s\n", strerror(errno));
- return 0;
- }
- // ask OS to associate our scoket with the port specified on the form
- if(0 > bind(sock, form->ai_addr /* [?] has port # */, form->ai_addrlen)) {
- fprintf(stderr, "FATAL bind: %s\n", strerror(errno)); return 0;
- }
- // discard the form, it is not used anymore
- freeaddrinfo(form);
- // notify OS that this socket is going to listen for incoming connections
- if(0 > listen(sock, BACKLOG)) {
- fprintf(stderr, "FATAL listen: %s\n", strerror(errno)); return 0;
- }
- // give the caller the server socket file descriptor
- return sock;
- }
-
- struct client * allocateBunnies(int sock) {
- struct client * pool = malloc (sizeof(struct client) *POOL_SIZE);
- if(NULL == pool) return NULL;
- // initialize client pool
- for(uint32_t i = 0; i < POOL_SIZE; i++) pool[i].fd = -1;
- // server listen port is first socket file descriptor
- memset(&pool[0], 0, sizeof(pool[0])); pool[0].fd = sock;
- return pool;
- }
- int somethingNeedDoing(uint16_t milliseconds, struct client pool[]) {
- #ifdef USE_CLIENT_POOL
- if(!faceItMetal(1000 /* ms */, httpEcho, pool)) return softCuteBunnies(-1);
- #else
- if(!faceItMetal(sock, 1000 /* ms */, httpEcho)) return softCuteBunnies(-1);
- #endif
- return softCuteBunnies(0);
- }
- #ifdef _WIN32
- int dumbdumbdumbdumbdumb(WSADATA *w) { return !msftVendorLockInCode(w); }
- #endif
|