network.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814
  1. #ifndef CONFIG
  2. #define CONFIG "config.h"
  3. #endif // CONFIG
  4. #include CONFIG
  5. #ifndef USE_MSRPC
  6. #ifndef _GNU_SOURCE
  7. #define _GNU_SOURCE
  8. #endif
  9. #include <string.h>
  10. #ifndef _WIN32
  11. #include <signal.h>
  12. #include <unistd.h>
  13. #include <fcntl.h>
  14. #include <errno.h>
  15. #include <netinet/in.h>
  16. #endif // WIN32
  17. #include "network.h"
  18. #include "endian.h"
  19. #include "output.h"
  20. #include "helpers.h"
  21. #include "shared_globals.h"
  22. #include "rpc.h"
  23. #ifndef _WIN32
  24. typedef ssize_t (*sendrecv_t)(int, void*, size_t, int);
  25. #else
  26. typedef int (WINAPI *sendrecv_t)(SOCKET, void*, int, int);
  27. #endif
  28. // Send or receive a fixed number of bytes regardless if received in one or more chunks
  29. int_fast8_t sendrecv(SOCKET sock, BYTE *data, int len, int_fast8_t do_send)
  30. {
  31. int n;
  32. sendrecv_t f = do_send
  33. ? (sendrecv_t) send
  34. : (sendrecv_t) recv;
  35. do
  36. {
  37. n = f(sock, data, len, 0);
  38. }
  39. while (
  40. ( n < 0 && socket_errno == VLMCSD_EINTR ) || ( n > 0 && ( data += n, (len -= n) > 0 ) ));
  41. return ! len;
  42. }
  43. static int_fast8_t ip2str(char *restrict result, const size_t resultLength, const struct sockaddr *const restrict socketAddress, const socklen_t socketLength)
  44. {
  45. static const char *const fIPv4 = "%s:%s";
  46. static const char *const fIPv6 = "[%s]:%s";
  47. char ipAddress[64], portNumber[8];
  48. if (getnameinfo
  49. (
  50. socketAddress,
  51. socketLength,
  52. ipAddress,
  53. sizeof(ipAddress),
  54. portNumber,
  55. sizeof(portNumber),
  56. NI_NUMERICHOST | NI_NUMERICSERV
  57. ))
  58. {
  59. return FALSE;
  60. }
  61. if ((unsigned int)snprintf(result, resultLength, socketAddress->sa_family == AF_INET6 ? fIPv6 : fIPv4, ipAddress, portNumber) > resultLength) return FALSE;
  62. return TRUE;
  63. }
  64. static int_fast8_t getSocketList(struct addrinfo **saList, const char *const addr, const int flags, const int AddressFamily)
  65. {
  66. int status;
  67. char *szHost, *szPort;
  68. size_t len = strlen(addr) + 1;
  69. // Don't alloca too much
  70. if (len > 264) return FALSE;
  71. char *addrcopy = (char*)alloca(len);
  72. memcpy(addrcopy, addr, len);
  73. parseAddress(addrcopy, &szHost, &szPort);
  74. struct addrinfo hints;
  75. memset(&hints, 0, sizeof(struct addrinfo));
  76. hints.ai_family = AddressFamily;
  77. hints.ai_socktype = SOCK_STREAM;
  78. hints.ai_protocol = IPPROTO_TCP;
  79. hints.ai_flags = flags;
  80. if ((status = getaddrinfo(szHost, szPort, &hints, saList)))
  81. {
  82. printerrorf("Warning: %s: %s\n", addr, gai_strerror(status));
  83. return FALSE;
  84. }
  85. return TRUE;
  86. }
  87. static int_fast8_t setBlockingEnabled(SOCKET fd, int_fast8_t blocking)
  88. {
  89. if (fd == INVALID_SOCKET) return FALSE;
  90. #ifdef _WIN32
  91. unsigned long mode = blocking ? 0 : 1;
  92. return (ioctlsocket(fd, FIONBIO, &mode) == 0) ? TRUE : FALSE;
  93. #else // POSIX
  94. int flags = fcntl(fd, F_GETFL, 0);
  95. if (flags < 0) return FALSE;
  96. flags = blocking ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK);
  97. return (fcntl(fd, F_SETFL, flags) == 0) ? TRUE : FALSE;
  98. #endif // POSIX
  99. }
  100. int_fast8_t isDisconnected(const SOCKET s)
  101. {
  102. char buffer[1];
  103. if (!setBlockingEnabled(s, FALSE)) return TRUE;
  104. int n = recv(s, buffer, 1, MSG_PEEK);
  105. if (!setBlockingEnabled(s, TRUE)) return TRUE;
  106. if (n == 0) return TRUE;
  107. return FALSE;
  108. }
  109. // Connect to TCP address addr (e.g. "kms.example.com:1688") and return an
  110. // open socket for the connection if successful or INVALID_SOCKET otherwise
  111. SOCKET connectToAddress(const char *const addr, const int AddressFamily, int_fast8_t showHostName)
  112. {
  113. struct addrinfo *saList, *sa;
  114. SOCKET s = INVALID_SOCKET;
  115. char szAddr[128];
  116. if (!getSocketList(&saList, addr, 0, AddressFamily)) return INVALID_SOCKET;
  117. for (sa = saList; sa; sa = sa->ai_next)
  118. {
  119. // struct sockaddr_in* addr4 = (struct sockaddr_in*)sa->ai_addr;
  120. // struct sockaddr_in6* addr6 = (struct sockaddr_in6*)sa->ai_addr;
  121. if (ip2str(szAddr, sizeof(szAddr), sa->ai_addr, sa->ai_addrlen))
  122. {
  123. if (showHostName)
  124. printf("Connecting to %s (%s) ... ", addr, szAddr);
  125. else
  126. printf("Connecting to %s ... ", szAddr);
  127. fflush(stdout);
  128. }
  129. s = socket(sa->ai_family, SOCK_STREAM, IPPROTO_TCP);
  130. # if !defined(NO_TIMEOUT) && !__minix__
  131. # ifndef _WIN32 // Standard Posix timeout structure
  132. struct timeval to;
  133. to.tv_sec = 10;
  134. to.tv_usec = 0;
  135. # else // Windows requires a DWORD with milliseconds
  136. DWORD to = 10000;
  137. # endif // _WIN32
  138. setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (sockopt_t)&to, sizeof(to));
  139. setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, (sockopt_t)&to, sizeof(to));
  140. # endif // !defined(NO_TIMEOUT) && !__minix__
  141. if (!connect(s, sa->ai_addr, sa->ai_addrlen))
  142. {
  143. printf("successful\n");
  144. break;
  145. }
  146. errorout("%s\n", socket_errno == VLMCSD_EINPROGRESS ? "Timed out" : vlmcsd_strerror(socket_errno));
  147. socketclose(s);
  148. s = INVALID_SOCKET;
  149. }
  150. freeaddrinfo(saList);
  151. return s;
  152. }
  153. // fix for lame tomato toolchain
  154. # if !defined(IPV6_V6ONLY) && defined(__linux__)
  155. # define IPV6_V6ONLY (26)
  156. # endif // !defined(IPV6_V6ONLY) && defined(__linux__)
  157. #ifndef NO_SOCKETS
  158. #ifdef SIMPLE_SOCKETS
  159. static int_fast8_t allowSocketReuse(SOCKET s)
  160. {
  161. # if !defined(_WIN32) && !defined(__CYGWIN__)
  162. BOOL socketOption = TRUE;
  163. # else // _WIN32
  164. BOOL socketOption = FALSE;
  165. # endif // _WIN32
  166. if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (sockopt_t)&socketOption, sizeof(socketOption)))
  167. {
  168. # ifdef _PEDANTIC
  169. printerrorf("Warning: %s does not support socket option SO_REUSEADDR: %s\n", ipstr, vlmcsd_strerror(socket_errno));
  170. # endif // _PEDANTIC
  171. }
  172. return 0;
  173. }
  174. int listenOnAllAddresses()
  175. {
  176. uint32_t port_listen;
  177. if (!stringToInt(defaultport, 1, 65535, &port_listen))
  178. {
  179. printerrorf("Fatal: Port must be numeric between 1 and 65535.\n");
  180. exit(!0);
  181. }
  182. struct sockaddr_in6 addr;
  183. memset(&addr, 0, sizeof(addr));
  184. addr.sin6_family = AF_INET6;
  185. addr.sin6_port = BE16((uint16_t)port_listen);
  186. addr.sin6_addr = in6addr_any;
  187. BOOL v6only = FALSE;
  188. s_server = socket(AF_INET6, SOCK_STREAM, 0);
  189. if (s_server == INVALID_SOCKET
  190. || allowSocketReuse(s_server)
  191. || setsockopt(s_server, IPPROTO_IPV6, IPV6_V6ONLY, (sockopt_t)&v6only, sizeof(v6only))
  192. || bind(s_server, (struct sockaddr *)&addr, sizeof(addr))
  193. || listen(s_server, SOMAXCONN) )
  194. {
  195. socketclose(s_server);
  196. struct sockaddr_in addr = {
  197. .sin_family = AF_INET,
  198. .sin_port = BE16((uint16_t)port_listen),
  199. };
  200. addr.sin_addr.s_addr = BE32(INADDR_ANY);
  201. s_server = socket(AF_INET, SOCK_STREAM, 0);
  202. if ( s_server == INVALID_SOCKET
  203. || allowSocketReuse(s_server)
  204. || bind(s_server, (struct sockaddr *)&addr, sizeof(addr))
  205. || listen(s_server, SOMAXCONN) )
  206. {
  207. int error = socket_errno;
  208. printerrorf("Fatal: Cannot bind to TCP port %u: %s\n", port_listen, vlmcsd_strerror(error));
  209. return error;
  210. }
  211. }
  212. #ifndef NO_LOG
  213. logger("Listening on TCP port %u\n", port_listen);
  214. #endif // NO_LOG
  215. return 0;
  216. }
  217. #else // !SIMPLE_SOCKETS
  218. // Create a Listening socket for addrinfo sa and return socket s
  219. // szHost and szPort are for logging only
  220. static int listenOnAddress(const struct addrinfo *const ai, SOCKET *s)
  221. {
  222. int error;
  223. char ipstr[64];
  224. ip2str(ipstr, sizeof(ipstr), ai->ai_addr, ai->ai_addrlen);
  225. //*s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
  226. *s = socket(ai->ai_family, SOCK_STREAM, IPPROTO_TCP);
  227. if (*s == INVALID_SOCKET)
  228. {
  229. error = socket_errno;
  230. printerrorf("Warning: %s error. %s\n", ai->ai_family == AF_INET6 ? cIPv6 : cIPv4, vlmcsd_strerror(error));
  231. return error;
  232. }
  233. # if !defined(_WIN32) && !defined(NO_SIGHUP)
  234. int flags = fcntl(*s, F_GETFD, 0);
  235. if (flags != -1)
  236. {
  237. flags |= FD_CLOEXEC;
  238. fcntl(*s, F_SETFD, flags);
  239. }
  240. # ifdef _PEDANTIC
  241. else
  242. {
  243. printerrorf("Warning: Could not set FD_CLOEXEC flag on %s: %s\n", ipstr, vlmcsd_strerror(errno));
  244. }
  245. # endif // _PEDANTIC
  246. # endif // !defined(_WIN32) && !defined(NO_SIGHUP)
  247. BOOL socketOption = TRUE;
  248. # ifdef IPV6_V6ONLY
  249. if (ai->ai_family == AF_INET6 && setsockopt(*s, IPPROTO_IPV6, IPV6_V6ONLY, (sockopt_t)&socketOption, sizeof(socketOption)))
  250. {
  251. # ifdef _PEDANTIC
  252. # if defined(_WIN32) || defined(__CYGWIN__)
  253. // if (IsWindowsVistaOrGreater()) //Doesn't work with older version of MingW32-w64 toolchain
  254. if ((GetVersion() & 0xff) > 5)
  255. # endif // _WIN32
  256. printerrorf("Warning: %s does not support socket option IPV6_V6ONLY: %s\n", ipstr, vlmcsd_strerror(socket_errno));
  257. # endif // _PEDANTIC
  258. }
  259. # endif
  260. # ifndef _WIN32
  261. if (setsockopt(*s, SOL_SOCKET, SO_REUSEADDR, (sockopt_t)&socketOption, sizeof(socketOption)))
  262. {
  263. # ifdef _PEDANTIC
  264. printerrorf("Warning: %s does not support socket option SO_REUSEADDR: %s\n", ipstr, vlmcsd_strerror(socket_errno));
  265. # endif // _PEDANTIC
  266. }
  267. # endif // _WIN32
  268. # if HAVE_FREEBIND
  269. # if (defined(IP_NONLOCALOK) || __FreeBSD_kernel__ || __FreeBSD__) && !defined(IPV6_BINDANY)
  270. # define IPV6_BINDANY 64
  271. # endif // (defined(IP_NONLOCALOK) || __FreeBSD_kernel__ || __FreeBSD__) && !defined(IPV6_BINDANY)
  272. if (freebind)
  273. {
  274. # if defined(IP_FREEBIND) // Linux
  275. if (setsockopt(*s, IPPROTO_IP, IP_FREEBIND, (sockopt_t)&socketOption, sizeof(socketOption)))
  276. {
  277. printerrorf("Warning: Cannot use FREEBIND on %s: %s\n", ipstr, vlmcsd_strerror(socket_errno));
  278. }
  279. # endif // defined(IP_FREEBIND)
  280. # if defined(IP_BINDANY) // FreeBSD IPv4
  281. if (ai->ai_family == AF_INET && setsockopt(*s, IPPROTO_IP, IP_BINDANY, (sockopt_t)&socketOption, sizeof(socketOption)))
  282. {
  283. printerrorf("Warning: Cannot use BINDANY on %s: %s\n", ipstr, vlmcsd_strerror(socket_errno));
  284. }
  285. # endif // defined(IP_BINDANY)
  286. # if defined(IPV6_BINDANY) // FreeBSD IPv6
  287. if (ai->ai_family == AF_INET6 && setsockopt(*s, IPPROTO_IP, IPV6_BINDANY, (sockopt_t)&socketOption, sizeof(socketOption)))
  288. {
  289. # ifdef _PEDANTIC // FreeBSD defines the symbol but doesn't have BINDANY in IPv6 (Kame stack doesn't have it)
  290. printerrorf("Warning: Cannot use BINDANY on %s: %s\n", ipstr, vlmcsd_strerror(socket_errno));
  291. # endif
  292. }
  293. # endif // defined(IPV6_BINDANY)
  294. # if defined(IP_NONLOCALOK) && !defined(IP_BINDANY) // FreeBSD with GNU userspace IPv4
  295. if (ai->ai_family == AF_INET && setsockopt(*s, IPPROTO_IP, IP_NONLOCALOK, (sockopt_t)&socketOption, sizeof(socketOption)))
  296. {
  297. printerrorf("Warning: Cannot use BINDANY on %s: %s\n", ipstr, vlmcsd_strerror(socket_errno));
  298. }
  299. # endif // defined(IP_NONLOCALOK) && !defined(IP_BINDANY)
  300. }
  301. # endif // HAVE_FREEBIND
  302. if (bind(*s, ai->ai_addr, ai->ai_addrlen) || listen(*s, SOMAXCONN))
  303. {
  304. error = socket_errno;
  305. printerrorf("Warning: %s: %s\n", ipstr, vlmcsd_strerror(error));
  306. socketclose(*s);
  307. return error;
  308. }
  309. # ifndef NO_LOG
  310. logger("Listening on %s\n", ipstr);
  311. # endif
  312. return 0;
  313. }
  314. // Adds a listening socket for an address string,
  315. // e.g. 127.0.0.1:1688 or [2001:db8:dead:beef::1]:1688
  316. BOOL addListeningSocket(const char *const addr)
  317. {
  318. struct addrinfo *aiList, *ai;
  319. int result = FALSE;
  320. SOCKET *s = SocketList + numsockets;
  321. if (getSocketList(&aiList, addr, AI_PASSIVE | AI_NUMERICHOST, AF_UNSPEC))
  322. {
  323. for (ai = aiList; ai; ai = ai->ai_next)
  324. {
  325. // struct sockaddr_in* addr4 = (struct sockaddr_in*)sa->ai_addr;
  326. // struct sockaddr_in6* addr6 = (struct sockaddr_in6*)sa->ai_addr;
  327. if (numsockets >= FD_SETSIZE)
  328. {
  329. #ifdef _PEDANTIC // Do not report this error in normal builds to keep file size low
  330. printerrorf("Warning: Cannot listen on %s. Your OS only supports %u listening sockets in an FD_SET.\n", addr, FD_SETSIZE);
  331. #endif
  332. break;
  333. }
  334. if (!listenOnAddress(ai, s))
  335. {
  336. numsockets++;
  337. result = TRUE;
  338. }
  339. }
  340. freeaddrinfo(aiList);
  341. }
  342. return result;
  343. }
  344. // Just create some dummy sockets to see if we have a specific protocol (IPv4 or IPv6)
  345. __pure int_fast8_t checkProtocolStack(const int addressfamily)
  346. {
  347. SOCKET s; // = INVALID_SOCKET;
  348. s = socket(addressfamily, SOCK_STREAM, 0);
  349. int_fast8_t success = (s != INVALID_SOCKET);
  350. socketclose(s);
  351. return success;
  352. }
  353. // Build an fd_set of all listening socket then use select to wait for an incoming connection
  354. static SOCKET network_accept_any()
  355. {
  356. fd_set ListeningSocketsList;
  357. SOCKET maxSocket, sock;
  358. int i;
  359. int status;
  360. FD_ZERO(&ListeningSocketsList);
  361. maxSocket = 0;
  362. for (i = 0; i < numsockets; i++)
  363. {
  364. FD_SET(SocketList[i], &ListeningSocketsList);
  365. if (SocketList[i] > maxSocket) maxSocket = SocketList[i];
  366. }
  367. status = select(maxSocket + 1, &ListeningSocketsList, NULL, NULL, NULL);
  368. if (status < 0) return INVALID_SOCKET;
  369. sock = INVALID_SOCKET;
  370. for (i = 0; i < numsockets; i++)
  371. {
  372. if (FD_ISSET(SocketList[i], &ListeningSocketsList))
  373. {
  374. sock = SocketList[i];
  375. break;
  376. }
  377. }
  378. if (sock == INVALID_SOCKET)
  379. return INVALID_SOCKET;
  380. else
  381. return accept(sock, NULL, NULL);
  382. }
  383. #endif // !SIMPLE_SOCKETS
  384. void closeAllListeningSockets()
  385. {
  386. # ifdef SIMPLE_SOCKETS
  387. shutdown(s_server, VLMCSD_SHUT_RDWR);
  388. socketclose(s_server);
  389. # else // !SIMPLE_SOCKETS
  390. int i;
  391. for (i = 0; i < numsockets; i++)
  392. {
  393. shutdown(SocketList[i], VLMCSD_SHUT_RDWR);
  394. socketclose(SocketList[i]);
  395. }
  396. #endif // !SIMPLE_SOCKETS
  397. }
  398. #endif // NO_SOCKETS
  399. static void serveClient(const SOCKET s_client, const DWORD RpcAssocGroup)
  400. {
  401. # if !defined(NO_TIMEOUT) && !__minix__
  402. # ifndef _WIN32 // Standard Posix timeout structure
  403. struct timeval to;
  404. to.tv_sec = ServerTimeout;
  405. to.tv_usec = 0;
  406. #else // Windows requires a DWORD with milliseconds
  407. DWORD to = ServerTimeout * 1000;
  408. # endif // _WIN32
  409. # if !defined(NO_LOG) && defined(_PEDANTIC)
  410. int result =
  411. setsockopt(s_client, SOL_SOCKET, SO_RCVTIMEO, (sockopt_t)&to, sizeof(to)) ||
  412. setsockopt(s_client, SOL_SOCKET, SO_SNDTIMEO, (sockopt_t)&to, sizeof(to));
  413. if (result) logger("Warning: Set timeout failed: %s\n", vlmcsd_strerror(socket_errno));
  414. # else // !(!defined(NO_LOG) && defined(_PEDANTIC))
  415. setsockopt(s_client, SOL_SOCKET, SO_RCVTIMEO, (sockopt_t)&to, sizeof(to));
  416. setsockopt(s_client, SOL_SOCKET, SO_SNDTIMEO, (sockopt_t)&to, sizeof(to));
  417. # endif // !(!defined(NO_LOG) && defined(_PEDANTIC))
  418. # endif // !defined(NO_TIMEOUT) && !__minix__
  419. char ipstr[64];
  420. socklen_t len;
  421. struct sockaddr_storage addr;
  422. len = sizeof addr;
  423. if (getpeername(s_client, (struct sockaddr*)&addr, &len) ||
  424. !ip2str(ipstr, sizeof(ipstr), (struct sockaddr*)&addr, len))
  425. {
  426. # if !defined(NO_LOG) && defined(_PEDANTIC)
  427. logger("Fatal: Cannot determine client's IP address: %s\n", vlmcsd_strerror(errno));
  428. # endif // !defined(NO_LOG) && defined(_PEDANTIC)
  429. socketclose(s_client);
  430. return;
  431. }
  432. # ifndef NO_LOG
  433. const char *const connection_type = addr.ss_family == AF_INET6 ? cIPv6 : cIPv4;
  434. static const char *const cAccepted = "accepted";
  435. static const char *const cClosed = "closed";
  436. static const char *const fIP = "%s connection %s: %s.\n";
  437. logger(fIP, connection_type, cAccepted, ipstr);
  438. #endif // NO_LOG
  439. rpcServer(s_client, RpcAssocGroup, ipstr);
  440. # ifndef NO_LOG
  441. logger(fIP, connection_type, cClosed, ipstr);
  442. # endif // NO_LOG
  443. socketclose(s_client);
  444. }
  445. #ifndef NO_SOCKETS
  446. static void post_sem(void)
  447. {
  448. #if !defined(NO_LIMIT) && !__minix__
  449. if (!InetdMode && MaxTasks != SEM_VALUE_MAX)
  450. {
  451. semaphore_post(Semaphore);
  452. }
  453. #endif // !defined(NO_LIMIT) && !__minix__
  454. }
  455. static void wait_sem(void)
  456. {
  457. #if !defined(NO_LIMIT) && !__minix__
  458. if (!InetdMode && MaxTasks != SEM_VALUE_MAX)
  459. {
  460. semaphore_wait(Semaphore);
  461. }
  462. #endif // !defined(NO_LIMIT) && !__minix__
  463. }
  464. #endif // NO_SOCKETS
  465. #if defined(USE_THREADS) && !defined(NO_SOCKETS)
  466. #if defined(_WIN32) || defined(__CYGWIN__) // Win32 Threads
  467. static DWORD WINAPI serveClientThreadProc(PCLDATA clData)
  468. #else // Posix threads
  469. static void *serveClientThreadProc (PCLDATA clData)
  470. #endif // Thread proc is identical in WIN32 and Posix threads
  471. {
  472. serveClient(clData->socket, clData->RpcAssocGroup);
  473. free(clData);
  474. post_sem();
  475. return 0;
  476. }
  477. #endif // USE_THREADS
  478. #ifndef NO_SOCKETS
  479. #if defined(USE_THREADS) && (defined(_WIN32) || defined(__CYGWIN__)) // Windows Threads
  480. static int serveClientAsyncWinThreads(const PCLDATA thr_CLData)
  481. {
  482. wait_sem();
  483. HANDLE h = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)serveClientThreadProc, thr_CLData, 0, NULL);
  484. if (h)
  485. CloseHandle(h);
  486. else
  487. {
  488. socketclose(thr_CLData->socket);
  489. free(thr_CLData);
  490. post_sem();
  491. return GetLastError();
  492. }
  493. return NO_ERROR;
  494. }
  495. #endif // defined(USE_THREADS) && defined(_WIN32) // Windows Threads
  496. #if defined(USE_THREADS) && !defined(_WIN32) && !defined(__CYGWIN__) // Posix Threads
  497. static int ServeClientAsyncPosixThreads(const PCLDATA thr_CLData)
  498. {
  499. pthread_t p_thr;
  500. pthread_attr_t attr;
  501. wait_sem();
  502. // Must set detached state to avoid memory leak
  503. if (pthread_attr_init(&attr) ||
  504. pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) ||
  505. pthread_create(&p_thr, &attr, (void * (*)(void *))serveClientThreadProc, thr_CLData))
  506. {
  507. socketclose(thr_CLData->socket);
  508. free(thr_CLData);
  509. post_sem();
  510. return !0;
  511. }
  512. return 0;
  513. }
  514. #endif // defined(USE_THREADS) && !defined(_WIN32) // Posix Threads
  515. #ifndef USE_THREADS // fork() implementation
  516. static void ChildSignalHandler(const int signal)
  517. {
  518. if (signal == SIGHUP) return;
  519. post_sem();
  520. #ifndef NO_LOG
  521. logger("Warning: Child killed/crashed by %s\n", strsignal(signal));
  522. #endif // NO_LOG
  523. exit(!0);
  524. }
  525. static int ServeClientAsyncFork(const SOCKET s_client, const DWORD RpcAssocGroup)
  526. {
  527. int pid;
  528. wait_sem();
  529. if ((pid = fork()) < 0)
  530. {
  531. return errno;
  532. }
  533. else if ( pid )
  534. {
  535. // Parent process
  536. socketclose(s_client);
  537. return 0;
  538. }
  539. else
  540. {
  541. // Child process
  542. // Setup a Child Handler for most common termination signals
  543. struct sigaction sa;
  544. sa.sa_flags = 0;
  545. sa.sa_handler = ChildSignalHandler;
  546. static int signallist[] = { SIGHUP, SIGINT, SIGTERM, SIGSEGV, SIGILL, SIGFPE, SIGBUS };
  547. if (!sigemptyset(&sa.sa_mask))
  548. {
  549. uint_fast8_t i;
  550. for (i = 0; i < _countof(signallist); i++)
  551. {
  552. sigaction(signallist[i], &sa, NULL);
  553. }
  554. }
  555. serveClient(s_client, RpcAssocGroup);
  556. post_sem();
  557. exit(0);
  558. }
  559. }
  560. #endif
  561. int serveClientAsync(const SOCKET s_client, const DWORD RpcAssocGroup)
  562. {
  563. #ifndef USE_THREADS // fork() implementation
  564. return ServeClientAsyncFork(s_client, RpcAssocGroup);
  565. #else // threads implementation
  566. PCLDATA thr_CLData = (PCLDATA)vlmcsd_malloc(sizeof(CLDATA));
  567. thr_CLData->socket = s_client;
  568. thr_CLData->RpcAssocGroup = RpcAssocGroup;
  569. #if defined(_WIN32) || defined (__CYGWIN__) // Windows threads
  570. return serveClientAsyncWinThreads(thr_CLData);
  571. #else // Posix Threads
  572. return ServeClientAsyncPosixThreads(thr_CLData);
  573. #endif // Posix Threads
  574. #endif // USE_THREADS
  575. }
  576. #endif // NO_SOCKETS
  577. int runServer()
  578. {
  579. DWORD RpcAssocGroup = rand32();
  580. // If compiled for inetd-only mode just serve the stdin socket
  581. #ifdef NO_SOCKETS
  582. serveClient(STDIN_FILENO, RpcAssocGroup);
  583. return 0;
  584. #else
  585. // In inetd mode just handle the stdin socket
  586. if (InetdMode)
  587. {
  588. serveClient(STDIN_FILENO, RpcAssocGroup);
  589. return 0;
  590. }
  591. for (;;)
  592. {
  593. int error;
  594. SOCKET s_client;
  595. #ifdef SIMPLE_SOCKETS
  596. if ( (s_client = accept(s_server, NULL, NULL)) == INVALID_SOCKET )
  597. #else // Standalone mode fully featured sockets
  598. if ( (s_client = network_accept_any()) == INVALID_SOCKET )
  599. #endif // Standalone mode fully featured sockets
  600. {
  601. error = socket_errno;
  602. if (error == VLMCSD_EINTR || error == VLMCSD_ECONNABORTED) continue;
  603. #ifdef _NTSERVICE
  604. if (ServiceShutdown) return 0;
  605. #endif
  606. #ifndef NO_LOG
  607. logger("Fatal: %s\n",vlmcsd_strerror(error));
  608. #endif
  609. return error;
  610. }
  611. RpcAssocGroup++;
  612. serveClientAsync(s_client, RpcAssocGroup);
  613. }
  614. #endif // NO_SOCKETS
  615. return 0;
  616. }
  617. #endif // USE_MSRPC