Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

262 lines
8.9 KiB

  1. //
  2. // server.c - Simple TCP/UDP server using Winsock 2.2
  3. //
  4. // This is a part of the Microsoft Source Code Samples.
  5. // Copyright 1996 - 2000 Microsoft Corporation.
  6. // All rights reserved.
  7. // This source code is only intended as a supplement to
  8. // Microsoft Development Tools and/or WinHelp documentation.
  9. // See these sources for detailed information regarding the
  10. // Microsoft samples programs.
  11. //
  12. #define WIN32_LEAN_AND_MEAN
  13. #include <winsock2.h>
  14. #include <ws2tcpip.h>
  15. #include <tpipv6.h> // For IPv6 Tech Preview.
  16. #include <ip6.h>
  17. #include <stdlib.h>
  18. #include <stdio.h>
  19. #include <string.h>
  20. //
  21. // It's too much trouble to include icmp6.h
  22. //
  23. typedef struct ICMPv6Header {
  24. unsigned char Type;
  25. unsigned char Code;
  26. unsigned short Checksum;
  27. } ICMPv6Header;
  28. #define DEFAULT_PROTOCOL 254 // Arbitrary unassigned protocol
  29. #define BUFFER_SIZE 65536
  30. void Usage(char *ProgName) {
  31. fprintf(stderr, "\nRaw socket receive program.\n");
  32. fprintf(stderr, "\n%s [-p protocol] [-a address]\n\n",
  33. ProgName);
  34. fprintf(stderr, " protocol\t\tProtocol to receive messages for. (default %s)\n",
  35. DEFAULT_PROTOCOL);
  36. fprintf(stderr, " address\tIP address on which to bind. (default: unspecified address)\n");
  37. WSACleanup();
  38. exit(1);
  39. }
  40. LPSTR DecodeError(int ErrorCode)
  41. {
  42. static char Message[1024];
  43. // If this program was multi-threaded, we'd want to use
  44. // FORMAT_MESSAGE_ALLOCATE_BUFFER instead of a static buffer here.
  45. // (And of course, free the buffer when we were done with it)
  46. FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS |
  47. FORMAT_MESSAGE_MAX_WIDTH_MASK, NULL, ErrorCode,
  48. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  49. (LPSTR)Message, 1024, NULL);
  50. return Message;
  51. }
  52. int main(int argc, char **argv)
  53. {
  54. char Buffer[BUFFER_SIZE], Hostname[NI_MAXHOST];
  55. unsigned char Protocol = DEFAULT_PROTOCOL;
  56. char *Address = NULL;
  57. int i, NumSocks, RetVal, FromLen, AmountRead;
  58. SOCKADDR_STORAGE From;
  59. WSADATA wsaData;
  60. ADDRINFO Hints, *AddrInfo, *AI;
  61. SOCKET ServSock[FD_SETSIZE];
  62. fd_set SockSet;
  63. // Parse arguments
  64. if (argc > 1) {
  65. for(i = 1;i < argc; i++) {
  66. if ((argv[i][0] == '-') || (argv[i][0] == '/') &&
  67. (argv[i][1] != 0) && (argv[i][2] == 0)) {
  68. switch(tolower(argv[i][1])) {
  69. case 'a':
  70. if (argv[i+1]) {
  71. if (argv[i+1][0] != '-') {
  72. Address = argv[++i];
  73. break;
  74. }
  75. }
  76. Usage(argv[0]);
  77. break;
  78. case 'p':
  79. if (argv[i+1]) {
  80. if (argv[i+1][0] != '-') {
  81. Protocol = atoi(argv[++i]);
  82. break;
  83. }
  84. }
  85. Usage(argv[0]);
  86. break;
  87. default:
  88. Usage(argv[0]);
  89. break;
  90. }
  91. } else
  92. Usage(argv[0]);
  93. }
  94. }
  95. // Ask for Winsock version 2.2.
  96. if ((RetVal = WSAStartup(MAKEWORD(2, 2), &wsaData)) != 0) {
  97. fprintf(stderr, "WSAStartup failed with error %d: %s\n",
  98. RetVal, DecodeError(RetVal));
  99. WSACleanup();
  100. return -1;
  101. }
  102. //
  103. // By setting the AI_PASSIVE flag in the hints to getaddrinfo, we're
  104. // indicating that we intend to use the resulting address(es) to bind
  105. // to a socket(s) for accepting incoming connections. This means that
  106. // when the Address parameter is NULL, getaddrinfo will return one
  107. // entry per allowed protocol family containing the unspecified address
  108. // for that family.
  109. //
  110. memset(&Hints, 0, sizeof(Hints));
  111. Hints.ai_family = PF_INET6;
  112. Hints.ai_socktype = SOCK_DGRAM; // Lie until getaddrinfo is fixed.
  113. Hints.ai_flags = AI_NUMERICHOST | AI_PASSIVE;
  114. RetVal = getaddrinfo(Address, "1" /* Dummy */, &Hints, &AddrInfo);
  115. if (RetVal != 0) {
  116. fprintf(stderr, "getaddrinfo failed with error %d: %s\n",
  117. RetVal, gai_strerror(RetVal));
  118. WSACleanup();
  119. return -1;
  120. }
  121. //
  122. // For each address getaddrinfo returned, we create a new socket,
  123. // bind that address to it, and create a queue to listen on.
  124. //
  125. for (i = 0, AI = AddrInfo; AI != NULL; AI = AI->ai_next) {
  126. // Highly unlikely, but check anyway.
  127. if (i == FD_SETSIZE) {
  128. printf("getaddrinfo returned more addresses than we could use.\n");
  129. break;
  130. }
  131. ServSock[i] = socket(AI->ai_family, SOCK_RAW, Protocol);
  132. if (ServSock[i] == INVALID_SOCKET){
  133. fprintf(stderr, "socket() failed with error %d: %s\n",
  134. WSAGetLastError(), DecodeError(WSAGetLastError()));
  135. continue;
  136. }
  137. //
  138. // bind() associates a local address and port combination
  139. // with the socket just created. This is most useful when
  140. // the application is a server that has a well-known port
  141. // that clients know about in advance.
  142. //
  143. if (bind(ServSock[i], AI->ai_addr, AI->ai_addrlen) == SOCKET_ERROR) {
  144. fprintf(stderr,"bind() failed with error %d: %s\n",
  145. WSAGetLastError(), DecodeError(WSAGetLastError()));
  146. closesocket(ServSock[i]);
  147. continue;
  148. }
  149. i++;
  150. printf("Listening on protocol %d\n", Protocol);
  151. }
  152. freeaddrinfo(AddrInfo);
  153. if (i == 0) {
  154. fprintf(stderr, "Fatal error: unable to serve on any address.\n");
  155. WSACleanup();
  156. return -1;
  157. }
  158. NumSocks = i;
  159. //
  160. // We now put the server into an eternal loop,
  161. // serving requests as they arrive.
  162. //
  163. FD_ZERO(&SockSet);
  164. while(1) {
  165. FromLen = sizeof(From);
  166. //
  167. // For connection orientated protocols, we will handle the
  168. // packets comprising a connection collectively. For datagram
  169. // protocols, we have to handle each datagram individually.
  170. //
  171. //
  172. // Check to see if we have any sockets remaining to be served
  173. // from previous time through this loop. If not, call select()
  174. // to wait for a connection request or a datagram to arrive.
  175. //
  176. for (i = 0; i < NumSocks; i++){
  177. if (FD_ISSET(ServSock[i], &SockSet))
  178. break;
  179. }
  180. if (i == NumSocks) {
  181. for (i = 0; i < NumSocks; i++)
  182. FD_SET(ServSock[i], &SockSet);
  183. if (select(NumSocks, &SockSet, 0, 0, 0) == SOCKET_ERROR) {
  184. fprintf(stderr, "select() failed with error %d: %s\n",
  185. WSAGetLastError(), DecodeError(WSAGetLastError()));
  186. WSACleanup();
  187. return -1;
  188. }
  189. }
  190. for (i = 0; i < NumSocks; i++){
  191. if (FD_ISSET(ServSock[i], &SockSet)) {
  192. FD_CLR(ServSock[i], &SockSet);
  193. break;
  194. }
  195. }
  196. AmountRead = recvfrom(ServSock[i], Buffer, sizeof(Buffer), 0,
  197. (LPSOCKADDR)&From, &FromLen);
  198. if (AmountRead == SOCKET_ERROR) {
  199. fprintf(stderr, "recvfrom() failed with error %d: %s\n",
  200. WSAGetLastError(), DecodeError(WSAGetLastError()));
  201. closesocket(ServSock[i]);
  202. break;
  203. }
  204. if (AmountRead == 0) {
  205. // This should never happen on an unconnected socket, but...
  206. printf("recvfrom() returned zero, aborting\n");
  207. closesocket(ServSock[i]);
  208. break;
  209. }
  210. RetVal = getnameinfo((LPSOCKADDR)&From, FromLen, Hostname,
  211. sizeof(Hostname), NULL, 0, NI_NUMERICHOST);
  212. if (RetVal != 0) {
  213. fprintf(stderr, "getnameinfo() failed with error %d: %s\n",
  214. RetVal, DecodeError(RetVal));
  215. strcpy(Hostname, "<unknown>");
  216. }
  217. if (Protocol == IP_PROTOCOL_ICMPv6) {
  218. ICMPv6Header *ICMP = (ICMPv6Header *)Buffer;
  219. printf("Received a ICMP message from %s\n", Hostname);
  220. printf("Type = %u, Code = %u\n", ICMP->Type, ICMP->Code);
  221. printf("Data = \"%.*s\"\n",
  222. AmountRead - sizeof(*ICMP), Buffer + sizeof(*ICMP));
  223. } else {
  224. printf("Received a %d byte datagram from %s \"%.*s\"\n",
  225. AmountRead, Hostname, AmountRead, Buffer);
  226. }
  227. }
  228. return 0;
  229. }