Completed call setup

This commit is contained in:
Michiel Broek 2005-04-18 08:54:55 +00:00
parent 607f106244
commit 2de56de377

View File

@ -46,6 +46,9 @@ int ls; /* Listen socket */
struct sockaddr_in myaddr_in; /* Listen socket address */ struct sockaddr_in myaddr_in; /* Listen socket address */
struct sockaddr_in clientaddr_in; /* Remote socket address */ struct sockaddr_in clientaddr_in; /* Remote socket address */
int changed = FALSE; /* Databases changed */ int changed = FALSE; /* Databases changed */
char crbuf[512]; /* Chat receive buffer */
char csbuf[512]; /* Chat send buffer */
typedef enum {NCS_INIT, NCS_CALL, NCS_WAITPWD, NCS_CONNECT, NCS_HANGUP, NCS_FAIL, NCS_DEAD} NCSTYPE; typedef enum {NCS_INIT, NCS_CALL, NCS_WAITPWD, NCS_CONNECT, NCS_HANGUP, NCS_FAIL, NCS_DEAD} NCSTYPE;
@ -58,9 +61,20 @@ static char *ncsstate[] = {
/* /*
* Add a port to the portlist * Internal prototypes
*/ */
void fill_ncslist(ncs_list **, char *, char *, char *); void fill_ncslist(ncs_list **, char *, char *, char *);
void dump_ncslist(void);
int send_msg(int, struct sockaddr_in, char *, char *);
void check_servers(void);
void command_pass(char *, char *);
void receiver(struct servent *);
/*
* Add a server to the serverlist
*/
void fill_ncslist(ncs_list **fdp, char *server, char *myname, char *passwd) void fill_ncslist(ncs_list **fdp, char *server, char *myname, char *passwd)
{ {
ncs_list *tmp, *ta; ncs_list *tmp, *ta;
@ -94,7 +108,6 @@ void fill_ncslist(ncs_list **fdp, char *server, char *myname, char *passwd)
void dump_ncslist(void);
void dump_ncslist(void) void dump_ncslist(void)
{ {
ncs_list *tmp; ncs_list *tmp;
@ -134,7 +147,7 @@ int send_msg(int s, struct sockaddr_in servaddr, char *host, char *msg)
Syslog('r', "> %s: %s", host, printable(msg, 0)); Syslog('r', "> %s: %s", host, printable(msg, 0));
if (sendto(s, msg, strlen(msg), 0, (struct sockaddr *)&servaddr, sizeof(struct sockaddr_in)) == -1) { if (sendto(s, msg, strlen(msg), 0, (struct sockaddr *)&servaddr, sizeof(struct sockaddr_in)) == -1) {
Syslog('r', "$Can't send message"); Syslog('r', "$IBC: can't send message");
return -1; return -1;
} }
return 0; return 0;
@ -144,10 +157,10 @@ int send_msg(int s, struct sockaddr_in servaddr, char *host, char *msg)
void check_servers(void) void check_servers(void)
{ {
char *errmsg, scfgfn[PATH_MAX], buf[512]; char *errmsg, scfgfn[PATH_MAX];
FILE *fp; FILE *fp;
ncs_list *tnsl; ncs_list *tnsl;
int inlist; int j, inlist;
time_t now; time_t now;
int a1, a2, a3, a4; int a1, a2, a3, a4;
struct servent *se; struct servent *se;
@ -177,7 +190,7 @@ void check_servers(void)
Syslog('r', " not in neighbour list, add"); Syslog('r', " not in neighbour list, add");
fill_ncslist(&ncsl, ibcsrv.server, ibcsrv.myname, ibcsrv.passwd); fill_ncslist(&ncsl, ibcsrv.server, ibcsrv.myname, ibcsrv.passwd);
changed = TRUE; changed = TRUE;
Syslog('+', "Added Internet BBS Chatserver %s", ibcsrv.server); Syslog('+', "IBC: added Internet BBS Chatserver %s", ibcsrv.server);
} }
} }
} }
@ -245,20 +258,19 @@ void check_servers(void)
case NO_RECOVERY: errmsg = (char *)"Non recoverable errors"; break; case NO_RECOVERY: errmsg = (char *)"Non recoverable errors"; break;
default: errmsg = (char *)"Unknown error"; break; default: errmsg = (char *)"Unknown error"; break;
} }
Syslog('+', "No IP address for %s: %s", tnsl->server, errmsg); Syslog('+', "IBC: no IP address for %s: %s", tnsl->server, errmsg);
tnsl->state = NCS_FAIL; tnsl->state = NCS_FAIL;
break; break;
} }
tnsl->socket = socket(AF_INET, SOCK_DGRAM, 0); tnsl->socket = socket(AF_INET, SOCK_DGRAM, 0);
if (tnsl->socket == -1) { if (tnsl->socket == -1) {
Syslog('+', "$Can't create socket for %s", tnsl->server); Syslog('+', "$IBC: can't create socket for %s", tnsl->server);
tnsl->state = NCS_FAIL; tnsl->state = NCS_FAIL;
break; break;
} }
Syslog('r', "socket %d", tnsl->socket); Syslog('r', "socket %d", tnsl->socket);
tnsl->token = gettoken();
tnsl->state = NCS_CALL; tnsl->state = NCS_CALL;
tnsl->action = now + (time_t)1; tnsl->action = now + (time_t)1;
} else { } else {
@ -266,12 +278,17 @@ void check_servers(void)
} }
break; break;
case NCS_CALL: Syslog('r', "%s call", tnsl->server); case NCS_CALL: /*
sprintf(buf, "PASS %s 0000 IBC| %s\r\n", tnsl->passwd, tnsl->compress ? "Z":""); * In this state we accept PASS and SERVER commands from
send_msg(tnsl->socket, tnsl->servaddr_in, tnsl->server, buf); * the remote with the same token as we have sent.
sprintf(buf, "SERVER %s 0 %ld mbsebbs v%s\r\n", tnsl->myname, tnsl->token, VERSION); */
send_msg(tnsl->socket, tnsl->servaddr_in, tnsl->server, buf); Syslog('r', "%s call", tnsl->server);
tnsl->action = now + (time_t)50; tnsl->token = gettoken();
sprintf(csbuf, "PASS %s 0000 IBC| %s\r\n", tnsl->passwd, tnsl->compress ? "Z":"");
send_msg(tnsl->socket, tnsl->servaddr_in, tnsl->server, csbuf);
sprintf(csbuf, "SERVER %s 0 %ld mbsebbs v%s\r\n", tnsl->myname, tnsl->token, VERSION);
send_msg(tnsl->socket, tnsl->servaddr_in, tnsl->server, csbuf);
tnsl->action = now + (time_t)10;
tnsl->state = NCS_WAITPWD; tnsl->state = NCS_WAITPWD;
changed = TRUE; changed = TRUE;
break; break;
@ -281,7 +298,16 @@ void check_servers(void)
* by a reply from the remote if the connection is accepted. * by a reply from the remote if the connection is accepted.
*/ */
Syslog('r', "%s waitpwd", tnsl->server); Syslog('r', "%s waitpwd", tnsl->server);
tnsl->token = 0;
tnsl->state = NCS_CALL; tnsl->state = NCS_CALL;
srand(getpid());
while (TRUE) {
j = 1+(int) (1.0 * CFG.dialdelay * rand() / (RAND_MAX + 1.0));
if ((j > (CFG.dialdelay / 10)) && (j > 9))
break;
}
Syslog('r', "next call in %d seconds", j);
tnsl->action = now + (time_t)j;
break; break;
} }
} }
@ -295,8 +321,114 @@ void check_servers(void)
void command_pass(char *hostname, char *parameters) void command_pass(char *hostname, char *parameters)
{ {
ncs_list *tnsl; ncs_list *tnsl;
char *passwd, *version, *opts, *lnk;
for (tnsl = ncsl; tnsl; tnsl = tnsl->next) {
if (strcmp(tnsl->server, hostname) == 0) {
break;
} }
}
passwd = strtok(parameters, " \0");
version = strtok(NULL, " \0");
opts = strtok(NULL, " \0");
lnk = strtok(NULL, " \0");
Syslog('r', "passwd \"%s\"", printable(passwd, 0));
Syslog('r', "version \"%s\"", printable(version, 0));
Syslog('r', "opts \"%s\"", printable(opts, 0));
Syslog('r', "link \"%s\"", printable(lnk, 0));
if (version == NULL) {
sprintf(csbuf, "461 PASS: Not enough parameters");
send_msg(tnsl->socket, tnsl->servaddr_in, tnsl->server, csbuf);
return;
}
if (strcmp(passwd, tnsl->passwd)) {
Syslog('!', "IBC: got bad password %s from %s", passwd, hostname);
return;
}
tnsl->gotpass = TRUE;
tnsl->version = atoi(version);
if (lnk && strchr(lnk, 'Z'))
tnsl->compress = TRUE;
changed = TRUE;
}
void command_server(char *hostname, char *parameters)
{
ncs_list *tnsl;
char *name, *hops, *id;
time_t now;
unsigned long token;
for (tnsl = ncsl; tnsl; tnsl = tnsl->next) {
if (strcmp(tnsl->server, hostname) == 0) {
break;
}
}
name = strtok(parameters, " \0");
hops = strtok(NULL, " \0");
id = strtok(NULL, " \0");
Syslog('r', "name \"%s\"", printable(name, 0));
Syslog('r', "hops \"%s\"", printable(hops, 0));
Syslog('r', "id \"%s\"", printable(id, 0));
Syslog('r', "vers \"%s\"", printable(parameters, 0));
if (id == NULL) {
sprintf(csbuf, "461 SERVER: Not enough parameters");
send_msg(tnsl->socket, tnsl->servaddr_in, tnsl->server, csbuf);
return;
}
token = atoi(id);
now = time(NULL);
if (tnsl->token) {
/*
* We are in calling state, so we expect the token from the
* remote is the same as the token we sent.
* In that case, the session is authorized.
*/
if (tnsl->token == token) {
tnsl->gotserver = TRUE;
changed = TRUE;
tnsl->state = NCS_CONNECT;
tnsl->action = now + (time_t)10;
Syslog('+', "IBC: connected with %s", tnsl->server);
return;
}
Syslog('r', "IBC: collision with %s", tnsl->server);
return;
}
/*
* We are in waiting state, so we sent our PASS and SERVER
* messages and set the session to connected if we got a
* valid PASS command.
*/
if (tnsl->gotpass) {
sprintf(csbuf, "PASS %s 0000 IBC| %s\r\n", tnsl->passwd, tnsl->compress ? "Z":"");
send_msg(tnsl->socket, tnsl->servaddr_in, tnsl->server, csbuf);
sprintf(csbuf, "SERVER %s 0 %ld mbsebbs v%s\r\n", tnsl->myname, token, VERSION);
send_msg(tnsl->socket, tnsl->servaddr_in, tnsl->server, csbuf);
tnsl->gotserver = TRUE;
tnsl->state = NCS_CONNECT;
tnsl->action = now + (time_t)10;
Syslog('+', "IBC: connected with %s", tnsl->server);
changed = TRUE;
} else {
Syslog('r', "IBC: got SERVER command without PASS command from %s", hostname);
}
return;
}
void receiver(struct servent *se) void receiver(struct servent *se)
@ -306,7 +438,7 @@ void receiver(struct servent *se)
int rc, len, inlist; int rc, len, inlist;
socklen_t sl; socklen_t sl;
ncs_list *tnsl; ncs_list *tnsl;
char buf[1024], resp[512], *hostname, *prefix, *command, *parameters; char *hostname, *prefix, *command, *parameters;
pfd.fd = ls; pfd.fd = ls;
pfd.events = POLLIN; pfd.events = POLLIN;
@ -320,15 +452,15 @@ void receiver(struct servent *se)
if (pfd.revents & POLLIN || pfd.revents & POLLERR || pfd.revents & POLLHUP || pfd.revents & POLLNVAL) { if (pfd.revents & POLLIN || pfd.revents & POLLERR || pfd.revents & POLLHUP || pfd.revents & POLLNVAL) {
sl = sizeof(myaddr_in); sl = sizeof(myaddr_in);
memset(&clientaddr_in, 0, sizeof(struct sockaddr_in)); memset(&clientaddr_in, 0, sizeof(struct sockaddr_in));
memset(&buf, 0, sizeof(buf)); memset(&crbuf, 0, sizeof(crbuf));
if ((len = recvfrom(ls, &buf, sizeof(buf)-1, 0,(struct sockaddr *)&clientaddr_in, &sl)) != -1) { if ((len = recvfrom(ls, &crbuf, sizeof(crbuf)-1, 0,(struct sockaddr *)&clientaddr_in, &sl)) != -1) {
hp = gethostbyaddr((char *)&clientaddr_in.sin_addr, sizeof(struct in_addr), clientaddr_in.sin_family); hp = gethostbyaddr((char *)&clientaddr_in.sin_addr, sizeof(struct in_addr), clientaddr_in.sin_family);
if (hp == NULL) if (hp == NULL)
hostname = inet_ntoa(clientaddr_in.sin_addr); hostname = inet_ntoa(clientaddr_in.sin_addr);
else else
hostname = hp->h_name; hostname = hp->h_name;
if ((buf[strlen(buf) -2] != '\r') && (buf[strlen(buf) -1] != '\n')) { if ((crbuf[strlen(crbuf) -2] != '\r') && (crbuf[strlen(crbuf) -1] != '\n')) {
Syslog('r', "Message not terminated with CR-LF, dropped"); Syslog('r', "Message not terminated with CR-LF, dropped");
return; return;
} }
@ -341,37 +473,50 @@ void receiver(struct servent *se)
} }
} }
if (!inlist) { if (!inlist) {
Syslog('!', "Message from unknown host (%s), dropped", hostname); Syslog('!', "IBC: message from unknown host (%s), dropped", hostname);
return; return;
} }
buf[strlen(buf) -2] = '\0'; tnsl->last = time(NULL);
Syslog('r', "< %s: \"%s\"", hostname, printable(buf, 0)); crbuf[strlen(crbuf) -2] = '\0';
Syslog('r', "< %s: \"%s\"", hostname, printable(crbuf, 0));
/* /*
* Parse message * Parse message
*/ */
if (buf[0] == ':') { if (crbuf[0] == ':') {
prefix = strtok(buf, " "); prefix = strtok(crbuf, " ");
command = strtok(NULL, " \0"); command = strtok(NULL, " \0");
parameters = strtok(NULL, "\0"); parameters = strtok(NULL, "\0");
} else { } else {
prefix = NULL; prefix = NULL;
command = strtok(buf, " \0"); command = strtok(crbuf, " \0");
parameters = strtok(NULL, "\0"); parameters = strtok(NULL, "\0");
} }
Syslog('r', "prefix \"%s\"", printable(prefix, 0)); // Syslog('r', "prefix \"%s\"", printable(prefix, 0));
Syslog('r', "command \"%s\"", printable(command, 0)); // Syslog('r', "command \"%s\"", printable(command, 0));
Syslog('r', "parameters \"%s\"", printable(parameters, 0)); // Syslog('r', "parameters \"%s\"", printable(parameters, 0));
if (! strcmp(command, (char *)"PASS") && parameters) { if (! strcmp(command, (char *)"PASS")) {
if (parameters == NULL) {
sprintf(csbuf, "461 %s: Not enough parameters", command);
send_msg(tnsl->socket, tnsl->servaddr_in, tnsl->server, csbuf);
} else {
command_pass(hostname, parameters); command_pass(hostname, parameters);
}
} else if (! strcmp(command, (char *)"SERVER")) {
if (parameters == NULL) {
sprintf(csbuf, "461 %s: Not enough parameters", command);
send_msg(tnsl->socket, tnsl->servaddr_in, tnsl->server, csbuf);
} else {
command_server(hostname, parameters);
}
} else if (tnsl->state == NCS_CONNECT) { } else if (tnsl->state == NCS_CONNECT) {
/* /*
* Only if connected we send a error response * Only if connected we send a error response
*/ */
sprintf(resp, "421 %s: Unknown command\r\n", command); sprintf(csbuf, "421 %s: Unknown command\r\n", command);
send_msg(tnsl->socket, tnsl->servaddr_in, tnsl->server, resp); send_msg(tnsl->socket, tnsl->servaddr_in, tnsl->server, csbuf);
} }
} else { } else {
Syslog('r', "recvfrom returned len=%d", len); Syslog('r', "recvfrom returned len=%d", len);
@ -391,23 +536,23 @@ void *ibc_thread(void *dummy)
Syslog('+', "Starting IBC thread"); Syslog('+', "Starting IBC thread");
if ((se = getservbyname("fido", "udp")) == NULL) { if ((se = getservbyname("fido", "udp")) == NULL) {
Syslog('!', "No fido udp entry in /etc/services, cannot start Internet BBS Chat"); Syslog('!', "IBC: no fido udp entry in /etc/services, cannot start Internet BBS Chat");
goto exit; goto exit;
} }
myaddr_in.sin_family = AF_INET; myaddr_in.sin_family = AF_INET;
myaddr_in.sin_addr.s_addr = INADDR_ANY; myaddr_in.sin_addr.s_addr = INADDR_ANY;
myaddr_in.sin_port = se->s_port; myaddr_in.sin_port = se->s_port;
Syslog('+', "Listen on %s, port %d\n", inet_ntoa(myaddr_in.sin_addr), ntohs(myaddr_in.sin_port)); Syslog('+', "IBC: listen on %s, port %d\n", inet_ntoa(myaddr_in.sin_addr), ntohs(myaddr_in.sin_port));
ls = socket(AF_INET, SOCK_DGRAM, 0); ls = socket(AF_INET, SOCK_DGRAM, 0);
if (ls == -1) { if (ls == -1) {
Syslog('!', "$Can't create socket"); Syslog('!', "$IBC: can't create listen socket");
goto exit; goto exit;
} }
if (bind(ls, (struct sockaddr *)&myaddr_in, sizeof(struct sockaddr_in)) == -1) { if (bind(ls, (struct sockaddr *)&myaddr_in, sizeof(struct sockaddr_in)) == -1) {
Syslog('!', "$Can't bind socket"); Syslog('!', "$IBC: can't bind listen socket");
goto exit; goto exit;
} }