]>
Commit | Line | Data |
---|---|---|
5580185e | 1 | /* |
2 | * $Source$ | |
3 | * $Header$ | |
4 | */ | |
5 | ||
6 | #ifndef lint | |
7 | static char *rcsid_gdb_fserv_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_fserv.c | |
33 | /* | |
34 | /* GDB - Routines to implement forking servers. | |
35 | /* | |
36 | /* Author: Noah Mendelsohn | |
37 | /* Copyright: 1986 MIT Project Athena | |
38 | /* | |
39 | /************************************************************************/ | |
40 | ||
41 | #include <stdio.h> | |
42 | #include <sys/types.h> | |
43 | #include <sys/uio.h> | |
44 | #include <sys/socket.h> | |
45 | #include <sys/wait.h> | |
46 | #include <sys/signal.h> | |
47 | #include "gdb.h" | |
48 | #include <sys/resource.h> | |
49 | \f | |
50 | /************************************************************************/ | |
51 | /* | |
52 | /* create_forking_server (create_forking_server) | |
53 | /* | |
54 | /* Called by an application to turn itself into a forking model | |
55 | /* server. Returns from this routine occur only in the forked | |
56 | /* children. The parent lives in this routine forever, waiting | |
57 | /* for incoming connection requests and doing the appropriate | |
58 | /* forking. | |
59 | /* | |
60 | /* Children are expected to do their own cleanup, but this routine | |
61 | /* does do the work of reaping the resulting zombie processes. | |
62 | /* | |
63 | /* ARGUMENTS: | |
64 | /* ---------- | |
65 | /* | |
66 | /* service-id identifies the port to be used for | |
67 | /* listening. Same rules as for | |
68 | /* create_listening_connection. | |
69 | /* | |
70 | /* validate-rtn pointer to a function to be called to | |
71 | /* validate the incoming client. Should | |
72 | /* return TRUE if client is acceptable, | |
73 | /* else false. If this is NULL, all clients | |
74 | /* are accepted. | |
75 | /* | |
76 | /* GLOBAL VARIABLES | |
77 | /* ---------------- | |
78 | /* | |
79 | /* Children created by this routine inherit the global variables | |
80 | /* gdb_sockaddr_of_client, which is of type sockaddr_in and | |
81 | /* gdb_socklen, which is the returned length of the sockaddr. | |
82 | /* These are the Berkeley identifiers of the clients as accepted. | |
83 | /* Use of this interface is non-portable to other than Berkeley | |
84 | /* systems. | |
85 | /* | |
86 | /* The client's request tuple may be found in gdb_client_tuple. | |
87 | /* | |
88 | /************************************************************************/ | |
89 | ||
90 | ||
91 | CONNECTION | |
92 | create_forking_server(service, validate) | |
93 | char *service; | |
94 | int (*validate)(); | |
95 | { | |
96 | ||
97 | CONNECTION incoming; /* listen for incoming */ | |
98 | /* children here */ | |
99 | CONNECTION client = NULL; /* connection to client */ | |
100 | /* is created here */ | |
101 | OPERATION listenop; /* used to asynchronously */ | |
102 | /* listen for a child */ | |
103 | /* connection request */ | |
104 | GDB_INIT_CHECK | |
105 | ||
106 | /*----------------------------------------------------------*/ | |
107 | /* | |
108 | /* Set up parent execution environment | |
109 | /* | |
110 | /*----------------------------------------------------------*/ | |
111 | ||
112 | g_do_signals(); /* set up signal handling */ | |
113 | ||
114 | incoming = create_listening_connection(service); | |
115 | if (incoming == NULL) | |
116 | GDB_GIVEUP("create_forking_server: can't create listening connection") | |
117 | ||
118 | /*----------------------------------------------------------*/ | |
119 | /* | |
120 | /* Repeatedly listen for incoming | |
121 | /* | |
122 | /*----------------------------------------------------------*/ | |
123 | ||
124 | listenop = create_operation(); | |
125 | while (TRUE) { | |
126 | gdb_socklen = sizeof(gdb_sockaddr_of_client); | |
127 | client = NULL; | |
128 | (void) start_accepting_client(incoming, listenop, &client, | |
129 | gdb_sockaddr_of_client, &gdb_socklen, | |
130 | &gdb_client_tuple); | |
131 | if(complete_operation(listenop) != OP_COMPLETE || | |
132 | client == NULL) | |
133 | GDB_GIVEUP("create_forking_server: failed to accept client") | |
134 | ||
135 | ||
136 | /* | |
137 | * Call the validate routine, if it fails, | |
138 | * refuse the client. | |
139 | */ | |
140 | if (validate != NULL && !(*validate)()) { | |
141 | reset_operation(listenop); | |
142 | start_replying_to_client(listenop, client, | |
143 | GDB_REFUSED, "",""); | |
144 | (void) complete_operation(listenop); | |
145 | reset_operation(listenop); | |
146 | (void) sever_connection(client); | |
147 | continue; | |
148 | } | |
149 | /* | |
150 | * Create the child for this client | |
151 | */ | |
152 | if ((gdb_Debug & GDB_NOFORK) || fork() == 0) { | |
153 | /* | |
154 | * This is the child, or we're in noforking | |
155 | * debug mode. | |
156 | */ | |
157 | reset_operation(listenop); | |
158 | start_replying_to_client(listenop, client, | |
159 | GDB_ACCEPTED, "",""); | |
160 | if (complete_operation(listenop) != OP_COMPLETE) | |
161 | exit(8); | |
162 | return client; /* return to application */ | |
163 | /* program */ | |
164 | } | |
165 | /* | |
166 | * Still in the parent | |
167 | */ | |
168 | (void) sever_connection(client); | |
169 | reset_operation(listenop); | |
170 | } | |
171 | } | |
172 | \f | |
173 | /************************************************************************/ | |
174 | /* | |
175 | /* gdb_reaper | |
176 | /* | |
177 | /* Called on SIGCHILD to reap all dead children. | |
178 | /* | |
179 | /************************************************************************/ | |
180 | int | |
181 | gdb_reaper() | |
182 | { | |
183 | union wait status; | |
184 | extern char *sys_siglist[]; | |
185 | ||
186 | while (wait3(&status, WNOHANG, (struct rusage *)0) >0) { | |
187 | #ifdef notdef | |
188 | if (WIFEXITED(status)) { | |
189 | if (status.w_retcode) | |
190 | printf("exited with code %d\n", | |
191 | status.w_retcode); | |
192 | } | |
193 | if (WIFSIGNALED(status)) { | |
194 | printf("exited on %s signal%s\n", | |
195 | sys_siglist[status.w_termsig], | |
196 | (status.w_coredump?"; core dumped":0)); | |
197 | } | |
198 | #endif notdef | |
199 | } | |
200 | } | |
201 | \f | |
202 | /************************************************************************/ | |
203 | /* | |
204 | /* g_do_signals | |
205 | /* | |
206 | /* Set up signal handling for a forking server. | |
207 | /* | |
208 | /************************************************************************/ | |
209 | ||
210 | int | |
211 | g_do_signals() | |
212 | { | |
213 | (void) signal(SIGCHLD, gdb_reaper); | |
214 | } |