7 static char *rcsid_gdb_serv_c = "$Header$";
11 /************************************************************************
15 * GDB - Routines to implement the server/client model
18 * Author: Noah Mendelsohn
19 * Copyright: 1986 MIT Project Athena
20 * For copying and distribution information, please see
21 * the file <mit-copyright.h>.
23 ************************************************************************/
25 #include <mit-copyright.h>
29 #include <sys/ioctl.h>
31 #include <sys/filio.h>
37 /*----------------------------------------------------------
39 * The following field names and types describe the
40 * tuple sent from clients to servers during negotiation.
42 *----------------------------------------------------------*/
44 char *g_tsv_field_names[] = {"server_id",
48 FIELD_TYPE g_tsv_ftypes[] = {STRING_T,
53 #define TSV_FLDCOUNT 4
55 #define TSV_SERVER_ID 0
61 /*----------------------------------------------------------*/
63 /* The following field names and types describe the
64 /* tuple returned from the server to the client during
67 /*----------------------------------------------------------*/
69 char *g_fsv_field_names[] = {"disposition",
72 FIELD_TYPE g_fsv_ftypes[] = {INTEGER_T,
76 #define FSV_FLDCOUNT 3
78 #define FSV_DISPOSITION 0
79 #define FSV_SERVER_ID 1
83 /************************************************************************/
87 /* Initialize the server client layer.
89 /* This routine is called during gdb_init to do the processing
90 /* common to all server/client handing.
92 /* In particular, we build the tuple descriptors for the
93 /* messages used in negotiating the server/client startup.
95 /************************************************************************/
100 gdb_tosrv = create_tuple_descriptor(TSV_FLDCOUNT, g_tsv_field_names,
102 gdb_fmsrv = create_tuple_descriptor(FSV_FLDCOUNT, g_fsv_field_names,
104 gdb_client_tuple = NULL;
105 gdb_socklen = sizeof(gdb_sockaddr_of_client);
109 /************************************************************************/
111 /* start_server_connection (start_server_connection)
113 /* This routine is called from a client that wishes to make a
114 /* connection to a server. In the current implementation, the
115 /* string argument supplied is just the internet name of the
116 /* host on which the server runs. This will later be generalized
117 /* to a more flexible naming scheme.
119 /* This routine builds a connection to the requested server,
120 /* sends the server i.d. and parms to the server (as strings),
121 /* and waits for a response indicating whether the server has
122 /* agreed to the connection. The server responds in one of three
123 /* ways (1) connection accepted (2) connection declined (3) redirect.
124 /* In this last case, the server returns a forwarding address to
125 /* be substituted for the server_id, and the whole process is tried
126 /* again repeatedly until a connection is established or a
127 /* retry limit is exceeded.
129 /************************************************************************/
132 start_server_connection(server_id, parms)
136 CONNECTION con; /* the connection we're */
138 TUPLE response = NULL; /* each time we try a server */
139 /* it sends back its */
141 int retries = GDB_MAX_SERVER_RETRIES; /* number of servers we'll */
142 /* try before giving up in */
145 char serv_id[GDB_MAX_SERVER_ID_SIZE]; /* a place to store server */
146 /* id's. New ones go here */
147 /* when our request is */
149 char latest_parms[GDB_MAX_SERVER_PARMS_SIZE];
150 /* likewise for parms */
155 * Try to allocate a connection and fill it in with null values.
161 * Loop asking different servers to accept our connection
162 * until one does or we are flatly refused.
166 * Allocate a buffer, if necessary, and reset buffer pointers
167 * so first request will result in a long read into the buffer
169 g_allocate_connection_buffers(con);
172 g_try_server(&con, server_id, parms, &response);
174 while ((retries--) &&
177 *(int *)FIELD_FROM_TUPLE(response,FSV_DISPOSITION)==GDB_FORWARDED) {
179 (void) sever_connection(con);
181 (void) strcpy(serv_id,
182 STRING_DATA(*(STRING *)
183 (FIELD_FROM_TUPLE(response,
185 (void) strcpy(latest_parms,
186 STRING_DATA(*(STRING *)
187 (FIELD_FROM_TUPLE(response,
189 null_tuple_strings(response);
190 delete_tuple(response);
191 g_try_server(&con, serv_id, latest_parms, &response);
195 * At this point, we are done trying servers, now find out
196 * whether we get to keep the connnection or whether it
197 * didn't work. First, see whether the connection is even up.
200 connection_status(con) != CON_UP) {
205 * We have at least some active connection, now see whether we
206 * are going to get to keep it
208 if (response != NULL &&
209 *(int *)FIELD_FROM_TUPLE(response,FSV_DISPOSITION) == GDB_ACCEPTED) {
210 null_tuple_strings(response);
211 delete_tuple(response);
214 if (response != NULL) {
215 null_tuple_strings(response);
216 delete_tuple(response);
218 (void) sever_connection(con);
223 /************************************************************************/
227 /* Builds a single connection to a server and returns status
228 /* to indicate whether the connection has been accepted, declined,
229 /* or is to be retried. This status is conveyed in a tuple received
230 /* back from the server.
232 /************************************************************************/
235 g_try_server(conp, server_id, parms, responsep)
242 register CONNECTION con = *conp;
246 * In this implementation, we use a single fd for both inbound and
247 * outbound traffic. Try to connect to other side. Current
248 * implementation of this is synchronous--may be a problem? If the
249 * connections come up, then verify the level of protocol being
250 * observed on the connections. If incompatible, then turn off the
254 if(!g_try_connecting(con,server_id) ||
255 con->status != CON_STARTING) {
256 return; /* If there we an error, */
257 /* connection will have been */
258 /* left CON_STOPPING with */
259 /* possible errno set */
261 g_ver_oprotocol(con);
262 if (con->status != CON_UP) {
267 * We've successfully started the connection, now mark
268 * it for non-blocking I/O. Also, update the high water
269 * mark of fd's controlled by our system.
271 if(ioctl(con->in.fd, FIONBIO, (char *)&flag)== (-1)) {
272 g_stop_with_errno(con);
273 gdb_perror("gdb: ioctl for non-block failed");
276 if (con->in.fd +1 > gdb_mfd)
277 gdb_mfd = con->in.fd + 1;
279 g_ask_server(conp, server_id, parms, responsep);
285 /************************************************************************/
289 /* Called once we are in touch with the server and our physical
290 /* transmission protocol is comprehensible. This routine
291 /* sends out a tuple containing the server i.d. and parameter
292 /* strings and it returns a tuple received back from the server
293 /* containing the server's response.
295 /************************************************************************/
298 g_ask_server(conp, server_id, parms, responsep)
304 register CONNECTION con = *conp;
307 /*----------------------------------------------------------*/
309 /* Create a tuple to be sent out containing the
310 /* server_id and parms.
312 /*----------------------------------------------------------*/
314 out_tuple = create_tuple(gdb_tosrv); /* descriptor was pre- */
318 (void) string_alloc((STRING *)FIELD_FROM_TUPLE(out_tuple, TSV_SERVER_ID),
319 strlen(server_id)+1);
320 (void) strcpy(STRING_DATA(*((STRING *)FIELD_FROM_TUPLE(out_tuple,0))),
323 if (parms == NULL) parms = "";
324 (void) string_alloc((STRING *)FIELD_FROM_TUPLE(out_tuple, TSV_PARMS),
326 (void) strcpy(STRING_DATA(*((STRING *)FIELD_FROM_TUPLE(out_tuple,1))),
329 (void) string_alloc((STRING *)FIELD_FROM_TUPLE(out_tuple, TSV_HOST),
331 (void) strcpy(STRING_DATA(*((STRING *)FIELD_FROM_TUPLE(out_tuple,
334 (void) string_alloc((STRING *)FIELD_FROM_TUPLE(out_tuple, TSV_USER),
335 strlen(gdb_uname)+1);
336 (void) strcpy(STRING_DATA(*((STRING *)FIELD_FROM_TUPLE(out_tuple,TSV_USER))),
339 /*----------------------------------------------------------*/
341 /* Send the tuple to the server, and make sure that
344 /*----------------------------------------------------------*/
346 rc = send_object(con, (char *)&out_tuple, TUPLE_T);
348 null_tuple_strings(out_tuple);
349 delete_tuple(out_tuple);
351 if (rc != OP_SUCCESS) {
352 return; /* cleanup from dying send */
353 /* should have made this */
354 /* CON_STOPPING with errno */
357 /*----------------------------------------------------------*/
359 /* OK, we sent it out, now lets read back the response.
361 /*----------------------------------------------------------*/
363 rc = receive_object(con, (char *)responsep, TUPLE_T);
365 if (rc != OP_SUCCESS) {
366 return; /* cleanup from dying send */
367 /* should have made this */
368 /* CON_STOPPING with errno */
373 /************************************************************************/
375 /* start_replying_to_client
377 /* Queue an operation which will send a reply to the specified
380 /************************************************************************/
384 OPERATION tuple_send;
391 start_replying_to_client(op, con, disposition, serverid, parms)
395 char *serverid; /* null terminated */
396 char *parms; /* " " */
398 register struct rtc_data *arg;
402 * Make sure the supplied connection is a legal one
404 GDB_CHECK_CON(con, "start_replying_to_client")
406 arg = (struct rtc_data *)db_alloc(sizeof(struct rtc_data));
409 * create an empty operation and a tuple
411 arg->tuple_send = create_operation();
412 arg->reply_data = create_tuple(gdb_fmsrv);
414 * Fill in the response tuple
416 t = arg->reply_data; /* quicker and easier here */
418 *(int *)FIELD_FROM_TUPLE(t,FSV_DISPOSITION) = disposition;
419 (void) string_alloc((STRING *)FIELD_FROM_TUPLE(t, FSV_SERVER_ID),
421 (void) strcpy(STRING_DATA(*(STRING *)(FIELD_FROM_TUPLE(t, FSV_SERVER_ID))),
424 (void) string_alloc((STRING *)FIELD_FROM_TUPLE(t, FSV_PARMS),
426 (void) strcpy(STRING_DATA(*(STRING *)(FIELD_FROM_TUPLE(t, FSV_PARMS))),
430 * Queue an operation ahead of us which will send the response tuple
433 start_sending_object(arg->tuple_send, con, (char *)&arg->reply_data,
437 * Now queue us behind it. By the time we run our init routine,
438 * a connection should have been acquired.
440 initialize_operation(op, g_irtc, (char *)arg, (int (*)())NULL);
441 (void) queue_operation(con, CON_INPUT, op);
444 /*----------------------------------------------------------*/
448 /* Init routine for replying to a client. If all went
449 /* well, (or even if it didn't), then we are done.
450 /* All we have to do is clean up the stuff we've allocated.
452 /*----------------------------------------------------------*/
456 g_irtc(op, hcon, arg)
458 HALF_CONNECTION hcon;
459 struct rtc_data *arg;
464 * Figure out the return information to our caller
466 rc = OP_STATUS(arg->tuple_send);
469 * Release all transient data structures.
471 null_tuple_strings(arg->reply_data);
472 delete_tuple(arg->reply_data);
473 delete_operation(arg->tuple_send);
474 db_free((char *)arg, sizeof(struct rtc_data));