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