/* Copyright (c) 1993 Stephen F. White */
#include <stdio.h>
#ifdef SYSV
#include <string.h>
#else
#include <strings.h>
#endif
#include <sys/types.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <signal.h>
#include <netdb.h>
#include <ctype.h>
#include "config.h"
#include "string.h"
#include "netio.h"
#include "buf.h"
#include "netio_private.h"
#include "servers_private.h"
#include "servers.h"
#include "sys_proto.h"
#include "socket_proto.h"
static int
send_to_server(Server *s, const char *buf)
{
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(s->port);
addr.sin_addr.s_addr = htonl(s->addr);
if (sendto(yo_sock, buf, strlen(buf), 0, (struct sockaddr *) &addr,
sizeof(addr)) < 0) {
return -1;
} else {
return 0;
}
}
void
connect_to_servers(void)
{
char buf[128];
Server *s;
s = serv_id2server(0);
sprintf(buf, "*connect %s\n", s->name);
for (s = servers; s; s = s->next) {
if (s->id == 0) { /* skip local server */
continue;
}
if (send_to_server(s, buf)) {
writelog();
fprintf(stderr, "Couldn't send connect msg to server ");
perror(s->name);
}
}
}
void
disconnect_from_servers(void)
{
char buf[128];
Server *s;
s = serv_id2server(0);
sprintf(buf, "*disconnect %s\n", s->name);
for (s = servers; s; s = s->next) {
if (!s->id) { /* skip local server */
continue;
}
if (s->id && s->connected) {
if (send_to_server(s, buf)) {
writelog();
fprintf(stderr, "Couldn't send disconnect msg to server ");
perror(s->name);
}
}
}
}
int
yo(Serverid server, const char *msg)
{
Server *s;
if (!(s = serv_id2server(server))) {
return -1;
} else if (!s->connected) {
return -2;
} else {
if (send_to_server(s, msg)) {
return -3;
} else {
return 0;
}
}
}
Server *
promiscuous_connect(struct sockaddr_in *from, const char *name)
{
Server *s;
if (promiscuous) {
s = serv_add(from, name);
if (!s) {
writelog();
fprintf(stderr, "INVALID SERVER %s(%d), ignored\n",
addr_htoa(ntohl(from->sin_addr.s_addr)),
ntohs(from->sin_port));
}
} else {
writelog();
fprintf(stderr, "UNKNOWN SERVER %s(%d), refused\n",
addr_htoa(ntohl(from->sin_addr.s_addr)), htons(from->sin_port));
}
return s;
}
static void
meta_command(struct sockaddr_in *from, char *command)
{
Server *s;
char *cmd, *name, *dummy;
parse_connect(command, &cmd, &name, &dummy);
s = serv_name2server(name);
if (!strcmp(cmd + 1, "connect")) {
char buf[128];
Server *local;
if (!s) {
s = promiscuous_connect(from, name);
if (!s) {
return;
}
} else if (verify_servers && !verify_server(s, from)) {
return;
}
s->connected = 1;
s->last_msgid = -1;
writelog();
fprintf(stderr, "Server %s (%s %d) connected\n", s->name, s->hostname,
s->port);
local = serv_id2server(0);
sprintf(buf, "*connectok %s\n", local->name);
sendto(yo_sock, buf, strlen(buf), 0, (struct sockaddr *) from,
sizeof(*from));
connect_server(s->id);
} else if (!strcmp(cmd + 1, "connectok")) {
if (!s) {
s = promiscuous_connect(from, name);
if (!s) {
return;
}
} else if (verify_servers && !verify_server(s, from)) {
return;
}
s->connected = 1;
s->last_msgid = -1;
writelog();
fprintf(stderr, "Server %s (%s %d) connected ok\n", s->name,
s->hostname, s->port);
connect_server(s->id);
} else if (!strcmp(cmd + 1, "disconnect")) {
if (!s) {
return;
}
s->connected = 0;
writelog();
fprintf(stderr, "Server %s (%s %d) disconnected\n", s->name,
s->hostname, s->port);
disconnect_server(s->id);
} else {
if (!s) {
return;
}
writelog();
fprintf(stderr, "Unknown metacommand \"%s\" from server %s\n",
command, s->name);
}
}
void
server_command(struct sockaddr_in *from, char *cmd)
{
Server *s;
if (cmd[0] == '*') {
meta_command(from, cmd);
} else {
s = serv_addr2server(from);
/* quietly ignore messages from unconnected servers */
if (s && s->connected) {
receive_message(s->id, cmd);
}
}
}