[BACK]Return to server.c CVS log [TXT][DIR] Up to [local] / src / sbin / photurisd

File: [local] / src / sbin / photurisd / Attic / server.c (download)

Revision 1.9, Sun Jan 28 22:45:17 2001 UTC (23 years, 4 months ago) by niklas
Branch: MAIN
CVS Tags: OPENBSD_3_0_BASE, OPENBSD_3_0, OPENBSD_2_9_BASE, OPENBSD_2_9
Changes since 1.8: +3 -1 lines

$OpenBSD$

/*	$OpenBSD: server.c,v 1.9 2001/01/28 22:45:17 niklas Exp $	*/

/*
 * Copyright 1997-2000 Niels Provos <provos@citi.umich.edu>
 * All rights reserved.
 *
 * Parts derived from code by Angelos D. Keromytis, kermit@forthnet.gr
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *      This product includes software developed by Niels Provos.
 * 4. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
/*
 * server.c:
 * SERVER handling functions
 */

#ifndef lint
static char rcsid[] = "$OpenBSD: server.c,v 1.9 2001/01/28 22:45:17 niklas Exp $";
#endif

#define _SERVER_C_
#include <stdio.h>
#include <stdlib.h> 
#include <fcntl.h>
#include <sys/types.h>  
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/socket.h>  
#include <netinet/in.h>  
#include <arpa/inet.h>  
#include <netdb.h> 
#include <sys/ioctl.h> 
#include <net/if.h> 
#include <string.h>
#include <unistd.h>
#ifdef _AIX 
#include <sys/select.h> 
#endif 
#include <errno.h>
#include "config.h"
#include "photuris.h"
#include "server.h"
#include "api.h"
#include "packet.h"
#include "schedule.h"
#include "log.h"
#include "buffer.h"
#ifdef IPSEC
#include "spi.h"
#include "attributes.h"
#include "kernel.h"
#endif

int
init_server(void)
{
     struct sockaddr_in sin, *sin2; 
     struct protoent *proto; 
     struct stat sb;
     int sock, d, i, ip, on = 1; 
     struct ifconf ifconf; 
     void *newbuf;
     char buf[4096];

     readfds = normfds = NULL;

     if (global_port == 0) {
#ifndef PHOTURIS_PORT  
	  struct servent *ser;

	  if ((ser = getservbyname("photuris", "udp")) == (struct servent *) NULL)
	       log_fatal("getservbyname(\"photuris\") in init_server()");

	  global_port = ser->s_port;
#else  
	  global_port = PHOTURIS_PORT;
#endif  
     }

     if ((proto = getprotobyname("udp")) == (struct protoent *) NULL)
          log_fatal("getprotobyname() in init_server()"); 
 
     if ((global_socket = socket(PF_INET, SOCK_DGRAM, proto->p_proto)) < 0)
          log_fatal("socket() in init_server()"); 
     
     setsockopt(global_socket, SOL_SOCKET, SO_REUSEADDR, (void *)&on, 
		sizeof(on));
#ifdef IPSEC
     kernel_set_socket_policy(global_socket);
#endif	  

     /* get the local addresses */ 
 
     ifconf.ifc_len = sizeof(buf); 
     ifconf.ifc_buf = buf; 
     bzero(buf, 1024); 
 
     if (ioctl(global_socket, SIOCGIFCONF, &ifconf) == -1) 
          log_fatal("ioctl() in init_server()"); 

     sin.sin_port = htons(global_port);
     sin.sin_addr.s_addr = INADDR_ANY; 
     sin.sin_family = AF_INET; 
     
     if (bind(global_socket, (struct sockaddr *)&sin, sizeof(struct sockaddr)) < 0)
	  log_fatal("bind() in init_server()"); 
 
     /* Save interfaces addresses here */
     addresses = (char **) calloc(1+1, sizeof(char *)); 
     if (addresses == (char **) NULL) 
	  log_fatal("calloc() in init_server()"); 
     addresses[1] = (char *) NULL; 
 
     sockets = (int *) calloc(1+1, sizeof(int)); 
     if (sockets == (int *) NULL) 
	  log_fatal("calloc() in init_server()"); 
     sockets[1] = -1;
 
     if (lstat(PHOTURIS_FIFO, &sb) == -1) {
	  if (errno != ENOENT)
	       log_fatal("stat() in init_server()");
	  if (mkfifo(PHOTURIS_FIFO, 0660) == -1)
	       log_fatal("mkfifo() in init_server()");
     } else if (!(sb.st_mode & S_IFIFO))
	  log_print("%s is not a FIFO in init_server()", PHOTURIS_FIFO);

     /* We listen on a named pipe */
#if defined(linux) || defined(_AIX)
     if ((sockets[0] = open(PHOTURIS_FIFO, O_RDWR| O_NONBLOCK, 0)) == -1)
#else
     if ((sockets[0] = open(PHOTURIS_FIFO, O_RDONLY | O_NONBLOCK, 0)) == -1)
#endif
	  log_fatal("open() in init_server()");
     i = 1;                  /* One interface already */

#ifdef IPSEC
     /* We also listen on pfkeyv2 for notify messages */
     newbuf = realloc(addresses, (i + 2) * sizeof(char *)); 
     if (newbuf == NULL) {
	  if (addresses != NULL)
	       free (addresses);
	  log_fatal("realloc() in init_server()"); 
     }
     addresses = (char **) newbuf;
     
     addresses[i + 1] = (char *) NULL; 

     newbuf = realloc(sockets, (i + 2)* sizeof(int));
     if (newbuf == NULL) {
	  if (sockets != NULL)
	       free (sockets);
	  log_fatal("realloc() in init_server()");
     }
     sockets = (int *) newbuf;

     sockets[i] = kernel_get_socket();
     sockets[i+1] = -1;

     i++;                    /* Next interface */
#endif

     for (ip = 0, d = 0; d < ifconf.ifc_len; d += IFNAMSIZ + 
#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(_AIX)
	       buf[IFNAMSIZ + d] 
#else 
	       sizeof(struct sockaddr) 
#endif 
	       , i++, ip++) {
	  sin2 = (struct sockaddr_in *) &buf[IFNAMSIZ + d]; 
 
	  if (sin2->sin_family != AF_INET) { 
	       i--; ip--;
	       continue; 
	  } 
 
	  newbuf =  realloc(addresses, (i + 2) * sizeof(char *)); 
	  if (newbuf == NULL) {
	       if (addresses != NULL)
		    free (addresses);
	       log_fatal("realloc() in init_server()"); 
	  }
	  addresses = (char **) newbuf;
	     
	  addresses[i] = strdup(inet_ntoa(sin2->sin_addr)); 
	  if (addresses[i] == (char *) NULL) 
	       log_fatal("strdup() in init_server()"); 
	  addresses[i + 1] = (char *) NULL; 

	  newbuf = realloc(sockets, (i + 2)* sizeof(int));
	  if (newbuf == NULL) {
	       if (sockets != NULL)
		    free (sockets);
	       log_fatal("realloc() in init_server()");
	  }
	  sockets = (int *) newbuf;

	  sockets[i+1] = -1;

	  if ((sock = socket(PF_INET, SOCK_DGRAM, proto->p_proto)) < 0)
	       log_fatal("socket() in init_server()"); 
	  setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on, 
		     sizeof(on)); 
#ifdef IPSEC
	  kernel_set_socket_policy(sock);
#endif	  
	  sockets[i] = sock;

#ifdef DEBUG 
	  printf("Local interface %s, address %s.\n", buf + d, 
		 addresses[i]); 
#endif 

	  bzero((void *)&sin, sizeof(sin));
	  sin.sin_port = htons(global_port);
	  sin.sin_addr.s_addr = inet_addr(addresses[i]);
	  sin.sin_family = AF_INET; 
     
	  if (bind(sockets[i], (struct sockaddr *)&sin, sizeof(struct sockaddr)) < 0)
	       log_fatal("bind() in init_server()"); 
  
     } 

     num_ifs = i;
 
#ifdef DEBUG 
     printf("%d local interfaces supporting IP found.\n", ip); 
#endif 

     return 1;
}

int 
server(void)
{
     struct sockaddr_in sin; 
     struct timeval timeout; 
     int i, d, size;

     setvbuf(stdout, (char *)NULL, _IOLBF, 0);

     size = howmany(sockets[num_ifs-1], NFDBITS) * sizeof(fd_mask);
     normfds = (fd_set *)malloc(size);
     if (normfds == NULL)
	  log_fatal("malloc(%d) for fd_set", size);

     readfds = (fd_set *)malloc(size);
     if (readfds == NULL)
	  log_fatal("malloc(%d) for fd_set", size);

     memset((void *)normfds, 0, size); 

     for (i = 0; i < num_ifs; i++)
	  FD_SET(sockets[i], normfds);

     while (1) {
	  extern sig_atomic_t wantconfig;

	  if (wantconfig) {
		reconfig(0);
		wantconfig = 0;
	  }

	  bcopy(normfds, readfds, size);

	  /* Timeout till next job */
	  timeout.tv_usec = 0;
	  timeout.tv_sec = schedule_next();

#ifdef DEBUG2
	  printf("Sleeping for %ld seconds\n", timeout.tv_sec);
#endif

	  if (select(sockets[num_ifs-1]+1, 
		     readfds, (fd_set *) NULL, (fd_set *) NULL, 
		     (timeout.tv_sec == -1 ? NULL : &timeout)) < 0) {
	       if (errno == EINTR) 
                    continue; 
	       else
                    log_fatal("select() in server()"); 
	  }

	  for (i=0; i<num_ifs; i++) {
	       if (FD_ISSET(sockets[i], readfds)) {
#ifdef IPSEC
		    if (i == 1)       /* PF_ENCAP NOTIFIES */
			 kernel_handle_notify(sockets[i]);
		    else
#endif
			 if (addresses[i] == NULL)
				 process_api(sockets[i], global_socket); 
			 else {
				 d = sizeof(struct sockaddr_in);
				 if (recvfrom(sockets[i], 
#ifdef BROKEN_RECVFROM
					      (char *) buffer, 1,
#else
					      (char *) NULL, 0, 
#endif
					      MSG_PEEK,
					      (struct sockaddr *)&sin,
					      &d) == -1) {
					 log_error("recvfrom() in server()"); 
					 return -1;
				 }
				 handle_packet(sockets[i], addresses[i]);
 		    }
	       } 
	  }

#ifdef IPSEC
	  /* 
	   * Deal with queue acquire and expire message, since we
	   * dont have proper timeout code, it needs to go here.
	   */
	  kernel_handle_queue();
#endif

	  schedule_process(global_socket);
	  fflush(stdout);
	  fflush(stderr);
     }

     /* We will never reach this place - it's called limbo */

}