]>
Commit | Line | Data |
---|---|---|
5580185e | 1 | /* |
2 | * $Source$ | |
3 | * $Header$ | |
4 | */ | |
5 | ||
6 | #ifndef lint | |
7 | static char *rcsid_gdb_serv_c = "$Header$"; | |
8 | #endif lint | |
9 | ||
10 | ||
11 | ||
12 | ||
13 | ||
14 | ||
15 | ||
16 | ||
17 | ||
18 | ||
19 | ||
20 | ||
21 | ||
22 | ||
23 | ||
24 | ||
25 | ||
26 | ||
27 | ||
28 | ||
29 | ||
30 | /************************************************************************/ | |
31 | /* | |
32 | /* gdb_serv.c | |
33 | /* | |
34 | /* GDB - Routines to implement the server/client model | |
35 | /* of connections. | |
36 | /* | |
37 | /* Author: Noah Mendelsohn | |
38 | /* Copyright: 1986 MIT Project Athena | |
39 | /* | |
40 | /************************************************************************/ | |
41 | ||
42 | #include <stdio.h> | |
43 | #include <strings.h> | |
44 | #include "gdb.h" | |
45 | #include <sys/ioctl.h> | |
46 | ||
47 | /*----------------------------------------------------------*/ | |
48 | /* | |
49 | /* The following field names and types describe the | |
50 | /* tuple sent from clients to servers during negotiation. | |
51 | /* | |
52 | /*----------------------------------------------------------*/ | |
53 | ||
54 | char *g_tsv_field_names[] = {"server_id", | |
55 | "parms", | |
56 | "host", | |
57 | "user"}; | |
58 | FIELD_TYPE g_tsv_ftypes[] = {STRING_T, | |
59 | STRING_T, | |
60 | STRING_T, | |
61 | STRING_T}; | |
62 | ||
63 | #define TSV_FLDCOUNT 4 | |
64 | ||
65 | #define TSV_SERVER_ID 0 | |
66 | #define TSV_PARMS 1 | |
67 | #define TSV_HOST 2 | |
68 | #define TSV_USER 3 | |
69 | ||
70 | ||
71 | /*----------------------------------------------------------*/ | |
72 | /* | |
73 | /* The following field names and types describe the | |
74 | /* tuple returned from the server to the client during | |
75 | /* negotiation. | |
76 | /* | |
77 | /*----------------------------------------------------------*/ | |
78 | ||
79 | char *g_fsv_field_names[] = {"disposition", | |
80 | "server_id", | |
81 | "parms"}; | |
82 | FIELD_TYPE g_fsv_ftypes[] = {INTEGER_T, | |
83 | STRING_T, | |
84 | STRING_T}; | |
85 | ||
86 | #define FSV_FLDCOUNT 3 | |
87 | ||
88 | #define FSV_DISPOSITION 0 | |
89 | #define FSV_SERVER_ID 1 | |
90 | #define FSV_PARMS 2 | |
91 | ||
92 | \f | |
93 | /************************************************************************/ | |
94 | /* | |
95 | /* gdb_i_srv | |
96 | /* | |
97 | /* Initialize the server client layer. | |
98 | /* | |
99 | /* This routine is called during gdb_init to do the processing | |
100 | /* common to all server/client handing. | |
101 | /* | |
102 | /* In particular, we build the tuple descriptors for the | |
103 | /* messages used in negotiating the server/client startup. | |
104 | /* | |
105 | /************************************************************************/ | |
106 | ||
107 | int | |
108 | gdb_i_srv() | |
109 | { | |
110 | gdb_tosrv = create_tuple_descriptor(TSV_FLDCOUNT, g_tsv_field_names, | |
111 | g_tsv_ftypes); | |
112 | gdb_fmsrv = create_tuple_descriptor(FSV_FLDCOUNT, g_fsv_field_names, | |
113 | g_fsv_ftypes); | |
114 | gdb_client_tuple = NULL; | |
115 | gdb_socklen = sizeof(gdb_sockaddr_of_client); | |
116 | } | |
117 | ||
118 | \f | |
119 | /************************************************************************/ | |
120 | /* | |
121 | /* start_server_connection (start_server_connection) | |
122 | /* | |
123 | /* This routine is called from a client that wishes to make a | |
124 | /* connection to a server. In the current implementation, the | |
125 | /* string argument supplied is just the internet name of the | |
126 | /* host on which the server runs. This will later be generalized | |
127 | /* to a more flexible naming scheme. | |
128 | /* | |
129 | /* This routine builds a connection to the requested server, | |
130 | /* sends the server i.d. and parms to the server (as strings), | |
131 | /* and waits for a response indicating whether the server has | |
132 | /* agreed to the connection. The server responds in one of three | |
133 | /* ways (1) connection accepted (2) connection declined (3) redirect. | |
134 | /* In this last case, the server returns a forwarding address to | |
135 | /* be substituted for the server_id, and the whole process is tried | |
136 | /* again repeatedly until a connection is established or a | |
137 | /* retry limit is exceeded. | |
138 | /* | |
139 | /************************************************************************/ | |
140 | ||
141 | CONNECTION | |
142 | start_server_connection(server_id, parms) | |
143 | char *server_id; | |
144 | char *parms; | |
145 | { | |
146 | CONNECTION con; /* the connection we're */ | |
147 | /* creating */ | |
148 | TUPLE response = NULL; /* each time we try a server */ | |
149 | /* it sends back its */ | |
150 | /* response here */ | |
151 | int retries = GDB_MAX_SERVER_RETRIES; /* number of servers we'll */ | |
152 | /* try before giving up in */ | |
153 | /* fear of a loop */ | |
154 | ||
155 | char serv_id[GDB_MAX_SERVER_ID_SIZE]; /* a place to store server */ | |
156 | /* id's. New ones go here */ | |
157 | /* when our request is */ | |
158 | /* forwarded */ | |
159 | char latest_parms[GDB_MAX_SERVER_PARMS_SIZE]; | |
160 | /* likewise for parms */ | |
161 | ||
162 | GDB_INIT_CHECK | |
163 | ||
164 | /* | |
165 | * Try to allocate a connection and fill it in with null values. | |
166 | */ | |
167 | ||
168 | con = g_make_con(); | |
169 | ||
170 | /* | |
171 | * Loop asking different servers to accept our connection | |
172 | * until one does or we are flatly refused. | |
173 | */ | |
174 | ||
175 | /* | |
176 | * Allocate a buffer, if necessary, and reset buffer pointers | |
177 | * so first request will result in a long read into the buffer | |
178 | */ | |
179 | g_allocate_connection_buffers(con); | |
180 | ||
181 | ||
182 | g_try_server(&con, server_id, parms, &response); | |
183 | ||
184 | while ((retries--) && | |
185 | con != NULL && | |
186 | response != NULL && | |
187 | *(int *)FIELD_FROM_TUPLE(response,FSV_DISPOSITION)==GDB_FORWARDED) { | |
188 | ||
189 | (void) sever_connection(con); | |
190 | con = g_make_con(); | |
191 | (void) strcpy(serv_id, | |
192 | STRING_DATA(*(STRING *) | |
193 | (FIELD_FROM_TUPLE(response, | |
194 | FSV_SERVER_ID)))); | |
195 | (void) strcpy(latest_parms, | |
196 | STRING_DATA(*(STRING *) | |
197 | (FIELD_FROM_TUPLE(response, | |
198 | FSV_PARMS)))); | |
199 | null_tuple_strings(response); | |
200 | delete_tuple(response); | |
201 | g_try_server(&con, serv_id, latest_parms, &response); | |
202 | } | |
203 | ||
204 | /* | |
205 | * At this point, we are done trying servers, now find out | |
206 | * whether we get to keep the connnection or whether it | |
207 | * didn't work. First, see whether the connection is even up. | |
208 | */ | |
209 | if (con == NULL || | |
210 | connection_status(con) != CON_UP) { | |
211 | return con; | |
212 | } | |
213 | ||
214 | /* | |
215 | * We have at least some active connection, now see whether we | |
216 | * are going to get to keep it | |
217 | */ | |
218 | if (response != NULL && | |
219 | *(int *)FIELD_FROM_TUPLE(response,FSV_DISPOSITION) == GDB_ACCEPTED) { | |
220 | null_tuple_strings(response); | |
221 | delete_tuple(response); | |
222 | return con; | |
223 | } else { | |
224 | if (response != NULL) { | |
225 | null_tuple_strings(response); | |
226 | delete_tuple(response); | |
227 | } | |
228 | (void) sever_connection(con); | |
229 | return NULL; | |
230 | } | |
231 | } | |
232 | \f | |
233 | /************************************************************************/ | |
234 | /* | |
235 | /* g_try_server | |
236 | /* | |
237 | /* Builds a single connection to a server and returns status | |
238 | /* to indicate whether the connection has been accepted, declined, | |
239 | /* or is to be retried. This status is conveyed in a tuple received | |
240 | /* back from the server. | |
241 | /* | |
242 | /************************************************************************/ | |
243 | ||
244 | int | |
245 | g_try_server(conp, server_id, parms, responsep) | |
246 | CONNECTION *conp; | |
247 | char *server_id; | |
248 | char *parms; | |
249 | TUPLE *responsep; | |
250 | { | |
251 | ||
252 | register CONNECTION con = *conp; | |
253 | int flag = 1; | |
254 | ||
255 | /* | |
256 | * In this implementation, we use a single fd for both inbound and | |
257 | * outbound traffic. Try to connect to other side. Current | |
258 | * implementation of this is synchronous--may be a problem? If the | |
259 | * connections come up, then verify the level of protocol being | |
260 | * observed on the connections. If incompatible, then turn off the | |
261 | * connection. | |
262 | */ | |
263 | ||
264 | if(!g_try_connecting(con,server_id) || | |
265 | con->status != CON_STARTING) { | |
266 | return; /* If there we an error, */ | |
267 | /* connection will have been */ | |
268 | /* left CON_STOPPING with */ | |
269 | /* possible errno set */ | |
270 | } | |
271 | g_ver_oprotocol(con); | |
272 | if (con->status != CON_UP) { | |
273 | return; | |
274 | } | |
275 | ||
276 | /* | |
277 | * We've successfully started the connection, now mark | |
278 | * it for non-blocking I/O. Also, update the high water | |
279 | * mark of fd's controlled by our system. | |
280 | */ | |
281 | if(ioctl(con->in.fd, FIONBIO, (char *)&flag)== (-1)) { | |
282 | g_stop_with_errno(con); | |
283 | gdb_perror("gdb: ioctl for non-block failed"); | |
284 | return; | |
285 | } | |
286 | if (con->in.fd +1 > gdb_mfd) | |
287 | gdb_mfd = con->in.fd + 1; | |
288 | ||
289 | g_ask_server(conp, server_id, parms, responsep); | |
290 | ||
291 | return; | |
292 | } | |
293 | ||
294 | \f | |
295 | /************************************************************************/ | |
296 | /* | |
297 | /* g_ask_server | |
298 | /* | |
299 | /* Called once we are in touch with the server and our physical | |
300 | /* transmission protocol is comprehensible. This routine | |
301 | /* sends out a tuple containing the server i.d. and parameter | |
302 | /* strings and it returns a tuple received back from the server | |
303 | /* containing the server's response. | |
304 | /* | |
305 | /************************************************************************/ | |
306 | ||
307 | int | |
308 | g_ask_server(conp, server_id, parms, responsep) | |
309 | CONNECTION *conp; | |
310 | char *server_id; | |
311 | char *parms; | |
312 | TUPLE *responsep; | |
313 | { | |
314 | register CONNECTION con = *conp; | |
315 | TUPLE out_tuple; | |
316 | int rc; | |
317 | /*----------------------------------------------------------*/ | |
318 | /* | |
319 | /* Create a tuple to be sent out containing the | |
320 | /* server_id and parms. | |
321 | /* | |
322 | /*----------------------------------------------------------*/ | |
323 | ||
324 | out_tuple = create_tuple(gdb_tosrv); /* descriptor was pre- */ | |
325 | /* built during */ | |
326 | /* initialization*/ | |
327 | ||
328 | (void) string_alloc((STRING *)FIELD_FROM_TUPLE(out_tuple, TSV_SERVER_ID), | |
329 | strlen(server_id)+1); | |
330 | (void) strcpy(STRING_DATA(*((STRING *)FIELD_FROM_TUPLE(out_tuple,0))), | |
331 | server_id); | |
332 | ||
333 | (void) string_alloc((STRING *)FIELD_FROM_TUPLE(out_tuple, TSV_PARMS), | |
334 | strlen(parms)+1); | |
335 | (void) strcpy(STRING_DATA(*((STRING *)FIELD_FROM_TUPLE(out_tuple,1))), | |
336 | parms); | |
337 | ||
338 | (void) string_alloc((STRING *)FIELD_FROM_TUPLE(out_tuple, TSV_HOST), | |
339 | strlen(gdb_host)+1); | |
340 | (void) strcpy(STRING_DATA(*((STRING *)FIELD_FROM_TUPLE(out_tuple, | |
341 | TSV_HOST))), | |
342 | gdb_host); | |
343 | (void) string_alloc((STRING *)FIELD_FROM_TUPLE(out_tuple, TSV_USER), | |
344 | strlen(gdb_uname)+1); | |
345 | (void) strcpy(STRING_DATA(*((STRING *)FIELD_FROM_TUPLE(out_tuple,TSV_USER))), | |
346 | gdb_uname); | |
347 | ||
348 | /*----------------------------------------------------------*/ | |
349 | /* | |
350 | /* Send the tuple to the server, and make sure that | |
351 | /* we succeeded. | |
352 | /* | |
353 | /*----------------------------------------------------------*/ | |
354 | ||
355 | rc = send_object(con, (char *)&out_tuple, TUPLE_T); | |
356 | ||
357 | null_tuple_strings(out_tuple); | |
358 | delete_tuple(out_tuple); | |
359 | ||
360 | if (rc != OP_SUCCESS) { | |
361 | return; /* cleanup from dying send */ | |
362 | /* should have made this */ | |
363 | /* CON_STOPPING with errno */ | |
364 | } | |
365 | ||
366 | /*----------------------------------------------------------*/ | |
367 | /* | |
368 | /* OK, we sent it out, now lets read back the response. | |
369 | /* | |
370 | /*----------------------------------------------------------*/ | |
371 | ||
372 | rc = receive_object(con, (char *)responsep, TUPLE_T); | |
373 | ||
374 | if (rc != OP_SUCCESS) { | |
375 | return; /* cleanup from dying send */ | |
376 | /* should have made this */ | |
377 | /* CON_STOPPING with errno */ | |
378 | } | |
379 | } | |
380 | \f | |
381 | /************************************************************************/ | |
382 | /* | |
383 | /* start_replying_to_client | |
384 | /* | |
385 | /* Queue an operation which will send a reply to the specified | |
386 | /* client. | |
387 | /* | |
388 | /************************************************************************/ | |
389 | ||
390 | struct rtc_data { | |
391 | TUPLE reply_data; | |
392 | OPERATION tuple_send; | |
393 | }; | |
394 | ||
395 | int g_irtc(); | |
396 | int g_i2rtc(); | |
397 | ||
398 | int | |
399 | start_replying_to_client(op, con, disposition, serverid, parms) | |
400 | OPERATION op; | |
401 | CONNECTION con; | |
402 | int disposition; | |
403 | char *serverid; /* null terminated */ | |
404 | char *parms; /* " " */ | |
405 | { | |
406 | register struct rtc_data *arg; | |
407 | register TUPLE t; | |
408 | ||
409 | /* | |
410 | * Make sure the supplied connection is a legal one | |
411 | */ | |
412 | GDB_CHECK_CON(con, "start_replying_to_client") | |
413 | ||
414 | arg = (struct rtc_data *)db_alloc(sizeof(struct rtc_data)); | |
415 | ||
416 | /* | |
417 | * create an empty operation and a tuple | |
418 | */ | |
419 | arg->tuple_send = create_operation(); | |
420 | arg->reply_data = create_tuple(gdb_fmsrv); | |
421 | /* | |
422 | * Fill in the response tuple | |
423 | */ | |
424 | t = arg->reply_data; /* quicker and easier here */ | |
425 | ||
426 | *(int *)FIELD_FROM_TUPLE(t,FSV_DISPOSITION) = disposition; | |
427 | (void) string_alloc((STRING *)FIELD_FROM_TUPLE(t, FSV_SERVER_ID), | |
428 | strlen(serverid)+1); | |
429 | (void) strcpy(STRING_DATA(*(STRING *)(FIELD_FROM_TUPLE(t, FSV_SERVER_ID))), | |
430 | serverid); | |
431 | ||
432 | (void) string_alloc((STRING *)FIELD_FROM_TUPLE(t, FSV_PARMS), | |
433 | strlen(parms)+1); | |
434 | (void) strcpy(STRING_DATA(*(STRING *)(FIELD_FROM_TUPLE(t, FSV_PARMS))), | |
435 | parms); | |
436 | ||
437 | /* | |
438 | * Queue an operation ahead of us which will send the response tuple | |
439 | * to the client | |
440 | */ | |
441 | start_sending_object(arg->tuple_send, con, (char *)&arg->reply_data, | |
442 | TUPLE_T); | |
443 | ||
444 | /* | |
445 | * Now queue us behind it. By the time we run our init routine, | |
446 | * a connection should have been acquired. | |
447 | */ | |
448 | initialize_operation(op, g_irtc, (char *)arg, (int (*)())NULL); | |
449 | (void) queue_operation(con, CON_INPUT, op); | |
450 | } | |
451 | ||
452 | /*----------------------------------------------------------*/ | |
453 | /* | |
454 | /* g_irtc | |
455 | /* | |
456 | /* Init routine for replying to a client. If all went | |
457 | /* well, (or even if it didn't), then we are done. | |
458 | /* All we have to do is clean up the stuff we've allocated. | |
459 | /* | |
460 | /*----------------------------------------------------------*/ | |
461 | ||
462 | int | |
463 | g_irtc(op, hcon, arg) | |
464 | OPERATION op; | |
465 | HALF_CONNECTION hcon; | |
466 | struct rtc_data *arg; | |
467 | { | |
468 | int rc; | |
469 | ||
470 | /* | |
471 | * Figure out the return information to our caller | |
472 | */ | |
473 | rc = OP_STATUS(arg->tuple_send); | |
474 | ||
475 | /* | |
476 | * Release all transient data structures. | |
477 | */ | |
478 | null_tuple_strings(arg->reply_data); | |
479 | delete_tuple(arg->reply_data); | |
480 | delete_operation(arg->tuple_send); | |
481 | db_free((char *)arg, sizeof(struct rtc_data)); | |
482 | return rc; | |
483 | } |