2 * Copyright (C) 1998-2002 Daiki Ueno
4 * This file is part of Liece.
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;
78 printf("%s (Liece) 1.4.0\n"
79 "Copyright (C) 1998, 1999 Daiki Ueno\n"
80 "This is free software; see the source for copying conditions. There is NO\n"
81 "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n",
86 printf("Usage: %s [global-options] command [command-options-and-arguments]\n"
87 "where global-options are -v, -h, etc.\n"
88 "where command is one of send, receive, chat, resolve.\n"
89 "where command-options-and-arguments depend on the specific command.\n\n"
90 "send <host> <port> <filename>\n"
91 "receive <host> <port> <size> <filename>\n"
92 "chat listen <port>\n"
93 "chat connect <host> <port>\n"
94 "resolve [hosts ...]\n",
98 int prepare_listen_port (int ip_port) {
101 static struct sockaddr_in server;
104 if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
105 perror("opening stream socket");
110 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
111 (char *)&opt, sizeof (opt)) < 0) {
112 perror ("setsockopt SO_REUSEADDR");
116 /* Bind a port to listen for new connections */
118 server.sin_family = AF_INET;
119 server.sin_addr.s_addr = INADDR_ANY;
120 server.sin_port = htons (ip_port);
121 for (tries = 0; tries < 10; tries++) {
122 if (bind (sock, (struct sockaddr *) &server, sizeof (server))) {
124 perror ("binding stream socket");
127 perror ("binding stream socket. retry in 20 seconds");
128 sleep (20); /* wait 20 seconds and try again */
136 u_long get_address_externally(char *ircserver) {
140 struct sockaddr_in server, client;
142 addr = 0xc6290004; /* dummy addr --- rootA */
143 if (ircserver && (hp = gethostbyname(ircserver)) != NULL) {
144 addr = ntohl(((struct in_addr *)hp->h_addr_list[0])->s_addr);
146 if ((dummy = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
147 perror("opening stream socket");
150 server.sin_family = AF_INET;
151 server.sin_addr.s_addr = htonl(addr);
152 server.sin_port = htons(7); /* dummy port --- echo */
153 for (i = 0; i < 8; i++) {
154 server.sin_zero[i] = 0;
156 if (connect(dummy, (struct sockaddr *)&server, sizeof(server)) < 0) {
157 perror ("connecting remote socket");
160 len = sizeof(client);
161 if (getsockname(dummy, (struct sockaddr *)&client, &len) < 0)
164 return ntohl(client.sin_addr.s_addr);
169 * send_file(int port, char *ifile)
170 * listens to connections to port, and when connection established
171 * sends ifile to that socket
173 int send_file (int port, char *ifile) {
174 int sock, ifd, ofd, len;
175 u_long addr, bytessent = 0;
176 char buf[ BUFSIZ * 8 ];
177 fd_set readfds, writefds, fdset;
179 char namebuf[ MAXHOSTNAMELEN ];
181 struct sockaddr_in sin;
183 if ((ifd = open (ifile, O_RDONLY)) < 0) {
184 /* error in opening file to send */
189 gethostname(namebuf, sizeof (namebuf));
190 fstat (ifd, &statbuf);
192 sock = prepare_listen_port(port);
193 len = sizeof (struct sockaddr_in);
194 if (getsockname(sock, (struct sockaddr *)&sin, &len) == 0)
195 port = ntohs(sin.sin_port);
197 if ((addr = get_address_externally (NULL)) < 0) {
198 gethostname(namebuf, sizeof (namebuf));
199 if (hp = gethostbyname(namebuf))
200 addr = ((struct in_addr *) (hp->h_addr_list)[0])->s_addr;
205 printf ("DCC send %s %d %u %d\n", ifile, port, addr, statbuf.st_size);
207 ofd = accept(sock, (struct sockaddr *) 0, (int *) 0);
209 while ((len = read (ifd, buf, sizeof (buf))) > 0) {
210 write (ofd, buf, len);
212 while ((len = read (ofd, buf, sizeof (u_long))) &&
213 ntohl (*(u_long *) buf) != bytessent);
217 printf ("*** DCC file %s sent\n", ifile);
223 * receive_file(u_long host, int port, char *ifile)
224 * connects to (host,port) and reads everything send from there
225 * for every packet received gives back how much actually got
226 * puts everything in ifile
228 int receive_file (u_long host, int port, int size, char *ifile) {
229 int sock, ifd, ofd, len, bytesreceived = 0, toread, prev = 0;
230 char buf[ BUFSIZ * 8 ];
231 fd_set readfds, writefds, fdset;
234 if ((ofd = open(ifile, O_WRONLY|O_CREAT|O_TRUNC, 0600)) < 0) {
235 fprintf(stderr, "open: opening file: %s\n", ifile);
238 ifd = prepare_connect_port (host, port);
239 if ((toread = sizeof (buf)) > size)
241 while (bytesreceived < size && (len = read (ifd, buf, toread)) > 0) {
242 write (ofd, buf, len);
243 bytesreceived += len;
244 netsize = htonl (bytesreceived);
246 write (ifd, &netsize, 4);
248 if (toread > size - bytesreceived)
249 toread = size - bytesreceived;
250 if (bytesreceived - prev > size / 5) {
251 printf ("DCC %s %d%% (%d/%d bytes) received\n", ifile,
252 100 * bytesreceived / size, bytesreceived, size);
253 prev = bytesreceived;
256 printf ("*** DCC file %s received\n", ifile);
264 * select_loop(int sfd)
265 * listens fd given, reads stdin and sends it to socket
266 * anything read from socket is send to stdout
268 int select_loop (int sfd) {
269 int ofd, len, bytesreceived = 0;
270 char buf[ BUFSIZ * 8 ];
271 fd_set readfds, writefds, fdset;
275 FD_SET (sfd, &readfds);
276 FD_SET (0, &readfds);
277 if (select (32, &readfds, 0, 0, 0) < 0) {
283 if (FD_ISSET (sfd, &readfds)) {
284 if ((len = read(sfd, buf, sizeof (buf))) == 0) {
289 FD_CLR (sfd, &readfds);
291 if (FD_ISSET (0, &readfds)) {
292 if ((len = read (0, buf, sizeof (buf))) == 0) {
296 write(sfd, buf, len);
297 FD_CLR (ofd, &readfds);
302 int prepare_connect_port (u_long host, int port) {
304 static struct hostent *hp;
305 static struct sockaddr_in server;
307 sock = socket (AF_INET, SOCK_STREAM, 0);
309 perror ("opening stream socket");
312 server.sin_family = AF_INET;
314 server.sin_addr.s_addr = ntohl (host);
315 server.sin_port = htons (port);
317 if (connect(sock, (struct sockaddr *) &server, sizeof (server)) < 0) {
318 perror ("connecting remote socket");
325 u_long extract_addr_of_string (char *str) {
330 result = result * 10 + *str - '0';
331 #else /* !HAVE_STRTOUL */
332 result = strtoul(str, NULL, 10);
333 #endif /* HAVE_STRTOUL */
337 u_long primary_address_of (char *host) {
341 if ((hp = gethostbyname(host)) == NULL)
342 addr = inet_addr(host);
344 memmove(&addr, hp->h_addr_list[ 0 ], 4);
349 int chat_listen(int port) {
350 struct sockaddr_in sin;
354 char namebuf[ MAXHOSTNAMELEN ];
356 sock = prepare_listen_port (port);
358 len = sizeof (struct sockaddr_in);
359 if (getsockname(sock, (struct sockaddr *)&sin, &len) == 0)
360 port = ntohs(sin.sin_port);
362 if ((addr = get_address_externally (NULL)) < 0) {
363 gethostname(namebuf, sizeof (namebuf));
364 if (hp = gethostbyname(namebuf))
365 addr = ((struct in_addr *) (hp->h_addr_list)[0])->s_addr;
370 printf("DCC chat %u %d\n", addr, port);
372 if ((sock = accept(sock, (struct sockaddr *) 0, (int *) 0)) > -1) {
373 printf("DCC chat established\n");
374 return select_loop(sock);
380 int chat_connect(u_long host, int port) {
383 if ((sock = prepare_connect_port(host, port)) > -1) {
384 printf("DCC chat established\n");
385 return select_loop(sock);
392 int main (int argc, char **argv) {
393 char *host = "localhost";
397 progname = (char *)basename(argv[ 0 ]);
400 int this_option_optind = optind ? optind : 1;
401 int option_index = 0;
402 static struct option long_options[] = {
403 {"version", 0, 0, 'v'},
408 c = getopt_long (argc, argv, "vh", long_options, &option_index);
433 if (!strcmp(action, "resolve")) {
439 for (i = 2; i < argc; i++) {
440 addr = primary_address_of(argv[i]);
442 printf("%u\n", addr);
450 if (!strcmp(action, "send")) {
455 status = send_file (atoi(argv[ 2 ]), argv[ 3 ]);
456 } else if (!strcmp(action, "receive")) {
462 receive_file (extract_addr_of_string(argv[ 2 ]),
463 atoi(argv[ 3 ]), atoi(argv[ 4 ]), argv[ 5 ]);
464 } else if (!strcmp(action, "chat")) {
466 if (!strcmp(argv[ 2 ], "listen")) {
471 status = chat_listen(atoi(argv[ 3 ]));
472 } else if (!strcmp(argv[ 2 ], "connect")) {
477 status = chat_connect(extract_addr_of_string(argv[ 3 ]),
494 * compile-command: "gcc -DHAVE_STRTOUL -Wall -O6 -o dcc dcc.c"