mars-nwe/nwserv.c

1015 lines
31 KiB
C

/* nwserv.c 22-Nov-95 */
/* (C)opyright (C) 1993,1995 Martin Stover, Marburg, Germany
*
* This program 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 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "net.h"
static int conn_gid=1;
static int conn_uid=1;
static int ncpserv_debug=0;
static int nwconn_debug=0;
#define MY_BROADCAST_SLOT 0 /* Server Broadcast OUT */
#define WDOG_SLOT 1 /* Watchdog send + recv */
#define SAP_SLOT 2
#define RIP_SLOT 3
#define ROUTE_SLOT 4
#define DIAG_SLOT 5
#if 0
#define ECHO_SLOT 6
#define ERR_SLOT 7
#endif
uint16 ipx_sock_nummern[]={ 0, /* auto sock */
0, /* auto sock */
SOCK_SAP,
SOCK_RIP,
SOCK_ROUTE,
SOCK_DIAGNOSE
#if 0
,
SOCK_ECHO,
SOCK_ERROR,
#endif
};
#define NEEDED_SOCKETS (sizeof(ipx_sock_nummern) / sizeof(uint16))
#define NEEDED_POLLS (NEEDED_SOCKETS+1)
static uint16 sock_nummern [NEEDED_SOCKETS];
static int sockfd [NEEDED_SOCKETS];
static struct pollfd polls[NEEDED_POLLS];
static ipxAddr_t my_server_adr; /* Address of this server */
static uint16 spx_diag_socket; /* SPX DIAGNOSE SOCKET */
static ipxAddr_t nw386_adr; /* Address of NW-TEST Server */
static int nw386_found = 0;
static int client_mode = 0;
static uint32 network = 0x0L;
static uint32 internal_net = 0x0L;
static char my_nwname[50];
static int ipxdebug = 0;
static int pid_ncpserv = -1;
static int fd_ncpserv_out = -1; /* ctrl-pipe out to ncpserv */
static int fd_ncpserv_in = -1; /* ctrl-pipe in from ncpserv */
#ifndef LINUX
static int frame=0;
#else
static int frame=IPX_FRAME_8023;
static char devname[40];
#endif
static time_t akttime_stamp;
static int bytes_to_write_to_ncpserv=0;
static void inform_ncpserv(void)
{
if (bytes_to_write_to_ncpserv) {
kill(pid_ncpserv, SIGHUP); /* tell ncpserv to read input */
bytes_to_write_to_ncpserv=0;
}
}
static void write_to_ncpserv(int what, int connection,
char *data, int data_size)
{
switch (what) {
case 0x5555 : /* kill connection */
bytes_to_write_to_ncpserv +=
write(fd_ncpserv_out, (char*) &what, sizeof(int));
bytes_to_write_to_ncpserv +=
write(fd_ncpserv_out, (char*) &connection, sizeof(int));
break;
case 0x3333 : /* 'bindery' calls */
bytes_to_write_to_ncpserv +=
write(fd_ncpserv_out, (char*) &what, sizeof(int));
bytes_to_write_to_ncpserv +=
write(fd_ncpserv_out, (char*) &data_size, sizeof(int));
bytes_to_write_to_ncpserv +=
write(fd_ncpserv_out, data, data_size);
break;
default : break;
}
if (bytes_to_write_to_ncpserv > 255) inform_ncpserv();
}
static void ins_del_bind_net_addr(char *name, ipxAddr_t *adr)
{
uint8 buf[1024];
uint8 *p = buf;
int len = 0;
if (NULL != adr) { /* insert */
*p=0x01;
p+=2; len+=2;
U16_TO_BE16(0x4, p);
p+=2; len+=2;
*p = strlen(name);
strmaxcpy(p+1, name, *p);
len += (*p+1); p+=(*p + 1);
memcpy(p, adr, sizeof(ipxAddr_t));
len+=sizeof(ipxAddr_t);
} else { /* delete */
*p=0x02;
p+=2; len+=2;
U16_TO_BE16(0x4, p);
p+=2; len+=2;
*p = strlen(name);
strmaxcpy(p+1, name, *p);
len += (*p+1); p+=(*p + 1);
}
write_to_ncpserv(0x3333, 0, buf, len);
}
static int open_ipx_socket(uint16 sock_nr, int nr, int open_mode)
{
int ipx_fd=t_open("/dev/ipx", open_mode, NULL);
struct t_bind bind;
if (ipx_fd < 0) {
t_error("t_open !Ok");
return(-1);
}
U16_TO_BE16(sock_nr, my_server_adr.sock); /* actual read socket */
bind.addr.len = sizeof(ipxAddr_t);
bind.addr.maxlen = sizeof(ipxAddr_t);
bind.addr.buf = (char*)&my_server_adr;
bind.qlen = 0; /* immer */
if (t_bind(ipx_fd, &bind, &bind) < 0){
char sxx[200];
sprintf(sxx,"NWSERV:t_bind !OK in open_ipx_socket, sock=%d", sock_nr);
t_error(sxx);
t_close(ipx_fd);
return(-1);
}
sock_nummern[nr] = GET_BE16(my_server_adr.sock); /* really socket nmbr */
if (nw_debug) print_ipx_addr(&my_server_adr);
return(ipx_fd);
}
static int start_ncpserv(char *nwname, ipxAddr_t *addr)
{
int fds_out[2];
int fds_in[2];
int pid;
if (pipe(fds_out) < 0 || pipe(fds_in) < 0) return(-1);
switch (pid=fork()) {
case 0 : { /* new Process */
char *progname="ncpserv";
char addrstr[100];
char pathname[300];
char gidstr[10];
char uidstr[10];
char debug1[5];
char debug2[5];
char debug3[5];
int j = FD_NWSERV;
close(fds_out[1]); /* no need to write */
dup2(fds_out[0], 0); /* becommes stdin */
close(fds_out[0]); /* no longer needed */
close(fds_in[0]); /* no need to read */
dup2(fds_in[1], FD_NWSERV); /* becommes fd FD_NWSERV */
close(fds_in[1]); /* no longer needed */
while (j++ < 100) close(j); /* close all > 4 */
ipx_addr_to_adr(addrstr, addr);
sprintf(gidstr, "%d", conn_gid);
sprintf(uidstr, "%d", conn_uid);
sprintf(debug1, "%d", ncpserv_debug);
sprintf(debug2, "%d", nwconn_debug);
sprintf(debug3, "%d", ipxdebug);
execl(get_exec_path(pathname, progname), progname,
nwname, addrstr,
gidstr, uidstr,
debug1, debug2, debug3, NULL);
exit(1);
}
break;
case -1: close(fds_out[0]);
close(fds_out[1]);
close(fds_in[0]);
close(fds_in[1]);
return(-1); /* error */
}
fds_out[0] = -1;
fd_ncpserv_out = fds_out[1];
fds_in[1] = -1;
fd_ncpserv_in = fds_in[0];
pid_ncpserv = pid;
return(0); /* OK */
}
static int start_nwclient(void)
{
switch (fork()){
case 0 : { /* new Process */
char *progname="nwclient";
char pathname[300];
char my_addrstr[100];
char serv_addrstr[100];
ipx_addr_to_adr(my_addrstr, &my_server_adr);
ipx_addr_to_adr(serv_addrstr, &nw386_adr);
execl(get_exec_path(pathname, progname), progname,
my_addrstr, serv_addrstr, NULL);
}
exit(1);
case -1: return(-1); /* error */
}
return(0); /* OK */
}
/* =========================== WDOG =============================== */
static void send_wdog_packet(ipxAddr_t *addr, int conn, int what)
{
uint8 data[2];
data[0] = (uint8) conn;
data[1] = (uint8) what;
send_ipx_data(sockfd[WDOG_SLOT], 17, 2, data, addr, "WDOG");
}
static void send_bcast_packet(ipxAddr_t *addr, int conn, int signature)
{
uint8 data[2];
data[0] = (uint8) conn;
data[1] = (uint8) signature;
/* signatures
* '!' = broadcast waiting inform
* '@' = sft_iii server change over inform.
*/
send_ipx_data(sockfd[WDOG_SLOT], 17, 2, data, addr, "BCAST");
}
typedef struct {
ipxAddr_t addr; /* address of client */
time_t last_time; /* last wdog packet sent */
int counter; /* max. 11 packets */
} CONN;
static CONN conns[MAX_CONNECTIONS];
static int hi_conn=0;
static void insert_wdog_conn(int conn, ipxAddr_t *adr)
{
if (conn > 0 && conn <= MAX_CONNECTIONS) {
CONN *c;
while (hi_conn < conn) {
c=&(conns[hi_conn++]);
memset(c, 0, sizeof(CONN));
}
c=&(conns[--conn]);
c->last_time = akttime_stamp;
c->counter = 0;
if (NULL != adr) memcpy(&(c->addr), adr, sizeof(ipxAddr_t));
}
}
static void reset_wdog_conn(int conn)
{
if (conn > 0 && --conn < hi_conn) {
CONN *c=&(conns[conn]);
c->last_time = akttime_stamp;
c->counter = 0;
}
}
static void remove_wdog_conn(int conn)
{
if (conn > 0 && --conn < hi_conn) {
CONN *c=&(conns[conn]);
memset(c, 0, sizeof(CONN));
if (conn + 1 == hi_conn) {
while (hi_conn) {
CONN *c=&(conns[hi_conn-1]);
if (!c->last_time) hi_conn--;
else break;
}
}
}
}
#ifdef _WDOG_TESTING_
/* for testing */
# define WDOG_TRIE_AFTER_SEC 1
# define MAX_WDOG_TRIES 1
#else
# define WDOG_TRIE_AFTER_SEC 300 /* ca. 5 min. */
# define MAX_WDOG_TRIES 11 /* Standardtries */
#endif
static void send_wdogs(void)
{
int k = hi_conn;
while (k--) {
CONN *c = &(conns[k]);
if (c->last_time) {
time_t t_diff = akttime_stamp - c->last_time;
if (c->counter || t_diff > WDOG_TRIE_AFTER_SEC) { /* max. 5 minutes */
if (c->counter > MAX_WDOG_TRIES) {
/* now its enough with trying */
/* clear connection */
write_to_ncpserv(0x5555, k+1, NULL, 0);
} else {
ipxAddr_t adr;
c->last_time = akttime_stamp;
memcpy(&adr, &(c->addr), sizeof(ipxAddr_t));
U16_TO_BE16(GET_BE16(adr.sock)+1, adr.sock);
send_wdog_packet(&adr, k+1, '?');
}
c->counter++;
}
}
}
}
static void send_bcasts(int conn)
{
if (conn > 0 && --conn < hi_conn) {
CONN *c = &(conns[conn]);
ipxAddr_t adr;
memcpy(&adr, &(c->addr), sizeof(ipxAddr_t));
U16_TO_BE16(GET_BE16(adr.sock)+2, adr.sock);
send_bcast_packet(&adr, conn+1, '!'); /* notify */
}
}
/* =========================== SERVER BROADCAST ======================== */
static int send_broadcast(int fd, int firsttime, int down)
/* periodic Broadcast Message */
{
IPX_DATA ipx_data;
int ipx_pack_typ = 17;
ipxAddr_t wild;
memset(&wild, 0, sizeof(ipxAddr_t));
U32_TO_BE32(network, wild.net);
memset(wild.node, 0xFF, IPX_NODE_SIZE);
U16_TO_BE16(SOCK_SAP, wild.sock);
memset(&ipx_data, 0, sizeof(ipx_data.sip));
strcpy(ipx_data.sip.server_name, my_nwname);
memcpy(&ipx_data.sip.server_adr, &my_server_adr, sizeof(ipxAddr_t));
U16_TO_BE16(SOCK_NCP, ipx_data.sip.server_adr.sock);
/* NCP SOCKET verwenden */
if (firsttime && start_ncpserv(ipx_data.sip.server_name,
&ipx_data.sip.server_adr)) return(-1);
U16_TO_BE16(2, ipx_data.sip.response_type); /* General */
U16_TO_BE16(4, ipx_data.sip.server_type); /* Fileserver */
if (down) {
U16_TO_BE16(16, ipx_data.sip.intermediate_networks);
} else {
U16_TO_BE16(1, ipx_data.sip.intermediate_networks);
/* I think 1 is ok here */
}
send_ipx_data(fd, ipx_pack_typ,
sizeof(ipx_data.sip),
(char *)&(ipx_data.sip),
&wild, "SIP Broadcast");
return(0);
}
static void send_server_respons(int fd, uint8 ipx_pack_typ,
int respond_typ, int server_typ,
ipxAddr_t *to_addr)
{
IPX_DATA ipx_data;
memset(&ipx_data, 0, sizeof(ipx_data.sip));
strcpy(ipx_data.sip.server_name, my_nwname);
memcpy(&ipx_data.sip.server_adr, &my_server_adr, sizeof(ipxAddr_t));
U16_TO_BE16(SOCK_NCP, ipx_data.sip.server_adr.sock);
/* NCP SOCKET verwenden */
U16_TO_BE16(respond_typ, ipx_data.sip.response_type);
U16_TO_BE16(server_typ, ipx_data.sip.server_type);
U16_TO_BE16(0, ipx_data.sip.intermediate_networks);
send_ipx_data(fd, ipx_pack_typ,
sizeof(ipx_data.sip),
(char *)&(ipx_data.sip),
to_addr, "Server Response");
}
void get_server_data(char *name,
ipxAddr_t *adr,
ipxAddr_t *from_addr)
{
#ifdef LINUX
if (memcmp(adr->net, my_server_adr.net, IPX_NET_SIZE))
/* don't add our own netroute twice */
myipx_route_add(adr->net, from_addr->net, from_addr->node);
#endif
if (!nw386_found) {
memcpy(&nw386_adr, adr, sizeof(ipxAddr_t));
nw386_found++;
if (client_mode) {
start_nwclient();
client_mode = 0; /* only start once */
}
}
DPRINTF(("NW386 %s found at:%s\n", name, visable_ipx_adr(adr)));
ins_del_bind_net_addr(name, adr);
}
void handle_sap(int fd,
int ipx_pack_typ,
int data_len,
IPX_DATA *ipxdata,
ipxAddr_t *from_addr)
{
int query_type = GET_BE16(ipxdata->sqp.query_type);
int server_type = GET_BE16(ipxdata->sqp.server_type);
if (query_type == 3) {
DPRINTF(("SAP NEAREST SERVER request typ=%d von %s\n", server_type, visable_ipx_adr(from_addr)));
if (server_type == 4) {
/* Get Nearest File Server */
send_server_respons(fd, ipx_pack_typ,
4, server_type, from_addr);
}
} else if (query_type == 1) { /* general Request */
DPRINTF(("SAP GENERAL request server_type =%d\n", server_type));
if (server_type == 4) {
/* Get General File Server Request */
send_server_respons(fd, ipx_pack_typ,
4, server_type, from_addr);
}
} else if (query_type == 2) { /* periodic general or shutdown response */
DPRINTF(("SAP PERIODIC response von %s\n", visable_ipx_adr(from_addr)));
if (server_type == 4) { /* from Fileserver */
DPRINTF(("FROM SERVER intermediate=%d\n",
GET_BE16(ipxdata->sip.intermediate_networks)));
if (16 == GET_BE16(ipxdata->sip.intermediate_networks)) {
/* shutdown */
if (memcmp(ipxdata->sip.server_adr.net,
my_server_adr.net, IPX_NET_SIZE)) {
/* don't kill our own netroute */
DPRINTF(("SERVER %s IS GOING DOWN\n", ipxdata->sip.server_name));
ins_del_bind_net_addr(ipxdata->sip.server_name, NULL);
#ifdef LINUX
myipx_route_del(ipxdata->sip.server_adr.net);
#endif
} else {
DPRINTF(("SHUTDOWN RESPONSE from SERVER %s\n", ipxdata->sip.server_name));
}
} else {
get_server_data(ipxdata->sip.server_name, &(ipxdata->sip.server_adr),
from_addr);
}
}
} else if (query_type == 4) { /* nearests Service Response */
DPRINTF(("SAP nearest Service response\n"));
if (server_type == 4){
get_server_data(ipxdata->sip.server_name, &(ipxdata->sip.server_adr),
from_addr);
}
} else DPRINTF(("UNKNOWN SAP query %x, server %x\n", query_type, server_type));
}
static void send_rip(ipxAddr_t *from_addr)
{
RIP rip;
ipxAddr_t to_addr;
memset(&rip, 0, sizeof(RIP));
if (from_addr) memcpy(&to_addr, from_addr, sizeof(ipxAddr_t));
else {
memset(&to_addr, 0, sizeof(ipxAddr_t));
U32_TO_BE32(network, to_addr.net);
memset(to_addr.node, 0xFF, IPX_NODE_SIZE);
U16_TO_BE16(SOCK_RIP, to_addr.sock);
}
memcpy(rip.network, my_server_adr.net, IPX_NET_SIZE);
U16_TO_BE16(2, rip.operation); /* rip response or general */
U16_TO_BE16(1, rip.ticks); /* on ethernets allways 1 Tick */
U16_TO_BE16(0, rip.hops);
send_ipx_data(sockfd[RIP_SLOT],
1,
sizeof(RIP),
(char *)&rip,
&to_addr, "SEND RIP");
}
static void handle_rip(int fd, int ipx_pack_typ,
int data_len, IPX_DATA *ipxdata,
ipxAddr_t *from_addr)
{
int operation = GET_BE16(ipxdata->rip.operation);
int hops = GET_BE16(ipxdata->rip.hops);
int ticks = GET_BE16(ipxdata->rip.ticks);
DPRINTF(("Rip %s hops %d, ticks %d, network:%02x.%02x.%02x.%02x\n",
(operation == 1) ? "Request" : "Response",
hops, ticks,
(int)ipxdata->rip.network[0],
(int)ipxdata->rip.network[1],
(int)ipxdata->rip.network[2],
(int)ipxdata->rip.network[3]));
if (operation == 1) { /* rip request */
send_rip(from_addr);
} else if (operation != 2) /* NICHT RIP response */
DPRINTF(("UNKNOWN RIP operation %d\n", operation));
}
/*
** Task state constants (IPX Connection States)
**
**
** IPX_TASK_FREE - Task node is currently on the free list
** IPX_TASK_INUSE - Task has been allocated for use
** IPX_TASK_TRANSMIT - Packet has been transmitted (SendPacket)
** IPX_TASK_TIMEDOUT - Task has been disabled due to watchdog or
** retry fail
** IPX_TASK_DYING - Last NCP Response had Bad Connection Status
** Bit (Server Gone or Connection Gone).
** IPX_TASK_CONNECTED - Task is connected by address to the server
** IPX_TASK_BURST - A Packet Burst transaction is in progress
**
*/
#if 0
#define IPX_TASK_FREE 0 /* Not in use */
#define IPX_TASK_INUSE (1<<0) /* In use */
#define IPX_TASK_TRANSMIT (1<<1) /* Packet on the wire */
#define IPX_TASK_TIMEDOUT (1<<2) /* Connection is timed out */
#define IPX_TASK_DYING (1<<3) /* Connection no longer valid */
#define IPX_TASK_CONNECTED (1<<4) /* Connection in place */
#define IPX_TASK_BURST (1<<5) /* Packet Burst in progress */
#define CONN_STATUS_BAD_CONNECTION 0x01
#define CONN_STATUS_NO_SLOTS_AVAIL 0x04
#define CONN_STATUS_SERVER_DOWN 0x10
#define CONN_STATUS_MESSSAGE_WAITING 0x01
#endif
static void response_ipx_diag(int fd, int ipx_pack_typ,
ipxAddr_t *to_addr)
{
IPX_DATA ipxdata;
DIAGRESP *dia = &ipxdata.diaresp;
uint8 *p = (uint8*) (dia+1);
int datalen = sizeof(DIAGRESP); /* erstmal */
dia->majorversion = 1;
dia->minorversion = 1;
U16_TO_BE16(spx_diag_socket, dia->spx_diag_sock);
dia->anz = 3;
*p++ = 0; /* IPX/SPX */
datalen++;
*p++ = 1; /* Bridge Driver */
datalen++;
/* Jetzt extended */
*p++ = 6; /* Fileserver/Bridge (internal) */
datalen++;
*p++ = 1; /* Anz. Networks */
datalen++;
*p++ = 0; /* LAN BOARD */
datalen++;
memcpy(p, my_server_adr.net, IPX_NET_SIZE);
p += IPX_NET_SIZE;
datalen += IPX_NET_SIZE;
memcpy(p, my_server_adr.node, IPX_NODE_SIZE);
datalen += IPX_NODE_SIZE;
send_ipx_data(fd, ipx_pack_typ,
datalen,
(char*)&ipxdata,
to_addr, "DIAG Response");
}
static void handle_diag(int fd, int ipx_pack_typ,
int data_len, IPX_DATA *ipxdata,
ipxAddr_t *from_addr)
/* should handle CONFIGURATION REQUESTS one time */
{
CONFREQ *conf = &(ipxdata->confreq);
int count = (int) conf->count;
int j = count;
uint8 *exnodes = conf->ex_node;
while (j--) {
if IPXCMPNODE(exnodes, my_server_adr.node) {
DPRINTF(("NO RESPONSE TO DIAG\n"));
return;
}
exnodes += IPX_NODE_SIZE;
}
DPRINTF(("DIAG Request, ipx_pack_typ %d, data_len %d, count %d\n",
(int)ipx_pack_typ, data_len, count));
response_ipx_diag(fd, ipx_pack_typ, from_addr);
}
static void handle_event(int fd, uint16 socknr, int slot)
{
struct t_unitdata ud;
ipxAddr_t source_adr;
uint8 ipx_pack_typ;
IPX_DATA ipx_data_buff;
int flags = 0;
ud.opt.len = sizeof(ipx_pack_typ);
ud.opt.maxlen = sizeof(ipx_pack_typ);
ud.opt.buf = (char*)&ipx_pack_typ; /* gets actual typ */
ud.addr.len = sizeof(ipxAddr_t);
ud.addr.maxlen = sizeof(ipxAddr_t);
ud.addr.buf = (char*)&source_adr;
ud.udata.len = IPX_MAX_DATA;
ud.udata.maxlen = IPX_MAX_DATA;
ud.udata.buf = (char*)&ipx_data_buff;
if (t_rcvudata(fd, &ud, &flags) < 0){
struct t_uderr uderr;
ipxAddr_t erradr;
uint8 err_pack_typ;
uderr.addr.len = sizeof(ipxAddr_t);
uderr.addr.maxlen = sizeof(ipxAddr_t);
uderr.addr.buf = (char*)&erradr;
uderr.opt.len = sizeof(err_pack_typ);
uderr.opt.maxlen = sizeof(err_pack_typ);
uderr.opt.buf = (char*)&err_pack_typ; /* get actual typ */
ud.addr.buf = (char*)&source_adr;
t_rcvuderr(fd, &uderr);
DPRINTF(("Error from %s, Code = 0x%lx\n", visable_ipx_adr(&erradr), uderr.error));
t_error("t_rcvudata !OK");
return;
}
DPRINTF(("Ptyp:%d von: %s\n", (int)ipx_pack_typ, visable_ipx_adr(&source_adr) ));
if IPXCMPNODE(source_adr.node, my_server_adr.node) {
int source_sock = (int) GET_BE16(source_adr.sock);
if ( source_sock == sock_nummern[MY_BROADCAST_SLOT]
|| source_sock == sock_nummern[WDOG_SLOT]
|| source_sock == SOCK_RIP) {
DPRINTF(("OWN Packet, ignored\n"));
return;
}
/* it also can be Packets from DOSEMU OR ncpfs on this machine */
DPRINTF(("Packet from OWN maschine:sock=0x%x\n", source_sock));
}
switch (socknr) {
case SOCK_SAP : handle_sap( fd, (int) ipx_pack_typ, ud.udata.len, &ipx_data_buff, &source_adr); break;
case SOCK_RIP : handle_rip( fd, (int) ipx_pack_typ, ud.udata.len, &ipx_data_buff, &source_adr); break;
case SOCK_DIAGNOSE : handle_diag(fd, (int) ipx_pack_typ, ud.udata.len, &ipx_data_buff, &source_adr); break;
default :
if (WDOG_SLOT == slot) { /* this is a watchdog packet */
DPRINTF(("WDOG Packet len=%d connid=%d, status=%d\n",
(int)ud.udata.len, (int) ipx_data_buff.wdog.connid,
(int)ipx_data_buff.wdog.status));
if (2 == ud.udata.len) {
if ('Y' == ipx_data_buff.wdog.status)
reset_wdog_conn(ipx_data_buff.wdog.connid);
}
} else {
uint8 *p = (uint8*)&ipx_data_buff;
int k = 0;
DPRINTF(("UNKNOWN"));
while (k++ < ud.udata.len){
DPRINTF((" %x", (int) *p++));
}
DPRINTF(("\n"));
/*
print_ud_data(&ud);
*/
}
break;
}
}
static void get_server(void)
{
if (!nw386_found) { /* no other server was found yet. */
SQP sqp;
ipxAddr_t wild;
memset(&wild, 0, sizeof(ipxAddr_t));
memset(wild.node, 0xFF, IPX_NODE_SIZE);
U32_TO_BE32(network, wild.net);
U16_TO_BE16(SOCK_SAP, wild.sock);
U16_TO_BE16(3, sqp.query_type);
U16_TO_BE16(4, sqp.server_type);
send_ipx_data(sockfd[SAP_SLOT], 17, sizeof(SQP),
(char*)&sqp, &wild, "SERVER Query");
}
}
static void get_ini(void)
{
FILE *f=open_nw_ini();
char *frname=NULL;
#ifdef LINUX
strcpy(devname, "eth0"); /* default */
#endif
gethostname(my_nwname, 48);
upstr(my_nwname);
if (f){
char buff[500];
int what;
while (0 != (what =get_ini_entry(f, 0, (char*)buff, sizeof(buff)))) {
char inhalt[500];
char inhalt2[500];
char inhalt3[500];
char dummy;
int anz;
if ((anz=sscanf((char*)buff, "%s %s %s", inhalt, inhalt2, inhalt3)) > 0) {
switch (what) {
case 2 : strncpy(my_nwname, inhalt, 48);
my_nwname[47] = '\0';
upstr(my_nwname);
break;
#ifdef LINUX
case 3 :
if (sscanf(inhalt, "%ld%c", &internal_net, &dummy) != 1)
sscanf(inhalt, "%lx", &internal_net);
break;
#endif
case 4 :
if (sscanf(inhalt, "%ld%c", &network, &dummy) != 1)
sscanf(inhalt, "%lx", &network);
#ifdef LINUX
if (anz > 1) {
strncpy(devname, inhalt2, sizeof(devname));
devname[sizeof(devname)-1] = '\0';
}
if (anz > 2) {
upstr(inhalt3);
if (!strcmp(inhalt3, "802.3")) frame=IPX_FRAME_8023;
else if (!strcmp(inhalt3, "802.2"))
frame=IPX_FRAME_8022;
else if (!strcmp(inhalt3, "SNAP"))
frame=IPX_FRAME_SNAP;
else if (!strcmp(inhalt3, "ETHERNET_II"))
frame=IPX_FRAME_ETHERII;
}
#endif
break;
case 10 :
sscanf(inhalt, "%d", &conn_gid);
break;
case 11 :
sscanf(inhalt, "%d", &conn_uid);
break;
case 100 :
sscanf(inhalt, "%d", &ipxdebug);
break;
case 101 :
sscanf(inhalt, "%d", &nw_debug);
break;
case 102 :
sscanf(inhalt, "%d", &ncpserv_debug);
break;
case 103 :
sscanf(inhalt, "%d", &nwconn_debug);
break;
default : break;
} /* switch */
} /* if */
} /* while */
fclose(f);
}
#ifdef LINUX
switch (frame) {
case IPX_FRAME_8022 : frname = "802.2"; break;
case IPX_FRAME_8023 : frname = "802.3"; break;
case IPX_FRAME_SNAP : frname = "SNAP"; break;
case IPX_FRAME_ETHERII : frname = "ETHERNET_II";break;
default : break;
} /* switch */
#else
frname = "ETHERNET_II";
#endif
fprintf(stdout,
"Servername='%s', NETWORK='0x%lx', NODE='0x%lx'\n",
my_nwname, network, internal_net);
#ifdef LINUX
fprintf(stdout, "Device=%s, Frame=%s\n", devname, frname);
init_ipx(devname, &network, internal_net, frame, frname, ipxdebug);
fprintf(stdout, "NETWORK is=0x%lx\n", network);
#endif
}
static void send_down_broadcast(void)
{
int j = 20;
while (j--) send_broadcast(sockfd[MY_BROADCAST_SLOT], 0, 1);
}
static void close_all(void)
{
int j = NEEDED_SOCKETS;
if (pid_ncpserv > 0) {
if (fd_ncpserv_out > -1) close(fd_ncpserv_out);
if (fd_ncpserv_in > -1) close(fd_ncpserv_in);
kill(pid_ncpserv, SIGTERM); /* terminate ncpserv */
kill(pid_ncpserv, SIGKILL); /* kill ncpserv */
}
while (j--) {
t_unbind(sockfd[j]);
t_close(sockfd[j]);
}
#ifdef LINUX
fprintf(stdout, "Close Device=%s\n", devname);
exit_ipx(devname, network, frame);
#endif
}
static void sig_quit(int rsig)
{
signal(SIGINT, SIG_IGN);
signal(SIGQUIT, SIG_IGN);
signal(SIGTERM, SIG_IGN);
signal(SIGHUP, SIG_IGN);
signal(SIGPIPE, SIG_IGN);
send_down_broadcast();
close_all();
exit(1);
}
static int fl_get_debug=0;
static void get_new_debug(void)
{
get_ini_debug(1);
fl_get_debug=0;
}
static void sig_hup(int rsig)
{
signal(SIGHUP, SIG_IGN);
fl_get_debug++;
signal(SIGHUP, sig_hup);
}
static void set_sigs(void)
{
signal(SIGTERM, sig_quit);
signal(SIGQUIT, sig_quit);
signal(SIGINT, sig_quit);
signal(SIGPIPE, SIG_IGN);
signal(SIGHUP, sig_hup);
}
int main(int argc, char **argv)
{
int j = -1;
tzset();
if (argc > 1) client_mode++;
/* in client mode the testprog 'nwclient' will be startet. */
get_ini();
while (++j < NEEDED_POLLS) {
polls[j].events = POLLIN|POLLPRI;
polls[j].revents = 0;
if (j < NEEDED_SOCKETS) {
int fd = open_ipx_socket(ipx_sock_nummern[j], j, O_RDWR);
if (fd < 0) {
while (j--) {
t_unbind(sockfd[j]);
t_close(sockfd[j]);
}
return(1);
} else {
sockfd[j] = fd;
polls[j].fd = fd;
}
} else {
polls[j].fd = -1;
}
}
if (!send_broadcast(sockfd[MY_BROADCAST_SLOT], 1, 0)) {
/* Jetzt POLLEN */
time_t broadtime;
time(&broadtime);
set_sigs();
polls[NEEDED_SOCKETS].fd = fd_ncpserv_in;
while (1) {
int anz_poll = poll(polls, NEEDED_POLLS,
(!client_mode) ? 30000 : 15000);
if (fl_get_debug) get_new_debug();
time(&akttime_stamp);
if (anz_poll > 0) { /* i have to work */
struct pollfd *p = &polls[0];
j = -1;
while (++j < NEEDED_POLLS) {
if (p->revents){
if (j < NEEDED_SOCKETS) { /* socket */
/*
DPRINTF(("POLL %d, SOCKET %x, ", p->revents, sock_nummern[j]));
*/
if (p->revents & ~POLLIN) perror("STREAM error");
else handle_event(p->fd, sock_nummern[j], j);
} else { /* fd_ncpserv_in */
DPRINTF(("POLL %d, fh=%d\n", p->revents, p->fd));
if (p->revents & ~POLLIN) perror("STREAM error");
else {
if (p->fd == fd_ncpserv_in) {
int what;
int conn;
ipxAddr_t adr;
if (sizeof(int) == read(fd_ncpserv_in,
(char*)&what, sizeof(int))) {
DPRINTF(("GOT ncpserv_in what=0x%x\n", what));
switch (what) {
case 0x2222 : /* insert wdog connection */
if (sizeof(int) == read(fd_ncpserv_in,
(char*)&conn, sizeof(int))
&& sizeof(ipxAddr_t) == read(fd_ncpserv_in,
(char*)&adr, sizeof(ipxAddr_t)))
insert_wdog_conn(conn, &adr);
break;
case 0x4444 : /* reset wdog connection */
if (sizeof(int) == read(fd_ncpserv_in,
(char*)&conn, sizeof(int)))
reset_wdog_conn(conn);
break;
case 0x6666 : /* remove wdog connection */
if (sizeof(int) == read(fd_ncpserv_in,
(char*)&conn, sizeof(int)))
remove_wdog_conn(conn);
break;
case 0x8888 : /* bcast message */
if (sizeof(int) == read(fd_ncpserv_in,
(char*)&conn, sizeof(int)))
send_bcasts(conn);
break;
default : break;
}
}
}
}
}
if (! --anz_poll) break;
} /* if */
p++;
} /* while */
} else {
/* if (anz_poll < 0) perror("POLL error"); */
if (nw_debug > 2) DPRINTF(("POLLING ...\n"));
}
if (akttime_stamp - broadtime > 59) { /* ca. 60 seconds */
send_wdogs();
send_broadcast(sockfd[MY_BROADCAST_SLOT], 0, 0);
send_rip(NULL);
get_server();
inform_ncpserv();
broadtime = akttime_stamp;
} else if (client_mode) get_server(); /* Here more often */
} /* while */
send_down_broadcast();
}
close_all();
return(0);
}