/* * 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 #include #include #include #include #include #include #include /* setitimer() */ /* includes below are order dependent */ #include /* htons() */ #include /* socket() */ #include /* socket() */ #include /* inet_addr() INADDR_ANY */ #include /* inet_addr() */ #include /* gethostbyname() */ #ifdef SOCKS #include #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 */