1 // client->cpp : Defines the entry point for the console application.
2 //
3 // sample client command line app using Thrift IPC.
4 // Quick n Dirty example, may not have very robust error handling
5 // for the sake of simplicity.
6 
7 #ifdef _WIN32
8 #  include "stdafx.h"
9 #else
10 #  include "config.h"
11 #endif
12 
13 
14 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
15 //Include this before the generated includes
16 #include "ThriftCommon.h"
17 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
18 //Tailor these to your generated files
19 #include "../gen-cpp/SampleService.h"
20 #include "../gen-cpp/SampleCallback.h"
21 
22 using namespace Sample; //declared in .thrift file
23 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
24 
25 void ClientListenerThreadProc();
26 bool bSocket = false;
27 bool bAnonPipe = false;
28 int srvPort;
29 std::string pipename;
30 std::string pipename_client;
31 #ifdef _WIN32
32  HANDLE hConsole;
33 #endif
34 
35 //Customized version of printf that changes the text color
36 //This depends on hConsole global being initialized
hlprintf(const char * _Format,...)37 void hlprintf(const char* _Format, ...)
38 {
39 #ifdef _WIN32
40 	SetConsoleTextAttribute(hConsole, 0xE);
41 #endif
42 	va_list ap;
43 	int r;
44 	va_start (ap, _Format);
45 	r = vprintf (_Format, ap);
46 	va_end (ap);
47 #ifdef _WIN32
48 	SetConsoleTextAttribute(hConsole, 7);
49 #endif
50 }
51 
52 //-----------------------------------------------------------------------------
53 // Client-side RPC implementations: Called by the server to the client for
54 // bidirectional eventing.
55 //
56 class SampleCallbackHandler : virtual public SampleCallbackIf {
57  public:
SampleCallbackHandler()58   SampleCallbackHandler() {
59     // initialization goes here
60   }
61 
pingclient()62   void pingclient()
63   {
64     hlprintf("<<<Ping received from server (server-to-client event).\n");
65   }
66 
67 };
68 //-----------------------------------------------------------------------------
69 
70 
71 #ifdef _WIN32
_tmain(int argc,_TCHAR * argv[])72 int _tmain(int argc, _TCHAR* argv[])
73 #else
74 int main(int argc, char **argv)
75 #endif
76 {
77 	//Process cmd line args to determine named vs anon pipes.
78 	bool usage = false;
79 #ifdef _WIN32
80 	HANDLE ReadPipe, WritePipe;
81 	hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
82 #endif
83 
84 	//Process command line params
85 	if(argc > 1)
86 	{
87 		if(_tcscmp(argv[1], TEXT("-sp")) == 0)
88 		{	//Socket Port specified
89 			srvPort = _tstoi(argv[2]);
90 			bSocket = true;
91 		}
92 		else if(_tcscmp(argv[1], TEXT("-np")) == 0)
93 		{	//Named Pipe specified
94 #ifdef _WIN32
95                         std::wstring wpipe(argv[2]);
96                         pipename.resize(wpipe.length());
97                         std::copy(wpipe.begin(), wpipe.end(), pipename.begin());
98 #else
99                         pipename = argv[2];
100 #endif
101 			pipename_client = pipename + "_client";
102 		}
103 		else if(argc == 3)
104 		{	//Anonymous Pipe specified
105 #ifdef _WIN32
106 			ReadPipe  = (HANDLE)_tstoi(argv[1]);
107 			WritePipe = (HANDLE)_tstoi(argv[2]);
108 			bAnonPipe = true;
109 #else
110                         printf("Anonymous pipes not (yet) supported under *NIX\n");
111 #endif
112 		}
113 		else
114 			usage = true;
115 	}
116 	else
117 		usage = true;
118 
119 	if(usage)
120 	{
121 		hlprintf("Thrift sample client usage:\n\n");
122 		hlprintf("Socket Port to connect to: -sp <port#>\n");
123 		hlprintf("Named Pipe to connect to:  -np <pipename> (e.g. affpipe)\n");
124 		hlprintf("Anonymous Pipe (must be launched by anon pipe creator):\n");
125 		hlprintf("                           <Read Handle> <Write Handle>\n");
126 		return 0;
127 	}
128 
129 	//Client side connection to server.
130 	boost::shared_ptr<SampleServiceClient> client; //Client class from Thrift-generated code.
131 	boost::shared_ptr<TTransport> transport;
132 
133 	if(bSocket)
134 	{	//Socket transport
135 #ifdef _WIN32
136 		TWinsockSingleton::create();
137 #endif
138 		hlprintf("Using socket transport port %d\n", srvPort);
139 		thriftcommon::ConnectToServer<SampleServiceClient, TTransport>(client, transport, srvPort);
140 	}
141 	else if(!bAnonPipe)
142 	{
143 		hlprintf("Using Named Pipe %s\n", pipename.c_str());
144 		thriftcommon::ConnectToServer<SampleServiceClient, TTransport>(client, transport, pipename);
145 	}
146 	else
147 	{
148 #ifdef _WIN32
149 		hlprintf("Using Anonymous Pipe transport\n");
150 		thriftcommon::ConnectToServer<SampleServiceClient, TTransport>(client, transport, ReadPipe, WritePipe);
151 #endif
152 	}
153 
154 #ifdef _WIN32
155 	//Start a thread to receive inbound connection from server for 2-way event signaling.
156 	boost::thread ClientListenerThread(ClientListenerThreadProc);
157 #endif
158 
159 	try {
160 		transport->open();
161 
162 		//Notify server what to connect back on.
163 		if(bSocket)
164 			client->ClientSideListenPort(srvPort + 1); //Socket
165 		else if(!bAnonPipe)
166 			client->ClientSidePipeName(pipename_client); //Named Pipe
167 
168 		//Run some more RPCs
169 		std::string hellostr = "Hello how are you?";
170 		std::string returnstr;
171 		client->HelloThere(returnstr, hellostr);
172 		hlprintf("\n>>>Sent: %s\n", hellostr.c_str());
173 		hlprintf("<<<Received: %s\n", returnstr.c_str());
174 
175 		hlprintf("\n>>>Calling ServerDoSomething() which delays for 5 seconds.\n");
176 		client->ServerDoSomething();
177 		hlprintf(">>>ServerDoSomething() done.\n\n");
178 
179 		transport->close();
180 	} catch (TException &tx) {
181 		hlprintf("ERROR: %s\n", tx.what());
182 	}
183 
184 	return 0;
185 }
186 
187 
188 //Thread Routine
ClientListenerThreadProc()189 void ClientListenerThreadProc()
190 {
191 	if(bSocket)
192 		thriftcommon::RunThriftServer<SampleCallbackHandler, SampleCallbackProcessor>(1, srvPort + 1);
193 	else if(!bAnonPipe)
194 		thriftcommon::RunThriftServer<SampleCallbackHandler, SampleCallbackProcessor>(1, pipename_client);
195 }
196