1 /* This file is part of Liece.
2 Copyright (C) 1998 Daiki Ueno <daiki@kake.info.waseda.ac.jp>
4 Author: Daiki Ueno <daiki@kake.info.waseda.ac.jp>
7 Keywords: IRC, liece, DCC
9 This file is part of Liece.
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2, or (at your option)
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with GNU Emacs; see the file COPYING. If not, write to the
23 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
24 Boston, MA 02111-1307, USA.
27 #include <sys/types.h>
29 #include <sys/socket.h>
31 #include <sys/ioctl.h>
39 #include <netinet/in.h>
43 #ifndef MAXHOSTNAMELEN
44 # define MAXHOSTNAMELEN 31
47 #ifdef HAVE_SYS_SELECT_H
48 # include <sys/select.h>
60 # define memmove(x,y,z) bcopy((y), (x), (z))
64 # define basename(path) (rindex((path), '/') + 1)
68 static int prepare_listen_port();
69 static int prepare_connect_port();
71 static int receive_file();
72 static int send_file();
73 static int select_loop();
74 static int chat_listen();
75 static int chat_connect();
77 static u_long primary_address_of();
78 static u_long extract_addr_of_string();
79 static u_long get_address_externally();
81 static char *progname;
84 printf("%s (Liece) 1.4.0\n"
85 "Copyright (C) 1998, 1999 Daiki Ueno\n"
86 "This is free software; see the source for copying conditions. There is NO\n"
87 "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n",
92 printf("Usage: %s [global-options] command [command-options-and-arguments]\n"
93 "where global-options are -v, -h, etc.\n"
94 "where command is one of send, receive, chat, resolve.\n"
95 "where command-options-and-arguments depend on the specific command.\n\n"
96 "send <host> <port> <filename>\n"
97 "receive <host> <port> <size> <filename>\n"
98 "chat listen <port>\n"
99 "chat connect <host> <port>\n"
100 "resolve [hosts ...]\n",
104 int prepare_listen_port (int ip_port) {
107 static struct sockaddr_in server;
110 if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
111 perror("opening stream socket");
116 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
117 (char *)&opt, sizeof (opt)) < 0) {
118 perror ("setsockopt SO_REUSEADDR");
122 /* Bind a port to listen for new connections */
124 server.sin_family = AF_INET;
125 server.sin_addr.s_addr = INADDR_ANY;
126 server.sin_port = htons (ip_port);
127 for (tries = 0; tries < 10; tries++) {
128 if (bind (sock, (struct sockaddr *) &server, sizeof (server))) {
130 perror ("binding stream socket");
133 perror ("binding stream socket. retry in 20 seconds");
134 sleep (20); /* wait 20 seconds and try again */
142 u_long get_address_externally(char *ircserver) {
146 struct sockaddr_in server, client;
148 addr = 0xc6290004; /* dummy addr --- rootA */
149 if (ircserver && (hp = gethostbyname(ircserver)) != NULL) {
150 addr = ntohl(((struct in_addr *)hp->h_addr_list[0])->s_addr);
152 if ((dummy = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
153 perror("opening stream socket");
156 server.sin_family = AF_INET;
157 server.sin_addr.s_addr = htonl(addr);
158 server.sin_port = htons(7); /* dummy port --- echo */
159 for (i = 0; i < 8; i++) {
160 server.sin_zero[i] = 0;
162 if (connect(dummy, (struct sockaddr *)&server, sizeof(server)) < 0) {
163 perror ("connecting remote socket");
166 len = sizeof(client);
167 if (getsockname(dummy, (struct sockaddr *)&client, &len) < 0)
170 return ntohl(client.sin_addr.s_addr);
175 * send_file(int port, char *ifile)
176 * listens to connections to port, and when connection established
177 * sends ifile to that socket
179 int send_file (int port, char *ifile) {
180 int sock, ifd, ofd, len;
181 u_long addr, bytessent = 0;
182 char buf[ BUFSIZ * 8 ];
183 fd_set readfds, writefds, fdset;
185 char namebuf[ MAXHOSTNAMELEN ];
187 struct sockaddr_in sin;
189 if ((ifd = open (ifile, O_RDONLY)) < 0) {
190 /* error in opening file to send */
195 gethostname(namebuf, sizeof (namebuf));
196 fstat (ifd, &statbuf);
198 sock = prepare_listen_port(port);
199 len = sizeof (struct sockaddr_in);
200 if (getsockname(sock, (struct sockaddr *)&sin, &len) == 0)
201 port = ntohs(sin.sin_port);
203 if ((addr = get_address_externally (NULL)) < 0) {
204 gethostname(namebuf, sizeof (namebuf));
205 if (hp = gethostbyname(namebuf))
206 addr = ((struct in_addr *) (hp->h_addr_list)[0])->s_addr;
211 printf ("DCC send %s %d %u %d\n", ifile, port, addr, statbuf.st_size);
213 ofd = accept(sock, (struct sockaddr *) 0, (int *) 0);
215 while ((len = read (ifd, buf, sizeof (buf))) > 0) {
216 write (ofd, buf, len);
218 while ((len = read (ofd, buf, sizeof (u_long))) &&
219 ntohl (*(u_long *) buf) != bytessent);
223 printf ("*** DCC file %s sent\n", ifile);
229 * receive_file(u_long host, int port, char *ifile)
230 * connects to (host,port) and reads everything send from there
231 * for every packet received gives back how much actually got
232 * puts everything in ifile
234 int receive_file (u_long host, int port, int size, char *ifile) {
235 int sock, ifd, ofd, len, bytesreceived = 0, toread, prev = 0;
236 char buf[ BUFSIZ * 8 ];
237 fd_set readfds, writefds, fdset;
240 if ((ofd = open(ifile, O_WRONLY|O_CREAT|O_TRUNC, 0600)) < 0) {
241 fprintf(stderr, "open: opening file: %s\n", ifile);
244 ifd = prepare_connect_port (host, port);
245 if ((toread = sizeof (buf)) > size)
247 while (bytesreceived < size && (len = read (ifd, buf, toread)) > 0) {
248 write (ofd, buf, len);
249 bytesreceived += len;
250 netsize = htonl (bytesreceived);
252 write (ifd, &netsize, 4);
254 if (toread > size - bytesreceived)
255 toread = size - bytesreceived;
256 if (bytesreceived - prev > size / 5) {
257 printf ("DCC %s %d%% (%d/%d bytes) received\n", ifile,
258 100 * bytesreceived / size, bytesreceived, size);
259 prev = bytesreceived;
262 printf ("*** DCC file %s received\n", ifile);
270 * select_loop(int sfd)
271 * listens fd given, reads stdin and sends it to socket
272 * anything read from socket is send to stdout
274 int select_loop (int sfd) {
275 int ofd, len, bytesreceived = 0;
276 char buf[ BUFSIZ * 8 ];
277 fd_set readfds, writefds, fdset;
281 FD_SET (sfd, &readfds);
282 FD_SET (0, &readfds);
283 if (select (32, &readfds, 0, 0, 0) < 0) {
289 if (FD_ISSET (sfd, &readfds)) {
290 if ((len = read(sfd, buf, sizeof (buf))) == 0) {
295 FD_CLR (sfd, &readfds);
297 if (FD_ISSET (0, &readfds)) {
298 if ((len = read (0, buf, sizeof (buf))) == 0) {
302 write(sfd, buf, len);
303 FD_CLR (ofd, &readfds);
308 int prepare_connect_port (u_long host, int port) {
310 static struct hostent *hp;
311 static struct sockaddr_in server;
313 sock = socket (AF_INET, SOCK_STREAM, 0);
315 perror ("opening stream socket");
318 server.sin_family = AF_INET;
320 server.sin_addr.s_addr = ntohl (host);
321 server.sin_port = htons (port);
323 if (connect(sock, (struct sockaddr *) &server, sizeof (server)) < 0) {
324 perror ("connecting remote socket");
331 u_long extract_addr_of_string (char *str) {
336 result = result * 10 + *str - '0';
337 #else /* !HAVE_STRTOUL */
338 result = strtoul(str, NULL, 10);
339 #endif /* HAVE_STRTOUL */
343 u_long primary_address_of (char *host) {
347 if ((hp = gethostbyname(host)) == NULL)
348 addr = inet_addr(host);
350 memmove(&addr, hp->h_addr_list[ 0 ], 4);
355 int chat_listen(int port) {
356 struct sockaddr_in sin;
360 char namebuf[ MAXHOSTNAMELEN ];
362 sock = prepare_listen_port (port);
364 len = sizeof (struct sockaddr_in);
365 if (getsockname(sock, (struct sockaddr *)&sin, &len) == 0)
366 port = ntohs(sin.sin_port);
368 if ((addr = get_address_externally (NULL)) < 0) {
369 gethostname(namebuf, sizeof (namebuf));
370 if (hp = gethostbyname(namebuf))
371 addr = ((struct in_addr *) (hp->h_addr_list)[0])->s_addr;
376 printf("DCC chat %u %d\n", addr, port);
378 if ((sock = accept(sock, (struct sockaddr *) 0, (int *) 0)) > -1) {
379 printf("DCC chat established\n");
380 return select_loop(sock);
386 int chat_connect(u_long host, int port) {
389 if ((sock = prepare_connect_port(host, port)) > -1) {
390 printf("DCC chat established\n");
391 return select_loop(sock);
398 int main (int argc, char **argv) {
399 char *host = "localhost";
403 progname = (char *)basename(argv[ 0 ]);
406 int this_option_optind = optind ? optind : 1;
407 int option_index = 0;
408 static struct option long_options[] = {
409 {"version", 0, 0, 'v'},
414 c = getopt_long (argc, argv, "vh", long_options, &option_index);
439 if (!strcmp(action, "resolve")) {
445 for (i = 2; i < argc; i++) {
446 addr = primary_address_of(argv[i]);
448 printf("%u\n", addr);
456 if (!strcmp(action, "send")) {
461 status = send_file (atoi(argv[ 2 ]), argv[ 3 ]);
462 } else if (!strcmp(action, "receive")) {
468 receive_file (extract_addr_of_string(argv[ 2 ]),
469 atoi(argv[ 3 ]), atoi(argv[ 4 ]), argv[ 5 ]);
470 } else if (!strcmp(action, "chat")) {
472 if (!strcmp(argv[ 2 ], "listen")) {
477 status = chat_listen(atoi(argv[ 3 ]));
478 } else if (!strcmp(argv[ 2 ], "connect")) {
483 status = chat_connect(extract_addr_of_string(argv[ 3 ]),
500 * compile-command: "gcc -DHAVE_STRTOUL -Wall -O6 -o dcc dcc.c"