PageRenderTime 46ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/server.c

http://github.com/welterde/lua-moo
C | 160 lines | 127 code | 25 blank | 8 comment | 22 complexity | 719b2e0a2a8af64a10af8ca9e162b49a MD5 | raw file
  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <lua.h>
  4. #include <lauxlib.h>
  5. #include <lualib.h>
  6. #include <sys/types.h>
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <unistd.h>
  10. #include <string.h>
  11. #include <sys/socket.h>
  12. #include <netdb.h>
  13. #include <pthread.h>
  14. #define NUM_THREADS 10
  15. struct thread_init{
  16. int clientfd;
  17. lua_State *L;
  18. };
  19. #define WEBSOCKET_HANDSHAKE "HTTP/1.1 101 Web Socket Protocol Handshake\r\nUpgrade: WebSocket\r\nConnection: Upgrade\r\n"
  20. char *websocket_handshake() {}
  21. void *handle_client(void *thread) {
  22. char buffer[1024];
  23. size_t bytes = 0;
  24. struct thread_init *client = (struct thread_init *)thread;
  25. lua_State *L = client->L;
  26. int clientfd = client->clientfd;
  27. int cmd_count = 0;
  28. int websocket = 0;
  29. char *origin,*host,*end;
  30. while ((bytes = recv(clientfd, buffer, 1024, 0)) > 0) {
  31. printf("[C:server]::%s\n", buffer);
  32. if (cmd_count == 0) {
  33. // Detect websocket clients
  34. if (strncmp("GET /luamoo HTTP/1.1", buffer, 20) == 0) {
  35. websocket = 1;
  36. printf("[C:server]::WebSocket client detected\n");
  37. if (strstr(buffer, "\r\n\r\n") == 0) {
  38. printf("[C:websocket]::%s\n", buffer);
  39. }
  40. send(clientfd, WEBSOCKET_HANDSHAKE,
  41. strlen(WEBSOCKET_HANDSHAKE), 0);
  42. // Send Websocket-Location
  43. origin = strstr(buffer,"Origin:"); //Find the client's "Origin"
  44. if (origin) {
  45. end = strstr(origin,"\r\n"); //Find the endline
  46. if (end) {
  47. send(clientfd, "Websocket-", 10, 0); //Upgrade it to Websocket-Origin
  48. send(clientfd, origin, (int)(end - origin) + 2, 0); //Send it back
  49. }
  50. }
  51. // Send Websocket-Location
  52. host = strstr(buffer,"Host:"); //Find the "Host"
  53. if (host) {
  54. end = strstr(host,"\r\n"); //Find the endline
  55. host += 6; //Chop off "Host: "
  56. send(clientfd, "Websocket-Location: ws://", 25, 0); //Send Websocket-Location header with schema
  57. send(clientfd, host, (int)(end - host), 0); //add the hostname
  58. send(clientfd, "/luamoo\r\n\r\n", 11, 0); //add the location and terminate the response
  59. }
  60. cmd_count++;
  61. continue;
  62. }
  63. }
  64. if (!websocket && bytes >= 2) buffer[bytes - 2] = 0;
  65. // Pass the input off to Lua
  66. // Probably not safe at all with threading but who knows!
  67. lua_getglobal(L, "wizard");
  68. lua_pushstring(L, "input");
  69. lua_gettable(L, -2);
  70. lua_getglobal(L, "wizard"); // self
  71. if (websocket)
  72. lua_pushlstring(L, buffer+1, bytes-2);
  73. else
  74. lua_pushlstring(L, buffer, bytes-2);
  75. // 2 arg, 1 result
  76. if (lua_pcall(L, 2, 1, 0) != 0) {
  77. printf("[C:error running function `input':]\n\t%s\n", lua_tostring(L, -1));
  78. //error(L, "error running function `f': %s",
  79. //lua_tostring(L, -1));
  80. }
  81. else {
  82. const char *result = lua_tostring(L, -1);
  83. if (!lua_isstring(L, -1))
  84. printf("[C:error function `input` must return a string\n");
  85. if (websocket) send(clientfd, "\0", 1, 0); // <
  86. send(clientfd, result, strlen(result), 0);
  87. if (websocket) send(clientfd, "\xFF", 1, 0); // >
  88. }
  89. cmd_count++;
  90. }
  91. printf("[C:Disconnect]\n");
  92. close(clientfd);
  93. pthread_exit(NULL);
  94. }
  95. int server(lua_State *L) {
  96. struct addrinfo hints, *res;
  97. int sockfd, clientfd;
  98. socklen_t addr_size;
  99. struct sockaddr_storage their_addr;
  100. struct thread_init clients[NUM_THREADS];
  101. pthread_t client_threads[NUM_THREADS];
  102. long t = 0;
  103. int true = 1;
  104. memset(&hints, 0, sizeof hints);
  105. hints.ai_family = AF_UNSPEC; // use IPv4 or IPv6, whichever
  106. hints.ai_socktype = SOCK_STREAM;
  107. hints.ai_flags = AI_PASSIVE; // fill in my IP for me
  108. getaddrinfo(NULL, "7777", &hints, &res);
  109. sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
  110. setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &true, sizeof true);
  111. bind(sockfd, res->ai_addr, res->ai_addrlen);
  112. listen(sockfd, 10);
  113. while (1) {
  114. addr_size = sizeof their_addr;
  115. clientfd = accept(sockfd, (struct sockaddr *)&their_addr, &addr_size);
  116. printf("[C:New connection]\n");
  117. clients[t].clientfd = clientfd;
  118. clients[t].L = L;
  119. pthread_create(&client_threads[t], NULL, handle_client, (void *)&clients[t]);
  120. t++;
  121. }
  122. }
  123. int main (void) {
  124. int error;
  125. lua_State *L = lua_open();
  126. luaL_openlibs(L);
  127. error = luaL_loadfile(L, "core.lua") || lua_pcall(L, 0, 0, 0);
  128. if (error) {
  129. fprintf(stderr, "%s", lua_tostring(L, -1));
  130. lua_pop(L, 1); /* pop error message from the stack */
  131. }
  132. server(L);
  133. lua_close(L);
  134. pthread_exit(NULL);
  135. }