]> andersk Git - moira.git/blob - gdb/tsr.c
fix RCS Id strings
[moira.git] / gdb / tsr.c
1 /*
2  *      $Source$
3  *      $Header$
4  */
5
6 #ifndef lint
7 static char *rcsid_tsr_c = "$Header$";
8 #endif  lint
9
10 /************************************************************************/
11 /*      
12 /*                        tsr (test server)
13 /*                        -----------------
14 /*      
15 /*      Author: Noah Mendelsohn (IBM T.J. Watson Research and MIT Project
16 /*                               Athena)
17 /*      
18 /*      Copyright: 1986 MIT Project Athena
19 /*      
20 /************************************************************************/
21 /*      
22 /*      PURPOSE
23 /*      -------
24 /*      
25 /*      A GDB server program demonstrating techniques for asynchronously
26 /*      communicating with an arbitrary number of clients from a single
27 /*      Unix server process.  This server accepts GDB connections from
28 /*      clients as requests come in (up to the arbitrary maximum
29 /*      MAXCLIENTS.)  On each connection, it receives a stream of integers,
30 /*      which it interprets as ASCII characters.  The characters are
31 /*      converted to uppercase, and then sent back to the client from
32 /*      which they came.  
33 /*      
34 /*      All of this is done completely asynchronously.  No client is 
35 /*      locked out while characters are being echoed to another, and
36 /*      new connections are accepted at any time.
37 /*      
38 /*      NOTES
39 /*      -----
40 /*      
41 /*      1) The complete state of each client is kept in the array
42 /*         named client.  The client[i].state variable indicates whether
43 /*         client i is active, and if so, the client[i].action variable
44 /*         indicates what kind of asynchronous activity the client is 
45 /*         engaged in.  Note that these are local conventions, having
46 /*         nothing to do with GDB or its interfaces.  
47 /*      
48 /*      2) Communication to each client is done over its connection,
49 /*         named client[i].con.
50 /*      
51 /*      3) There is at most one asynchronous activity pending to 
52 /*         each client at any given time, and its state is tracked
53 /*         in the variable named client[i].pending_op.  The operation
54 /*         may be a send, a receive, or an accept, depending on 
55 /*         the contents of client[i].action.  These operations are
56 /*         allocated when the server starts up, and then re-used
57 /*         repeatedly.  They are the GDB analog of a lightweight process,
58 /*         which is activated when queued on a connection.
59 /*      
60 /*      4) A special form of connection and a special listening operation
61 /*         are used for asynchronously listening for new connection
62 /*         requests.  These are 'listencon' and 'listenop' respectively.
63 \f/*     
64 /*      5) GDB includes a special form of select which waits for 
65 /*         completion of operations as well as for activity on user
66 /*         specified file descriptors.  The list of operations to be
67 /*         monitored is stored in the variable
68 /*         named op_list.  The call to op_select_any hangs until one
69 /*         or more of these operations complete, then terminates.
70 /*      
71 /*      6) The main server loop acts on any new connection requests,
72 /*         processes any newly completed activity on the active
73 /*         clients, then drops into op_select_any to allow asynchronous
74 /*         activities to progress.  
75 /*      
76 /*      
77 /************************************************************************/
78
79 #include <stdio.h>
80 #include "gdb.h"
81
82 extern int errno;
83
84 \f
85 /************************************************************************/
86 /*      
87 /*                           DECLARATIONS
88 /*      
89 /************************************************************************/
90
91 #define MAXCLIENTS 10
92
93         /*----------------------------------------------------------*/
94         /*      
95         /*      State of each possible client
96         /*      
97         /*----------------------------------------------------------*/
98
99 struct client {
100         int state;                              /* state of this client */
101                                                 /* descriptor */
102 #define CL_DEAD 1                               /* client not started */
103 #define CL_STARTING 2                           /* accepted, reply ongoing */
104 #define CL_UP 3                                 /* ready to go */
105         int action;                             /* what are we doing now */
106 #define CL_RECEIVE 4                            /* waiting for a packet */
107 #define CL_SEND    5                            /* sending a packet */
108 #define CL_ACCEPT  6                            /* sending a reply */
109         CONNECTION con;                         /* connection to this */
110                                                 /* client, if any */
111         OPERATION pending_op;                   /* pending operation */
112                                                 /* on this connection, */
113                                                 /* if any */
114         int data;                               /* the character to echo */
115                                                 /* goes here, expressed as */
116                                                 /* an int  */
117 };
118
119 struct client client[MAXCLIENTS];
120
121         /*----------------------------------------------------------*/
122         /*      
123         /*      Connections and operations for listening for
124         /*      new clients.
125         /*      
126         /*----------------------------------------------------------*/
127
128 CONNECTION listencon;                           /* listen on this */
129                                                 /* connection */
130 OPERATION  listenop;                            /* this operation is used */
131                                                 /* repeatedly for listening */
132                                                 /* for new clients */
133
134 int     nextcl = 0;                             /* index of the next client */
135                                                 /* we'll accept */
136
137 \f       /*----------------------------------------------------------*/
138         /*      
139         /*      Miscellaneous variables used in acquiring connections.
140         /*      These are ignored in a simple server like this;  a 
141         /*      more sophisticated server might want to validate the
142         /*      names of its clients before accepting connections.
143         /*      
144         /*----------------------------------------------------------*/
145
146 TUPLE client_tuple;                             /* client request goes */
147                                                 /* here */
148 char otherside[100];
149 int othersize;
150
151
152 \f
153 /************************************************************************/
154 /*      
155 /*                              MAIN
156 /*      
157 /************************************************************************/
158
159 int
160 main(argc, argv)
161 int argc;
162 char *argv[];
163 {
164         /*----------------------------------------------------------*/
165         /*      
166         /*                     LOCAL VARIABLES
167         /*      
168         /*----------------------------------------------------------*/
169
170         register int i;                         /* loop index */
171         LIST_OF_OPERATIONS op_list;             /* for op_select_any */
172
173         /*----------------------------------------------------------*/
174         /*      
175         /*      Check parameters
176         /*      
177         /*----------------------------------------------------------*/
178
179         if (argc != 2) {
180                 fprintf(stderr,"Correct form is %s <servicename>\n",
181                         argv[0]);
182                 exit(4);
183         }
184
185         /*----------------------------------------------------------*/
186         /*      
187         /*                      Initialize
188         /*      
189         /*----------------------------------------------------------*/
190
191         gdb_init();                             /* set up gdb */
192         init_clients();                         /* null the client states */
193         do_listen(argv[1]);                     /* start the listening */
194                                                 /* connection and queue */
195                                                 /* a listening operation */
196         make_oplist(&op_list);                  /* create wait list */
197
198         /*----------------------------------------------------------*/
199         /*      
200         /*           Loop forever taking care of business.
201         /*      
202         /*      1) If any new connection requests have come in,
203         /*         accept them.
204         /*      
205         /*      2) For each client on which some activity is newly
206         /*         completed, take care of it.
207         /*      
208         /*----------------------------------------------------------*/
209
210         while (TRUE) {
211                 if (OP_DONE(listenop))
212                         new_connection();
213                 for (i=0; i<MAXCLIENTS; i++) {
214                         if (OP_DONE(client[i].pending_op))
215                                 do_client(i);
216                 }
217                 if(op_select_any(op_list, 0, NULL, NULL, NULL, NULL)==(-1)) {
218                         perror("op_select_any returned error");
219                         exit(32);
220                 }
221         }
222 }
223 \f
224 /************************************************************************/
225 /*      
226 /*                              do_client
227 /*      
228 /*      An operation has completed on the specified client.
229 /*      
230 /************************************************************************/
231
232 int
233 do_client(id)
234 int id;
235 {
236         register struct client *cp = &(client[id]);
237
238        /*
239         * If there has been an error, shutdown the client.
240         */
241         connection_perror(cp->con, "Unix error on send or receive"); 
242                                                 /* print error if any */
243         if (connection_status(cp->con) != CON_UP ||
244             OP_STATUS(cp->pending_op) == OP_CANCELLED) {
245                 sever_connection(cp->con);
246                 reset_operation(cp->pending_op);
247                 cp->state = CL_DEAD;
248                 cp->action = 0;
249                 return;
250         }
251        /*
252         * The operation completed successfully.  Figure out what it was
253         * and do the right thing.
254         */
255         switch (cp->action) {
256               case CL_ACCEPT:
257               case CL_SEND:
258                 start_receiving_object(cp->pending_op, cp->con, 
259                                        (char *)&cp->data,
260                                        INTEGER_T);
261                 cp->action = CL_RECEIVE;
262                 break;
263               case CL_RECEIVE:
264                 if (cp->data >= 'a' && cp->data <= 'z')
265                         cp->data += 'A'-'a';    /* upcase the response */
266                 start_sending_object(cp->pending_op, cp->con, 
267                                        (char *)&cp->data,
268                                        INTEGER_T);
269                 cp->action = CL_SEND;
270         }
271 }
272 \f
273 /************************************************************************/
274 /*      
275 /*                        init_clients
276 /*      
277 /************************************************************************/
278
279 int
280 init_clients()
281 {
282         register struct client *c;
283
284         for (c=client; c<client+MAXCLIENTS; c++){
285                 c->state = CL_DEAD;
286                 c->action = 0;
287                 c->con = NULL;
288                 c->pending_op = create_operation();
289                 reset_operation(c->pending_op);         
290         }
291 }
292
293
294
295 /************************************************************************/
296 /*      
297 /*                      make_oplist
298 /*      
299 /************************************************************************/
300
301 int
302 make_oplist(oplp)
303 LIST_OF_OPERATIONS *oplp;
304 {
305        /*
306         * ugh! we've got to fix create_list_of_operations to be
307         * more flexible!!
308         */
309
310         *oplp = create_list_of_operations(MAXCLIENTS+1, listenop,
311                                           client[0].pending_op,
312                                           client[1].pending_op,
313                                           client[2].pending_op,
314                                           client[3].pending_op,
315                                           client[4].pending_op,
316                                           client[5].pending_op,
317                                           client[6].pending_op,
318                                           client[7].pending_op,
319                                           client[8].pending_op,
320                                           client[9].pending_op);
321 }
322 \f/************************************************************************/
323 /*      
324 /*                              do_listen
325 /*      
326 /*      Do the one time setup for listening for clients, and
327 /*      also start a listen for an actual client.
328 /*      
329 /************************************************************************/
330
331 int
332 do_listen(service)
333 char *service;
334 {
335
336         /*----------------------------------------------------------*/
337         /*      
338         /*      Make a listening connection
339         /*      
340         /*----------------------------------------------------------*/
341
342         fprintf(stderr, "Server creating listening connection\n");
343         listencon = create_listening_connection(service);
344
345         if (listencon == NULL  || connection_status(listencon) != CON_UP) {
346                 if(connection_status(listencon) == CON_STOPPING) {
347                         connection_perror(listencon, 
348                                           "Unix error creating listening connection");
349                 }
350                 fprintf(stderr,"tsr: could not create listening connection\n");
351                 exit (4);
352         }
353
354         /*----------------------------------------------------------*/
355         /*      
356         /*      On that connection, put up an operation to listen
357         /*      for our first client.
358         /*      
359         /*----------------------------------------------------------*/
360
361         listenop = create_operation();
362
363         othersize = sizeof(otherside);
364
365         start_accepting_client(listencon, listenop, &(client[nextcl].con),
366                                (char *)otherside,
367                                &othersize, &client_tuple);
368
369 }
370 \f
371 /************************************************************************/
372 /*      
373 /*                      new_connection
374 /*      
375 /*      We have just gotten a connection for client nextcl.  
376 /*      
377 /************************************************************************/
378
379 int
380 new_connection()
381 {
382         register struct client *cp = &client[nextcl];
383        /*
384         * Make sure there's been no error
385         */
386         if(connection_status(listencon) != CON_UP) {
387                 connection_perror(listencon, "Unix error on listening connection");
388                 fprintf(gdb_log, "Listening connection has died.\n");
389                 exit(8);
390         }
391         if(OP_STATUS(listenop) != OP_COMPLETE ||
392            cp->con == NULL || connection_status(cp->con) != CON_UP) {
393                 fprintf(stderr,"Error on listening operation\n");
394                 if (cp->con != NULL && 
395                     connection_status(cp->con)==CON_STOPPING) {
396                          connection_perror(cp->con, 
397                                            "Error on newly started client connection.");
398                          sever_connection(cp->con);
399                          cp->con = NULL;
400                 } else
401                         exit(8);
402         } else {
403                /*
404                 * Set up the new connection and reply to the client
405                 */
406                 cp->state = CL_STARTING;
407                 cp->action = CL_ACCEPT;
408                 start_replying_to_client(cp->pending_op, cp->con, GDB_ACCEPTED,
409                                          "", "");
410                /*
411                 * Find a new free connection descriptor.  Blow up if
412                 * we've used the last one
413                 */
414                 for (nextcl=0; nextcl<MAXCLIENTS; nextcl++)
415                         if (client[nextcl].state == CL_DEAD)
416                                 break;
417
418                 if (nextcl == MAXCLIENTS) {
419                         fprintf(stderr,"Too many clients, giving up\n");
420                         exit(8);
421                 }
422         }
423        /*
424         * Start listening again
425         */
426         reset_operation(listenop);
427         othersize = sizeof(otherside);
428
429         start_accepting_client(listencon, listenop, &(client[nextcl].con),
430                                (char *)otherside,
431                                &othersize, &client_tuple);
432
433
434 }
This page took 0.092219 seconds and 5 git commands to generate.