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