mbtask added portcheck, code cleanup

This commit is contained in:
Michiel Broek 2002-02-22 21:15:21 +00:00
parent 9cefcf9b3a
commit 19183e73b6
12 changed files with 828 additions and 551 deletions

View File

@ -4637,6 +4637,8 @@ v0.33.20 10-Feb-2002
Removed some debug logging.
Creates the semafore is_inet when the internet connections is
available, and removes it when it is down.
Added test for ISDN/modem lines in use.
Lost of code cleanup.
mbcico:
Fixed binkp driver to accept incoming unprotected sessions.

View File

@ -5,11 +5,14 @@
include ../Makefile.global
SRCS = callstat.c nodelist.c scanout.c taskcomm.c taskinfo.c taskstat.c \
mbtask.c outstat.c signame.c taskdisk.c taskregs.c taskutil.c
mbtask.c outstat.c signame.c taskdisk.c taskregs.c taskutil.c \
ports.c calllist.c ping.c
HDRS = callstat.h mbtask.h outstat.h signame.h taskdisk.h taskregs.h taskutil.h \
libs.h nodelist.h scanout.h taskcomm.h taskinfo.h taskstat.h
libs.h nodelist.h scanout.h taskcomm.h taskinfo.h taskstat.h \
ports.h calllist.h ping.h
OBJS = callstat.o nodelist.o scanout.o taskcomm.o taskinfo.o taskstat.o \
mbtask.o outstat.o signame.o taskdisk.o taskregs.o taskutil.o
mbtask.o outstat.o signame.o taskdisk.o taskregs.o taskutil.o \
ports.o calllist.o ping.o
OTHER = Makefile issue issue.netbsd
#############################################################################
@ -80,10 +83,13 @@ scanout.o: libs.h ../lib/structs.h taskutil.h scanout.h
taskcomm.o: libs.h ../lib/structs.h taskstat.h taskregs.h taskdisk.h taskinfo.h taskutil.h taskcomm.h
taskinfo.o: libs.h ../lib/structs.h taskinfo.h
taskstat.o: libs.h ../lib/structs.h taskstat.h callstat.h outstat.h taskutil.h
mbtask.o: libs.h ../lib/structs.h signame.h taskstat.h taskutil.h taskregs.h taskcomm.h callstat.h outstat.h nodelist.h mbtask.h
outstat.o: libs.h ../lib/structs.h taskutil.h taskstat.h scanout.h nodelist.h callstat.h outstat.h
mbtask.o: libs.h ../lib/structs.h signame.h taskstat.h taskutil.h taskregs.h taskcomm.h callstat.h outstat.h nodelist.h ports.h calllist.h ping.h mbtask.h
outstat.o: libs.h ../lib/structs.h taskutil.h taskstat.h scanout.h nodelist.h callstat.h ports.h outstat.h
signame.o: signame.h
taskdisk.o: libs.h ../lib/structs.h taskdisk.h taskutil.h
taskregs.o: libs.h ../lib/structs.h taskstat.h taskregs.h taskutil.h
taskutil.o: libs.h ../lib/structs.h signame.h scanout.h taskutil.h
ports.o: libs.h ../lib/structs.h taskutil.h nodelist.h ports.h
calllist.o: libs.h ../lib/structs.h taskstat.h taskutil.h callstat.h outstat.h mbtask.h ports.h calllist.h
ping.o: libs.h ../lib/structs.h taskstat.h taskutil.h ping.h
# End of generated dependencies

154
mbtask/calllist.c Normal file
View File

@ -0,0 +1,154 @@
/*****************************************************************************
*
* $Id$
* Purpose ...............: mbtask - calllist
*
*****************************************************************************
* Copyright (C) 1997-2002
*
* Michiel Broek FIDO: 2:280/2802
* Beekmansbos 10
* 1971 BV IJmuiden
* the Netherlands
*
* This file is part of MBSE BBS.
*
* This BBS is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* MBSE BBS is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MBSE BBS; see the file COPYING. If not, write to the Free
* Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*****************************************************************************/
#include "libs.h"
#include "../lib/structs.h"
#include "taskstat.h"
#include "taskutil.h"
#include "callstat.h"
#include "outstat.h"
#include "mbtask.h"
#include "ports.h"
#include "calllist.h"
/*
* Global variables
*/
tocall calllist[MAXTASKS]; /* Array with calllist */
extern int internet; /* Internet is down */
extern int s_scanout; /* Scan outbound sema */
extern int s_do_inet; /* Internet wanted */
extern _alist_l *alist; /* Nodes to call list */
extern int pots_calls;
extern int isdn_calls;
extern int inet_calls;
/*
* Check the actual list of nodes to call.
*/
int check_calllist(void)
{
int i, found, call_work;
struct _alist *tmp;
/*
* Check callist, remove obsolete entries.
*/
for (i = 0; i < MAXTASKS; i++) {
if (calllist[i].addr.zone) {
found = FALSE;
for (tmp = alist; tmp; tmp = tmp->next) {
if ((calllist[i].addr.zone == tmp->addr.zone) && (calllist[i].addr.net == tmp->addr.net) &&
(calllist[i].addr.node == tmp->addr.node) && (calllist[i].addr.point == tmp->addr.point) &&
((tmp->flavors) & F_CALL)) {
found = TRUE;
}
}
if (!found) {
tasklog('c', "Removing slot %d node %s from calllist", i, ascfnode(calllist[i].addr, 0x0f));
memset(&calllist[i], 0, sizeof(tocall));
}
}
}
check_ports();
if (pots_calls || isdn_calls || inet_calls) {
call_work = 0;
for (tmp = alist; tmp; tmp = tmp->next) {
if (tmp->callmode != CM_NONE) {
call_work++;
found = FALSE;
for (i = 0; i < MAXTASKS; i++) {
if ((calllist[i].addr.zone == tmp->addr.zone) && (calllist[i].addr.net == tmp->addr.net) &&
(calllist[i].addr.node == tmp->addr.node) && (calllist[i].addr.point == tmp->addr.point)) {
found = TRUE;
/*
* Refresh last call status
*/
calllist[i].cst = tmp->cst;
}
}
if (!found) {
for (i = 0; i < MAXTASKS; i++) {
if (!calllist[i].addr.zone) {
tasklog('c', "Adding %s to calllist slot %d", ascfnode(tmp->addr, 0x1f), i);
calllist[i].addr = tmp->addr;
calllist[i].cst = tmp->cst;
calllist[i].callmode = tmp->callmode;
calllist[i].moflags = tmp->moflags;
calllist[i].diflags = tmp->diflags;
calllist[i].ipflags = tmp->ipflags;
break;
}
}
}
}
}
tasklog('o', "%d systems to call", call_work);
} else {
if (s_scanout)
sem_set((char *)"scanout", FALSE);
}
/*
* Check if we need to remove the do_inet semafore
*/
if (!inet_calls && internet && s_do_inet) {
tasklog('c', "Removing do_inet semafore");
s_do_inet = FALSE;
if (IsSema((char *)"do_inet")) {
RemoveSema((char *)"do_inet");
}
}
call_work = 0;
for (i = 0; i < MAXTASKS; i++) {
if (calllist[i].addr.zone) {
if (!call_work) {
tasklog('c', "Slot Call Pid Try Status Mode Modem ISDN TCP/IP Address");
tasklog('c', "---- ----- ----- --- ------- ------- -------- -------- -------- ----------------");
}
call_work++;
tasklog('c', "%4d %s %5d %3d %s %s %08x %08x %08x %s", i, calllist[i].calling?"true ":"false", calllist[i].taskpid,
calllist[i].cst.tryno, callstatus(calllist[i].cst.trystat), callmode(calllist[i].callmode),
calllist[i].moflags, calllist[i].diflags, calllist[i].ipflags, ascfnode(calllist[i].addr, 0x1f));
}
}
return call_work;
}

26
mbtask/calllist.h Normal file
View File

@ -0,0 +1,26 @@
/* $Id$ */
#ifndef _CALLLIST_H
#define _CALLLIST_H
/*
* Callist
*/
typedef struct _tocall {
fidoaddr addr; /* Address to call */
int callmode; /* Method to use */
callstat cst; /* Last call status */
int calling; /* Is calling */
pid_t taskpid; /* Task pid number */
unsigned long moflags; /* Modem flags */
unsigned long diflags; /* ISDN flags */
unsigned long ipflags; /* TCP/IP flags */
} tocall;
int check_calllist(void);
#endif

View File

@ -38,32 +38,18 @@
#include "callstat.h"
#include "outstat.h"
#include "nodelist.h"
#include "ports.h"
#include "calllist.h"
#include "ping.h"
#include "mbtask.h"
/*
* Defines.
* SLOWRUN is number of seconds for scheduling mailer calls. Leave at 20!
*/
#define MAXTASKS 10
#define SLOWRUN 20
#define TMPNAME "TMP."
#define LCKNAME "LOCKTASK"
#define ICMP_BASEHDR_LEN 8
#define ICMP_MAX_ERRS 5
#define SET_SOCKA_LEN4(socka)
typedef enum {P_INIT, P_SENT, P_FAIL, P_OK, P_ERROR, P_NONE} PINGSTATE;
/*
* Global variables
*/
static onetask task[MAXTASKS]; /* Array with tasks */
static tocall calllist[MAXTASKS]; /* Array with calllist */
extern tocall calllist[MAXTASKS]; /* Array with calllist */
reg_info reginfo[MAXCLIENT]; /* Array with clients */
static pid_t pgrp; /* Pids group */
static char lockfile[PATH_MAX]; /* Lockfile */
@ -85,8 +71,7 @@ time_t tty_time; /* TTY config time */
char tcfgfn[PATH_MAX]; /* Config file name */
char cfgfn[PATH_MAX]; /* Config file name */
char ttyfn[PATH_MAX]; /* TTY file name */
int ping_isocket; /* Ping socket */
int icmp_errs = 0; /* ICMP error counter */
extern int ping_isocket; /* Ping socket */
int internet = FALSE; /* Internet is down */
double Load; /* System Load */
int Processing; /* Is system running */
@ -101,10 +86,7 @@ extern int s_newnews; /* New news semafore */
extern int s_reqindex; /* Create req index sem */
extern int s_msglink; /* Messages link sem */
extern int s_do_inet; /* Internet wanted */
int pingstate = P_INIT; /* Ping state */
int pingnr = 1; /* Ping #, 1 or 2 */
int pingresult[2]; /* Ping results */
char pingaddress[41]; /* Ping current address */
extern int pingresult[2]; /* Ping results */
int masterinit = FALSE; /* Master init needed */
int ptimer = PAUSETIME; /* Pause timer */
int tflags = FALSE; /* if nodes with Txx */
@ -466,103 +448,6 @@ void load_taskcfg(void)
/*
* Check the actual list of nodes to call.
*/
int check_calllist(void);
int check_calllist(void)
{
int i, found, call_work;
struct _alist *tmp;
/*
* Check callist, remove obsolete entries.
*/
for (i = 0; i < MAXTASKS; i++) {
if (calllist[i].addr.zone) {
found = FALSE;
for (tmp = alist; tmp; tmp = tmp->next) {
if ((calllist[i].addr.zone == tmp->addr.zone) && (calllist[i].addr.net == tmp->addr.net) &&
(calllist[i].addr.node == tmp->addr.node) && (calllist[i].addr.point == tmp->addr.point) &&
((tmp->flavors) & F_CALL)) {
found = TRUE;
}
}
if (!found) {
tasklog('c', "Removing slot %d node %s from calllist", i, ascfnode(calllist[i].addr, 0x0f));
memset(&calllist[i], 0, sizeof(tocall));
}
}
}
if (pots_calls || isdn_calls || inet_calls) {
call_work = 0;
for (tmp = alist; tmp; tmp = tmp->next) {
if (tmp->callmode != CM_NONE) {
call_work++;
found = FALSE;
for (i = 0; i < MAXTASKS; i++) {
if ((calllist[i].addr.zone == tmp->addr.zone) && (calllist[i].addr.net == tmp->addr.net) &&
(calllist[i].addr.node == tmp->addr.node) && (calllist[i].addr.point == tmp->addr.point)) {
found = TRUE;
/*
* Refresh last call status
*/
calllist[i].cst = tmp->cst;
}
}
if (!found) {
for (i = 0; i < MAXTASKS; i++) {
if (!calllist[i].addr.zone) {
tasklog('c', "Adding %s to calllist slot %d", ascfnode(tmp->addr, 0x1f), i);
calllist[i].addr = tmp->addr;
calllist[i].cst = tmp->cst;
calllist[i].callmode = tmp->callmode;
calllist[i].moflags = tmp->moflags;
calllist[i].diflags = tmp->diflags;
calllist[i].ipflags = tmp->ipflags;
break;
}
}
}
}
}
tasklog('o', "%d systems to call", call_work);
} else {
if (s_scanout)
sem_set((char *)"scanout", FALSE);
}
/*
* Check if we need to remove the do_inet semafore
*/
if (!inet_calls && internet && s_do_inet) {
tasklog('c', "Removing do_inet semafore");
s_do_inet = FALSE;
if (IsSema((char *)"do_inet")) {
RemoveSema((char *)"do_inet");
}
}
call_work = 0;
for (i = 0; i < MAXTASKS; i++) {
if (calllist[i].addr.zone) {
if (!call_work) {
tasklog('c', "Slot Call Pid Try Status Mode Modem ISDN TCP/IP Address");
tasklog('c', "---- ----- ----- --- ------- ------- -------- -------- -------- ----------------");
}
call_work++;
tasklog('c', "%4d %s %5d %3d %s %s %08x %08x %08x %s", i, calllist[i].calling?"true ":"false", calllist[i].taskpid,
calllist[i].cst.tryno, callstatus(calllist[i].cst.trystat), callmode(calllist[i].callmode),
calllist[i].moflags, calllist[i].diflags, calllist[i].ipflags, ascfnode(calllist[i].addr, 0x1f));
}
}
return call_work;
}
/*
* Launch an external program in the background.
* On success add it to the tasklist and return
@ -885,216 +770,6 @@ void ulocktask(void)
}
/* different names, same thing... be careful, as these are macros... */
#if defined(__FreeBSD__) || defined(__NetBSD__)
# define icmphdr icmp
# define iphdr ip
# define ip_saddr ip_src.s_addr
# define ip_daddr ip_dst.s_addr
#else
# define ip_saddr saddr
# define ip_daddr daddr
# define ip_hl ihl
# define ip_p protocol
#endif
#ifdef __linux__
# define icmp_type type
# define icmp_code code
# define icmp_cksum checksum
# ifdef icmp_id
# undef icmp_id
# endif
# define icmp_id un.echo.id
# ifdef icmp_seq
# undef icmp_seq
# endif
# define icmp_seq un.echo.sequence
#endif
#if defined(__FreeBSD__) || defined(__NetBSD__)
# define ICMP_DEST_UNREACH ICMP_UNREACH
# define ICMP_TIME_EXCEEDED ICMP_TIMXCEED
#endif
#define ICMP_BASEHDR_LEN 8
#define ICMP4_ECHO_LEN ICMP_BASEHDR_LEN
/*
* Takes a packet as send out and a recieved ICMP packet and looks whether the ICMP packet is
* an error reply on the sent-out one. packet is only the packet (without IP header).
* errmsg includes an IP header.
* to is the destination address of the original packet (the only thing that is actually
* compared of the IP header). The RFC sais that we get at least 8 bytes of the offending packet.
* We do not compare more, as this is all we need.
*/
static int icmp4_errcmp(char *packet, int plen, struct in_addr *to, char *errmsg, int elen, int errtype)
{
struct iphdr iph;
struct icmphdr icmph;
struct iphdr eiph;
char *data;
/* XXX: lots of memcpy to avoid unaligned accesses on alpha */
if (elen < sizeof(struct iphdr))
return 0;
memcpy(&iph, errmsg, sizeof(iph));
if (iph.ip_p != IPPROTO_ICMP || elen < iph.ip_hl * 4 + ICMP_BASEHDR_LEN + sizeof(eiph))
return 0;
memcpy(&icmph, errmsg + iph.ip_hl * 4, ICMP_BASEHDR_LEN);
memcpy(&eiph, errmsg + iph.ip_hl * 4 + ICMP_BASEHDR_LEN, sizeof(eiph));
if (elen < iph.ip_hl * 4 + ICMP_BASEHDR_LEN + eiph.ip_hl * 4 + 8)
return 0;
data = errmsg + iph.ip_hl * 4 + ICMP_BASEHDR_LEN + eiph.ip_hl * 4;
return icmph.icmp_type == errtype && memcmp(&to->s_addr, &eiph.ip_daddr, sizeof(to->s_addr)) == 0 &&
memcmp(data, packet, plen < 8 ?plen:8) == 0;
}
unsigned short get_rand16(void)
{
return random()&0xffff;
}
short p_sequence = 0;
unsigned short id;
struct icmphdr icmpd;
struct sockaddr_in to;
/*
* IPv4/ICMPv4 ping. Called from ping (see below)
*/
int ping_send(struct in_addr addr)
{
int len;
int isock;
#ifdef __linux__
struct icmp_filter f;
#else
struct protoent *pe;
int SOL_IP;
#endif
unsigned long sum;
unsigned short *ptr;
#ifndef __linux__
if (!(pe = getprotobyname("ip"))) {
tasklog('?', "icmp ping: getprotobyname() failed: %s", strerror(errno));
return -1;
}
SOL_IP = pe->p_proto;
#endif
isock = ping_isocket;
p_sequence = 1;
id = (unsigned short)get_rand16(); /* randomize a ping id */
#ifdef __linux__
/* Fancy ICMP filering -- only on Linux (as far is I know) */
/* In fact, there should be macros for treating icmp_filter, but I haven't found them in Linux 2.2.15.
* So, set it manually and unportable ;-) */
/* This filter lets ECHO_REPLY (0), DEST_UNREACH(3) and TIME_EXCEEDED(11) pass. */
/* !(0000 1000 0000 1001) = 0xff ff f7 f6 */
f.data=0xfffff7f6;
if (setsockopt(isock, SOL_RAW, ICMP_FILTER, &f, sizeof(f)) == -1) {
if (icmp_errs < ICMP_MAX_ERRS)
tasklog('?', "$icmp ping: setsockopt() failed %d", isock);
return -1;
}
#endif
icmpd.icmp_type = ICMP_ECHO;
icmpd.icmp_code = 0;
icmpd.icmp_cksum = 0;
icmpd.icmp_id = htons((short)id);
icmpd.icmp_seq = htons(p_sequence);
/* Checksumming - Algorithm taken from nmap. Thanks... */
ptr = (unsigned short *)&icmpd;
sum = 0;
for (len = 0; len < 4; len++) {
sum += *ptr++;
}
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
icmpd.icmp_cksum = ~sum;
memset(&to, 0, sizeof(to));
to.sin_family = AF_INET;
to.sin_port = 0;
to.sin_addr = addr;
SET_SOCKA_LEN4(to);
if (sendto(isock, &icmpd, ICMP4_ECHO_LEN, 0, (struct sockaddr *)&to, sizeof(to)) == -1) {
return -2;
}
return 0;
}
int ping_receive(struct in_addr addr)
{
char buf[1024];
int isock;
int len;
struct sockaddr_in ffrom;
struct icmphdr icmpp;
struct iphdr iph;
socklen_t sl;
struct pollfd pfd;
isock = ping_isocket;
pfd.fd = isock;
pfd.events = POLLIN;
/*
* 10 mSec is enough, this function is called at regular intervals.
*/
if (poll(&pfd, 1, 10) < 0) {
if (icmp_errs < ICMP_MAX_ERRS)
tasklog('?', "$poll/select failed");
return -3;
}
if (pfd.revents & POLLIN || pfd.revents & POLLERR || pfd.revents & POLLHUP || pfd.revents & POLLNVAL) {
sl = sizeof(ffrom);
if ((len = recvfrom(isock, &buf, sizeof(buf), 0,(struct sockaddr *)&ffrom, &sl)) != -1) {
if (len > sizeof(struct iphdr)) {
memcpy(&iph, buf, sizeof(iph));
if (len - iph.ip_hl * 4 >= ICMP_BASEHDR_LEN) {
memcpy(&icmpp, ((unsigned long int *)buf)+iph.ip_hl, sizeof(icmpp));
if (iph.ip_saddr == addr.s_addr &&
icmpp.icmp_type == ICMP_ECHOREPLY &&
ntohs(icmpp.icmp_id) == id &&
ntohs(icmpp.icmp_seq) <= p_sequence) {
return 0;
} else {
/* No regular echo reply. Maybe an error? */
if (icmp4_errcmp((char *)&icmpd, ICMP4_ECHO_LEN,
&to.sin_addr, buf, len, ICMP_DEST_UNREACH) ||
icmp4_errcmp((char *)&icmpd, ICMP4_ECHO_LEN,
&to.sin_addr, buf, len, ICMP_TIME_EXCEEDED)) {
return -4;
}
}
}
}
} else {
return -5; /* error */
}
}
return -6; /* no answer */
}
/*
* External Semafore Checks
@ -1169,7 +844,6 @@ void scheduler(void)
FILE *fp;
#endif
struct pollfd pfd;
struct in_addr paddr;
int call_work;
static int call_entry = MAXTASKS;
double loadavg[3];
@ -1271,7 +945,7 @@ void scheduler(void)
check_sema();
/*
* Check the systems load average. FIXME: doesn't work in FreeBSD !!!
* Check the systems load average.
*/
Load = loadavg[0] = loadavg[1] = loadavg[2] = 0.0;
#if defined(__FreeBSD__) || defined(__NetBSD__)
@ -1345,6 +1019,7 @@ void scheduler(void)
if (file_time(ttyfn) != tty_time) {
tasklog('+', "Ports configuration changed, reloading");
load_ports();
check_ports();
sem_set((char *)"scanout", TRUE);
}
@ -1440,69 +1115,7 @@ void scheduler(void)
*/
oldmin = tm->tm_sec / SLOWRUN;
/*
* If the previous pingstat is still P_SENT, then we now consider it a timeout.
*/
if (pingstate == P_SENT) {
pingresult[pingnr] = FALSE;
icmp_errs++;
if (icmp_errs < ICMP_MAX_ERRS)
tasklog('p', "ping %s seq=%d timeout", pingaddress, p_sequence);
}
/*
* Check internet connection with ICMP ping
*/
rc = 0;
if (pingnr == 1) {
pingnr = 2;
if (strlen(TCFG.isp_ping2)) {
sprintf(pingaddress, "%s", TCFG.isp_ping2);
} else {
pingstate = P_NONE;
}
} else {
pingnr = 1;
if (strlen(TCFG.isp_ping1)) {
sprintf(pingaddress, "%s", TCFG.isp_ping1);
} else {
pingstate = P_NONE;
}
}
if (inet_aton(pingaddress, &paddr)) {
rc = ping_send(paddr);
if (rc) {
if (icmp_errs++ < ICMP_MAX_ERRS)
tasklog('?', "ping send %s rc=%d", pingaddress, rc);
pingstate = P_FAIL;
pingresult[pingnr] = FALSE;
} else {
pingstate = P_SENT;
}
} else {
if (icmp_errs++ < ICMP_MAX_ERRS)
tasklog('?', "Ping address %d is invalid \"%s\"", pingnr, pingaddress);
pingstate = P_NONE;
}
if (pingresult[1] == FALSE && pingresult[2] == FALSE) {
icmp_errs++;
if (internet) {
tasklog('!', "Internet connection is down");
internet = FALSE;
sem_set((char *)"scanout", TRUE);
RemoveSema((char *)"is_inet");
}
} else {
if (!internet) {
tasklog('!', "Internet connection is up");
internet = TRUE;
sem_set((char *)"scanout", TRUE);
CreateSema((char *)"is_inet");
}
icmp_errs = 0;
}
check_ping();
/*
* Update outbound status if needed.
@ -1580,19 +1193,7 @@ void scheduler(void)
/*
* PING state changes
*/
switch (pingstate) {
case P_NONE: pingresult[pingnr] = TRUE;
break;
case P_SENT: rc = ping_receive(paddr);
if (!rc) {
pingstate = P_OK;
pingresult[pingnr] = TRUE;
} else {
if (rc != -6)
tasklog('p', "ping recv %s id=%d rc=%d", pingaddress, id, rc);
}
break;
}
state_ping();
} else {
if (Processing) {
@ -1679,6 +1280,7 @@ int main(int argc, char **argv)
sprintf(ttyfn, "%s/etc/ttyinfo.data", getenv("MBSE_ROOT"));
load_ports();
check_ports();
/*
* Now that init is complete and this program is locked, it is

View File

@ -1,6 +1,16 @@
/* $Id */
#ifndef _MBTASK_H
#define _MBTASK_H
/*
* Defines.
* SLOWRUN is number of seconds for scheduling mailer calls. Leave at 20!
*/
#define MAXTASKS 10
#define SLOWRUN 20
#define TMPNAME "TMP."
#define LCKNAME "LOCKTASK"
/*
@ -19,22 +29,6 @@ typedef struct _onetask {
/*
* Callist
*/
typedef struct _tocall {
fidoaddr addr; /* Address to call */
int callmode; /* Method to use */
callstat cst; /* Last call status */
int calling; /* Is calling */
pid_t taskpid; /* Task pid number */
unsigned long moflags; /* Modem flags */
unsigned long diflags; /* ISDN flags */
unsigned long ipflags; /* TCP/IP flags */
} tocall;
/*
* Logging flagbits, ' ' ? ! + -
*/
@ -53,10 +47,6 @@ pid_t launch(char *, char *, char *, int);
int runtasktype(int);
int checktasks(int);
void die(int);
static int icmp4_errcmp(char *, int, struct in_addr *, char *, int, int);
unsigned short get_rand16(void);
int ping_send(struct in_addr);
int ping_receive(struct in_addr);
void scheduler(void);
int locktask(char *);
void ulocktask(void);

View File

@ -35,6 +35,7 @@
#include "scanout.h"
#include "nodelist.h"
#include "callstat.h"
#include "ports.h"
#include "outstat.h"
@ -42,13 +43,11 @@ extern int do_quiet;
extern int internet; /* Internet status */
extern struct sysconfig CFG; /* Main configuration */
extern struct taskrec TCFG; /* Task configuration */
extern char ttyfn[]; /* TTY file name */
extern time_t tty_time; /* TTY update time */
int nxt_hour, nxt_min; /* Time of next event */
int inet_calls; /* Internet calls to make */
int isdn_calls; /* ISDN calls to make */
int pots_calls; /* POTS calls to make */
pp_list *pl = NULL; /* Portlist */
extern pp_list *pl; /* Portlist */
_alist_l *alist = NULL; /* Nodes to call list */
extern int s_do_inet; /* Internet wanted */
@ -383,7 +382,7 @@ int outstat()
*/
if ((tmp->callmode == CM_NONE) && TCFG.max_isdn) {
/*
* Dialup node, check available dialout ports
* ISDN node, check available dialout ports
*/
for (tpl = pl; tpl; tpl = tpl->next) {
if (tpl->dflags & tmp->diflags) {
@ -394,6 +393,9 @@ int outstat()
}
}
if ((tmp->callmode == CM_NONE) && TCFG.max_pots) {
/*
* POTS node, check available modems
*/
for (tpl = pl; tpl; tpl = tpl->next) {
if (tpl->mflags & tmp->moflags) {
pots_calls++;
@ -563,99 +565,3 @@ int each(faddr *addr, char flavor, int isflo, char *fname)
}
/*
* Tidy the portlist
*/
void tidy_portlist(pp_list **);
void tidy_portlist(pp_list ** fdp)
{
pp_list *tmp, *old;
tasklog('p', "tidy_portlist");
for (tmp = *fdp; tmp; tmp = old) {
old = tmp->next;
free(tmp);
}
*fdp = NULL;
}
/*
* Add a port to the portlist
*/
void fill_portlist(pp_list **, pp_list *);
void fill_portlist(pp_list **fdp, pp_list *new)
{
pp_list *tmp, *ta;
tmp = (pp_list *)malloc(sizeof(pp_list));
tmp->next = NULL;
strncpy(tmp->tty, new->tty, 6);
tmp->mflags = new->mflags;
tmp->dflags = new->dflags;
if (*fdp == NULL) {
*fdp = tmp;
} else {
for (ta = *fdp; ta; ta = ta->next)
if (ta->next == NULL) {
ta->next = (pp_list *)tmp;
break;
}
}
}
/*
* Build a list of available dialout ports.
*/
void load_ports()
{
FILE *fp;
pp_list new;
int count = 0, j, stdflag;
char *p, *q;
tidy_portlist(&pl);
if ((fp = fopen(ttyfn, "r")) == NULL) {
tasklog('?', "$Can't open %s", ttyfn);
return;
}
fread(&ttyinfohdr, sizeof(ttyinfohdr), 1, fp);
tasklog('p', "Building portlist...");
while (fread(&ttyinfo, ttyinfohdr.recsize, 1, fp) == 1) {
if (((ttyinfo.type == POTS) || (ttyinfo.type == ISDN)) && (ttyinfo.available) && (ttyinfo.callout)) {
memset(&new, 0, sizeof(new));
strncpy(new.tty, ttyinfo.tty, 6);
stdflag = TRUE;
q = xstrcpy(ttyinfo.flags);
for (p = q; p; p = q) {
if ((q = strchr(p, ',')))
*q++ = '\0';
if ((strncasecmp(p, "U", 1) == 0) && (strlen(p) == 1)) {
stdflag = FALSE;
} else {
for (j = 0; fkey[j].key; j++)
if (strcasecmp(p, fkey[j].key) == 0)
new.mflags |= fkey[j].flag;
for (j = 0; dkey[j].key; j++)
if (strcasecmp(p, dkey[j].key) == 0)
new.dflags |= dkey[j].flag;
}
}
tasklog('p', "port %s modem %08lx ISDN %08lx", new.tty, new.mflags, new.dflags);
fill_portlist(&pl, &new);
count++;
}
}
fclose(fp);
tty_time = file_time(ttyfn);
tasklog('p', "make_portlist %d ports", count);
}

View File

@ -31,17 +31,6 @@ typedef struct _alist
} _alist_l;
/*
* Linked list of available dialout ports.
*/
typedef struct _pp_list {
struct _pp_list *next;
char tty[7]; /* tty name of the port */
unsigned long mflags; /* Analogue modem flags */
unsigned long dflags; /* ISDN flags */
int locked; /* If port is locked */
} pp_list;
/*
* Bitmasks for calling status
@ -58,15 +47,9 @@ typedef struct _pp_list {
struct _ttyinfohdr ttyinfohdr; /* TTY lines */
struct _ttyinfo ttyinfo;
int each(faddr *, char, int, char *);
char *callstatus(int);
char *callmode(int);
int outstat(void);
void load_ports(void);
#endif

370
mbtask/ping.c Normal file
View File

@ -0,0 +1,370 @@
/*****************************************************************************
*
* $Id$
* Purpose ...............: mbtask - ping functions
*
*****************************************************************************
* Copyright (C) 1997-2002
*
* Michiel Broek FIDO: 2:280/2802
* Beekmansbos 10
* 1971 BV IJmuiden
* the Netherlands
*
* This file is part of MBSE BBS.
*
* This BBS is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* MBSE BBS is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MBSE BBS; see the file COPYING. If not, write to the Free
* Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*****************************************************************************/
#include "libs.h"
#include "../lib/structs.h"
#include "taskstat.h"
#include "taskutil.h"
#include "ping.h"
/*
* Global variables
*/
extern struct taskrec TCFG; /* Task config record */
int ping_isocket; /* Ping socket */
int icmp_errs = 0; /* ICMP error counter */
extern int internet; /* Internet is down */
int pingstate = P_INIT; /* Ping state */
int pingnr = 1; /* Ping #, 1 or 2 */
int pingresult[2]; /* Ping results */
char pingaddress[41]; /* Ping current address */
struct in_addr paddr; /* Current ping address */
static int icmp4_errcmp(char *, int, struct in_addr *, char *, int, int);
unsigned short get_rand16(void);
int ping_send(struct in_addr);
int ping_receive(struct in_addr);
/*
* different names, same thing... be careful, as these are macros...
*/
#if defined(__FreeBSD__) || defined(__NetBSD__)
# define icmphdr icmp
# define iphdr ip
# define ip_saddr ip_src.s_addr
# define ip_daddr ip_dst.s_addr
#else
# define ip_saddr saddr
# define ip_daddr daddr
# define ip_hl ihl
# define ip_p protocol
#endif
#ifdef __linux__
# define icmp_type type
# define icmp_code code
# define icmp_cksum checksum
# ifdef icmp_id
# undef icmp_id
# endif
# define icmp_id un.echo.id
# ifdef icmp_seq
# undef icmp_seq
# endif
# define icmp_seq un.echo.sequence
#endif
#if defined(__FreeBSD__) || defined(__NetBSD__)
# define ICMP_DEST_UNREACH ICMP_UNREACH
# define ICMP_TIME_EXCEEDED ICMP_TIMXCEED
#endif
#define ICMP_BASEHDR_LEN 8
#define ICMP4_ECHO_LEN ICMP_BASEHDR_LEN
/*
* Takes a packet as send out and a recieved ICMP packet and looks whether the ICMP packet is
* an error reply on the sent-out one. packet is only the packet (without IP header).
* errmsg includes an IP header.
* to is the destination address of the original packet (the only thing that is actually
* compared of the IP header). The RFC sais that we get at least 8 bytes of the offending packet.
* We do not compare more, as this is all we need.
*/
static int icmp4_errcmp(char *packet, int plen, struct in_addr *to, char *errmsg, int elen, int errtype)
{
struct iphdr iph;
struct icmphdr icmph;
struct iphdr eiph;
char *data;
/* XXX: lots of memcpy to avoid unaligned accesses on alpha */
if (elen < sizeof(struct iphdr))
return 0;
memcpy(&iph, errmsg, sizeof(iph));
if (iph.ip_p != IPPROTO_ICMP || elen < iph.ip_hl * 4 + ICMP_BASEHDR_LEN + sizeof(eiph))
return 0;
memcpy(&icmph, errmsg + iph.ip_hl * 4, ICMP_BASEHDR_LEN);
memcpy(&eiph, errmsg + iph.ip_hl * 4 + ICMP_BASEHDR_LEN, sizeof(eiph));
if (elen < iph.ip_hl * 4 + ICMP_BASEHDR_LEN + eiph.ip_hl * 4 + 8)
return 0;
data = errmsg + iph.ip_hl * 4 + ICMP_BASEHDR_LEN + eiph.ip_hl * 4;
return icmph.icmp_type == errtype && memcmp(&to->s_addr, &eiph.ip_daddr, sizeof(to->s_addr)) == 0 &&
memcmp(data, packet, plen < 8 ?plen:8) == 0;
}
unsigned short get_rand16(void)
{
return random()&0xffff;
}
short p_sequence = 0;
unsigned short id;
struct icmphdr icmpd;
struct sockaddr_in to;
/*
* IPv4/ICMPv4 ping. Called from ping (see below)
*/
int ping_send(struct in_addr addr)
{
int len;
int isock;
#ifdef __linux__
struct icmp_filter f;
#else
struct protoent *pe;
int SOL_IP;
#endif
unsigned long sum;
unsigned short *ptr;
#ifndef __linux__
if (!(pe = getprotobyname("ip"))) {
tasklog('?', "icmp ping: getprotobyname() failed: %s", strerror(errno));
return -1;
}
SOL_IP = pe->p_proto;
#endif
isock = ping_isocket;
p_sequence = 1;
id = (unsigned short)get_rand16(); /* randomize a ping id */
#ifdef __linux__
/* Fancy ICMP filering -- only on Linux (as far is I know) */
/* In fact, there should be macros for treating icmp_filter, but I haven't found them in Linux 2.2.15.
* So, set it manually and unportable ;-) */
/* This filter lets ECHO_REPLY (0), DEST_UNREACH(3) and TIME_EXCEEDED(11) pass. */
/* !(0000 1000 0000 1001) = 0xff ff f7 f6 */
f.data=0xfffff7f6;
if (setsockopt(isock, SOL_RAW, ICMP_FILTER, &f, sizeof(f)) == -1) {
if (icmp_errs < ICMP_MAX_ERRS)
tasklog('?', "$icmp ping: setsockopt() failed %d", isock);
return -1;
}
#endif
icmpd.icmp_type = ICMP_ECHO;
icmpd.icmp_code = 0;
icmpd.icmp_cksum = 0;
icmpd.icmp_id = htons((short)id);
icmpd.icmp_seq = htons(p_sequence);
/* Checksumming - Algorithm taken from nmap. Thanks... */
ptr = (unsigned short *)&icmpd;
sum = 0;
for (len = 0; len < 4; len++) {
sum += *ptr++;
}
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
icmpd.icmp_cksum = ~sum;
memset(&to, 0, sizeof(to));
to.sin_family = AF_INET;
to.sin_port = 0;
to.sin_addr = addr;
SET_SOCKA_LEN4(to);
if (sendto(isock, &icmpd, ICMP4_ECHO_LEN, 0, (struct sockaddr *)&to, sizeof(to)) == -1) {
return -2;
}
return 0;
}
int ping_receive(struct in_addr addr)
{
char buf[1024];
int isock;
int len;
struct sockaddr_in ffrom;
struct icmphdr icmpp;
struct iphdr iph;
socklen_t sl;
struct pollfd pfd;
isock = ping_isocket;
pfd.fd = isock;
pfd.events = POLLIN;
/*
* 10 mSec is enough, this function is called at regular intervals.
*/
if (poll(&pfd, 1, 10) < 0) {
if (icmp_errs < ICMP_MAX_ERRS)
tasklog('?', "$poll/select failed");
return -3;
}
if (pfd.revents & POLLIN || pfd.revents & POLLERR || pfd.revents & POLLHUP || pfd.revents & POLLNVAL) {
sl = sizeof(ffrom);
if ((len = recvfrom(isock, &buf, sizeof(buf), 0,(struct sockaddr *)&ffrom, &sl)) != -1) {
if (len > sizeof(struct iphdr)) {
memcpy(&iph, buf, sizeof(iph));
if (len - iph.ip_hl * 4 >= ICMP_BASEHDR_LEN) {
memcpy(&icmpp, ((unsigned long int *)buf)+iph.ip_hl, sizeof(icmpp));
if (iph.ip_saddr == addr.s_addr &&
icmpp.icmp_type == ICMP_ECHOREPLY &&
ntohs(icmpp.icmp_id) == id &&
ntohs(icmpp.icmp_seq) <= p_sequence) {
return 0;
} else {
/* No regular echo reply. Maybe an error? */
if (icmp4_errcmp((char *)&icmpd, ICMP4_ECHO_LEN,
&to.sin_addr, buf, len, ICMP_DEST_UNREACH) ||
icmp4_errcmp((char *)&icmpd, ICMP4_ECHO_LEN,
&to.sin_addr, buf, len, ICMP_TIME_EXCEEDED)) {
return -4;
}
}
}
}
} else {
return -5; /* error */
}
}
return -6; /* no answer */
}
void check_ping(void)
{
int rc;
/*
* If the previous pingstat is still P_SENT, then we now consider it a timeout.
*/
if (pingstate == P_SENT) {
pingresult[pingnr] = FALSE;
icmp_errs++;
if (icmp_errs < ICMP_MAX_ERRS)
tasklog('p', "ping %s seq=%d timeout", pingaddress, p_sequence);
}
/*
* Check internet connection with ICMP ping
*/
rc = 0;
if (pingnr == 1) {
pingnr = 2;
if (strlen(TCFG.isp_ping2)) {
sprintf(pingaddress, "%s", TCFG.isp_ping2);
} else {
pingstate = P_NONE;
}
} else {
pingnr = 1;
if (strlen(TCFG.isp_ping1)) {
sprintf(pingaddress, "%s", TCFG.isp_ping1);
} else {
pingstate = P_NONE;
}
}
if (inet_aton(pingaddress, &paddr)) {
rc = ping_send(paddr);
if (rc) {
if (icmp_errs++ < ICMP_MAX_ERRS)
tasklog('?', "ping send %s rc=%d", pingaddress, rc);
pingstate = P_FAIL;
pingresult[pingnr] = FALSE;
} else {
pingstate = P_SENT;
}
} else {
if (icmp_errs++ < ICMP_MAX_ERRS)
tasklog('?', "Ping address %d is invalid \"%s\"", pingnr, pingaddress);
pingstate = P_NONE;
}
if (pingresult[1] == FALSE && pingresult[2] == FALSE) {
icmp_errs++;
if (internet) {
tasklog('!', "Internet connection is down");
internet = FALSE;
sem_set((char *)"scanout", TRUE);
RemoveSema((char *)"is_inet");
}
} else {
if (!internet) {
tasklog('!', "Internet connection is up");
internet = TRUE;
sem_set((char *)"scanout", TRUE);
CreateSema((char *)"is_inet");
}
icmp_errs = 0;
}
}
void state_ping(void)
{
int rc;
/*
* PING state changes
*/
switch (pingstate) {
case P_NONE: pingresult[pingnr] = TRUE;
break;
case P_SENT: rc = ping_receive(paddr);
if (!rc) {
pingstate = P_OK;
pingresult[pingnr] = TRUE;
} else {
if (rc != -6)
tasklog('p', "ping recv %s id=%d rc=%d", pingaddress, id, rc);
}
break;
}
}

22
mbtask/ping.h Normal file
View File

@ -0,0 +1,22 @@
/* $Id */
#ifndef _PING_H
#define _PING_H
typedef enum {P_INIT, P_SENT, P_FAIL, P_OK, P_ERROR, P_NONE} PINGSTATE;
/*
* Defines.
*/
#define ICMP_BASEHDR_LEN 8
#define ICMP_MAX_ERRS 5
#define SET_SOCKA_LEN4(socka)
void check_ping(void);
void state_ping(void);
#endif

188
mbtask/ports.c Normal file
View File

@ -0,0 +1,188 @@
/*****************************************************************************
*
* $Id$
* Purpose ...............: mbtask - mode portlists
*
*****************************************************************************
* Copyright (C) 1997-2002
*
* Michiel Broek FIDO: 2:280/2802
* Beekmansbos 10
* 1971 BV IJmuiden
* the Netherlands
*
* This file is part of MBSE BBS.
*
* This BBS is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* MBSE BBS is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MBSE BBS; see the file COPYING. If not, write to the Free
* Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*****************************************************************************/
#include "libs.h"
#include "../lib/structs.h"
#include "taskutil.h"
#include "nodelist.h"
#include "ports.h"
#ifndef LOCKDIR
#if defined(__FreeBSD__) || defined(__NetBSD__)
#define LOCKDIR "/var/spool/lock"
#else
#define LOCKDIR "/var/lock"
#endif
#endif
#define LCKPREFIX LOCKDIR"/LCK.."
#define LCKTMP LOCKDIR"/TMP."
extern char ttyfn[]; /* TTY file name */
extern time_t tty_time; /* TTY update time */
pp_list *pl = NULL; /* Portlist */
/*
* Tidy the portlist
*/
void tidy_portlist(pp_list **);
void tidy_portlist(pp_list ** fdp)
{
pp_list *tmp, *old;
tasklog('p', "tidy_portlist");
for (tmp = *fdp; tmp; tmp = old) {
old = tmp->next;
free(tmp);
}
*fdp = NULL;
}
/*
* Add a port to the portlist
*/
void fill_portlist(pp_list **, pp_list *);
void fill_portlist(pp_list **fdp, pp_list *new)
{
pp_list *tmp, *ta;
tmp = (pp_list *)malloc(sizeof(pp_list));
tmp->next = NULL;
strncpy(tmp->tty, new->tty, 6);
tmp->mflags = new->mflags;
tmp->dflags = new->dflags;
if (*fdp == NULL) {
*fdp = tmp;
} else {
for (ta = *fdp; ta; ta = ta->next)
if (ta->next == NULL) {
ta->next = (pp_list *)tmp;
break;
}
}
}
/*
* Build a list of available dialout ports.
*/
void load_ports()
{
FILE *fp;
pp_list new;
int count = 0, j, stdflag;
char *p, *q;
tidy_portlist(&pl);
if ((fp = fopen(ttyfn, "r")) == NULL) {
tasklog('?', "$Can't open %s", ttyfn);
return;
}
fread(&ttyinfohdr, sizeof(ttyinfohdr), 1, fp);
tasklog('p', "Building portlist...");
while (fread(&ttyinfo, ttyinfohdr.recsize, 1, fp) == 1) {
if (((ttyinfo.type == POTS) || (ttyinfo.type == ISDN)) && (ttyinfo.available) && (ttyinfo.callout)) {
memset(&new, 0, sizeof(new));
strncpy(new.tty, ttyinfo.tty, 6);
stdflag = TRUE;
q = xstrcpy(ttyinfo.flags);
for (p = q; p; p = q) {
if ((q = strchr(p, ',')))
*q++ = '\0';
if ((strncasecmp(p, "U", 1) == 0) && (strlen(p) == 1)) {
stdflag = FALSE;
} else {
for (j = 0; fkey[j].key; j++)
if (strcasecmp(p, fkey[j].key) == 0)
new.mflags |= fkey[j].flag;
for (j = 0; dkey[j].key; j++)
if (strcasecmp(p, dkey[j].key) == 0)
new.dflags |= dkey[j].flag;
}
}
tasklog('p', "port %s modem %08lx ISDN %08lx", new.tty, new.mflags, new.dflags);
fill_portlist(&pl, &new);
count++;
}
}
fclose(fp);
tty_time = file_time(ttyfn);
tasklog('p', "make_portlist %d ports", count);
}
/*
* Check status of all modem/ISDN ports
*/
void check_ports(void)
{
pp_list *tpl;
char lckname[256];
FILE *lf;
int tmppid;
pid_t rempid = 0;
for (tpl = pl; tpl; tpl = tpl->next) {
sprintf(lckname, "%s%s", LCKPREFIX, tpl->tty);
// tasklog('p', "checking %s", lckname);
if ((lf = fopen(lckname, "r")) == NULL) {
if (tpl->locked) {
tpl->locked = 0;
tasklog('+', "Port %s is now free", tpl->tty);
}
} else {
fscanf(lf, "%d", &tmppid);
rempid = tmppid;
fclose(lf);
if (kill(rempid, 0) && (errno == ESRCH)) {
tasklog('+', "Stale lockfile for %s, unlink", tpl->tty);
unlink(lckname);
} else {
if (!tpl->locked) {
tpl->locked = rempid;
tasklog('+', "Port %s locked, pid %d", tpl->tty, rempid);
}
}
}
}
}

28
mbtask/ports.h Normal file
View File

@ -0,0 +1,28 @@
/* $Id$ */
#ifndef _PORTS_H
#define _PORTS_H
/*
* Linked list of available dialout ports.
*/
typedef struct _pp_list {
struct _pp_list *next;
char tty[7]; /* tty name of the port */
unsigned long mflags; /* Analogue modem flags */
unsigned long dflags; /* ISDN flags */
int locked; /* If port is locked */
} pp_list;
struct _ttyinfohdr ttyinfohdr; /* TTY lines */
struct _ttyinfo ttyinfo;
void load_ports(void); /* Initialize portlist */
void check_ports(void); /* Check status of all ports */
#endif