7 static char *rcsid_tsr_c = "$Header$";
10 /************************************************************************/
15 /* Author: Noah Mendelsohn (IBM T.J. Watson Research and MIT Project
18 /* Copyright: 1986 MIT Project Athena
20 /************************************************************************/
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
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.
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.
48 /* 2) Communication to each client is done over its connection,
49 /* named client[i].con.
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.
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.
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.
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.
77 /************************************************************************/
85 /************************************************************************/
89 /************************************************************************/
93 /*----------------------------------------------------------*/
95 /* State of each possible client
97 /*----------------------------------------------------------*/
100 int state; /* state of this client */
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 */
111 OPERATION pending_op; /* pending operation */
112 /* on this connection, */
114 int data; /* the character to echo */
115 /* goes here, expressed as */
119 struct client client[MAXCLIENTS];
121 /*----------------------------------------------------------*/
123 /* Connections and operations for listening for
126 /*----------------------------------------------------------*/
128 CONNECTION listencon; /* listen on this */
130 OPERATION listenop; /* this operation is used */
131 /* repeatedly for listening */
132 /* for new clients */
134 int nextcl = 0; /* index of the next client */
137 \f /*----------------------------------------------------------*/
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.
144 /*----------------------------------------------------------*/
146 TUPLE client_tuple; /* client request goes */
153 /************************************************************************/
157 /************************************************************************/
164 /*----------------------------------------------------------*/
168 /*----------------------------------------------------------*/
170 register int i; /* loop index */
171 LIST_OF_OPERATIONS op_list; /* for op_select_any */
173 /*----------------------------------------------------------*/
177 /*----------------------------------------------------------*/
180 fprintf(stderr,"Correct form is %s <servicename>\n",
185 /*----------------------------------------------------------*/
189 /*----------------------------------------------------------*/
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 */
198 /*----------------------------------------------------------*/
200 /* Loop forever taking care of business.
202 /* 1) If any new connection requests have come in,
205 /* 2) For each client on which some activity is newly
206 /* completed, take care of it.
208 /*----------------------------------------------------------*/
211 if (OP_DONE(listenop))
213 for (i=0; i<MAXCLIENTS; i++) {
214 if (OP_DONE(client[i].pending_op))
217 if(op_select_any(op_list, 0, NULL, NULL, NULL, NULL)==(-1)) {
218 perror("op_select_any returned error");
224 /************************************************************************/
228 /* An operation has completed on the specified client.
230 /************************************************************************/
236 register struct client *cp = &(client[id]);
239 * If there has been an error, shutdown the client.
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);
252 * The operation completed successfully. Figure out what it was
253 * and do the right thing.
255 switch (cp->action) {
258 start_receiving_object(cp->pending_op, cp->con,
261 cp->action = 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,
269 cp->action = CL_SEND;
273 /************************************************************************/
277 /************************************************************************/
282 register struct client *c;
284 for (c=client; c<client+MAXCLIENTS; c++){
288 c->pending_op = create_operation();
289 reset_operation(c->pending_op);
295 /************************************************************************/
299 /************************************************************************/
303 LIST_OF_OPERATIONS *oplp;
306 * ugh! we've got to fix create_list_of_operations to be
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);
322 \f/************************************************************************/
326 /* Do the one time setup for listening for clients, and
327 /* also start a listen for an actual client.
329 /************************************************************************/
336 /*----------------------------------------------------------*/
338 /* Make a listening connection
340 /*----------------------------------------------------------*/
342 fprintf(stderr, "Server creating listening connection\n");
343 listencon = create_listening_connection(service);
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");
350 fprintf(stderr,"tsr: could not create listening connection\n");
354 /*----------------------------------------------------------*/
356 /* On that connection, put up an operation to listen
357 /* for our first client.
359 /*----------------------------------------------------------*/
361 listenop = create_operation();
363 othersize = sizeof(otherside);
365 start_accepting_client(listencon, listenop, &(client[nextcl].con),
367 &othersize, &client_tuple);
371 /************************************************************************/
375 /* We have just gotten a connection for client nextcl.
377 /************************************************************************/
382 register struct client *cp = &client[nextcl];
384 * Make sure there's been no error
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");
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);
404 * Set up the new connection and reply to the client
406 cp->state = CL_STARTING;
407 cp->action = CL_ACCEPT;
408 start_replying_to_client(cp->pending_op, cp->con, GDB_ACCEPTED,
411 * Find a new free connection descriptor. Blow up if
412 * we've used the last one
414 for (nextcl=0; nextcl<MAXCLIENTS; nextcl++)
415 if (client[nextcl].state == CL_DEAD)
418 if (nextcl == MAXCLIENTS) {
419 fprintf(stderr,"Too many clients, giving up\n");
424 * Start listening again
426 reset_operation(listenop);
427 othersize = sizeof(otherside);
429 start_accepting_client(listencon, listenop, &(client[nextcl].con),
431 &othersize, &client_tuple);