1/* ex: set shiftwidth=4 softtabstop=4 expandtab: */
2/*
3 * echo_client  : demo DCE RPC application
4 *
5 * Jim Doyle, jrd@bu.edu, 09-05-1998
6 *
7 *
8 */
9#if HAVE_CONFIG_H
10#include <config.h>
11#endif
12
13#include <stdio.h>
14#include <string.h>
15#include <stdlib.h>
16#include <unistd.h>
17#include <compat/dcerpc.h>
18#include "echo.h"
19#include "misc.h"
20
21#ifndef HAVE_GETOPT_H
22#include "getopt.h"
23#endif
24
25#define MAX_USER_INPUT 128
26#define MAX_LINE 100 * 1024
27
28#ifdef _WIN32
29#define EOF_STRING "^Z"
30#else
31#define EOF_STRING "^D"
32#endif
33
34/*
35 * Forward declarations
36 */
37
38static int
39get_client_rpc_binding(
40    rpc_binding_handle_t * binding_handle,
41    rpc_if_handle_t interface_spec,
42    const char * hostname,
43    const char * protocol,
44    const char * endpoint
45    );
46
47/*
48 * usage()
49 */
50
51static void usage(void)
52{
53    printf("usage: echo_server [-h hostname] -e endpoint  -n|-u|-t\n");
54    printf("         -h:  specify host of RPC server (default is localhost)\n");
55    printf("         -e:  specify endpoint for protocol\n");
56    printf("         -n:  use named pipe protocol\n");
57    printf("         -u:  use UDP protocol\n");
58    printf("         -t:  use TCP protocol (default)\n");
59    printf("         -g:  instead of prompting, generate a data string of the specified length\n");
60    printf("         -d:  turn on debugging\n");
61    printf("\n");
62    exit(1);
63}
64
65/* XXX this needs a home in the public headers ... */
66extern void rpc__dbg_set_switches(
67        const char      * /*s*/,
68        unsigned32      * /*st*/
69    );
70
71int
72main(
73    int argc,
74    char *argv[]
75    )
76{
77
78    /*
79     * command line processing and options stuff
80     */
81
82    extern char *optarg;
83    extern int optind, opterr, optopt;
84    int c;
85
86    const char * rpc_host = "127.0.0.1";
87    const char * protocol = PROTOCOL_TCP;
88    const char * endpoint = NULL;
89
90    char buf[MAX_LINE+1];
91
92    /*
93     * stuff needed to make RPC calls
94     */
95
96    unsigned32 status;
97    rpc_binding_handle_t echo_server;
98    args * inargs;
99    args * outargs;
100    int ok;
101    unsigned32 i;
102    int generate_length = -1;
103
104    char * nl;
105
106    /*
107     * Process the cmd line args
108     */
109
110    while ((c = getopt(argc, argv, "h:e:nutdg:")) != EOF)
111    {
112        switch (c)
113        {
114        case 'h':
115            rpc_host = optarg;
116            break;
117        case 'e':
118            endpoint = optarg;
119            break;
120        case 'n':
121            protocol = PROTOCOL_NP;
122            break;
123        case 'u':
124            protocol = PROTOCOL_UDP;
125            break;
126        case 't':
127            protocol = PROTOCOL_TCP;
128            break;
129        case 'd':
130#ifdef _WIN32
131	    printf("This option is only supported on Linux.\n");
132#else
133            rpc__dbg_set_switches("0-19.10", &status);
134            //Skip 20, which is memory allocs and frees
135            rpc__dbg_set_switches("21-43.10", &status);
136#endif
137            break;
138        case 'g':
139            generate_length = strtol(optarg, NULL, 10);
140            break;
141        default:
142            usage();
143        }
144    }
145
146    if(!endpoint || !protocol)
147    {
148        usage();
149        exit(1);
150    }
151
152    /*
153     * Get a binding handle to the server using the following params:
154     *
155     *  1. the hostname where the server lives
156     *  2. the interface description structure of the IDL interface
157     *  3. the desired transport protocol (UDP or TCP)
158     */
159
160    if (get_client_rpc_binding(&echo_server,
161                               echo_v1_0_c_ifspec,
162                               rpc_host,
163                               protocol,
164                               endpoint) == 0)
165    {
166        printf ("Couldn't obtain RPC server binding. exiting.\n");
167        exit(1);
168    }
169
170
171    /*
172     * Allocate an "args" struct with enough room to accomodate
173     * the max number of lines of text we can can from stdin.
174     */
175
176    inargs = (args *)malloc(sizeof(args) + MAX_USER_INPUT * sizeof(string_t));
177    if (inargs == NULL) printf("FAULT. Didn't allocate inargs.\n");
178
179    if (generate_length < 0)
180    {
181        /*
182         * Get text from the user and pack into args.
183         */
184
185        printf ("enter stuff (%s on an empty line when done):\n\n\n", EOF_STRING);
186        i = 0;
187        while (!feof(stdin) && i < MAX_USER_INPUT )
188        {
189            if (NULL==fgets(buf, MAX_LINE, stdin))
190                break;
191            if ((nl=strchr(buf, '\n')))                   /* strip the newline */
192                *nl=0;
193            inargs->argv[i] = (string_t)strdup(buf);      /* copy from buf */
194            i++;
195        }
196        inargs->argc = i;
197    }
198    else
199    {
200        inargs->argv[0] = malloc(generate_length + 1);
201        inargs->argv[0][0] = 's';
202
203        for(i = 1; i < (unsigned long)generate_length; i++)
204        {
205            inargs->argv[0][i] = i%10 + '0';
206        }
207
208        if(generate_length > 0)
209            inargs->argv[0][generate_length - 1] = 'e';
210        inargs->argv[0][generate_length] = '\0';
211        inargs->argc = 1;
212    }
213
214    /*
215     * Do the RPC call
216     */
217
218    printf ("calling server\n");
219    ok = ReverseIt(echo_server, inargs, &outargs, &status);
220
221    /*
222     * Print the results
223     */
224
225    if (ok && status == error_status_ok)
226    {
227        printf ("got response from server. results: \n");
228        for (i=0; i<outargs->argc; i++)
229            printf("\t[%d]: %s\n", i, outargs->argv[i]);
230        printf("\n===================================\n");
231
232    }
233
234    if (status != error_status_ok)
235        chk_dce_err(status, "ReverseIt()", "main()", 1);
236
237    /*
238     * Done. Now gracefully teardown the RPC binding to the server
239     */
240
241    rpc_binding_free(&echo_server, &status);
242    exit(0);
243
244}
245
246/*==========================================================================
247 *
248 * get_client_rpc_binding()
249 *
250 *==========================================================================
251 *
252 * Gets a binding handle to an RPC interface.
253 *
254 * parameters:
255 *
256 *    [out]     binding_handle
257 *    [in]      interface_spec <- DCE Interface handle for service
258 *    [in]      hostname       <- Internet hostname where server lives
259 *    [in]      protocol       <- "ncacn_ip_tcp", etc.
260 *    [in]      endpoint       <- optional
261 *
262 *==========================================================================*/
263
264static int
265get_client_rpc_binding(
266    rpc_binding_handle_t * binding_handle,
267    rpc_if_handle_t interface_spec,
268    const char * hostname,
269    const char * protocol,
270    const char * endpoint
271    )
272{
273    unsigned_char_p_t string_binding = NULL;
274    error_status_t status;
275
276    /*
277     * create a string binding given the command line parameters and
278     * resolve it into a full binding handle using the endpoint mapper.
279     *  The binding handle resolution is handled by the runtime library
280     */
281
282    rpc_string_binding_compose(NULL,
283			       (unsigned_char_p_t)protocol,
284			       (unsigned_char_p_t)hostname,
285			       (unsigned_char_p_t)endpoint,
286			       NULL,
287			       &string_binding,
288			       &status);
289    chk_dce_err(status, "rpc_string_binding_compose()", "get_client_rpc_binding", 1);
290
291
292    rpc_binding_from_string_binding(string_binding,
293                                    binding_handle,
294                                    &status);
295    chk_dce_err(status, "rpc_binding_from_string_binding()", "get_client_rpc_binding", 1);
296
297    if (!endpoint)
298    {
299        /*
300         * Resolve the partial binding handle using the endpoint mapper
301         */
302
303        rpc_ep_resolve_binding(*binding_handle,
304                               interface_spec,
305                               &status);
306        chk_dce_err(status, "rpc_ep_resolve_binding()", "get_client_rpc_binding", 1);
307    }
308
309    rpc_string_free(&string_binding, &status);
310    chk_dce_err(status, "rpc_string_free()", "get_client_rpc_binding", 1);
311
312    /*
313     * Get a printable rendition of the binding handle and echo to
314     * the user.
315     */
316
317    rpc_binding_to_string_binding(*binding_handle,
318                                  (unsigned char **)&string_binding,
319                                  &status);
320    chk_dce_err(status, "rpc_binding_to_string_binding()", "get_client_rpc_binding", 1);
321
322    printf("fully resolving binding for server is: %s\n", string_binding);
323
324    rpc_string_free(&string_binding, &status);
325    chk_dce_err(status, "rpc_string_free()", "get_client_rpc_binding", 1);
326
327    return 1;
328}
329