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