PageRenderTime 51ms CodeModel.GetById 28ms RepoModel.GetById 1ms app.codeStats 0ms

/src/mupnp/http/http_server.c

http://github.com/cybergarage/CyberLink4C
C | 401 lines | 254 code | 93 blank | 54 comment | 51 complexity | bdc3bd52cb8f67c8d9c0c3ecdbad7c79 MD5 | raw file
Possible License(s): LGPL-2.0, BSD-3-Clause
  1. /******************************************************************
  2. *
  3. * mUPnP for C
  4. *
  5. * Copyright (C) Satoshi Konno 2005
  6. * Copyright (C) 2006 Nokia Corporation. All rights reserved.
  7. *
  8. * This is licensed under BSD-style license, see file COPYING.
  9. *
  10. ******************************************************************/
  11. #ifdef HAVE_CONFIG_H
  12. #include "config.h"
  13. #endif
  14. #include <mupnp/http/http.h>
  15. #include <mupnp/util/thread.h>
  16. #include <mupnp/util/log.h>
  17. #include <mupnp/util/string.h>
  18. #if defined(HAVE_UNAME) || defined(TARGET_OS_MAC) || defined(TARGET_OS_IPHONE)
  19. #include <sys/utsname.h>
  20. #endif
  21. /****************************************
  22. * mupnp_http_server_new
  23. ****************************************/
  24. mUpnpHttpServer* mupnp_http_server_new()
  25. {
  26. mUpnpHttpServer* httpServer;
  27. mupnp_log_debug_l4("Entering...\n");
  28. httpServer = (mUpnpHttpServer*)malloc(sizeof(mUpnpHttpServer));
  29. if (NULL != httpServer) {
  30. mupnp_list_node_init((mUpnpList*)httpServer);
  31. httpServer->sock = NULL;
  32. httpServer->acceptThread = NULL;
  33. httpServer->listener = NULL;
  34. /**** Thanks for Makela Aapo (10/31/05) ****/
  35. httpServer->clientThreads = NULL;
  36. mupnp_http_server_setuserdata(httpServer, NULL);
  37. mupnp_http_server_settimeout(httpServer, MUPNP_HTTP_SERVER_READ_TIMEOUT);
  38. /* Mutex */
  39. httpServer->mutex = mupnp_mutex_new();
  40. }
  41. mupnp_log_debug_l4("Leaving...\n");
  42. return httpServer;
  43. }
  44. /****************************************
  45. * mupnp_http_server_delete
  46. ****************************************/
  47. void mupnp_http_server_delete(mUpnpHttpServer* httpServer)
  48. {
  49. mupnp_log_debug_l4("Entering...\n");
  50. mupnp_http_server_stop(httpServer);
  51. mupnp_http_server_close(httpServer);
  52. if (httpServer->mutex)
  53. mupnp_mutex_delete(httpServer->mutex);
  54. mupnp_list_remove((mUpnpList*)httpServer);
  55. free(httpServer);
  56. mupnp_log_debug_l4("Leaving...\n");
  57. }
  58. /****************************************
  59. * mupnp_http_server_delete
  60. ****************************************/
  61. bool mupnp_http_server_open(mUpnpHttpServer* httpServer, int bindPort, const char* bindAddr)
  62. {
  63. mupnp_log_debug_l4("Entering...\n");
  64. if (mupnp_http_server_isopened(httpServer) == true)
  65. return false;
  66. httpServer->sock = mupnp_socket_stream_new();
  67. if (mupnp_socket_bind(httpServer->sock, bindPort, bindAddr, true, false) == false) {
  68. mupnp_socket_delete(httpServer->sock);
  69. httpServer->sock = NULL;
  70. return false;
  71. }
  72. if (mupnp_socket_listen(httpServer->sock) == false) {
  73. mupnp_socket_delete(httpServer->sock);
  74. httpServer->sock = NULL;
  75. return false;
  76. }
  77. mupnp_log_debug_l4("Leaving...\n");
  78. return true;
  79. }
  80. /****************************************
  81. * mupnp_http_server_delete
  82. ****************************************/
  83. bool mupnp_http_server_close(mUpnpHttpServer* httpServer)
  84. {
  85. mupnp_log_debug_l4("Entering...\n");
  86. mupnp_http_server_stop(httpServer);
  87. if (httpServer->sock != NULL) {
  88. mupnp_socket_close(httpServer->sock);
  89. mupnp_socket_delete(httpServer->sock);
  90. httpServer->sock = NULL;
  91. }
  92. mupnp_log_debug_l4("Leaving...\n");
  93. return true;
  94. }
  95. /****************************************
  96. * mupnp_http_server_thread
  97. ****************************************/
  98. typedef struct _mUpnpHttpServerClientData {
  99. mUpnpSocket* clientSock;
  100. mUpnpHttpServer* httpServer;
  101. } mUpnpHttpServerClientData;
  102. static mUpnpHttpServerClientData* mupnp_http_server_clientdata_new(mUpnpHttpServer* httpServer, mUpnpSocket* clientSock)
  103. {
  104. mUpnpHttpServerClientData* clientData;
  105. mupnp_log_debug_l4("Entering...\n");
  106. clientData = (mUpnpHttpServerClientData*)malloc(sizeof(mUpnpHttpServerClientData));
  107. if (NULL != clientData) {
  108. clientData->httpServer = httpServer;
  109. clientData->clientSock = clientSock;
  110. }
  111. mupnp_log_debug_l4("Leaving...\n");
  112. return clientData;
  113. }
  114. static void mupnp_http_server_clientdata_delete(mUpnpHttpServerClientData* clientData)
  115. {
  116. mupnp_log_debug_l4("Entering...\n");
  117. free(clientData);
  118. mupnp_log_debug_l4("Leaving...\n");
  119. }
  120. static void mupnp_http_server_clientthread(mUpnpThread* thread)
  121. {
  122. mUpnpHttpServerClientData* clientData;
  123. mUpnpHttpServer* httpServer;
  124. mUpnpSocket* clientSock;
  125. void* httpServerUserData;
  126. mUpnpHttpRequest* httpReq;
  127. char* version = NULL;
  128. mupnp_log_debug_l4("Entering...\n");
  129. clientData = (mUpnpHttpServerClientData*)mupnp_thread_getuserdata(thread);
  130. httpServer = clientData->httpServer;
  131. clientSock = clientData->clientSock;
  132. httpServerUserData = mupnp_http_server_getuserdata(httpServer);
  133. httpReq = mupnp_http_request_new();
  134. mupnp_http_request_setsocket(httpReq, clientSock);
  135. /**** Thanks for Makela Aapo (10/31/05) ****/
  136. while (mupnp_http_request_read(httpReq, clientSock) == true && mupnp_thread_isrunnable(thread) == true) {
  137. /* Check some validity of the request */
  138. version = mupnp_http_request_getversion(httpReq);
  139. if (mupnp_strcmp(version, MUPNP_HTTP_VER11) == 0) {
  140. /* According to HTTP/1.1 spec, we must not tolerate
  141. HTTP/1.1 request without HOST-header */
  142. if (mupnp_http_request_gethost(httpReq) == NULL) {
  143. mupnp_http_request_postbadrequest(httpReq);
  144. continue;
  145. }
  146. }
  147. if (httpServer->listener != NULL) {
  148. mupnp_http_request_setuserdata(httpReq, httpServerUserData);
  149. httpServer->listener(httpReq);
  150. }
  151. /* Close connection according to HTTP version and headers */
  152. if (mupnp_strcmp(version, MUPNP_HTTP_VER10) == 0) {
  153. /* Terminate connection after HTTP/1.0 request */
  154. break;
  155. }
  156. /* We are having HTTP/1.1 or better => terminate, if requested */
  157. if (mupnp_http_request_iskeepaliveconnection(httpReq) == false) {
  158. break;
  159. }
  160. }
  161. mupnp_log_debug_s("Dropping HTTP client\n");
  162. mupnp_http_request_delete(httpReq);
  163. mupnp_socket_close(clientSock);
  164. mupnp_socket_delete(clientSock);
  165. mupnp_http_server_clientdata_delete(clientData);
  166. mupnp_thread_setuserdata(thread, NULL);
  167. // This code frequently crashes. mutex lock referencing free'd memory.
  168. mupnp_http_server_lock(httpServer);
  169. mupnp_thread_remove(thread);
  170. mupnp_http_server_unlock(httpServer);
  171. mupnp_log_debug_l4("Leaving...\n");
  172. mupnp_thread_delete(thread);
  173. }
  174. /****************************************
  175. * mupnp_http_server_thread
  176. ****************************************/
  177. static void mupnp_http_server_thread(mUpnpThread* thread)
  178. {
  179. mUpnpHttpServer* httpServer;
  180. mUpnpThread* httpClientThread;
  181. mUpnpHttpServerClientData* clientData;
  182. mUpnpSocket* serverSock;
  183. mUpnpSocket* clientSock;
  184. mupnp_log_debug_l4("Entering...\n");
  185. httpServer = (mUpnpHttpServer*)mupnp_thread_getuserdata(thread);
  186. if (mupnp_http_server_isopened(httpServer) == false)
  187. return;
  188. serverSock = httpServer->sock;
  189. while (mupnp_thread_isrunnable(thread) == true) {
  190. clientSock = mupnp_socket_stream_new();
  191. if (mupnp_socket_accept(serverSock, clientSock) == false) {
  192. mupnp_socket_delete(clientSock);
  193. break;
  194. }
  195. mupnp_socket_settimeout(clientSock, mupnp_http_server_gettimeout(httpServer));
  196. clientData = mupnp_http_server_clientdata_new(httpServer, clientSock);
  197. httpClientThread = mupnp_thread_new();
  198. mupnp_thread_setaction(httpClientThread, mupnp_http_server_clientthread);
  199. mupnp_thread_setuserdata(httpClientThread, clientData);
  200. /**** Thanks for Makela Aapo (10/31/05) ****/
  201. mupnp_http_server_lock(httpServer);
  202. mupnp_threadlist_add(httpServer->clientThreads, httpClientThread);
  203. mupnp_http_server_unlock(httpServer);
  204. mupnp_thread_start(httpClientThread);
  205. }
  206. mupnp_log_debug_l4("Leaving...\n");
  207. }
  208. /****************************************
  209. * mupnp_http_server_start
  210. ****************************************/
  211. bool mupnp_http_server_start(mUpnpHttpServer* httpServer)
  212. {
  213. mupnp_log_debug_l4("Entering...\n");
  214. if (httpServer->acceptThread != NULL)
  215. return false;
  216. httpServer->acceptThread = mupnp_thread_new();
  217. mupnp_thread_setaction(httpServer->acceptThread, mupnp_http_server_thread);
  218. mupnp_thread_setuserdata(httpServer->acceptThread, httpServer);
  219. /**** Thanks for Makela Aapo (10/31/05) ****/
  220. httpServer->clientThreads = mupnp_threadlist_new();
  221. if (mupnp_thread_start(httpServer->acceptThread) == false) {
  222. mupnp_thread_delete(httpServer->acceptThread);
  223. httpServer->acceptThread = NULL;
  224. /**** Thanks for Makela Aapo (10/31/05) ****/
  225. mupnp_threadlist_delete(httpServer->clientThreads);
  226. httpServer->clientThreads = NULL;
  227. return false;
  228. }
  229. mupnp_log_debug_l4("Leaving...\n");
  230. return true;
  231. }
  232. /****************************************
  233. * mupnp_http_server_stop
  234. ****************************************/
  235. bool mupnp_http_server_stop(mUpnpHttpServer* httpServer)
  236. {
  237. mupnp_log_debug_l4("Entering...\n");
  238. if (httpServer->acceptThread != NULL) {
  239. mupnp_thread_stop(httpServer->acceptThread);
  240. mupnp_thread_delete(httpServer->acceptThread);
  241. httpServer->acceptThread = NULL;
  242. }
  243. /**** Thanks for Makela Aapo (10/31/05) ****/
  244. if (httpServer->clientThreads != NULL) {
  245. mupnp_threadlist_stop(httpServer->clientThreads);
  246. mupnp_threadlist_delete(httpServer->clientThreads);
  247. httpServer->clientThreads = NULL;
  248. }
  249. mupnp_log_debug_l4("Leaving...\n");
  250. return true;
  251. }
  252. /****************************************
  253. * mupnp_http_server_setlistener
  254. ****************************************/
  255. void mupnp_http_server_setlistener(mUpnpHttpServer* httpServer, MUPNP_HTTP_LISTENER listener)
  256. {
  257. mupnp_log_debug_l4("Entering...\n");
  258. httpServer->listener = listener;
  259. mupnp_log_debug_l4("Leaving...\n");
  260. }
  261. /****************************************
  262. * mupnp_http_getservername()
  263. ****************************************/
  264. const char* mupnp_http_getservername(char* buf, size_t bufSize)
  265. {
  266. #if defined(WIN32) && !defined(ITRON)
  267. OSVERSIONINFO verInfo;
  268. mupnp_strcpy(buf, "Platform 1.0");
  269. ZeroMemory(&verInfo, sizeof(OSVERSIONINFO));
  270. verInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  271. if (GetVersionEx(&verInfo)) {
  272. #if defined(HAVE_SNPRINTF)
  273. snprintf(buf, bufSize, "Windows %d.%d", verInfo.dwMajorVersion, verInfo.dwMinorVersion);
  274. #else
  275. sprintf(buf, "Windows %d.%d", verInfo.dwMajorVersion, verInfo.dwMinorVersion);
  276. #endif
  277. }
  278. #elif defined(BTRON)
  279. T_VER verInfo;
  280. mupnp_strcpy(buf, "Platform 1.0");
  281. if (get_ver(&verInfo) == 0) {
  282. #if defined(HAVE_SNPRINTF)
  283. snprintf(buf, bufSize, "BTRON %hd", verInfo.spver);
  284. #else
  285. sprintf(buf, "BTRON %hd", verInfo.spver);
  286. #endif
  287. }
  288. #elif defined(ITRON)
  289. mupnp_strcpy(buf, "uITRON 4.0");
  290. #elif defined(TENGINE)
  291. mupnp_strcpy(buf, "T-Engine 1.0");
  292. #elif defined(HAVE_UNAME) || defined(TARGET_OS_MAC) || defined(TARGET_OS_IPHONE)
  293. struct utsname unameBuf;
  294. mupnp_strcpy(buf, "Platform 1.0");
  295. if (uname(&unameBuf) == 0) {
  296. #if defined(HAVE_SNPRINTF)
  297. snprintf(buf, bufSize, "%s %s", unameBuf.sysname, unameBuf.release);
  298. #else
  299. sprintf(buf, "%s %s", unameBuf.sysname, unameBuf.release);
  300. #endif
  301. }
  302. #else
  303. mupnp_strcpy(buf, "Platform 1.0");
  304. #endif
  305. mupnp_log_debug_l4("Entering...\n");
  306. return buf;
  307. mupnp_log_debug_l4("Leaving...\n");
  308. }