fester.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. /* shared library frontend for qwixx
  2. * create the so or dll with:
  3. gcc -shared -o libfester.dll -fPIC fester.c .\http-server.o .\server.o -lws2_32
  4. compile the example
  5. gcc .\example.c -L . -lfester -lws2_32
  6. */
  7. #include "server.h"
  8. #include "fester.h"
  9. #include "http-server/http-server.h"
  10. /* Handles the setup of a socket for the use by the server. The steps to
  11. * get and configure a socket on an Operating System are:
  12. * 1. request a socket file descriptor from the OS
  13. * 2. optionally set the reuse flag for this socket
  14. * 3. set the non-blocking flag for this socket
  15. * 4. request that the socket has a reserved port exclusive for our use
  16. * 5. set socket passive, incoming connections are queued by the OS
  17. *
  18. * The system calls for steps 1-5 are: socket, setsockopt, fcntl, bind, listen
  19. *
  20. * The setup process will step through each of these system calls and return
  21. * the file descriptor. Any error will result in the system error printed
  22. * to standard error and a zero returned to the caller, the program should
  23. * exit. To improve on this, just use the same system calls in a new function
  24. * that can handle the various errors.
  25. *
  26. * setup makes use of the getaddrinfo helper function which when using Msft
  27. * products only exists in their Winsock2 API. There is not that big of a
  28. * difference not using getaddrinfo, but it does make it easier for the user
  29. * to switch to either a IPV4 or IPV6 address scheme easier.
  30. *
  31. * [?] The pre-processor macro, MYPORT is used to set the listening port
  32. *
  33. * [!] If using Msft, you are required to run their proprietary code before
  34. * calling this routine. This is important enough to Msft that they make
  35. * it impossible to use sockets without doing so. Doing this aids Msft in
  36. * maintaining a monopoly by generating applications and code that only
  37. * work on Msft platforms. It is pretty easy, albeit annoying, to sidestep
  38. * this by keeping track of Msft's shenanigans (see WSAStartup).
  39. */
  40. int setup() {
  41. int c, sock;
  42. struct addrinfo hints, *form;
  43. #ifndef _WIN32
  44. /* install a signal handler so that when send attempts to write to a
  45. * broken pipe and the OS sends the SIGPIPE error we can keep running
  46. * instead of having our process killed off
  47. */
  48. signal(SIGPIPE, handle_sigpipe);
  49. #endif
  50. // setup the helper structure for getaddrinfo() routine
  51. { memset(&hints, 0, sizeof(hints));
  52. hints.ai_family = AF_INET;
  53. hints.ai_socktype = SOCK_STREAM;
  54. hints.ai_flags = AI_PASSIVE;
  55. }
  56. // fill out request form using a port, and previously defined hints
  57. if(0 != (c = getaddrinfo(NULL, MYPORT, &hints, &form))) {
  58. fprintf(stderr, "FATAL getaddrinfo: %s\n", gai_strerror(c)); return 0;
  59. }
  60. // request socket from operating system (OS) using completed form
  61. if(0 > (sock = socket(form->ai_family, form->ai_socktype, form->ai_protocol))) {
  62. fprintf(stderr, "FATAL socket: %s\n", strerror(errno)); return 0;
  63. }
  64. /* [!] Deal with a minor annoyance, OSes prevent applications from using
  65. * an address that was recently used and subsequently returned. This
  66. * feature is not desired - turn it off before we lock in the port portion
  67. * of the address (currently the socket only has IP, no Port).
  68. */
  69. { optType okay = 1;
  70. if(0 > setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &okay, sizeof(okay))) {
  71. fprintf(stderr, "FATAL reuse: %s\n", strerror(errno)); return 0;
  72. }
  73. }
  74. // ask OS to set the non-blocking flag on the socket
  75. if(0 > setNonBlocking(sock)) {
  76. fprintf(stderr, "FATAL non-blocking flag request: %s\n", strerror(errno));
  77. return 0;
  78. }
  79. // ask OS to associate our scoket with the port specified on the form
  80. if(0 > bind(sock, form->ai_addr /* [?] has port # */, form->ai_addrlen)) {
  81. fprintf(stderr, "FATAL bind: %s\n", strerror(errno)); return 0;
  82. }
  83. // discard the form, it is not used anymore
  84. freeaddrinfo(form);
  85. // notify OS that this socket is going to listen for incoming connections
  86. if(0 > listen(sock, BACKLOG)) {
  87. fprintf(stderr, "FATAL listen: %s\n", strerror(errno)); return 0;
  88. }
  89. // give the caller the server socket file descriptor
  90. return sock;
  91. }
  92. struct client * allocateBunnies(int sock) {
  93. struct client * pool = malloc (sizeof(struct client) *POOL_SIZE);
  94. if(NULL == pool) return NULL;
  95. // initialize client pool
  96. for(uint32_t i = 0; i < POOL_SIZE; i++) pool[i].fd = -1;
  97. // server listen port is first socket file descriptor
  98. memset(&pool[0], 0, sizeof(pool[0])); pool[0].fd = sock;
  99. return pool;
  100. }
  101. int somethingNeedDoing(uint16_t milliseconds, struct client pool[]) {
  102. #ifdef USE_CLIENT_POOL
  103. if(!faceItMetal(1000 /* ms */, httpEcho, pool)) return softCuteBunnies(-1);
  104. #else
  105. if(!faceItMetal(sock, 1000 /* ms */, httpEcho)) return softCuteBunnies(-1);
  106. #endif
  107. return softCuteBunnies(0);
  108. }
  109. #ifdef _WIN32
  110. int dumbdumbdumbdumbdumb(WSADATA *w) { return !msftVendorLockInCode(w); }
  111. #endif