/*
* brocas.c - IP Messenger 1.20 protocol
* Copyright (C) 1996 by candy
*/
char rcsid_brocas[] = "$Id: brocas.c,v 3.1 1996/11/21 13:28:23 candy Exp candy $";
#include <ctype.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <sys/time.h> /* setitimer() */
/* includes below are order dependent */
#include <sys/param.h> /* htons() */
#include <sys/types.h> /* socket() */
#include <sys/socket.h> /* socket() */
#include <netinet/in.h> /* inet_addr() INADDR_ANY */
#include <arpa/inet.h> /* inet_addr() */
#include <netdb.h> /* gethostbyname() */
#ifdef SOCKS
#include <socks.h>
#endif
#include "xipmsg.h"
#include "kanji.h"
#include "brocas.h"
#include "dyna.h"
#if defined BSD4_4
#define SENDTO(s,msg,len,flags,to,tolen) sendto(s,msg,len,flags,to,tolen)
#define SETSOCKOPT(s,level,optname,optval,optlen) setsockopt(s,level,optname,optval,optlen)
#else
#define SENDTO(s,msg,len,flags,to,tolen) sendto(s,msg,len,flags,(struct sockaddr *)to,tolen)
#define SETSOCKOPT(s,level,optname,optval,optlen) setsockopt(s,level,optname,(char *)optval,optlen)
#endif
static int debug_flag;
static int bro_socket;
static int bro_port;
static char *bro_user;
static const char *bro_host;
static int verbose;
static char *myname;
#define lan_width 32
#define lan_height 32
static unsigned char lan_bits[] = {
0xe0,0x00,0x00,0x1f,0x50,0x07,0xc0,0x35,0xb0,0xfa,0xbf,0x2a,0x58,0x55,0x55,
0x35,0xa8,0xaa,0xaa,0x2a,0x58,0x55,0x55,0x55,0xa8,0xaa,0xaa,0x6a,0x58,0x55,
0x55,0x55,0xa8,0xaa,0xaa,0x6a,0x58,0x01,0x55,0x50,0xa8,0x00,0x08,0x60,0x58,
0x18,0x00,0x46,0x28,0x18,0x00,0x46,0x50,0x00,0x00,0x40,0x30,0x30,0x00,0x46,
0x30,0x78,0x00,0x4f,0x30,0x78,0x00,0x4f,0x20,0x30,0x00,0x46,0x20,0x00,0x00,
0x40,0x58,0x00,0x00,0x40,0x6c,0x00,0x00,0x40,0xd6,0x00,0x60,0x40,0xab,0x00,
0xf0,0x40,0x55,0x01,0x60,0x20,0xaa,0x02,0x00,0x20,0x55,0x05,0x00,0x30,0xaa,
0x1a,0x00,0x38,0x55,0x61,0xf8,0x6f,0xaa,0x80,0x27,0x55,0x55,0x00,0x04,0x6b,
0xaa,0x00,0x88,0xd0,0x55,0x00,0x70,0xa8
};
static unsigned char *icon = lan_bits;
static unsigned long
atoaddr(const char *host)
{
unsigned long ret = INADDR_NONE;
struct hostent *he = gethostbyname(host);
if (he == NULL) {
fprintf(stderr, "%s: %s: unknown host.\n", myname, host);
}
if (he != NULL) {
if (he->h_addrtype == AF_INET && he->h_length <= sizeof(ret)) {
memcpy(&ret, he->h_addr_list[0], he->h_length);
}
}
return ret;
}/* atoaddr */
static size_t
iov_total(const struct iov_t *v)
{
size_t total = 0;
while (v != NULL) {
total += v->iov_len;
v = v->iov_next;
}/* while */
return total;
}/* iov_total */
static void *
iov_gather(void *buf_, const struct iov_t *v)
{
char *buf = buf_;
while (v != NULL) {
memcpy(buf, v->iov_base, v->iov_len);
buf += v->iov_len;
v = v->iov_next;
}/* while */
return buf_;
}/* iov_gather */
static ssize_t
sendtov(int so, int flags, const struct sockaddr *to, int tolen, const struct iov_t *iov)
{
ssize_t err = -1;
size_t total = iov_total(iov);
char *buf = malloc(total);
if (buf != NULL) {
iov_gather(buf, iov);
err = SENDTO(so, buf, total, flags, to, tolen);
if (err < 0)
perror("sendto");
free(buf);
}
return err;
}/* sendtov */
static unsigned long msg_number;
static int
send_msgv(int so, const union saddr *to, unsigned long command, int retryflag, const struct iov_t *iov)
{
char lbuf[2 + 12 + USERNAME_MAX + 1 + HOSTNAME_MAX + 1 + 12];
int err = -1, flags = 0;
struct iov_t v;
sprintf(lbuf, "1:%ld:%.*s:%.*s:%lu:", msg_number++, USERNAME_MAX, bro_user, HOSTNAME_MAX, bro_host, command);
SET_IOV(&v, (void *)iov, lbuf, strlen(lbuf));
if (retryflag) {
err = sendtov(so, flags, &to->sa, sizeof(to->sin), &v);
}
return err;
}/* send_msgv */
/*
* ネットワークの登録
*/
struct dynet_t STRUCT_DYNA(union saddr);
struct dynet_t dynet;
static int
network_add(const char *broad)
{
unsigned long addr = atoaddr(broad);
if (addr != INADDR_NONE) {
union saddr *net;
net = DYNA_NEXT(&dynet);
if (net != NULL) {
memset(net, '\0', sizeof(*net));
net->sin.sin_family = AF_INET;
net->sin.sin_addr.s_addr = atoaddr(broad);
net->sin.sin_port = htons(bro_port);
}
}
return 0;
}/* network_add */
static int
network_bro_send(int so, const char *msg)
{
union saddr *sin = DYNA_BUF(&dynet);
if (sin != NULL) {
char *sjis = malloc(strlen(msg) + 1);
if (sjis != NULL) {
unsigned long cmd = IPMSG_SENDMSG | IPMSG_SENDCHECKOPT;
int retry = 1;
int i, err;
struct iov_t v[2];
stretos(sjis, msg);
SET_IOV(&v[0], &v[1], sjis, strlen(sjis) + 1);
SET_IOV(&v[1], NULL, (void *)icon, 128);
for (i = 0; i < DYNA_USED(&dynet); i++) {
err = send_msgv(so, sin, cmd, retry, v);
sin++;
}/* for */
free(sjis);
}
}
return 0;
}/* network_bro_send */
/*
*
*/
int
bro_init(int port, const char *user, const char *host, const char * const *bros)
{
int so = socket(PF_INET, SOCK_DGRAM, 0);
DYNA_IZ(&dynet, 32);
bro_port = port;
bro_user = malloc(strlen(user) * 2 + 1);
if (bro_user != NULL)
stretos(bro_user, user);
else
bro_user = (char *)user;
bro_host = host;
msg_number = time(NULL);
while (*bros != NULL)
network_add(*bros++);
if (so >= 0) {
int optval = 1;
int err = SETSOCKOPT(so, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(optval));
if (err < 0) {
close(so);
so = -1;
}
}
bro_socket = so;
return so;
}/* bro_init */
static int
fnain(int so, FILE *fp)
{
char buf[5120];
size_t size = fread(buf, 1, sizeof(buf) - 1, fp);
buf[size] = '\0';
return network_bro_send(so, buf);
}/* fnain */
static int
nain(int so, const char *name)
{
FILE *fp = fopen(name, "r");
int err = -1;
if (fp != NULL) {
err = fnain(so, fp);
fclose(fp);
}
return err;
}/* nain */
static char *
get_env(const char *e)
{
char *ret = NULL, *p = getenv(e);
if (p != NULL) {
ret = malloc(strlen(p) + 1);
if (ret != NULL)
strcpy(ret, p);
}
return p;
}/* get_env */
static char usage_msg[] =
"usage: %s [-v][-d n] {[-f file] | [-m message]} [-p port] [-u user] address address...\n"
;
int
main(int argc, char *argv[])
{
int ex, show_usage = 0, ch;
int port = 2425;
char *user = get_env("USER"), *filename = NULL, *message = NULL;
myname = argv[0];
while ((ch = getopt(argc, argv, "d:f:m:p:u:vV")) != EOF) {
switch (ch) {
default:
case 'V':
show_usage++;
break;
case 'd':
debug_flag = strtol(optarg, NULL, 0);
break;
case 'f':
filename = optarg;
break;
case 'm':
message = optarg;
break;
case 'p':
port = strtol(optarg, NULL, 0);
break;
case 'u':
user = optarg;
break;
case 'v':
verbose++;
break;
}/* switch */
}/* while */
if (argc - optind < 1)
show_usage++;
ex = 1;
if (show_usage) {
fprintf(stderr, usage_msg, myname);
}
else {
const char * const *v = (const char * const *)&argv[optind];
char hostname[64];
int so;
if (user == NULL)
user = "anonymous";
gethostname(hostname, sizeof(hostname));
if (strchr(hostname, '.') != NULL)
*strchr(hostname, '.') = '\0';
so = bro_init(port, user, hostname, v);
if (so >= 0) {
int err = 0;
if (message != NULL)
err = network_bro_send(so, message);
else if (filename != NULL)
err = nain(so, filename);
else
err = fnain(so, stdin);
ex = err != 0;
}
}
return ex;
}/* main */
syntax highlighted by Code2HTML, v. 0.9.1