1 /* pptp_callmgr.c ... Call manager for PPTP connections.
2 * Handles TCP port 1723 protocol.
3 * C. Scott Ananian <cananian@alumni.princeton.edu>
5 * $Id: pptp_callmgr.c,v 1.2 2002/08/23 01:23:28 honor Exp $
11 #include <sys/socket.h>
12 #include <netinet/in.h>
13 #include <arpa/inet.h>
22 #include "pptp_callmgr.h"
23 #include "pptp_ctrl.h"
30 int open_inetsock(struct in_addr inetaddr
);
31 int open_unixsock(struct in_addr inetaddr
);
32 void close_inetsock(int fd
, struct in_addr inetaddr
);
33 void close_unixsock(int fd
, struct in_addr inetaddr
);
37 void sighandler(int sig
) {
41 void do_nothing(int sig
) {
42 /* do nothing signal handler */
45 struct local_callinfo
{
50 struct local_conninfo
{
55 /* Connection callback */
56 void conn_callback(PPTP_CONN
*conn
, enum conn_state state
) {
65 log("Unhandled connection callback state [%d].", (int) state
);
70 void call_callback(PPTP_CONN
*conn
, PPTP_CALL
*call
, enum call_state state
) {
71 struct local_callinfo
*lci
;
72 struct local_conninfo
*conninfo
;
77 /* okey dokey. This means that the call_id and peer_call_id are now
78 * valid, so lets send them on to our friends who requested this call.
80 lci
= pptp_call_closure_get(conn
, call
); assert(lci
!= NULL
);
81 pptp_call_get_ids(conn
, call
, &call_id
[0], &call_id
[1]);
82 write(lci
->unix_sock
, &call_id
, sizeof(call_id
));
83 /* Our duty to the fatherland is now complete. */
88 /* don't need to do anything here, except make sure tables are sync'ed */
89 log("Closing connection");
90 conninfo
= pptp_conn_closure_get(conn
);
91 lci
= pptp_call_closure_get(conn
, call
);
92 assert(lci
!= NULL
&& conninfo
!= NULL
);
93 if (vector_contains(conninfo
->call_list
, lci
->unix_sock
)) {
94 vector_remove(conninfo
->call_list
, lci
->unix_sock
);
95 close(lci
->unix_sock
);
96 FD_CLR(lci
->unix_sock
, conninfo
->call_set
);
97 if(lci
->pid
[0]) kill(lci
->pid
[0], SIGTERM
);
98 if(lci
->pid
[1]) kill(lci
->pid
[1], SIGTERM
);
102 log("Unhandled call callback state [%d].", (int) state
);
109 /* NOTE ABOUT 'VOLATILE': */
110 /* several variables here get a volatile qualifier to silence warnings */
111 /* from older (before 3.0) gccs. once the longjmp stuff is removed, */
112 /* the volatile qualifiers should be removed as well. */
113 int main(int argc
, char **argv
, char **envp
) {
114 struct in_addr inetaddr
;
115 int inet_sock
, unix_sock
;
120 volatile int first
=1;
123 char * volatile phonenr
;
125 /* Step 0: Check arguments */
127 fatal("Usage: %s ip.add.ress.here [--phone <phone number>]", argv
[0]);
128 phonenr
= argc
==3 ? argv
[2] : NULL
;
129 if (inet_aton(argv
[1], &inetaddr
)==0)
130 fatal("Invalid IP address: %s", argv
[1]);
132 /* Step 1: Open sockets. */
133 if ((inet_sock
= open_inetsock(inetaddr
)) < 0)
134 fatal("Could not open control connection to %s", argv
[1]);
135 if ((unix_sock
= open_unixsock(inetaddr
)) < 0)
136 fatal("Could not open unix socket for %s", argv
[1]);
138 /* Step 1b: FORK and return status to calling process. */
140 case 0: /* child. stick around. */
142 case -1: /* failure. Fatal. */
143 fatal("Could not fork.");
144 default: /* Parent. Return status to caller. */
148 /* Step 1c: Clean up unix socket on TERM */
149 if (sigsetjmp(env
, 1)!=0)
152 signal(SIGINT
, sighandler
);
153 signal(SIGTERM
, sighandler
);
155 signal(SIGPIPE
, do_nothing
);
156 signal(SIGUSR1
, do_nothing
); /* signal state change; wake up accept */
158 /* Step 2: Open control connection and register callback */
159 if ((conn
= pptp_conn_open(inet_sock
, 1, NULL
/* callback */)) == NULL
) {
160 close(unix_sock
); close(inet_sock
); fatal("Could not open connection.");
165 call_list
= vector_create();
167 struct local_conninfo
*conninfo
= malloc(sizeof(*conninfo
));
168 if (conninfo
==NULL
) {
169 close(unix_sock
); close(inet_sock
); fatal("No memory.");
171 conninfo
->call_list
= call_list
;
172 conninfo
->call_set
= &call_set
;
173 pptp_conn_closure_put(conn
, conninfo
);
176 if (sigsetjmp(env
, 1)!=0) goto shutdown
;
178 /* Step 3: Get FD_SETs */
181 fd_set read_set
= call_set
, write_set
;
182 FD_ZERO (&write_set
);
183 FD_SET (unix_sock
, &read_set
);
184 pptp_fd_set(conn
, &read_set
, &write_set
, &max_fd
);
186 for (; max_fd
> 0 ; max_fd
--) {
187 if (FD_ISSET (max_fd
, &read_set
) ||
188 FD_ISSET (max_fd
, &write_set
))
192 /* Step 4: Wait on INET or UNIX event */
194 if ((rc
= select(max_fd
+1, &read_set
, &write_set
, NULL
, NULL
)) <0)
195 /* a signal or somesuch. */
198 /* Step 5a: Handle INET events */
199 pptp_dispatch(conn
, &read_set
, &write_set
);
201 /* Step 5b: Handle new connection to UNIX socket */
202 if (FD_ISSET(unix_sock
, &read_set
)) {
204 struct sockaddr_un from
;
205 int len
= sizeof(from
);
207 struct local_callinfo
*lci
;
210 /* Accept the socket */
211 FD_CLR (unix_sock
, &read_set
);
212 if ((s
= accept(unix_sock
, (struct sockaddr
*) &from
, &len
))<0) {
213 warn("Socket not accepted: %s", strerror(errno
));
216 /* Allocate memory for local call information structure. */
217 if ((lci
= malloc(sizeof(*lci
))) == NULL
) {
218 warn("Out of memory."); close(s
); goto skip_accept
;
222 /* Give the initiator time to write the PIDs while we open the call */
223 call
= pptp_call_open(conn
, call_callback
, phonenr
);
224 /* Read and store the associated pids */
225 read(s
, &lci
->pid
[0], sizeof(lci
->pid
[0]));
226 read(s
, &lci
->pid
[1], sizeof(lci
->pid
[1]));
227 /* associate the local information with the call */
228 pptp_call_closure_put(conn
, call
, (void *) lci
);
229 /* The rest is done on callback. */
231 /* Keep alive; wait for close */
232 retval
= vector_insert(call_list
, s
, call
); assert(retval
);
233 if (s
> max_fd
) max_fd
= s
;
234 FD_SET(s
, &call_set
);
238 /* Step 5c: Handle socket close */
239 for (i
=0; i
<max_fd
+1; i
++)
240 if (FD_ISSET(i
, &read_set
)) {
243 retval
= vector_search(call_list
, i
, &call
);
245 struct local_callinfo
*lci
= pptp_call_closure_get(conn
, call
);
246 log("Closing connection");
247 if(lci
->pid
[0]) kill(lci
->pid
[0], SIGTERM
);
248 if(lci
->pid
[1]) kill(lci
->pid
[1], SIGTERM
);
250 /* soft shutdown. Callback will do hard shutdown later */
251 pptp_call_close(conn
, call
);
252 vector_remove(call_list
, i
);
254 FD_CLR(i
, &call_set
);
257 } while (vector_size(call_list
)>0 || first
);
261 fd_set read_set
, write_set
;
263 /* warn("Shutdown"); */
264 /* kill all open calls */
265 for (i
=0; i
<vector_size(call_list
); i
++) {
266 PPTP_CALL
*call
= vector_get_Nth(call_list
, i
);
267 struct local_callinfo
*lci
= pptp_call_closure_get(conn
, call
);
268 log("Closing connection");
269 pptp_call_close(conn
, call
);
270 if(lci
->pid
[0]) kill(lci
->pid
[0], SIGTERM
);
271 if(lci
->pid
[1]) kill(lci
->pid
[1], SIGTERM
);
273 /* attempt to dispatch these messages */
276 pptp_fd_set(conn
, &read_set
, &write_set
, &max_fd
);
278 pptp_dispatch(conn
, &read_set
, &write_set
);
280 /* no more open calls. Close the connection. */
281 pptp_conn_close(conn
, PPTP_STOP_LOCAL_SHUTDOWN
);
284 pptp_fd_set(conn
, &read_set
, &write_set
, &max_fd
);
286 pptp_dispatch(conn
, &read_set
, &write_set
);
288 /* with extreme prejudice */
289 pptp_conn_destroy(conn
);
290 vector_destroy(call_list
);
293 close_inetsock(inet_sock
, inetaddr
);
294 close_unixsock(unix_sock
, inetaddr
);
299 * Connect socket, but with a timeout.
300 * A signal will interrupt this function.
302 * param: msec is the timeout in milliseconds
303 * return: -1 on error, errno is set
307 int connect_timeout(int socket
, struct sockaddr
*addr
, socklen_t len
, int msec
)
309 int oldflags
; /* flags to be restored later */
310 int newflags
; /* nonblocking sockopt for socket */
311 int ret
; /* Result of syscalls */
312 int value
; /* Value to be returned */
314 /* Make sure the socket is nonblocking */
315 oldflags
= fcntl(socket
, F_GETFL
, 0);
318 newflags
= oldflags
| O_NONBLOCK
;
319 ret
= fcntl(socket
, F_SETFL
, newflags
);
323 /* Issue the connect request */
324 ret
= connect(socket
, addr
, len
);
329 /* Connect finished directly */
331 else if(errno
== EINPROGRESS
|| errno
== EWOULDBLOCK
)
337 FD_SET(socket
, &wset
);
339 tv
.tv_sec
= msec
/ 1000;
340 tv
.tv_usec
= 1000*(msec
% 1000);
342 ret
= select(socket
+1, NULL
, &wset
, NULL
, &tv
);
344 if(ret
== 1 && FD_ISSET(socket
, &wset
))
347 socklen_t optlen
= sizeof(optval
);
349 ret
= getsockopt(socket
, SOL_SOCKET
, SO_ERROR
, &optval
, &optlen
);
359 warn("connect timeout for %d seconds",msec
/ 1000);
360 value
= -2; /* select timeout */
363 warn("select error");
364 value
= -1; /* select error */
370 /* Restore the socket flags */
371 ret
= fcntl(socket
, F_SETFL
, oldflags
);
373 perror("restoring socket flags: fcntl");
378 int open_inetsock(struct in_addr inetaddr
) {
379 struct sockaddr_in dest
;
382 dest
.sin_family
= AF_INET
;
383 dest
.sin_port
= htons(PPTP_PORT
);
384 dest
.sin_addr
= inetaddr
;
386 if ((s
= socket(AF_INET
, SOCK_STREAM
, 0)) < 0) {
387 warn("socket: %s", strerror(errno
));
390 if (connect_timeout(s
, (struct sockaddr
*) &dest
, sizeof(dest
), 15000) < 0) {
391 warn("connect: %s", strerror(errno
));
396 int open_unixsock(struct in_addr inetaddr
) {
397 struct sockaddr_un where
;
402 if ((s
= socket(AF_UNIX
, SOCK_STREAM
, 0)) < 0) {
403 warn("socket: %s", strerror(errno
));
407 where
.sun_family
= AF_UNIX
;
408 snprintf(where
.sun_path
, sizeof(where
.sun_path
),
409 PPTP_SOCKET_PREFIX
"%s", inet_ntoa(inetaddr
));
411 if (stat(where
.sun_path
, &st
) >= 0) {
412 warn("Call manager for %s is already running.", inet_ntoa(inetaddr
));
416 /* Make sure path is valid. */
417 dir
= dirname(where
.sun_path
);
418 if (!make_valid_path(dir
, 0770))
419 fatal("Could not make path to %s: %s", where
.sun_path
, strerror(errno
));
422 if (bind(s
, (struct sockaddr
*) &where
, sizeof(where
)) < 0) {
423 warn("bind: %s", strerror(errno
));
427 chmod(where
.sun_path
, 0777);
433 void close_inetsock(int fd
, struct in_addr inetaddr
) {
436 void close_unixsock(int fd
, struct in_addr inetaddr
) {
437 struct sockaddr_un where
;
439 snprintf(where
.sun_path
, sizeof(where
.sun_path
),
440 PPTP_SOCKET_PREFIX
"%s", inet_ntoa(inetaddr
));
441 unlink(where
.sun_path
);