2 * Copyright (C) 1998-2003 Daiki Ueno
4 * This file is part of Riece.
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 #include <sys/types.h>
23 #include <sys/socket.h>
25 #include <sys/ioctl.h>
33 #include <netinet/in.h>
37 #ifndef MAXHOSTNAMELEN
38 # define MAXHOSTNAMELEN 31
41 #ifdef HAVE_SYS_SELECT_H
42 # include <sys/select.h>
54 # define memmove(x,y,z) bcopy((y), (x), (z))
58 # define basename(path) (rindex((path), '/') + 1)
62 static int prepare_listen_port();
63 static int prepare_connect_port();
65 static int receive_file();
66 static int send_file();
67 static int select_loop();
68 static int chat_listen();
69 static int chat_connect();
71 static u_long primary_address_of();
72 static u_long extract_addr_of_string();
73 static u_long get_address_externally();
75 static char *progname;
80 "Copyright (C) 1998-2003 Daiki Ueno\n"
81 "This is free software; see the source for copying conditions. There is NO\n"
82 "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n",
83 progname, PACKAGE, VERSION);
88 "Usage: %s [global-options] command [arguments...]\n"
89 "where global-options are -v, -h, etc.\n"
90 "where command is one of send, receive, chat, resolve.\n"
91 "where arguments depend on the specific command.\n\n"
92 "send <port> <filename>\n"
93 "receive <host> <port> <size> <filename>\n"
94 "chat listen <port>\n"
95 "chat connect <host> <port>\n"
96 "resolve [hosts ...]\n",
100 int prepare_listen_port (int ip_port) {
103 static struct sockaddr_in server;
106 if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
107 perror("opening stream socket");
112 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
113 (char *)&opt, sizeof (opt)) < 0) {
114 perror ("setsockopt SO_REUSEADDR");
118 /* Bind a port to listen for new connections */
120 server.sin_family = AF_INET;
121 server.sin_addr.s_addr = INADDR_ANY;
122 server.sin_port = htons (ip_port);
123 for (tries = 0; tries < 10; tries++) {
124 if (bind (sock, (struct sockaddr *) &server, sizeof (server))) {
126 perror ("binding stream socket");
129 perror ("binding stream socket. retry in 20 seconds");
130 sleep (20); /* wait 20 seconds and try again */
138 u_long get_address_externally(char *ircserver) {
142 struct sockaddr_in server, client;
144 addr = 0xc6290004; /* dummy addr --- rootA */
145 if (ircserver && (hp = gethostbyname(ircserver)) != NULL) {
146 addr = ntohl(((struct in_addr *)hp->h_addr_list[0])->s_addr);
148 if ((dummy = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
149 perror("opening stream socket");
152 server.sin_family = AF_INET;
153 server.sin_addr.s_addr = htonl(addr);
154 server.sin_port = htons(7); /* dummy port --- echo */
155 for (i = 0; i < 8; i++) {
156 server.sin_zero[i] = 0;
158 if (connect(dummy, (struct sockaddr *)&server, sizeof(server)) < 0) {
159 perror ("connecting remote socket");
162 len = sizeof(client);
163 if (getsockname(dummy, (struct sockaddr *)&client, &len) < 0)
166 return ntohl(client.sin_addr.s_addr);
171 * send_file(int port, char *ifile)
172 * listens to connections to port, and when connection established
173 * sends ifile to that socket
175 int send_file (int port, char *ifile) {
176 int sock, ifd, ofd, len;
177 u_long addr, bytessent = 0;
178 char buf[ BUFSIZ * 8 ];
179 fd_set readfds, writefds, fdset;
181 char namebuf[ MAXHOSTNAMELEN ];
183 struct sockaddr_in sin;
185 if ((ifd = open (ifile, O_RDONLY)) < 0) {
186 /* error in opening file to send */
191 gethostname(namebuf, sizeof (namebuf));
192 fstat (ifd, &statbuf);
194 sock = prepare_listen_port(port);
195 len = sizeof (struct sockaddr_in);
196 if (getsockname(sock, (struct sockaddr *)&sin, &len) == 0)
197 port = ntohs(sin.sin_port);
199 if ((addr = get_address_externally (NULL)) < 0) {
200 gethostname(namebuf, sizeof (namebuf));
201 if (hp = gethostbyname(namebuf))
202 addr = ((struct in_addr *) (hp->h_addr_list)[0])->s_addr;
207 printf ("DCC send %s %d %u %d\n", ifile, port, addr, statbuf.st_size);
209 ofd = accept(sock, (struct sockaddr *) 0, (int *) 0);
211 while ((len = read (ifd, buf, sizeof (buf))) > 0) {
212 write (ofd, buf, len);
214 while ((len = read (ofd, buf, sizeof (u_long))) &&
215 ntohl (*(u_long *) buf) != bytessent);
219 printf ("*** DCC file %s sent\n", ifile);
225 * receive_file(u_long host, int port, char *ifile)
226 * connects to (host,port) and reads everything send from there
227 * for every packet received gives back how much actually got
228 * puts everything in ifile
230 int receive_file (u_long host, int port, int size, char *ifile) {
231 int sock, ifd, ofd, len, bytesreceived = 0, toread, prev = 0;
232 char buf[ BUFSIZ * 8 ];
233 fd_set readfds, writefds, fdset;
236 if ((ofd = open(ifile, O_WRONLY|O_CREAT|O_TRUNC, 0600)) < 0) {
237 fprintf(stderr, "open: opening file: %s\n", ifile);
240 ifd = prepare_connect_port (host, port);
241 if ((toread = sizeof (buf)) > size)
243 while (bytesreceived < size && (len = read (ifd, buf, toread)) > 0) {
244 write (ofd, buf, len);
245 bytesreceived += len;
246 netsize = htonl (bytesreceived);
248 write (ifd, &netsize, 4);
250 if (toread > size - bytesreceived)
251 toread = size - bytesreceived;
252 if (bytesreceived - prev > size / 5) {
253 printf ("DCC %s %d%% (%d/%d bytes) received\n", ifile,
254 100 * bytesreceived / size, bytesreceived, size);
255 prev = bytesreceived;
258 printf ("*** DCC file %s received\n", ifile);
266 * select_loop(int sfd)
267 * listens fd given, reads stdin and sends it to socket
268 * anything read from socket is send to stdout
270 int select_loop (int sfd) {
271 int ofd, len, bytesreceived = 0;
272 char buf[ BUFSIZ * 8 ];
273 fd_set readfds, writefds, fdset;
277 FD_SET (sfd, &readfds);
278 FD_SET (0, &readfds);
279 if (select (32, &readfds, 0, 0, 0) < 0) {
285 if (FD_ISSET (sfd, &readfds)) {
286 if ((len = read(sfd, buf, sizeof (buf))) == 0) {
291 FD_CLR (sfd, &readfds);
293 if (FD_ISSET (0, &readfds)) {
294 if ((len = read (0, buf, sizeof (buf))) == 0) {
298 write(sfd, buf, len);
299 FD_CLR (ofd, &readfds);
304 int prepare_connect_port (u_long host, int port) {
306 static struct hostent *hp;
307 static struct sockaddr_in server;
309 sock = socket (AF_INET, SOCK_STREAM, 0);
311 perror ("opening stream socket");
314 server.sin_family = AF_INET;
316 server.sin_addr.s_addr = ntohl (host);
317 server.sin_port = htons (port);
319 if (connect(sock, (struct sockaddr *) &server, sizeof (server)) < 0) {
320 perror ("connecting remote socket");
327 u_long extract_addr_of_string (char *str) {
332 result = result * 10 + *str - '0';
333 #else /* !HAVE_STRTOUL */
334 result = strtoul(str, NULL, 10);
335 #endif /* HAVE_STRTOUL */
339 u_long primary_address_of (char *host) {
343 if ((hp = gethostbyname(host)) == NULL)
344 addr = inet_addr(host);
346 memmove(&addr, hp->h_addr_list[ 0 ], 4);
351 int chat_listen(int port) {
352 struct sockaddr_in sin;
356 char namebuf[ MAXHOSTNAMELEN ];
358 sock = prepare_listen_port (port);
360 len = sizeof (struct sockaddr_in);
361 if (getsockname(sock, (struct sockaddr *)&sin, &len) == 0)
362 port = ntohs(sin.sin_port);
364 if ((addr = get_address_externally (NULL)) < 0) {
365 gethostname(namebuf, sizeof (namebuf));
366 if (hp = gethostbyname(namebuf))
367 addr = ((struct in_addr *) (hp->h_addr_list)[0])->s_addr;
372 printf("DCC chat %u %d\n", addr, port);
374 if ((sock = accept(sock, (struct sockaddr *) 0, (int *) 0)) > -1) {
375 printf("DCC chat established\n");
376 return select_loop(sock);
382 int chat_connect(u_long host, int port) {
385 if ((sock = prepare_connect_port(host, port)) > -1) {
386 printf("DCC chat established\n");
387 return select_loop(sock);
394 int main (int argc, char **argv) {
395 char *host = "localhost";
399 progname = (char *)basename(argv[ 0 ]);
402 int this_option_optind = optind ? optind : 1;
403 int option_index = 0;
404 static struct option long_options[] = {
405 {"version", 0, 0, 'v'},
410 c = getopt_long (argc, argv, "vh", long_options, &option_index);
435 if (!strcmp(action, "resolve")) {
441 for (i = 2; i < argc; i++) {
442 addr = primary_address_of(argv[i]);
444 printf("%u\n", addr);
452 if (!strcmp(action, "send")) {
457 status = send_file (atoi(argv[ 2 ]), argv[ 3 ]);
458 } else if (!strcmp(action, "receive")) {
464 receive_file (extract_addr_of_string(argv[ 2 ]),
465 atoi(argv[ 3 ]), atoi(argv[ 4 ]), argv[ 5 ]);
466 } else if (!strcmp(action, "chat")) {
468 if (!strcmp(argv[ 2 ], "listen")) {
473 status = chat_listen(atoi(argv[ 3 ]));
474 } else if (!strcmp(argv[ 2 ], "connect")) {
479 status = chat_connect(extract_addr_of_string(argv[ 3 ]),
496 * compile-command: "gcc -DHAVE_STRTOUL -Wall -O6 -o dcc dcc.c"