249 lines
5.3 KiB
C
Executable File
249 lines
5.3 KiB
C
Executable File
/*
|
|
*
|
|
* LECS main code
|
|
*
|
|
* $Id: //BBN_Linux/Branch/Branch_for_Rel_TP_ASEAN_20161216/tclinux_phoenix/apps/public/linux-atm/lane/lecs.c#1 $
|
|
*
|
|
*/
|
|
|
|
/* Standard includes*/
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <getopt.h>
|
|
#include <signal.h>
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
#include <netinet/in.h>
|
|
#include <unistd.h>
|
|
#include <sys/types.h>
|
|
#include <sys/time.h>
|
|
|
|
/* ATM includes */
|
|
#include <atm.h>
|
|
|
|
/* Local includes */
|
|
#include "lecs_load.h"
|
|
#include "ldb.h"
|
|
#include "mem_lecs.h"
|
|
#include "lecs.h"
|
|
#include "atm_lecs.h"
|
|
|
|
/* Protos */
|
|
static void sig_reset(int foobar);
|
|
static void sig_kill(int foobar);
|
|
static void usage(const char *progname);
|
|
int send_response(int fd, unsigned char *buffer, int len);
|
|
|
|
/* Local data */
|
|
#define COMP_NAME "MAIN"
|
|
#define MAX_FD 32
|
|
#define P_SIZE 1024
|
|
static int stay_alive = 1;
|
|
static int reset = 0;
|
|
|
|
#define DUMP_PACKETS 0
|
|
|
|
static void
|
|
usage(const char *progname)
|
|
{
|
|
printf("Usage: %s [-f configuration_file][-l listen_address][-d]\n",
|
|
progname);
|
|
}
|
|
|
|
static void
|
|
sig_reset(int foobar)
|
|
{
|
|
reset = 1;
|
|
}
|
|
|
|
static void
|
|
sig_kill(int foobar)
|
|
{
|
|
stay_alive = 0;
|
|
}
|
|
|
|
int
|
|
send_response(int fd, unsigned char *buffer, int len)
|
|
{
|
|
LaneControl_t *dp;
|
|
Elan_t *elan;
|
|
unsigned short response;
|
|
#ifdef DUMP_PACKETS
|
|
int i;
|
|
#endif
|
|
|
|
if (len < sizeof(LaneControl_t))
|
|
return -1;
|
|
|
|
dp = (LaneControl_t *)buffer;
|
|
|
|
if (dp->marker != htons(LE_MARKER) ||
|
|
dp->protocol != LE_PROTOCOL ||
|
|
dp->version != LE_VERSION ||
|
|
dp->opcode != htons(LE_CONFIGURE_REQUEST)) {
|
|
return -1;
|
|
}
|
|
dp->opcode = htons(LE_CONFIGURE_RESPONSE);
|
|
elan = find_elan(dp->source_atm, dp->lan_type, dp->max_frame,
|
|
(char*)dp->elan_name, dp->elan_name_size, &response);
|
|
if (!elan) {
|
|
dp->status = htons(response);
|
|
} else {
|
|
dp->status = htons(LE_STATUS_SUCCESS);
|
|
dp->lan_type = elan->type;
|
|
dp->max_frame = elan->max_frame;
|
|
memcpy(dp->elan_name, elan->elan_name, elan->elan_name_size);
|
|
dp->elan_name_size = elan->elan_name_size;
|
|
memcpy(dp->target_atm, elan->les_addr, ATM_ESA_LEN);
|
|
}
|
|
#ifdef DUMP_PACKETS
|
|
for(i=0;i<len;i++) {
|
|
printf("%2.2x ",0xff&buffer[i]);
|
|
}
|
|
printf("\n");
|
|
#endif
|
|
return write(fd, buffer, len);
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
int i =0;
|
|
char *config_file =NULL;
|
|
char *listen_addr = NULL;
|
|
int fd_arr[MAX_FD];
|
|
int no_fds=1;
|
|
int just_dump=0;
|
|
fd_set fds;
|
|
struct sockaddr_atmsvc client;
|
|
int len;
|
|
unsigned char buffer[P_SIZE];
|
|
|
|
while(i!=-1) {
|
|
i = getopt(argc, argv, "f:l:d");
|
|
switch(i) {
|
|
case 'd':
|
|
printf("Dumping databasefile\n");
|
|
just_dump=1;
|
|
break;
|
|
case 'f':
|
|
if (config_file) {
|
|
usage(argv[0]);
|
|
exit(-1);
|
|
}
|
|
config_file = (char*)mem_alloc(COMP_NAME, strlen(optarg)+1);
|
|
if (!config_file) {
|
|
exit(-1);
|
|
}
|
|
memcpy(config_file, optarg, strlen(optarg)+1);
|
|
break;
|
|
case 'l':
|
|
if (listen_addr) {
|
|
usage(argv[0]);
|
|
exit(-1);
|
|
}
|
|
listen_addr = (char*)mem_alloc(COMP_NAME, strlen(optarg)+1);
|
|
if (!listen_addr)
|
|
exit(-1);
|
|
memcpy(listen_addr, optarg, strlen(optarg)+1);
|
|
break;
|
|
case -1:
|
|
break;
|
|
default:
|
|
usage(argv[0]);
|
|
exit(-1);
|
|
}
|
|
}
|
|
if (argc != optind) {
|
|
usage(argv[0]);
|
|
exit(-1);
|
|
}
|
|
/* Following gets run in the beginning or when lecs is restarted */
|
|
while (stay_alive) {
|
|
|
|
/* Read configuration file */
|
|
if (config_file) {
|
|
if (load_db(config_file)<0)
|
|
exit(-1);
|
|
} else {
|
|
if (load_db(DEFAULT_CONFIG)<0)
|
|
exit(-1);
|
|
}
|
|
if (just_dump) {
|
|
dump_db(NULL);
|
|
exit(0);
|
|
}
|
|
|
|
/* Reserve signals */
|
|
signal(SIGHUP, sig_reset);
|
|
signal(SIGINT, sig_kill);
|
|
signal(SIGQUIT, sig_kill);
|
|
signal(SIGABRT, sig_kill);
|
|
signal(SIGTERM, sig_kill);
|
|
signal(SIGSEGV, sig_kill);
|
|
|
|
/* CHANGE: First parameter, then configuration file! */
|
|
fd_arr[0] = atm_create_socket(CONFIGURATION_DIRECT,
|
|
get_lecs_addr());
|
|
no_fds=1;
|
|
if (fd_arr[0] <0) {
|
|
stay_alive=0; /* No need to go on */
|
|
}
|
|
while(!reset && stay_alive) {
|
|
FD_ZERO(&fds);
|
|
for(i=0;i<no_fds;i++) {
|
|
FD_SET(fd_arr[i],&fds);
|
|
}
|
|
|
|
if (select(MAX_FD, &fds, NULL, NULL, NULL)<0) {
|
|
perror("select(MAX_FD,...)");
|
|
stay_alive=0;
|
|
} else {
|
|
if (FD_ISSET(fd_arr[0],&fds)) { /* Incoming call */
|
|
if (no_fds == MAX_FD) {
|
|
close(fd_arr[1]); /* Oldest */
|
|
memmove(&fd_arr[1], &fd_arr[2], sizeof(int)*(MAX_FD-2));
|
|
no_fds--;
|
|
}
|
|
len = sizeof(client);
|
|
fd_arr[no_fds] = accept(fd_arr[0], (struct sockaddr*)&client,
|
|
&len);
|
|
if (fd_arr[no_fds]<0) {
|
|
if (errno==ENETRESET)
|
|
reset=1;
|
|
if (errno==EUNATCH)
|
|
stay_alive=1;
|
|
} else {
|
|
no_fds++;
|
|
}
|
|
}
|
|
for(i=1;i<no_fds;i++) {
|
|
if (FD_ISSET(fd_arr[i],&fds)) {
|
|
len = read(fd_arr[i], buffer, P_SIZE);
|
|
if (len <0 && (errno == ENETRESET || errno == EUNATCH)) {
|
|
reset=0;
|
|
}
|
|
if (len<=0) {
|
|
close(fd_arr[i]);
|
|
memmove(&fd_arr[i], &fd_arr[i+1], sizeof(int)*(--no_fds -i));
|
|
i--;
|
|
} else {
|
|
if(send_response(fd_arr[i], buffer, len)<0) {
|
|
close(fd_arr[i]);
|
|
memmove(&fd_arr[i], &fd_arr[i+1], sizeof(int)*(--no_fds -i));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/* This gets done if a signal has been caught, or if
|
|
network resets/becomes unavailable */
|
|
reset=0;
|
|
for(i=0;i<no_fds;i++)
|
|
close(fd_arr[i]);
|
|
no_fds=0;
|
|
reset_db();
|
|
}
|
|
return 0;
|
|
}
|