/*
** dcc.c (for irchat-jp)
** Copyright (C) 1995,1996,1998,1999 KIKUCHI Takahiro
**
** Author: KIKUCHI Takahiro <kick@kyoto.wide.ad.jp>
** Created: Mar 19, 1995
** Last Modified: Jul 7, 1999
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/file.h>
#include <netinet/in.h>
#include <stdio.h>
#include <fcntl.h>
#include <netdb.h>
#ifdef AIX
# include <sys/select.h>
#endif
#ifdef linux
# ifndef __GLIBC__
# include <linux/time.h>
# endif
#endif
#ifdef SOCKS
# include <socks.h>
#endif
int main(argc, argv)
int argc;
char **argv;
{
char *command, *type, *action;
int status = 1;
extern u_long atoul();
command = *argv++, argc--;
if (argc < 2) {
printf("DCC ERROR Not enough parameters\n");
fprintf(stderr, "Usage: %s <type> <command> <arg>...\n", command);
exit(1);
}
type = *argv++, argc--;
action = *argv++, argc--;
if (!strcmp(type, "file")) {
if (!strcmp(action, "send")) {
if (argc == 1) {
status = file_send(argv[0], 0, 0);
} else if (argc == 3) {
status = file_send(argv[0], atoi(argv[1]), argv[2]);
} else {
printf("DCC ERROR Wrong number of parameters\n");
fprintf(stderr,
"Usage: %s file send <filename> <port> <ircserver>\n",
command);
status = 1;
}
} else if (!strcmp(action, "get")) {
if (argc == 4) {
status = file_get(atoul(argv[0]), atoi(argv[1]),
atoi(argv[2]), argv[3]);
} else {
printf("DCC ERROR Wrong number of parameters\n");
fprintf(stderr,
"Usage: %s file get <addr> <port> <size> <filename>\n",
command);
status = 1;
}
} else {
printf("DCC ERROR Unsupported command %s %s\n", type, action);
status = 1;
}
} else if (!strcmp(type, "chat")) {
if (!strcmp(action, "listen")) {
if (argc == 0) {
status = chat_listen(0, 0);
} else if (argc == 2) {
status = chat_listen(atoi(argv[0]), argv[1]);
} else {
printf("DCC ERROR Wrong number of parameters\n");
fprintf(stderr, "Usage: %s chat listen <port> <ircserver>\n",
command);
status = 1;
}
} else if (!strcmp(action, "connect")) {
if (argc == 2) {
status = chat_connect(atoul(argv[0]), atoi(argv[1]));
} else {
printf("DCC ERROR Wrong number of parameters\n");
fprintf(stderr, "Usage: %s chat connect <addr> <port>\n",
command);
status = 1;
}
} else {
printf("DCC ERROR Unsupported command %s %s\n", type, action);
status = 1;
}
} else if (!strcmp(type, "tcp")) {
if (!strcmp(action, "connect")) {
if (argc == 2) {
status = tcp_connect(argv[0], argv[1]);
} else {
printf("DCC ERROR Wrong number of parameters\n");
fprintf(stderr, "Usage: %s chat connect <addr> <port>\n",
command);
status = 1;
}
} else {
printf("DCC ERROR Unsupported command %s %s\n", type, action);
status = 1;
}
} else {
printf("DCC ERROR Unsupported command %s\n", type);
status = 1;
}
if (status) {
sleep(3);
}
exit(status);
}
u_long getmyaddr(ircserver)
char *ircserver;
{
int i, len, dummy;
u_long addr;
char *p;
struct hostent *hp;
struct sockaddr_in server, client;
addr = 0xc6290004; /* dummy addr --- rootA */
if (ircserver && (hp = gethostbyname(ircserver)) != NULL) {
addr = ntohl(((struct in_addr *)hp->h_addr_list[0])->s_addr);
}
if ((dummy = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
printf("DCC ERROR Cannot create socket\n");
return -1;
}
for (i = 0, p = (char *)&server; i < sizeof(server); i++, *p++ = 0);
server.sin_family = AF_INET;
server.sin_addr.s_addr = htonl(addr);
server.sin_port = htons(7); /* dummy port --- echo */
if (connect(dummy, (struct sockaddr *)&server, sizeof(server)) < 0) {
printf("DCC ERROR Cannot connect socket\n");
return -1;
}
len = sizeof(client);
if (getsockname(dummy, (struct sockaddr *)&client, &len) < 0) {
printf("DCC ERROR Cannot getsockname\n");
return -1;
}
close(dummy);
return ntohl(client.sin_addr.s_addr);
}
int dcc_listen(paddr, pport, ircserver)
u_long *paddr;
u_short *pport;
char *ircserver;
{
int i, s, len;
char *p;
struct sockaddr_in server;
if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("DCC ERROR Cannot create socket\n");
return -1;
}
for (i = 0, p = (char *)&server; i < sizeof(server); i++, *p++ = 0);
server.sin_family = AF_INET;
server.sin_addr.s_addr = htonl(getmyaddr(ircserver));
server.sin_port = htons(*pport);
while (bind(s, (struct sockaddr *)&server, sizeof(server)) < 0) {
if (!*pport) {
printf("DCC ERROR Cannot bind socket\n");
return -1;
}
server.sin_port = htons(++(*pport));
}
if (listen(s, 1) < 0) {
printf("DCC ERROR Cannot listen socket\n");
return -1;
}
len = sizeof(server);
if (getsockname(s, (struct sockaddr *)&server, &len) < 0) {
printf("DCC ERROR Cannot getsockname\n");
return -1;
}
*pport = ntohs(server.sin_port);
*paddr = ntohl(server.sin_addr.s_addr);
return s;
}
int dcc_connect(addr, port)
u_long addr;
u_short port;
{
int i, remote;
char *p;
struct sockaddr_in server;
if ((remote = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("DCC ERROR Cannot create socket\n");
return -1;
}
for (i = 0, p = (char *)&server; i < sizeof(server); i++, *p++ = 0);
server.sin_family = AF_INET;
server.sin_addr.s_addr = htonl(addr);
server.sin_port = htons(port);
if (connect(remote, (struct sockaddr *)&server, sizeof(server)) < 0) {
printf("DCC ERROR Cannot connect %u/%d\n", addr, port);
return -1;
}
return remote;
}
u_long atoul(str)
char *str;
{
u_long val = 0;
while (*str) {
val = val * 10 + *str - '0';
str++;
}
return val;
}
u_long dottoul(str)
char *str;
{
u_long val, v;
for (val = v = 0; *str; str++) {
if (*str == '.') {
val = val * 256 + v;
v = 0;
} else {
v = v * 10 + *str - '0';
}
}
val = val * 256 + v;
return val;
}
int file_send(filename, port, ircserver)
char *filename;
u_short port;
char *ircserver;
{
int file, size, s, remote, len, count = 0;
u_long addr;
struct stat statbuf;
u_long done = 0;
u_long report;
char buf[4096];
if ((file = open(filename, O_RDONLY)) < 0) {
printf("DCC ERROR Cannot open file %s\n", filename);
return 1;
}
if (fstat(file, &statbuf) < 0) {
printf("DCC ERROR Cannot stat file %s\n", filename);
return 1;
}
size = statbuf.st_size;
if ((s = dcc_listen(&addr, &port, ircserver)) < 0) {
/* error report in dcc_listen */
return 1;
}
/* 'Setting -> 'Waiting (send DCC SEND to remote user) */
printf("DCC SEND %u %d %d\n", addr, port, size);
remote = accept(s, (struct sockaddr *) 0, (int *) 0);
close(s);
/* 'Waiting -> 'Sending (accepted from remote user) */
printf("DCC SENDING\n");
while ((len = read(file, buf, sizeof(buf))) > 0) {
write(remote, buf, len);
done += len;
if (++count == 16) {
count = 0;
while (read(remote, &report, sizeof(u_long)) > 0 &&
ntohl(report) != done);
printf("DCC REPORT %s %d%% (%d/%d bytes) sent\n",
filename, 100 * done / size, done, size);
}
}
while (read(remote, &report, sizeof(u_long)) > 0 &&
ntohl(report) != done);
/* 'Sending -> end */
close(remote);
close(file);
return 0;
}
int file_get(addr, port, size, filename)
u_long addr;
u_short port;
int size;
char *filename;
{
int remote, file, len, toread, count = 0;
u_long done = 0;
u_long report;
char buf[4096];
if ((file = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0600)) < 0) {
printf("DCC ERROR1 Cannot open file %s\n", filename);
return 1;
}
if ((remote = dcc_connect(addr, port)) < 0) {
/* error report in dcc_connect */
return 1;
}
/* 'Connect -> 'Getting (connected to remote user) */
printf("DCC GETTING\n");
toread = sizeof(buf);
while (size - done > 0) {
if (toread > size - done) {
toread = size - done;
}
if ((len = read(remote, buf, toread)) < 0) {
printf("DCC ERROR read error %s\n", filename);
return 1;
}
write(file, buf, len);
done += len;
report = htonl(done);
write(remote, &report, sizeof(report));
if (++count == 16) {
count = 0;
printf("DCC REPORT %s %d%% (%d/%d bytes) received\n",
filename, 100 * done / size, done, size);
}
}
/* 'Getting -> end */
close(remote);
close(file);
return 0;
}
int chat_listen(port, ircserver)
u_short port;
char *ircserver;
{
u_long addr;
int s, remote;
if ((s = dcc_listen(&addr, &port, ircserver)) < 0) {
return 1;
}
/* 'Setting -> 'Waiting (send DCC CHAT to remote user) */
printf("DCC CHAT %u %d\n", addr, port);
remote = accept(s, (struct sockaddr *) 0, (int *) 0);
close(s);
/* 'Waiting -> 'Active (accepted from remote user) */
printf("DCC CHATTING\n");
return loop(remote);
}
int chat_connect(addr, port)
u_long addr;
u_short port;
{
int remote;
if ((remote = dcc_connect(addr, port)) < 0) {
return 1;
}
/* 'Connect -> 'Active (connected to remote user) */
printf("DCC CHATTING\n");
return loop(remote);
}
int loop(remote)
int remote;
{
int n, len, cnt;
char *ptr, buf[1024];
fd_set rfds;
while (1) {
FD_ZERO(&rfds);
FD_SET(0, &rfds);
FD_SET(remote, &rfds);
if ((n = select(FD_SETSIZE, &rfds, NULL, NULL, NULL)) == -1) {
continue;
}
if (FD_ISSET(0, &rfds)) {
if ((len = read(0, buf, sizeof(buf))) <= 0) {
close(0);
close(remote);
if (len == 0) {
return 0;
} else {
return 1;
}
}
for (ptr = buf; len > 0; ptr+= cnt, len -= cnt) {
if ((cnt = write(remote, ptr, len)) < 0) {
close(0);
close(remote);
return 1;
}
}
}
if (FD_ISSET(remote, &rfds)) {
if ((len = read(remote, buf, sizeof(buf))) <= 0) {
close(0);
close(remote);
if (len == 0) {
return 0;
} else {
return 1;
}
}
for (ptr = buf; len > 0; ptr+= cnt, len -= cnt) {
if ((cnt = write(0, ptr, len)) < 0) {
close(0);
close(remote);
return 1;
}
}
}
}
}
int tcp_connect(straddr, strport)
char *straddr, *strport;
{
int remote;
#ifdef INET6
int eai;
struct addrinfo hints, *ai;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
if ((eai = getaddrinfo(straddr, strport, &hints, &ai)) != 0) {
printf("ERROR :Closing Link: [*@*] (Cannot resolve %s: %s)\n",
straddr, gai_strerror(eai));
return 0;
}
if ((remote = socket(ai->ai_family, SOCK_STREAM, 0)) < 0) {
printf("ERROR :Closing Link: [*@*] (Cannot create socket)\n");
return 0;
}
if (connect(remote, ai->ai_addr, ai->ai_addrlen) < 0) {
printf("ERROR :Closing Link: [*@*] (Cannot connect to %s/%s)\n",
straddr, strport);
return 0;
}
#else
int i;
u_long addr;
char *p;
struct hostent *hp;
struct sockaddr_in server;
if (*straddr >= '0' && *straddr <= '9') {
addr = dottoul(straddr);
} else if ((hp = gethostbyname(straddr)) != NULL) {
addr = ntohl(((struct in_addr *)hp->h_addr_list[0])->s_addr);
} else {
printf("ERROR :Closing Link: [*@*] (Cannot resolve %s)\n", straddr);
return 0;
}
if ((remote = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("ERROR :Closing Link: [*@*] (Cannot create socket)\n");
return 0;
}
for (i = 0, p = (char *)&server; i < sizeof(server); i++, *p++ = 0);
server.sin_family = AF_INET;
server.sin_addr.s_addr = htonl(addr);
server.sin_port = htons(atoi(strport));
if (connect(remote, (struct sockaddr *)&server, sizeof(server)) < 0) {
printf("ERROR :Closing Link: [*@*] (Cannot connect to %s/%s)\n",
straddr, strport);
return 0;
}
#endif
return loop(remote);
}
syntax highlighted by Code2HTML, v. 0.9.1