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