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.

360 lines
13 KiB

  1. //
  2. // client.c - Simple TCP/UDP client 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_SERVER NULL // Will use the loopback interface
  26. #define DEFAULT_FAMILY PF_UNSPEC // Accept either IPv4 or IPv6
  27. #define DEFAULT_SOCKTYPE SOCK_STREAM // TCP
  28. #define DEFAULT_PORT "5001" // Arbitrary, albiet a historical test port
  29. #define DEFAULT_EXTRA 0 // Number of "extra" bytes to send
  30. #define BUFFER_SIZE 65536
  31. void Usage(char *ProgName) {
  32. fprintf(stderr, "\nSimple socket sample client program.\n");
  33. fprintf(stderr, "\n%s [-s server] [-f family] [-t transport] [-p port] [-b bytes] [-n number]\n\n",
  34. ProgName);
  35. fprintf(stderr, " server\tServer name or IP address. (default: %s)\n",
  36. (DEFAULT_SERVER == NULL) ? "loopback address" : DEFAULT_SERVER);
  37. fprintf(stderr, " family\tOne of PF_INET, PF_INET6 or PF_UNSPEC. (default: %s)\n",
  38. (DEFAULT_FAMILY == PF_UNSPEC) ? "PF_UNSPEC" :
  39. ((DEFAULT_FAMILY == PF_INET) ? "PF_INET" : "PF_INET6"));
  40. fprintf(stderr, " transport\tEither TCP or UDP. (default: %s)\n",
  41. (DEFAULT_SOCKTYPE == SOCK_STREAM) ? "TCP" : "UDP");
  42. fprintf(stderr, " port\t\tPort on which to connect. (default: %s)\n",
  43. DEFAULT_PORT);
  44. fprintf(stderr, " bytes\t\tBytes of extra data to send. (default: %d)\n",
  45. DEFAULT_EXTRA);
  46. fprintf(stderr, " number\tNumber of sends to perform. (default: 1)\n");
  47. fprintf(stderr, " (-n by itself makes client run in an infinite loop,");
  48. fprintf(stderr, " Hit Ctrl-C to terminate)\n");
  49. WSACleanup();
  50. exit(1);
  51. }
  52. LPSTR DecodeError(int ErrorCode)
  53. {
  54. static char Message[1024];
  55. // If this program was multi-threaded, we'd want to use
  56. // FORMAT_MESSAGE_ALLOCATE_BUFFER instead of a static buffer here.
  57. // (And of course, free the buffer when we were done with it)
  58. FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS |
  59. FORMAT_MESSAGE_MAX_WIDTH_MASK,
  60. NULL, ErrorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  61. (LPSTR)Message, 1024, NULL);
  62. return Message;
  63. }
  64. int
  65. ReceiveAndPrint(SOCKET ConnSocket, char *Buffer, int BufLen)
  66. {
  67. int AmountRead;
  68. AmountRead = recv(ConnSocket, Buffer, BufLen, 0);
  69. if (AmountRead == SOCKET_ERROR) {
  70. fprintf(stderr, "recv() failed with error %d: %s\n",
  71. WSAGetLastError(), DecodeError(WSAGetLastError()));
  72. closesocket(ConnSocket);
  73. WSACleanup();
  74. exit(1);
  75. }
  76. //
  77. // We are not likely to see this with UDP, since there is no
  78. // 'connection' established.
  79. //
  80. if (AmountRead == 0) {
  81. printf("Server closed connection\n");
  82. closesocket(ConnSocket);
  83. WSACleanup();
  84. exit(0);
  85. }
  86. printf("Received %d bytes from server: [%.*s]\n",
  87. AmountRead, AmountRead, Buffer);
  88. return AmountRead;
  89. }
  90. int main(int argc, char **argv) {
  91. char Buffer[BUFFER_SIZE], AddrName[NI_MAXHOST];
  92. char *Server = DEFAULT_SERVER;
  93. int Family = DEFAULT_FAMILY;
  94. int SocketType = DEFAULT_SOCKTYPE;
  95. char *Port = DEFAULT_PORT;
  96. int i, RetVal, AddrLen, AmountToSend;
  97. int ExtraBytes = DEFAULT_EXTRA;
  98. unsigned int Iteration, MaxIterations = 1;
  99. BOOL RunForever = FALSE;
  100. WSADATA wsaData;
  101. ADDRINFO Hints, *AddrInfo, *AI;
  102. SOCKET ConnSocket;
  103. struct sockaddr_storage Addr;
  104. if (argc > 1) {
  105. for (i = 1;i < argc; i++) {
  106. if (((argv[i][0] == '-') || (argv[i][0] == '/')) &&
  107. (argv[i][1] != 0) && (argv[i][2] == 0)) {
  108. switch(tolower(argv[i][1])) {
  109. case 'f':
  110. if (!argv[i+1])
  111. Usage(argv[0]);
  112. if (!stricmp(argv[i+1], "PF_INET"))
  113. Family = PF_INET;
  114. else if (!stricmp(argv[i+1], "PF_INET6"))
  115. Family = PF_INET6;
  116. else if (!stricmp(argv[i+1], "PF_UNSPEC"))
  117. Family = PF_UNSPEC;
  118. else
  119. Usage(argv[0]);
  120. i++;
  121. break;
  122. case 't':
  123. if (!argv[i+1])
  124. Usage(argv[0]);
  125. if (!stricmp(argv[i+1], "TCP"))
  126. SocketType = SOCK_STREAM;
  127. else if (!stricmp(argv[i+1], "UDP"))
  128. SocketType = SOCK_DGRAM;
  129. else
  130. Usage(argv[0]);
  131. i++;
  132. break;
  133. case 's':
  134. if (argv[i+1]) {
  135. if (argv[i+1][0] != '-') {
  136. Server = argv[++i];
  137. break;
  138. }
  139. }
  140. Usage(argv[0]);
  141. break;
  142. case 'p':
  143. if (argv[i+1]) {
  144. if (argv[i+1][0] != '-') {
  145. Port = argv[++i];
  146. break;
  147. }
  148. }
  149. Usage(argv[0]);
  150. break;
  151. case 'b':
  152. if (argv[i+1]) {
  153. if (argv[i+1][0] != '-') {
  154. ExtraBytes = atoi(argv[++i]);
  155. if (ExtraBytes > sizeof(Buffer) - sizeof("Message #4294967295"))
  156. Usage(argv[0]);
  157. break;
  158. }
  159. }
  160. Usage(argv[0]);
  161. break;
  162. case 'n':
  163. if (argv[i+1]) {
  164. if (argv[i+1][0] != '-') {
  165. MaxIterations = atoi(argv[++i]);
  166. break;
  167. }
  168. }
  169. RunForever = TRUE;
  170. break;
  171. default:
  172. Usage(argv[0]);
  173. break;
  174. }
  175. }
  176. else
  177. Usage(argv[0]);
  178. }
  179. }
  180. // Ask for Winsock version 2.2.
  181. if ((RetVal = WSAStartup(MAKEWORD(2, 2), &wsaData)) != 0) {
  182. fprintf(stderr, "WSAStartup failed with error %d: %s\n",
  183. RetVal, DecodeError(RetVal));
  184. WSACleanup();
  185. return -1;
  186. }
  187. //
  188. // By not setting the AI_PASSIVE flag in the hints to getaddrinfo, we're
  189. // indicating that we intend to use the resulting address(es) to connect
  190. // to a service. This means that when the Server parameter is NULL,
  191. // getaddrinfo will return one entry per allowed protocol family
  192. // containing the loopback address for that family.
  193. //
  194. memset(&Hints, 0, sizeof(Hints));
  195. Hints.ai_family = Family;
  196. Hints.ai_socktype = SocketType;
  197. RetVal = getaddrinfo(Server, Port, &Hints, &AddrInfo);
  198. if (RetVal != 0) {
  199. fprintf(stderr, "Cannot resolve address [%s] and port [%s], error %d: %s\n",
  200. Server, Port, RetVal, gai_strerror(RetVal));
  201. WSACleanup();
  202. return -1;
  203. }
  204. //
  205. // Try each address getaddrinfo returned, until we find one to which
  206. // we can sucessfully connect.
  207. //
  208. for (AI = AddrInfo; AI != NULL; AI = AI->ai_next) {
  209. // Open a socket with the correct address family for this address.
  210. ConnSocket = socket(AI->ai_family, AI->ai_socktype, AI->ai_protocol);
  211. if (ConnSocket == INVALID_SOCKET) {
  212. fprintf(stderr,"Error Opening socket, error %d: %s\n",
  213. WSAGetLastError(), DecodeError(WSAGetLastError()));
  214. continue;
  215. }
  216. //
  217. // Notice that nothing in this code is specific to whether we
  218. // are using UDP or TCP.
  219. //
  220. // When connect() is called on a datagram socket, it does not
  221. // actually establish the connection as a stream (TCP) socket
  222. // would. Instead, TCP/IP establishes the remote half of the
  223. // (LocalIPAddress, LocalPort, RemoteIP, RemotePort) mapping.
  224. // This enables us to use send() and recv() on datagram sockets,
  225. // instead of recvfrom() and sendto().
  226. //
  227. printf("Attempting to connect to: %s\n", Server ? Server : "localhost");
  228. if (connect(ConnSocket, AI->ai_addr, AI->ai_addrlen) != SOCKET_ERROR)
  229. break;
  230. i = WSAGetLastError();
  231. if (getnameinfo(AI->ai_addr, AI->ai_addrlen, AddrName,
  232. sizeof(AddrName), NULL, 0, NI_NUMERICHOST) != 0)
  233. strcpy(AddrName, "<unknown>");
  234. fprintf(stderr, "connect() to %s failed with error %d: %s\n",
  235. AddrName, i, DecodeError(i));
  236. closesocket(ConnSocket);
  237. }
  238. if (AI == NULL) {
  239. fprintf(stderr, "Fatal error: unable to connect to the server.\n");
  240. WSACleanup();
  241. return -1;
  242. }
  243. //
  244. // This demonstrates how to determine to where a socket is connected.
  245. //
  246. AddrLen = sizeof(Addr);
  247. if (getpeername(ConnSocket, (LPSOCKADDR)&Addr, &AddrLen) == SOCKET_ERROR) {
  248. fprintf(stderr, "getpeername() failed with error %d: %s\n",
  249. WSAGetLastError(), DecodeError(WSAGetLastError()));
  250. } else {
  251. if (getnameinfo((LPSOCKADDR)&Addr, AddrLen, AddrName,
  252. sizeof(AddrName), NULL, 0, NI_NUMERICHOST) != 0)
  253. strcpy(AddrName, "<unknown>");
  254. printf("Connected to %s, port %d, protocol %s, protocol family %s\n",
  255. AddrName, ntohs(SS_PORT(&Addr)),
  256. (AI->ai_socktype == SOCK_STREAM) ? "TCP" : "UDP",
  257. (AI->ai_family == PF_INET) ? "PF_INET" : "PF_INET6");
  258. }
  259. // We are done with the address info chain, so we can free it.
  260. freeaddrinfo(AddrInfo);
  261. //
  262. // Find out what local address and port the system picked for us.
  263. //
  264. AddrLen = sizeof(Addr);
  265. if (getsockname(ConnSocket, (LPSOCKADDR)&Addr, &AddrLen) == SOCKET_ERROR) {
  266. fprintf(stderr, "getsockname() failed with error %d: %s\n",
  267. WSAGetLastError(), DecodeError(WSAGetLastError()));
  268. } else {
  269. if (getnameinfo((LPSOCKADDR)&Addr, AddrLen, AddrName,
  270. sizeof(AddrName), NULL, 0, NI_NUMERICHOST) != 0)
  271. strcpy(AddrName, "<unknown>");
  272. printf("Using local address %s, port %d\n",
  273. AddrName, ntohs(SS_PORT(&Addr)));
  274. }
  275. //
  276. // Send and receive in a loop for the requested number of iterations.
  277. //
  278. for (Iteration = 0; RunForever || Iteration < MaxIterations; Iteration++) {
  279. // Compose a message to send.
  280. AmountToSend = sprintf(Buffer, "Message #%u", Iteration + 1);
  281. for (i = 0; i < ExtraBytes; i++) {
  282. Buffer[AmountToSend++] = (char)((i & 0x3f) + 0x20);
  283. }
  284. // Send the message. Since we are using a blocking socket, this
  285. // call shouldn't return until it's able to send the entire amount.
  286. RetVal = send(ConnSocket, Buffer, AmountToSend, 0);
  287. if (RetVal == SOCKET_ERROR) {
  288. fprintf(stderr, "send() failed with error %d: %s\n",
  289. WSAGetLastError(), DecodeError(WSAGetLastError()));
  290. WSACleanup();
  291. return -1;
  292. }
  293. printf("Sent %d bytes (out of %d bytes) of data: [%.*s]\n",
  294. RetVal, AmountToSend, AmountToSend, Buffer);
  295. // Clear buffer just to prove we're really receiving something.
  296. memset(Buffer, 0, sizeof(Buffer));
  297. // Receive and print server's reply.
  298. ReceiveAndPrint(ConnSocket, Buffer, sizeof(Buffer));
  299. }
  300. // Tell system we're done sending.
  301. printf("Done sending\n");
  302. shutdown(ConnSocket, SD_SEND);
  303. //
  304. // Since TCP does not preserve message boundaries, there may still
  305. // be more data arriving from the server. So we continue to receive
  306. // data until the server closes the connection.
  307. //
  308. if (SocketType == SOCK_STREAM)
  309. while(ReceiveAndPrint(ConnSocket, Buffer, sizeof(Buffer)) != 0)
  310. ;
  311. closesocket(ConnSocket);
  312. WSACleanup();
  313. return 0;
  314. }