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