]>
Commit | Line | Data |
---|---|---|
5580185e | 1 | /* |
097e9b93 | 2 | * $Source$ |
3 | * $Header$ | |
5580185e | 4 | */ |
5 | ||
6 | #ifndef lint | |
7 | static char *rcsid_gdb_serv_c = "$Header$"; | |
d9f43d51 | 8 | #endif |
5580185e | 9 | |
10 | ||
097e9b93 | 11 | /************************************************************************ |
12 | * | |
13 | * gdb_serv.c | |
14 | * | |
15 | * GDB - Routines to implement the server/client model | |
16 | * of connections. | |
17 | * | |
18 | * Author: Noah Mendelsohn | |
19 | * Copyright: 1986 MIT Project Athena | |
20 | * For copying and distribution information, please see | |
21 | * the file <mit-copyright.h>. | |
22 | * | |
23 | ************************************************************************/ | |
5580185e | 24 | |
0a5ff702 | 25 | #include <mit-copyright.h> |
5580185e | 26 | #include <stdio.h> |
f4c08abd | 27 | #include <string.h> |
5580185e | 28 | #include "gdb.h" |
29 | #include <sys/ioctl.h> | |
097e9b93 | 30 | #ifdef SOLARIS |
31 | #include <sys/filio.h> | |
d9f43d51 | 32 | #endif |
33 | #ifdef POSIX | |
34 | #include <unistd.h> | |
097e9b93 | 35 | #endif |
5580185e | 36 | |
097e9b93 | 37 | /*---------------------------------------------------------- |
38 | * | |
39 | * The following field names and types describe the | |
40 | * tuple sent from clients to servers during negotiation. | |
41 | * | |
42 | *----------------------------------------------------------*/ | |
5580185e | 43 | |
44 | char *g_tsv_field_names[] = {"server_id", | |
45 | "parms", | |
46 | "host", | |
47 | "user"}; | |
48 | FIELD_TYPE g_tsv_ftypes[] = {STRING_T, | |
49 | STRING_T, | |
50 | STRING_T, | |
51 | STRING_T}; | |
52 | ||
53 | #define TSV_FLDCOUNT 4 | |
54 | ||
55 | #define TSV_SERVER_ID 0 | |
56 | #define TSV_PARMS 1 | |
57 | #define TSV_HOST 2 | |
58 | #define TSV_USER 3 | |
59 | ||
60 | ||
61 | /*----------------------------------------------------------*/ | |
62 | /* | |
63 | /* The following field names and types describe the | |
64 | /* tuple returned from the server to the client during | |
65 | /* negotiation. | |
66 | /* | |
67 | /*----------------------------------------------------------*/ | |
68 | ||
69 | char *g_fsv_field_names[] = {"disposition", | |
70 | "server_id", | |
71 | "parms"}; | |
72 | FIELD_TYPE g_fsv_ftypes[] = {INTEGER_T, | |
73 | STRING_T, | |
74 | STRING_T}; | |
75 | ||
76 | #define FSV_FLDCOUNT 3 | |
77 | ||
78 | #define FSV_DISPOSITION 0 | |
79 | #define FSV_SERVER_ID 1 | |
80 | #define FSV_PARMS 2 | |
81 | ||
097e9b93 | 82 | |
5580185e | 83 | /************************************************************************/ |
84 | /* | |
85 | /* gdb_i_srv | |
86 | /* | |
87 | /* Initialize the server client layer. | |
88 | /* | |
89 | /* This routine is called during gdb_init to do the processing | |
90 | /* common to all server/client handing. | |
91 | /* | |
92 | /* In particular, we build the tuple descriptors for the | |
93 | /* messages used in negotiating the server/client startup. | |
94 | /* | |
95 | /************************************************************************/ | |
96 | ||
97 | int | |
98 | gdb_i_srv() | |
99 | { | |
100 | gdb_tosrv = create_tuple_descriptor(TSV_FLDCOUNT, g_tsv_field_names, | |
101 | g_tsv_ftypes); | |
102 | gdb_fmsrv = create_tuple_descriptor(FSV_FLDCOUNT, g_fsv_field_names, | |
103 | g_fsv_ftypes); | |
104 | gdb_client_tuple = NULL; | |
105 | gdb_socklen = sizeof(gdb_sockaddr_of_client); | |
106 | } | |
107 | ||
097e9b93 | 108 | |
5580185e | 109 | /************************************************************************/ |
110 | /* | |
111 | /* start_server_connection (start_server_connection) | |
112 | /* | |
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. | |
118 | /* | |
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. | |
128 | /* | |
129 | /************************************************************************/ | |
130 | ||
131 | CONNECTION | |
132 | start_server_connection(server_id, parms) | |
133 | char *server_id; | |
134 | char *parms; | |
135 | { | |
136 | CONNECTION con; /* the connection we're */ | |
137 | /* creating */ | |
138 | TUPLE response = NULL; /* each time we try a server */ | |
139 | /* it sends back its */ | |
140 | /* response here */ | |
141 | int retries = GDB_MAX_SERVER_RETRIES; /* number of servers we'll */ | |
142 | /* try before giving up in */ | |
143 | /* fear of a loop */ | |
144 | ||
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 */ | |
148 | /* forwarded */ | |
149 | char latest_parms[GDB_MAX_SERVER_PARMS_SIZE]; | |
150 | /* likewise for parms */ | |
151 | ||
152 | GDB_INIT_CHECK | |
153 | ||
154 | /* | |
155 | * Try to allocate a connection and fill it in with null values. | |
156 | */ | |
157 | ||
158 | con = g_make_con(); | |
159 | ||
160 | /* | |
161 | * Loop asking different servers to accept our connection | |
162 | * until one does or we are flatly refused. | |
163 | */ | |
164 | ||
165 | /* | |
166 | * Allocate a buffer, if necessary, and reset buffer pointers | |
167 | * so first request will result in a long read into the buffer | |
168 | */ | |
169 | g_allocate_connection_buffers(con); | |
170 | ||
171 | ||
172 | g_try_server(&con, server_id, parms, &response); | |
173 | ||
174 | while ((retries--) && | |
175 | con != NULL && | |
176 | response != NULL && | |
177 | *(int *)FIELD_FROM_TUPLE(response,FSV_DISPOSITION)==GDB_FORWARDED) { | |
178 | ||
179 | (void) sever_connection(con); | |
180 | con = g_make_con(); | |
181 | (void) strcpy(serv_id, | |
182 | STRING_DATA(*(STRING *) | |
183 | (FIELD_FROM_TUPLE(response, | |
184 | FSV_SERVER_ID)))); | |
185 | (void) strcpy(latest_parms, | |
186 | STRING_DATA(*(STRING *) | |
187 | (FIELD_FROM_TUPLE(response, | |
188 | FSV_PARMS)))); | |
189 | null_tuple_strings(response); | |
190 | delete_tuple(response); | |
191 | g_try_server(&con, serv_id, latest_parms, &response); | |
192 | } | |
193 | ||
194 | /* | |
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. | |
198 | */ | |
199 | if (con == NULL || | |
200 | connection_status(con) != CON_UP) { | |
201 | return con; | |
202 | } | |
203 | ||
204 | /* | |
205 | * We have at least some active connection, now see whether we | |
206 | * are going to get to keep it | |
207 | */ | |
208 | if (response != NULL && | |
209 | *(int *)FIELD_FROM_TUPLE(response,FSV_DISPOSITION) == GDB_ACCEPTED) { | |
210 | null_tuple_strings(response); | |
211 | delete_tuple(response); | |
212 | return con; | |
213 | } else { | |
214 | if (response != NULL) { | |
215 | null_tuple_strings(response); | |
216 | delete_tuple(response); | |
217 | } | |
218 | (void) sever_connection(con); | |
219 | return NULL; | |
220 | } | |
221 | } | |
097e9b93 | 222 | |
5580185e | 223 | /************************************************************************/ |
224 | /* | |
225 | /* g_try_server | |
226 | /* | |
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. | |
231 | /* | |
232 | /************************************************************************/ | |
233 | ||
234 | int | |
235 | g_try_server(conp, server_id, parms, responsep) | |
236 | CONNECTION *conp; | |
237 | char *server_id; | |
238 | char *parms; | |
239 | TUPLE *responsep; | |
240 | { | |
241 | ||
242 | register CONNECTION con = *conp; | |
243 | int flag = 1; | |
244 | ||
245 | /* | |
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 | |
251 | * connection. | |
252 | */ | |
253 | ||
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 */ | |
260 | } | |
261 | g_ver_oprotocol(con); | |
262 | if (con->status != CON_UP) { | |
263 | return; | |
264 | } | |
265 | ||
266 | /* | |
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. | |
270 | */ | |
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"); | |
274 | return; | |
275 | } | |
276 | if (con->in.fd +1 > gdb_mfd) | |
277 | gdb_mfd = con->in.fd + 1; | |
278 | ||
279 | g_ask_server(conp, server_id, parms, responsep); | |
280 | ||
281 | return; | |
282 | } | |
283 | ||
097e9b93 | 284 | |
5580185e | 285 | /************************************************************************/ |
286 | /* | |
287 | /* g_ask_server | |
288 | /* | |
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. | |
294 | /* | |
295 | /************************************************************************/ | |
296 | ||
297 | int | |
298 | g_ask_server(conp, server_id, parms, responsep) | |
299 | CONNECTION *conp; | |
300 | char *server_id; | |
301 | char *parms; | |
302 | TUPLE *responsep; | |
303 | { | |
304 | register CONNECTION con = *conp; | |
305 | TUPLE out_tuple; | |
306 | int rc; | |
307 | /*----------------------------------------------------------*/ | |
308 | /* | |
309 | /* Create a tuple to be sent out containing the | |
310 | /* server_id and parms. | |
311 | /* | |
312 | /*----------------------------------------------------------*/ | |
313 | ||
314 | out_tuple = create_tuple(gdb_tosrv); /* descriptor was pre- */ | |
315 | /* built during */ | |
316 | /* initialization*/ | |
317 | ||
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))), | |
321 | server_id); | |
322 | ||
2251cae5 | 323 | if (parms == NULL) parms = ""; |
5580185e | 324 | (void) string_alloc((STRING *)FIELD_FROM_TUPLE(out_tuple, TSV_PARMS), |
325 | strlen(parms)+1); | |
326 | (void) strcpy(STRING_DATA(*((STRING *)FIELD_FROM_TUPLE(out_tuple,1))), | |
327 | parms); | |
328 | ||
329 | (void) string_alloc((STRING *)FIELD_FROM_TUPLE(out_tuple, TSV_HOST), | |
330 | strlen(gdb_host)+1); | |
331 | (void) strcpy(STRING_DATA(*((STRING *)FIELD_FROM_TUPLE(out_tuple, | |
332 | TSV_HOST))), | |
333 | gdb_host); | |
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))), | |
337 | gdb_uname); | |
338 | ||
339 | /*----------------------------------------------------------*/ | |
340 | /* | |
341 | /* Send the tuple to the server, and make sure that | |
342 | /* we succeeded. | |
343 | /* | |
344 | /*----------------------------------------------------------*/ | |
345 | ||
346 | rc = send_object(con, (char *)&out_tuple, TUPLE_T); | |
347 | ||
348 | null_tuple_strings(out_tuple); | |
349 | delete_tuple(out_tuple); | |
350 | ||
351 | if (rc != OP_SUCCESS) { | |
352 | return; /* cleanup from dying send */ | |
353 | /* should have made this */ | |
354 | /* CON_STOPPING with errno */ | |
355 | } | |
356 | ||
357 | /*----------------------------------------------------------*/ | |
358 | /* | |
359 | /* OK, we sent it out, now lets read back the response. | |
360 | /* | |
361 | /*----------------------------------------------------------*/ | |
362 | ||
363 | rc = receive_object(con, (char *)responsep, TUPLE_T); | |
364 | ||
365 | if (rc != OP_SUCCESS) { | |
366 | return; /* cleanup from dying send */ | |
367 | /* should have made this */ | |
368 | /* CON_STOPPING with errno */ | |
369 | } | |
370 | } | |
097e9b93 | 371 | |
372 | ||
5580185e | 373 | /************************************************************************/ |
374 | /* | |
375 | /* start_replying_to_client | |
376 | /* | |
377 | /* Queue an operation which will send a reply to the specified | |
378 | /* client. | |
379 | /* | |
380 | /************************************************************************/ | |
381 | ||
382 | struct rtc_data { | |
383 | TUPLE reply_data; | |
384 | OPERATION tuple_send; | |
385 | }; | |
386 | ||
387 | int g_irtc(); | |
388 | int g_i2rtc(); | |
389 | ||
390 | int | |
391 | start_replying_to_client(op, con, disposition, serverid, parms) | |
392 | OPERATION op; | |
393 | CONNECTION con; | |
394 | int disposition; | |
395 | char *serverid; /* null terminated */ | |
396 | char *parms; /* " " */ | |
397 | { | |
398 | register struct rtc_data *arg; | |
399 | register TUPLE t; | |
400 | ||
401 | /* | |
402 | * Make sure the supplied connection is a legal one | |
403 | */ | |
404 | GDB_CHECK_CON(con, "start_replying_to_client") | |
405 | ||
406 | arg = (struct rtc_data *)db_alloc(sizeof(struct rtc_data)); | |
407 | ||
408 | /* | |
409 | * create an empty operation and a tuple | |
410 | */ | |
411 | arg->tuple_send = create_operation(); | |
412 | arg->reply_data = create_tuple(gdb_fmsrv); | |
413 | /* | |
414 | * Fill in the response tuple | |
415 | */ | |
416 | t = arg->reply_data; /* quicker and easier here */ | |
417 | ||
418 | *(int *)FIELD_FROM_TUPLE(t,FSV_DISPOSITION) = disposition; | |
419 | (void) string_alloc((STRING *)FIELD_FROM_TUPLE(t, FSV_SERVER_ID), | |
420 | strlen(serverid)+1); | |
421 | (void) strcpy(STRING_DATA(*(STRING *)(FIELD_FROM_TUPLE(t, FSV_SERVER_ID))), | |
422 | serverid); | |
423 | ||
424 | (void) string_alloc((STRING *)FIELD_FROM_TUPLE(t, FSV_PARMS), | |
425 | strlen(parms)+1); | |
426 | (void) strcpy(STRING_DATA(*(STRING *)(FIELD_FROM_TUPLE(t, FSV_PARMS))), | |
427 | parms); | |
428 | ||
429 | /* | |
430 | * Queue an operation ahead of us which will send the response tuple | |
431 | * to the client | |
432 | */ | |
433 | start_sending_object(arg->tuple_send, con, (char *)&arg->reply_data, | |
434 | TUPLE_T); | |
435 | ||
436 | /* | |
437 | * Now queue us behind it. By the time we run our init routine, | |
438 | * a connection should have been acquired. | |
439 | */ | |
440 | initialize_operation(op, g_irtc, (char *)arg, (int (*)())NULL); | |
441 | (void) queue_operation(con, CON_INPUT, op); | |
442 | } | |
443 | ||
444 | /*----------------------------------------------------------*/ | |
445 | /* | |
446 | /* g_irtc | |
447 | /* | |
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. | |
451 | /* | |
452 | /*----------------------------------------------------------*/ | |
453 | ||
24582af9 | 454 | /*ARGSUSED*/ |
5580185e | 455 | int |
456 | g_irtc(op, hcon, arg) | |
457 | OPERATION op; | |
458 | HALF_CONNECTION hcon; | |
459 | struct rtc_data *arg; | |
460 | { | |
461 | int rc; | |
462 | ||
463 | /* | |
464 | * Figure out the return information to our caller | |
465 | */ | |
466 | rc = OP_STATUS(arg->tuple_send); | |
467 | ||
468 | /* | |
469 | * Release all transient data structures. | |
470 | */ | |
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)); | |
475 | return rc; | |
476 | } |