Source code of Windows XP (NT5)
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.

396 lines
15 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 <stdlib.h>
  17. #include <stdio.h>
  18. #include <string.h>
  19. //
  20. // This code assumes that at the transport level, the system only supports
  21. // one stream protocol (TCP) and one datagram protocol (UDP). Therefore,
  22. // specifying a socket type of SOCK_STREAM is equivalent to specifying TCP
  23. // and specifying a socket type of SOCK_DGRAM is equivalent to specifying UDP.
  24. //
  25. #define DEFAULT_FAMILY PF_UNSPEC // Accept either IPv4 or IPv6
  26. #define DEFAULT_SOCKTYPE SOCK_STREAM // TCP
  27. #define DEFAULT_PORT "5001" // Arbitrary, albiet a historical test port
  28. #define BUFFER_SIZE 64 // Set very small for demonstration purposes
  29. void Usage(char *ProgName) {
  30. fprintf(stderr, "\nSimple socket sample server program.\n");
  31. fprintf(stderr, "\n%s [-f family] [-t transport] [-p port] [-a address]\n\n",
  32. ProgName);
  33. fprintf(stderr, " family\tOne of PF_INET, PF_INET6 or PF_UNSPEC. (default %s)\n",
  34. (DEFAULT_FAMILY == PF_UNSPEC) ? "PF_UNSPEC" :
  35. ((DEFAULT_FAMILY == PF_INET) ? "PF_INET" : "PF_INET6"));
  36. fprintf(stderr, " transport\tEither TCP or UDP. (default: %s)\n",
  37. (DEFAULT_SOCKTYPE == SOCK_STREAM) ? "TCP" : "UDP");
  38. fprintf(stderr, " port\t\tPort on which to bind. (default %s)\n",
  39. DEFAULT_PORT);
  40. fprintf(stderr, " address\tIP address on which to bind. (default: unspecified address)\n");
  41. WSACleanup();
  42. exit(1);
  43. }
  44. LPSTR DecodeError(int ErrorCode)
  45. {
  46. static char Message[1024];
  47. // If this program was multi-threaded, we'd want to use
  48. // FORMAT_MESSAGE_ALLOCATE_BUFFER instead of a static buffer here.
  49. // (And of course, free the buffer when we were done with it)
  50. FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS |
  51. FORMAT_MESSAGE_MAX_WIDTH_MASK, NULL, ErrorCode,
  52. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  53. (LPSTR)Message, 1024, NULL);
  54. return Message;
  55. }
  56. int main(int argc, char **argv)
  57. {
  58. char Buffer[BUFFER_SIZE], Hostname[NI_MAXHOST];
  59. int Family = DEFAULT_FAMILY;
  60. int SocketType = DEFAULT_SOCKTYPE;
  61. char *Port = DEFAULT_PORT;
  62. char *Address = NULL;
  63. int i, NumSocks, RetVal, FromLen, AmountRead;
  64. SOCKADDR_STORAGE From;
  65. WSADATA wsaData;
  66. ADDRINFO Hints, *AddrInfo, *AI;
  67. SOCKET ServSock[FD_SETSIZE];
  68. fd_set SockSet;
  69. // Parse arguments
  70. if (argc > 1) {
  71. for(i = 1;i < argc; i++) {
  72. if ((argv[i][0] == '-') || (argv[i][0] == '/') &&
  73. (argv[i][1] != 0) && (argv[i][2] == 0)) {
  74. switch(tolower(argv[i][1])) {
  75. case 'f':
  76. if (!argv[i+1])
  77. Usage(argv[0]);
  78. if (!stricmp(argv[i+1], "PF_INET"))
  79. Family = PF_INET;
  80. else if (!stricmp(argv[i+1], "PF_INET6"))
  81. Family = PF_INET6;
  82. else if (!stricmp(argv[i+1], "PF_UNSPEC"))
  83. Family = PF_UNSPEC;
  84. else
  85. Usage(argv[0]);
  86. i++;
  87. break;
  88. case 't':
  89. if (!argv[i+1])
  90. Usage(argv[0]);
  91. if (!stricmp(argv[i+1], "TCP"))
  92. SocketType = SOCK_STREAM;
  93. else if (!stricmp(argv[i+1], "UDP"))
  94. SocketType = SOCK_DGRAM;
  95. else
  96. Usage(argv[0]);
  97. i++;
  98. break;
  99. case 'a':
  100. if (argv[i+1]) {
  101. if (argv[i+1][0] != '-') {
  102. Address = argv[++i];
  103. break;
  104. }
  105. }
  106. Usage(argv[0]);
  107. break;
  108. case 'p':
  109. if (argv[i+1]) {
  110. if (argv[i+1][0] != '-') {
  111. Port = argv[++i];
  112. break;
  113. }
  114. }
  115. Usage(argv[0]);
  116. break;
  117. default:
  118. Usage(argv[0]);
  119. break;
  120. }
  121. } else
  122. Usage(argv[0]);
  123. }
  124. }
  125. // Ask for Winsock version 2.2.
  126. if ((RetVal = WSAStartup(MAKEWORD(2, 2), &wsaData)) != 0) {
  127. fprintf(stderr, "WSAStartup failed with error %d: %s\n",
  128. RetVal, DecodeError(RetVal));
  129. WSACleanup();
  130. return -1;
  131. }
  132. if (Port == NULL) {
  133. Usage(argv[0]);
  134. }
  135. //
  136. // By setting the AI_PASSIVE flag in the hints to getaddrinfo, we're
  137. // indicating that we intend to use the resulting address(es) to bind
  138. // to a socket(s) for accepting incoming connections. This means that
  139. // when the Address parameter is NULL, getaddrinfo will return one
  140. // entry per allowed protocol family containing the unspecified address
  141. // for that family.
  142. //
  143. memset(&Hints, 0, sizeof(Hints));
  144. Hints.ai_family = Family;
  145. Hints.ai_socktype = SocketType;
  146. Hints.ai_flags = AI_NUMERICHOST | AI_PASSIVE;
  147. RetVal = getaddrinfo(Address, Port, &Hints, &AddrInfo);
  148. if (RetVal != 0) {
  149. fprintf(stderr, "getaddrinfo failed with error %d: %s\n",
  150. RetVal, gai_strerror(RetVal));
  151. WSACleanup();
  152. return -1;
  153. }
  154. //
  155. // For each address getaddrinfo returned, we create a new socket,
  156. // bind that address to it, and create a queue to listen on.
  157. //
  158. for (i = 0, AI = AddrInfo; AI != NULL; AI = AI->ai_next, i++) {
  159. // Highly unlikely, but check anyway.
  160. if (i == FD_SETSIZE) {
  161. printf("getaddrinfo returned more addresses than we could use.\n");
  162. break;
  163. }
  164. // This example only supports PF_INET and PF_INET6.
  165. if ((AI->ai_family != PF_INET) && (AI->ai_family != PF_INET6))
  166. continue;
  167. // Open a socket with the correct address family for this address.
  168. ServSock[i] = socket(AI->ai_family, AI->ai_socktype, AI->ai_protocol);
  169. if (ServSock[i] == INVALID_SOCKET){
  170. fprintf(stderr, "socket() failed with error %d: %s\n",
  171. WSAGetLastError(), DecodeError(WSAGetLastError()));
  172. continue;
  173. }
  174. //
  175. // bind() associates a local address and port combination
  176. // with the socket just created. This is most useful when
  177. // the application is a server that has a well-known port
  178. // that clients know about in advance.
  179. //
  180. if (bind(ServSock[i], AI->ai_addr, AI->ai_addrlen) == SOCKET_ERROR) {
  181. fprintf(stderr,"bind() failed with error %d: %s\n",
  182. WSAGetLastError(), DecodeError(WSAGetLastError()));
  183. continue;
  184. }
  185. //
  186. // So far, everything we did was applicable to TCP as well as UDP.
  187. // However, there are certain fundamental differences between stream
  188. // protocols such as TCP and datagram protocols such as UDP.
  189. //
  190. // Only connection orientated sockets, for example those of type
  191. // SOCK_STREAM, can listen() for incoming connections.
  192. //
  193. if (SocketType == SOCK_STREAM) {
  194. if (listen(ServSock[i], 5) == SOCKET_ERROR) {
  195. fprintf(stderr, "listen() failed with error %d: %s\n",
  196. WSAGetLastError(), DecodeError(WSAGetLastError()));
  197. continue;
  198. }
  199. }
  200. printf("'Listening' on port %s, protocol %s, protocol family %s\n",
  201. Port, (SocketType == SOCK_STREAM) ? "TCP" : "UDP",
  202. (AI->ai_family == PF_INET) ? "PF_INET" : "PF_INET6");
  203. }
  204. freeaddrinfo(AddrInfo);
  205. if (i == 0) {
  206. fprintf(stderr, "Fatal error: unable to serve on any address.\n");
  207. WSACleanup();
  208. return -1;
  209. }
  210. NumSocks = i;
  211. //
  212. // We now put the server into an eternal loop,
  213. // serving requests as they arrive.
  214. //
  215. FD_ZERO(&SockSet);
  216. while(1) {
  217. FromLen = sizeof(From);
  218. //
  219. // For connection orientated protocols, we will handle the
  220. // packets comprising a connection collectively. For datagram
  221. // protocols, we have to handle each datagram individually.
  222. //
  223. //
  224. // Check to see if we have any sockets remaining to be served
  225. // from previous time through this loop. If not, call select()
  226. // to wait for a connection request or a datagram to arrive.
  227. //
  228. for (i = 0; i < NumSocks; i++){
  229. if (FD_ISSET(ServSock[i], &SockSet))
  230. break;
  231. }
  232. if (i == NumSocks) {
  233. for (i = 0; i < NumSocks; i++)
  234. FD_SET(ServSock[i], &SockSet);
  235. if (select(NumSocks, &SockSet, 0, 0, 0) == SOCKET_ERROR) {
  236. fprintf(stderr, "select() failed with error %d: %s\n",
  237. WSAGetLastError(), DecodeError(WSAGetLastError()));
  238. WSACleanup();
  239. return -1;
  240. }
  241. }
  242. for (i = 0; i < NumSocks; i++){
  243. if (FD_ISSET(ServSock[i], &SockSet)) {
  244. FD_CLR(ServSock[i], &SockSet);
  245. break;
  246. }
  247. }
  248. if (SocketType == SOCK_STREAM) {
  249. SOCKET ConnSock;
  250. //
  251. // Since this socket was returned by the select(), we know we
  252. // have a connection waiting and that this accept() won't block.
  253. //
  254. ConnSock = accept(ServSock[i], (LPSOCKADDR)&From, &FromLen);
  255. if (ConnSock == INVALID_SOCKET) {
  256. fprintf(stderr, "accept() failed with error %d: %s\n",
  257. WSAGetLastError(), DecodeError(WSAGetLastError()));
  258. WSACleanup();
  259. return -1;
  260. }
  261. if (getnameinfo((LPSOCKADDR)&From, FromLen, Hostname,
  262. sizeof(Hostname), NULL, 0, NI_NUMERICHOST) != 0)
  263. strcpy(Hostname, "<unknown>");
  264. printf("\nAccepted connection from %s\n", Hostname);
  265. //
  266. // This sample server only handles connections sequentially.
  267. // To handle multiple connections simultaneously, a server
  268. // would likely want to launch another thread or process at this
  269. // point to handle each individual connection. Alternatively,
  270. // it could keep a socket per connection and use select()
  271. // on the fd_set to determine which to read from next.
  272. //
  273. // Here we just loop until this connection terminates.
  274. //
  275. while (1) {
  276. //
  277. // We now read in data from the client. Because TCP
  278. // does NOT maintain message boundaries, we may recv()
  279. // the client's data grouped differently than it was
  280. // sent. Since all this server does is echo the data it
  281. // receives back to the client, we don't need to concern
  282. // ourselves about message boundaries. But it does mean
  283. // that the message data we print for a particular recv()
  284. // below may contain more or less data than was contained
  285. // in a particular client send().
  286. //
  287. AmountRead = recv(ConnSock, Buffer, sizeof(Buffer), 0);
  288. if (AmountRead == SOCKET_ERROR) {
  289. fprintf(stderr, "recv() failed with error %d: %s\n",
  290. WSAGetLastError(), DecodeError(WSAGetLastError()));
  291. closesocket(ConnSock);
  292. break;
  293. }
  294. if (AmountRead == 0) {
  295. printf("Client closed connection\n");
  296. closesocket(ConnSock);
  297. break;
  298. }
  299. printf("Received %d bytes from client: [%.*s]\n",
  300. AmountRead, AmountRead, Buffer);
  301. printf("Echoing same data back to client\n");
  302. RetVal = send(ConnSock, Buffer, AmountRead, 0);
  303. if (RetVal == SOCKET_ERROR) {
  304. fprintf(stderr, "send() failed: error %d: %s\n",
  305. WSAGetLastError(), DecodeError(WSAGetLastError()));
  306. closesocket(ConnSock);
  307. break;
  308. }
  309. }
  310. } else {
  311. //
  312. // Since UDP maintains message boundaries, the amount of data
  313. // we get from a recvfrom() should match exactly the amount of
  314. // data the client sent in the corresponding sendto().
  315. //
  316. AmountRead = recvfrom(ServSock[i], Buffer, sizeof(Buffer), 0,
  317. (LPSOCKADDR)&From, &FromLen);
  318. if (AmountRead == SOCKET_ERROR) {
  319. fprintf(stderr, "recvfrom() failed with error %d: %s\n",
  320. WSAGetLastError(), DecodeError(WSAGetLastError()));
  321. closesocket(ServSock[i]);
  322. break;
  323. }
  324. if (AmountRead == 0) {
  325. // This should never happen on an unconnected socket, but...
  326. printf("recvfrom() returned zero, aborting\n");
  327. closesocket(ServSock[i]);
  328. break;
  329. }
  330. RetVal = getnameinfo((LPSOCKADDR)&From, FromLen, Hostname,
  331. sizeof(Hostname), NULL, 0, NI_NUMERICHOST);
  332. if (RetVal != 0) {
  333. fprintf(stderr, "getnameinfo() failed with error %d: %s\n",
  334. RetVal, DecodeError(RetVal));
  335. strcpy(Hostname, "<unknown>");
  336. }
  337. printf("Received a %d byte datagram from %s: [%.*s]\n",
  338. AmountRead, Hostname, AmountRead, Buffer);
  339. printf("Echoing same data back to client\n");
  340. RetVal = sendto(ServSock[i], Buffer, AmountRead, 0,
  341. (LPSOCKADDR)&From, FromLen);
  342. if (RetVal == SOCKET_ERROR) {
  343. fprintf(stderr, "send() failed with error %d: %s\n",
  344. WSAGetLastError(), DecodeError(WSAGetLastError()));
  345. }
  346. }
  347. }
  348. return 0;
  349. }