summaryrefslogtreecommitdiff
path: root/general/echo/umdfSocketEcho/Exe/socketechoserver.cpp
diff options
context:
space:
mode:
authorDave Wilson <[email protected]>2015-03-17 19:50:07 -0700
committerDave Wilson <[email protected]>2015-03-17 19:50:07 -0700
commit97cf5197cf5b882b2c689d8dc2b555f2edf8f418 (patch)
tree46f3701832d70b420eb0fc0eb93261f9da45db3f /general/echo/umdfSocketEcho/Exe/socketechoserver.cpp
parentef1905bf1e8825bb31120dfb27e0daf3154d859a (diff)
Initial publish
Diffstat (limited to 'general/echo/umdfSocketEcho/Exe/socketechoserver.cpp')
-rw-r--r--general/echo/umdfSocketEcho/Exe/socketechoserver.cpp512
1 files changed, 512 insertions, 0 deletions
diff --git a/general/echo/umdfSocketEcho/Exe/socketechoserver.cpp b/general/echo/umdfSocketEcho/Exe/socketechoserver.cpp
new file mode 100644
index 00000000..bfe5f546
--- /dev/null
+++ b/general/echo/umdfSocketEcho/Exe/socketechoserver.cpp
@@ -0,0 +1,512 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+Module Name:
+
+ socketserver.cpp
+
+Abstract:
+
+ A simple socket server application that listens on a specified port and echoes back data
+ received.
+
+Environment:
+
+ User Mode
+
+--*/
+
+#include "internal.h"
+
+
+DWORD
+Run(
+ LPVOID lpThreadParameter
+ )
+ /*++
+
+Routine Description:
+
+ This routine is invoked for each thread created for a new connection accepted by the server.
+ The rcv and send to socket happen in this thread routine.
+
+
+Arguments:
+
+ lpThreadParameter , The Thread parameter which contains socket information
+
+Return Value:
+
+ Thread Exit Code
+
+
+--*/
+{
+ #define DeleteBufferExitThread(dwExitCode) \
+ delete[] buffer; \
+ buffer = NULL; \
+ ExitThread(dwExitCode);
+
+ #define DeleteBufferReturn(dwExitCode) \
+ delete[] buffer; \
+ buffer = NULL; \
+ return dwExitCode;
+
+ int count =0;
+
+ char *buffer = new char[DATA_LENGTH];
+ if (NULL == buffer)
+ {
+ ExitThread(1);
+ }
+
+ DWORD Event;
+
+ //
+ // Look at socket information from thread arg.
+ //
+
+
+ CEchoServer *pThreadData = (CEchoServer*)lpThreadParameter;
+ if (pThreadData==NULL)
+ {
+ DeleteBufferExitThread(1);
+ }
+
+ SOCKET sClient = pThreadData->m_socket;
+ HANDLE NetworkEvent = pThreadData->m_NetworkEvent;
+ WSANETWORKEVENTS NetworkEvents;
+ printf("Client Start: 0x%Ix\n", sClient);
+ int actual = 0;
+ for(;;)
+ {
+ if ((Event = WSAWaitForMultipleEvents(
+ 1,
+ &NetworkEvent,
+ FALSE,
+ WSA_INFINITE,
+ FALSE)) == WSA_WAIT_FAILED)
+ {
+ printf("WSAWaitForMultipleEvents failed with error %d\n", WSAGetLastError());
+ DeleteBufferReturn(0);
+ }
+
+ if (WSAEnumNetworkEvents(sClient ,NetworkEvent, &NetworkEvents) == SOCKET_ERROR)
+ {
+ printf("WSAEnumNetworkEvents failed with error %d\n", WSAGetLastError());
+ DeleteBufferReturn(0);
+ }
+
+ if (NetworkEvents.lNetworkEvents & FD_READ)
+ {
+ if (NetworkEvents.lNetworkEvents & FD_READ && NetworkEvents.iErrorCode[FD_READ_BIT] != 0)
+ {
+ printf("FD_READ failed with error %d\n", NetworkEvents.iErrorCode[FD_READ_BIT]);
+ }
+ else
+ {
+
+ actual = recv(sClient,buffer,DATA_LENGTH*sizeof(char),0);
+ //
+ // socket connection has been reset ,so bail out .
+ //
+ if (actual == 0 || actual == WSAECONNRESET )
+ {
+ printf(" Could not get data , Error : 0x%lx \n",WSAGetLastError());
+ break; // socket shut-down
+
+ }
+ printf("FD_READ read buffer on client 0x%Ix with length %d \n",sClient,actual);
+ count = send(sClient, (const char*)buffer,actual,0);
+ if ( count == SOCKET_ERROR )
+ {
+ if ( WSAGetLastError()== WSAEWOULDBLOCK )
+ {
+ printf(" Could not send data as resource is unavaliable , do not retry until next Write event \n");
+ }
+ else
+ {
+ printf(" Could not send data , Error : 0x%lx \n",WSAGetLastError());
+ break;
+ }
+ }
+ else
+ {
+ printf("FD_WRITE write buffer on client 0x%Ix with length %d \n",sClient,count);
+ }
+ }
+ }
+ //
+ // if there is a write network event and there is data to write , write that
+ //
+ if (NetworkEvents.lNetworkEvents & FD_WRITE)
+ {
+ if (NetworkEvents.lNetworkEvents & FD_WRITE && NetworkEvents.iErrorCode[FD_WRITE_BIT] != 0)
+ {
+ printf("FD_WRITE failed with error %d\n", NetworkEvents.iErrorCode[FD_WRITE_BIT]);
+ }
+ else
+ {
+ count = send(sClient, (const char*)buffer,actual,0);
+ if ( count == SOCKET_ERROR )
+ {
+ if ( WSAGetLastError()== WSAEWOULDBLOCK )
+ {
+ printf(" Could not send data as resource is unavaliable , do not retry until next Write event ");
+ }
+ else
+ {
+ printf(" Could not send data , Error : 0x%lx \n",WSAGetLastError());
+ break;
+ }
+ }
+ else
+ {
+ printf("FD_WRITE write buffer on client 0x%Ix with length %d \n",sClient,count);
+ }
+ actual = 0;
+ }
+ }
+ if (NetworkEvents.lNetworkEvents & FD_CLOSE)
+ {
+ shutdown(sClient,FD_READ|FD_WRITE);
+ printf(" recived a close from client : 0x%Ix \n",sClient);
+ closesocket(sClient);
+ DeleteBufferExitThread(0);
+ }
+ }
+
+ DeleteBufferReturn(1);
+
+}
+
+CEchoServer::CEchoServer(
+ SOCKET socketclient
+ )
+/*++
+
+Routine Description:
+
+ This is the constructor routine for CEchoServer class. This is called for each instance of new
+ connection accepted by the server .
+
+Arguments:
+
+ Socket received from the accept
+
+Return Value:
+
+ None .
+
+--*/
+{
+ m_socket = socketclient;
+ m_NetworkEvent = WSACreateEvent();
+ printf("socket created : 0x%Ix \n", m_socket);
+
+}
+
+void
+CEchoServer::Start()
+/*++
+
+Routine Description:
+
+ This routine is to Start the thread which will rcv and send the data recieved on this instance of socket connection.
+
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+--*/
+{
+
+
+ if(WSAEventSelect(
+ m_socket,
+ m_NetworkEvent,
+ FD_READ|FD_WRITE|FD_CLOSE)== SOCKET_ERROR)
+ {
+ printf("Error in Event Select,Cannot start Server thread for this socket \n");
+ closesocket(m_socket);
+ goto Exit;
+ }
+//
+// Create thread to read/write data to this socket
+//
+
+ HANDLE hRunThread = CreateThread(
+ NULL, // Default Security Attrib.
+ 0, // Initial Stack Size,
+ (LPTHREAD_START_ROUTINE) Run, // Thread Func
+ this, // Arg to Thread Func.
+ 0, // Creation Flags
+ NULL // Don't need the Thread Id.
+ );
+ if (NULL == hRunThread)
+ {
+ printf(" Could not create socket server run thread : 0x%lx \n", GetLastError());
+ closesocket(m_socket);
+ goto Exit;
+ }
+
+Exit:
+
+ return ;
+ }
+
+void
+SocketServerMain(
+ _In_ unsigned short uPort
+ )
+/*++
+
+Routine Description:
+
+ This routine is the main entry for the app when the app is configured to
+ be a socket server.
+ It creates a a listening socket for incoming conenctions.
+
+
+Arguments:
+
+ uPort - Port Number that the socket server binds to
+
+Return Value:
+
+ None.
+--*/
+{
+
+
+ SOCKET ListenSocket;
+ int iResult;
+ #pragma warning( suppress: 24002 ) // suppress warning for IPv6 ,currently IPv4 specific
+ sockaddr_in service ;
+
+ // Initialize Winsock 2.2
+ WSADATA wsaData;
+ iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
+ if ( NO_ERROR != iResult )
+ {
+ printf("Error at WSAStartup() \n");
+ goto Exit;
+ }
+ //
+ // Create a SOCKET for listening for incoming connection requests.
+ //
+ ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if ( INVALID_SOCKET == ListenSocket)
+ {
+ printf("Error at socket(): %ld\n ", WSAGetLastError());
+ goto Cleanup;
+ }
+ // The sockaddr_in structure specifies the address family,
+ // IP address, and port for the socket that is being bound.
+ service.sin_family = AF_INET;
+ //
+ // Suppress overflow warning.
+ // inet_pton is annotated to write sizeof(IN6_ADDR) bytes to pAddrBuf,
+ // but it only writes sizeof(IN_ADDR) bytes when Family is AF_INET (IPv4).
+ // https://msdn.microsoft.com/en-us/library/windows/desktop/cc805844(v=vs.85).aspx
+ //
+ #pragma warning( suppress: 26000 )
+ iResult = inet_pton(AF_INET, "127.0.0.1", &service.sin_addr);
+ if (iResult != 1)
+ {
+ printf("Error at inet_pton(): %ld\n ", WSAGetLastError());
+ closesocket(ListenSocket);
+ goto Cleanup;
+ }
+ service.sin_port = htons(uPort);
+ if (SOCKET_ERROR == bind(
+ ListenSocket,
+ (SOCKADDR*) &service,
+ sizeof(service) ) )
+ {
+ printf("bind() failed. \n");
+ closesocket(ListenSocket);
+ goto Cleanup;
+ }
+
+ //
+ // Listen for incoming connection requests
+ // on the created socket upto MAX_CONNECTIONS
+ //
+ if ( SOCKET_ERROR == listen(
+ ListenSocket,
+ MAX_CONNECTIONS ) )
+ {
+ printf("Error listening on socket.\n");
+ }
+ printf("Listening on socket...\n");
+
+ //
+ // Set Socket RCVBUF and SNDBUF size to DATA_LENGTH , so large requests are not fragmented .
+ //
+ int iOptVal;
+ int iOptLen = sizeof(int);
+
+ if (getsockopt(ListenSocket, SOL_SOCKET, SO_RCVBUF, (char*)&iOptVal, &iOptLen) != SOCKET_ERROR)
+ {
+ printf("SO_RCVBUF value: %ld\n", iOptVal);
+ }
+ iOptVal = DATA_LENGTH;
+ iOptLen = sizeof(int);
+ if (setsockopt(ListenSocket, SOL_SOCKET, SO_RCVBUF, (char*)&iOptVal, iOptLen) != SOCKET_ERROR)
+ {
+ printf("Set SO_RCVBUF: ON\n");
+ }
+ iOptLen = sizeof(int);
+ if (getsockopt(ListenSocket, SOL_SOCKET, SO_RCVBUF, (char*)&iOptVal, &iOptLen) != SOCKET_ERROR)
+ {
+ printf("SO_RCVBUF Value: %ld\n", iOptVal);
+ }
+ iOptLen = sizeof(int);
+ if (getsockopt(ListenSocket, SOL_SOCKET, SO_SNDBUF, (char*)&iOptVal, &iOptLen) != SOCKET_ERROR)
+ {
+ printf("SO_SNDBUF value: %ld\n", iOptVal);
+ }
+ iOptVal = DATA_LENGTH;
+ iOptLen = sizeof(int);
+ if (setsockopt(ListenSocket, SOL_SOCKET, SO_SNDBUF, (char*)&iOptVal, iOptLen) != SOCKET_ERROR)
+ {
+ printf("Set SO_SNDBUF: ON\n");
+ }
+ iOptLen = sizeof(int);
+ if (getsockopt(ListenSocket, SOL_SOCKET, SO_SNDBUF, (char*)&iOptVal, &iOptLen) != SOCKET_ERROR)
+ {
+ printf("SO_SNDBUF Value: %ld\n", iOptVal);
+ }
+
+//
+// Loop the server to start accepting connections from clients on this socket
+//
+
+ for(;;)
+ {
+ CEchoServer *client = new CEchoServer(accept(ListenSocket,NULL,NULL));
+
+ if (client)
+ {
+ printf("Client connected.\n");
+ client->Start(); // Start receiving/sending data on the socket
+ }
+ }
+
+Cleanup:
+ //
+ // Invoke Winsock Cleanup
+ //
+
+ WSACleanup();
+
+ Exit:
+ return;
+
+}
+void
+Usage()
+
+/*++
+
+Routine Description:
+
+ This routine is invoked to display the usage of this application
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None .
+--*/
+
+{
+ printf("\n\n Usage: \n");
+ printf(" ------ \n\n");
+ printf(" socketechoapp Display Usage \n");
+ printf(" socketechoapp -h Display Usage\n");
+ printf(" socketechoapp -p Start the app as server listening on default port\n");
+ printf(" socketechoapp -p [port#] Start the app as server listening on this port \n");
+
+
+
+}
+
+
+/* */
+void __cdecl
+main(
+ _In_ int argc,
+ _In_reads_(argc) char* argv[]
+ )
+
+/*++
+
+Routine Description:
+
+
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+--*/
+{
+ unsigned short argIndex = 1 ;
+ unsigned short uPort = DEFAULT_PORT_ADDRESS ;
+
+
+ if (argc < 2)
+ {
+ Usage();
+ goto Exit;
+ }
+
+//
+// look at second arg and check for either -h which indicates user asked for help in Usage
+// of this commandline
+//
+
+ if (!strcmp(*(argv+argIndex),"-h"))
+ {
+ Usage();
+ goto Exit;
+ }
+//
+// check if its -p and proceed with otherwise show usage
+//
+ else if (!strcmp(*(argv+argIndex),"-p"))
+ {
+ //
+ // look at third arg, which should be the port#
+ //
+ if ( ++argIndex < argc )
+ {
+ uPort = (unsigned short)atoi(*(argv+(argIndex)));
+ }
+ SocketServerMain(uPort);
+
+ }
+ else
+ {
+ Usage();
+ goto Exit;
+ }
+
+Exit:
+ return;
+
+}
+
+