1/* 2 * echo_server : demo DCE RPC application 3 * 4 * Jim Doyle, jrd@bu.edu 09-05-1998 5 * 6 * 7 */ 8#if HAVE_CONFIG_H 9#include <config.h> 10#endif 11 12#ifndef _POSIX_PTHREAD_SEMANTICS 13#define _POSIX_PTHREAD_SEMANTICS 1 14#endif 15 16#include <stdio.h> 17#include <stdlib.h> 18#include <string.h> 19#include <signal.h> 20#include <unistd.h> 21#include <compat/dcerpc.h> 22#include "echo.h" 23#include "misc.h" 24 25#ifndef HAVE_GETOPT_H 26#include "getopt.h" 27#endif 28 29#ifndef _WIN32 30static void wait_for_signals(void); 31#endif 32 33/* 34 * 35 * A template DCE RPC server 36 * 37 * main() contains the basic calls needed to register an interface, 38 * get communications endpoints, and register the endpoints 39 * with the endpoint mapper. 40 * 41 * ReverseIt() implements the interface specified in echo.idl 42 * 43 */ 44 45static void 46bind_server( 47 rpc_binding_vector_p_t * server_binding, 48 rpc_if_handle_t interface_spec ATTRIBUTE_UNUSED, 49 const char * protocol, 50 const char * endpoint) 51{ 52 const char * function = "n/a"; 53 unsigned32 status; 54 55 /* 56 * Prepare the server binding handle 57 * use all avail protocols (UDP and TCP). This basically allocates 58 * new sockets for us and associates the interface UUID and 59 * object UUID of with those communications endpoints. 60 */ 61 62#if 0 63 rpc_server_use_all_protseqs_if(0, interface_spec, &status); 64#else 65 if (!endpoint) 66 { 67 if (!protocol) 68 { 69 function = "rpc_server_use_all_protseqs()"; 70 rpc_server_use_all_protseqs(rpc_c_protseq_max_calls_default, &status); 71 } 72 else 73 { 74 function = "rpc_server_use_protseq()"; 75 rpc_server_use_protseq((unsigned_char_p_t)protocol, 76 rpc_c_protseq_max_calls_default, &status); 77 } 78 } 79 else 80 { 81 function = "rpc_server_use_protseq_ep()"; 82 rpc_server_use_protseq_ep((unsigned_char_p_t)protocol, 83 rpc_c_protseq_max_calls_default, (unsigned_char_p_t)endpoint, &status); 84 } 85#endif 86 87 chk_dce_err(status, function, "", 1); 88 rpc_server_inq_bindings(server_binding, &status); 89 chk_dce_err(status, "rpc_server_inq_bindings()", "", 1); 90} 91 92static void usage(void) 93{ 94 printf("usage: echo_server -e endpoint -n|-u|-t\n"); 95 printf(" -e: specify endpoint\n"); 96 printf(" -n: use named pipe protocol\n"); 97 printf(" -u: use UDP protocol\n"); 98 printf(" -t: use TCP protocol (default)\n"); 99 printf("\n"); 100 exit(1); 101} 102 103int main(int argc, char *argv[]) 104{ 105 unsigned32 status; 106 rpc_binding_vector_p_t server_binding; 107 char * string_binding; 108 unsigned32 i; 109 const char * protocol = NULL; 110 const char * endpoint = NULL; 111 int c; 112 113 /* 114 * Process the cmd line args 115 */ 116 117 while ((c = getopt(argc, argv, "e:nut")) != EOF) 118 { 119 switch (c) 120 { 121 case 'e': 122 endpoint = optarg; 123 break; 124 case 'n': 125 protocol = PROTOCOL_NP; 126 break; 127 case 'u': 128 protocol = PROTOCOL_UDP; 129 break; 130 case 't': 131 protocol = PROTOCOL_TCP; 132 break; 133 default: 134 usage(); 135 } 136 } 137 138#if 0 139 if (endpoint && !protocol) 140 { 141 printf("ERROR: protocol is required when endpoint is specified\n"); 142 exit(1); 143 } 144#else 145 if(!endpoint || !protocol) 146 { 147 usage(); 148 exit(1); 149 } 150#endif 151 152#ifndef _WIN32 153 /* Temporarily disable using all protocols because something is currently busted on Unix */ 154 if (!protocol) 155 { 156 protocol = PROTOCOL_TCP; 157 } 158#endif 159 160 /* 161 * Register the Interface with the local endpoint mapper (rpcd) 162 */ 163 164 printf ("Registering server.... \n"); 165 rpc_server_register_if(echo_v1_0_s_ifspec, 166 NULL, 167 NULL, 168 &status); 169 chk_dce_err(status, "rpc_server_register_if()", "", 1); 170 171 printf("registered.\nPreparing binding handle...\n"); 172 173 bind_server(&server_binding, echo_v1_0_s_ifspec, protocol, endpoint); 174 175 if(!endpoint) 176 { 177 /* 178 * Register bindings with the endpoint mapper 179 */ 180 printf("registering bindings with endpoint mapper\n"); 181 182 rpc_ep_register(echo_v1_0_s_ifspec, 183 server_binding, 184 NULL, 185 (unsigned char *)"QDA application server", 186 &status); 187 chk_dce_err(status, "rpc_ep_register()", "", 1); 188 } 189 190 printf("registered.\n"); 191 192 /* 193 * Print out the servers endpoints (TCP and UDP port numbers) 194 */ 195 196 printf ("Server's communications endpoints are:\n"); 197 198 for (i=0; i<RPC_FIELD_COUNT(server_binding); i++) 199 { 200 rpc_binding_to_string_binding(RPC_FIELD_BINDING_H(server_binding)[i], 201 (unsigned char **)&string_binding, 202 &status); 203 if (string_binding) 204 printf("\t%s\n", string_binding); 205 } 206 207#ifndef _WIN32 208 /* 209 * Start the signal waiting thread in background. This thread will 210 * Catch SIGINT and gracefully shutdown the server. 211 */ 212 213 wait_for_signals(); 214#endif 215 216 /* 217 * Begin listening for calls 218 */ 219 220 printf ("listening for calls....\n"); 221 222 DCETHREAD_TRY 223 { 224 rpc_server_listen(rpc_c_listen_max_calls_default, &status); 225 } 226 DCETHREAD_CATCH_ALL(THIS_CATCH) 227 { 228 printf ("Server stoppped listening\n"); 229 } 230 DCETHREAD_ENDTRY; 231 232 /* 233 * If we reached this point, then the server was stopped, most likely 234 * by the signal handler thread called rpc_mgmt_stop_server(). 235 * gracefully cleanup and unregister the bindings from the 236 * endpoint mapper. 237 */ 238 239#ifndef _WIN32 240 /* 241 * Kill the signal handling thread 242 */ 243 244#endif 245 246 if (!endpoint) 247 { 248 printf ("Unregistering server from the endpoint mapper....\n"); 249 rpc_ep_unregister(echo_v1_0_s_ifspec, 250 server_binding, 251 NULL, 252 &status); 253 chk_dce_err(status, "rpc_ep_unregister()", "", 0); 254 } 255 256 /* 257 * retire the binding information 258 */ 259 260 printf("Cleaning up communications endpoints...\n"); 261 rpc_server_unregister_if(echo_v1_0_s_ifspec, 262 NULL, 263 &status); 264 chk_dce_err(status, "rpc_server_unregister_if()", "", 0); 265 266 exit(0); 267} 268 269 270/*========================================================================= 271 * 272 * Server implementation of ReverseIt() 273 * 274 *=========================================================================*/ 275 276idl_boolean 277ReverseIt( 278 rpc_binding_handle_t h, 279 args * in_text, 280 args ** out_text, 281 error_status_t * status 282 ) 283{ 284 285 char * binding_info; 286 error_status_t e; 287 unsigned result_size; 288 args * result; 289 unsigned32 i,j,l; 290 rpc_transport_info_handle_t transport_info = NULL; 291 unsigned32 rpcstatus = 0; 292 293#if 0 294 unsigned char* sesskey = NULL; 295 unsigned32 sesskey_len = 0; 296 unsigned char* principal_name = NULL; 297#endif 298 299 /* 300 * Get some info about the client binding 301 */ 302 303 rpc_binding_to_string_binding(h, (unsigned char **)&binding_info, &e); 304 if (e == rpc_s_ok) 305 { 306 printf ("ReverseIt() called by client: %s\n", binding_info); 307 } 308 309 rpc_binding_inq_transport_info(h, &transport_info, &rpcstatus); 310 311 /* SMB transport session calls temporarily disabled */ 312#if 0 313 if (transport_info) 314 { 315 rpc_smb_transport_info_inq_peer_principal_name(transport_info, &principal_name); 316 rpc_smb_transport_info_inq_session_key(transport_info, &sesskey, &sesskey_len); 317 318 printf ("Client principal name: %s\n", (char*) principal_name); 319 printf ("Session key: "); 320 321 for (i = 0; i < sesskey_len; i++) 322 { 323 printf("%X", sesskey[i]); 324 } 325 326 printf ("\n"); 327 } 328 329#endif /* 0 */ 330 331 if (in_text == NULL) return 0; 332 333 /* 334 * Print the in_text 335 */ 336 337 printf("\n\nFunction ReverseIt() -- input argments\n"); 338 339 for (i=0; i<in_text->argc; i++) 340 printf("\t[arg %d]: %s\n", i, in_text->argv[i]); 341 342 printf ("\n=========================================\n"); 343 344 /* 345 * Allocate the output args as dynamic storage bound 346 * to this RPC. The output args are the same size as the 347 * input args since we are simply reversing strings. 348 */ 349 350 result_size = sizeof(args) + in_text->argc * sizeof(string_t *); 351 result = (args * )rpc_ss_allocate(result_size); 352 result->argc = in_text->argc; 353 354 for (i=0; i < in_text->argc; i++) 355 { 356 result->argv[i] = 357 (string_t)rpc_ss_allocate(strlen((const char *)in_text->argv[i]) + 1); 358 } 359 360 /* 361 * do the string reversal 362 */ 363 364 for (i=0; i < in_text->argc; i++) 365 { 366 l = strlen((const char *)in_text->argv[i]); 367 for (j=0; j<l; j++) 368 { 369 result->argv[i][j] = in_text->argv[i][l-j-1]; 370 } 371 result->argv[i][l]=0; /* make sure its null terminated! */ 372 } 373 374 *out_text = result; 375 *status = error_status_ok; 376 377 return 1; 378} 379 380 381#ifndef _WIN32 382/*========================================================================= 383 * 384 * wait_for_signals() 385 * 386 * 387 * Set up the process environment to properly deal with signals. 388 * By default, we isolate all threads from receiving asynchronous 389 * signals. We create a thread that handles all async signals. 390 * The signal handling actions are handled in the handler thread. 391 * 392 * For AIX, we cant use a thread that sigwaits() on a specific signal, 393 * we use a plain old, lame old Unix signal handler. 394 * 395 *=========================================================================*/ 396 397void 398wait_for_signals(void) 399{ 400 sigset_t signals; 401 402 sigemptyset(&signals); 403 sigaddset(&signals, SIGINT); 404 405 dcethread_signal_to_interrupt(&signals, dcethread_self()); 406} 407 408#endif 409