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>
34 /*----------------------------------------------------------
36 * The following field names and types describe the
37 * tuple sent from clients to servers during negotiation.
39 *----------------------------------------------------------*/
41 char *g_tsv_field_names[] = {"server_id",
45 FIELD_TYPE g_tsv_ftypes[] = {STRING_T,
50 #define TSV_FLDCOUNT 4
52 #define TSV_SERVER_ID 0
58 /*----------------------------------------------------------*/
60 /* The following field names and types describe the
61 /* tuple returned from the server to the client during
64 /*----------------------------------------------------------*/
66 char *g_fsv_field_names[] = {"disposition",
69 FIELD_TYPE g_fsv_ftypes[] = {INTEGER_T,
73 #define FSV_FLDCOUNT 3
75 #define FSV_DISPOSITION 0
76 #define FSV_SERVER_ID 1
80 /************************************************************************/
84 /* Initialize the server client layer.
86 /* This routine is called during gdb_init to do the processing
87 /* common to all server/client handing.
89 /* In particular, we build the tuple descriptors for the
90 /* messages used in negotiating the server/client startup.
92 /************************************************************************/
97 gdb_tosrv = create_tuple_descriptor(TSV_FLDCOUNT, g_tsv_field_names,
99 gdb_fmsrv = create_tuple_descriptor(FSV_FLDCOUNT, g_fsv_field_names,
101 gdb_client_tuple = NULL;
102 gdb_socklen = sizeof(gdb_sockaddr_of_client);
106 /************************************************************************/
108 /* start_server_connection (start_server_connection)
110 /* This routine is called from a client that wishes to make a
111 /* connection to a server. In the current implementation, the
112 /* string argument supplied is just the internet name of the
113 /* host on which the server runs. This will later be generalized
114 /* to a more flexible naming scheme.
116 /* This routine builds a connection to the requested server,
117 /* sends the server i.d. and parms to the server (as strings),
118 /* and waits for a response indicating whether the server has
119 /* agreed to the connection. The server responds in one of three
120 /* ways (1) connection accepted (2) connection declined (3) redirect.
121 /* In this last case, the server returns a forwarding address to
122 /* be substituted for the server_id, and the whole process is tried
123 /* again repeatedly until a connection is established or a
124 /* retry limit is exceeded.
126 /************************************************************************/
129 start_server_connection(server_id, parms)
133 CONNECTION con; /* the connection we're */
135 TUPLE response = NULL; /* each time we try a server */
136 /* it sends back its */
138 int retries = GDB_MAX_SERVER_RETRIES; /* number of servers we'll */
139 /* try before giving up in */
142 char serv_id[GDB_MAX_SERVER_ID_SIZE]; /* a place to store server */
143 /* id's. New ones go here */
144 /* when our request is */
146 char latest_parms[GDB_MAX_SERVER_PARMS_SIZE];
147 /* likewise for parms */
152 * Try to allocate a connection and fill it in with null values.
158 * Loop asking different servers to accept our connection
159 * until one does or we are flatly refused.
163 * Allocate a buffer, if necessary, and reset buffer pointers
164 * so first request will result in a long read into the buffer
166 g_allocate_connection_buffers(con);
169 g_try_server(&con, server_id, parms, &response);
171 while ((retries--) &&
174 *(int *)FIELD_FROM_TUPLE(response,FSV_DISPOSITION)==GDB_FORWARDED) {
176 (void) sever_connection(con);
178 (void) strcpy(serv_id,
179 STRING_DATA(*(STRING *)
180 (FIELD_FROM_TUPLE(response,
182 (void) strcpy(latest_parms,
183 STRING_DATA(*(STRING *)
184 (FIELD_FROM_TUPLE(response,
186 null_tuple_strings(response);
187 delete_tuple(response);
188 g_try_server(&con, serv_id, latest_parms, &response);
192 * At this point, we are done trying servers, now find out
193 * whether we get to keep the connnection or whether it
194 * didn't work. First, see whether the connection is even up.
197 connection_status(con) != CON_UP) {
202 * We have at least some active connection, now see whether we
203 * are going to get to keep it
205 if (response != NULL &&
206 *(int *)FIELD_FROM_TUPLE(response,FSV_DISPOSITION) == GDB_ACCEPTED) {
207 null_tuple_strings(response);
208 delete_tuple(response);
211 if (response != NULL) {
212 null_tuple_strings(response);
213 delete_tuple(response);
215 (void) sever_connection(con);
220 /************************************************************************/
224 /* Builds a single connection to a server and returns status
225 /* to indicate whether the connection has been accepted, declined,
226 /* or is to be retried. This status is conveyed in a tuple received
227 /* back from the server.
229 /************************************************************************/
232 g_try_server(conp, server_id, parms, responsep)
239 register CONNECTION con = *conp;
243 * In this implementation, we use a single fd for both inbound and
244 * outbound traffic. Try to connect to other side. Current
245 * implementation of this is synchronous--may be a problem? If the
246 * connections come up, then verify the level of protocol being
247 * observed on the connections. If incompatible, then turn off the
251 if(!g_try_connecting(con,server_id) ||
252 con->status != CON_STARTING) {
253 return; /* If there we an error, */
254 /* connection will have been */
255 /* left CON_STOPPING with */
256 /* possible errno set */
258 g_ver_oprotocol(con);
259 if (con->status != CON_UP) {
264 * We've successfully started the connection, now mark
265 * it for non-blocking I/O. Also, update the high water
266 * mark of fd's controlled by our system.
268 if(ioctl(con->in.fd, FIONBIO, (char *)&flag)== (-1)) {
269 g_stop_with_errno(con);
270 gdb_perror("gdb: ioctl for non-block failed");
273 if (con->in.fd +1 > gdb_mfd)
274 gdb_mfd = con->in.fd + 1;
276 g_ask_server(conp, server_id, parms, responsep);
282 /************************************************************************/
286 /* Called once we are in touch with the server and our physical
287 /* transmission protocol is comprehensible. This routine
288 /* sends out a tuple containing the server i.d. and parameter
289 /* strings and it returns a tuple received back from the server
290 /* containing the server's response.
292 /************************************************************************/
295 g_ask_server(conp, server_id, parms, responsep)
301 register CONNECTION con = *conp;
304 /*----------------------------------------------------------*/
306 /* Create a tuple to be sent out containing the
307 /* server_id and parms.
309 /*----------------------------------------------------------*/
311 out_tuple = create_tuple(gdb_tosrv); /* descriptor was pre- */
315 (void) string_alloc((STRING *)FIELD_FROM_TUPLE(out_tuple, TSV_SERVER_ID),
316 strlen(server_id)+1);
317 (void) strcpy(STRING_DATA(*((STRING *)FIELD_FROM_TUPLE(out_tuple,0))),
320 if (parms == NULL) parms = "";
321 (void) string_alloc((STRING *)FIELD_FROM_TUPLE(out_tuple, TSV_PARMS),
323 (void) strcpy(STRING_DATA(*((STRING *)FIELD_FROM_TUPLE(out_tuple,1))),
326 (void) string_alloc((STRING *)FIELD_FROM_TUPLE(out_tuple, TSV_HOST),
328 (void) strcpy(STRING_DATA(*((STRING *)FIELD_FROM_TUPLE(out_tuple,
331 (void) string_alloc((STRING *)FIELD_FROM_TUPLE(out_tuple, TSV_USER),
332 strlen(gdb_uname)+1);
333 (void) strcpy(STRING_DATA(*((STRING *)FIELD_FROM_TUPLE(out_tuple,TSV_USER))),
336 /*----------------------------------------------------------*/
338 /* Send the tuple to the server, and make sure that
341 /*----------------------------------------------------------*/
343 rc = send_object(con, (char *)&out_tuple, TUPLE_T);
345 null_tuple_strings(out_tuple);
346 delete_tuple(out_tuple);
348 if (rc != OP_SUCCESS) {
349 return; /* cleanup from dying send */
350 /* should have made this */
351 /* CON_STOPPING with errno */
354 /*----------------------------------------------------------*/
356 /* OK, we sent it out, now lets read back the response.
358 /*----------------------------------------------------------*/
360 rc = receive_object(con, (char *)responsep, TUPLE_T);
362 if (rc != OP_SUCCESS) {
363 return; /* cleanup from dying send */
364 /* should have made this */
365 /* CON_STOPPING with errno */
370 /************************************************************************/
372 /* start_replying_to_client
374 /* Queue an operation which will send a reply to the specified
377 /************************************************************************/
381 OPERATION tuple_send;
388 start_replying_to_client(op, con, disposition, serverid, parms)
392 char *serverid; /* null terminated */
393 char *parms; /* " " */
395 register struct rtc_data *arg;
399 * Make sure the supplied connection is a legal one
401 GDB_CHECK_CON(con, "start_replying_to_client")
403 arg = (struct rtc_data *)db_alloc(sizeof(struct rtc_data));
406 * create an empty operation and a tuple
408 arg->tuple_send = create_operation();
409 arg->reply_data = create_tuple(gdb_fmsrv);
411 * Fill in the response tuple
413 t = arg->reply_data; /* quicker and easier here */
415 *(int *)FIELD_FROM_TUPLE(t,FSV_DISPOSITION) = disposition;
416 (void) string_alloc((STRING *)FIELD_FROM_TUPLE(t, FSV_SERVER_ID),
418 (void) strcpy(STRING_DATA(*(STRING *)(FIELD_FROM_TUPLE(t, FSV_SERVER_ID))),
421 (void) string_alloc((STRING *)FIELD_FROM_TUPLE(t, FSV_PARMS),
423 (void) strcpy(STRING_DATA(*(STRING *)(FIELD_FROM_TUPLE(t, FSV_PARMS))),
427 * Queue an operation ahead of us which will send the response tuple
430 start_sending_object(arg->tuple_send, con, (char *)&arg->reply_data,
434 * Now queue us behind it. By the time we run our init routine,
435 * a connection should have been acquired.
437 initialize_operation(op, g_irtc, (char *)arg, (int (*)())NULL);
438 (void) queue_operation(con, CON_INPUT, op);
441 /*----------------------------------------------------------*/
445 /* Init routine for replying to a client. If all went
446 /* well, (or even if it didn't), then we are done.
447 /* All we have to do is clean up the stuff we've allocated.
449 /*----------------------------------------------------------*/
453 g_irtc(op, hcon, arg)
455 HALF_CONNECTION hcon;
456 struct rtc_data *arg;
461 * Figure out the return information to our caller
463 rc = OP_STATUS(arg->tuple_send);
466 * Release all transient data structures.
468 null_tuple_strings(arg->reply_data);
469 delete_tuple(arg->reply_data);
470 delete_operation(arg->tuple_send);
471 db_free((char *)arg, sizeof(struct rtc_data));