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