Importing Liece 1.4.3.
[elisp/liece.git] / dcc / tcp.c
1 /*
2  * TCP/IP stream emulation for GNU Emacs.
3  * Copyright (C) 1988, 1989, 1992, 1993 Free Software Foundation, Inc.
4
5  * Author: Masanobu Umeda <umerin@mse.kyutech.ac.jp>
6  *         Daiki Ueno <daiki@kiss.kake.info.waseda.ac.jp>
7
8 This file is part of GNU Emacs.
9
10 GNU Emacs is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2, or (at your option)
13 any later version.
14
15 GNU Emacs is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with GNU Emacs; see the file COPYING.  If not, write to
22 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 Boston, MA 02111-1307, USA.
24  */
25
26 #include <sys/types.h>
27 #include <sys/time.h>
28 #include <sys/socket.h>
29 #include <sys/file.h>
30 #include <sys/ioctl.h>
31 #include <sys/stat.h>
32 #include <sys/time.h>
33 #include <netdb.h>
34 #include <stdio.h>
35 #include <signal.h>
36 #include <fcntl.h>
37 #include <netinet/in.h>
38 #define _GNU_SOURCE
39 #include <getopt.h>
40
41 #ifdef HAVE_SOCKS_H
42 #include <socks.h>
43 #endif 
44
45 #ifndef HAVE_GETADDRINFO
46 #include "getaddrinfo.h"
47 #endif /* !HAVE_GETADDRINFO */
48
49 #ifdef HAVE_BASENAME
50 # ifdef HAVE_LIBGEN_H
51 #  include <libgen.h>
52 #  ifdef basename
53 #   undef basename
54 #  endif
55 # endif
56 # include <string.h>
57 #else
58 # define basename(path) (rindex((path), '/') + 1)
59 #endif
60
61 #ifndef NI_MAXHOST
62 # define NI_MAXHOST 1025
63 #endif
64
65 static char *progname;
66
67 void version () {
68         printf("%s (Liece) 1.4.0\n"
69                "Copyright (C) 1998, 1999 Daiki Ueno\n"
70                "This is free software; see the source for copying conditions.  There is NO\n"
71                "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n", 
72                progname);
73 }
74
75 void usage() {
76   printf("Usage: %s [options] host [service]\n", progname);
77 }
78
79 \f
80 main (argc, argv)
81   int argc;
82   char *argv[];
83 {
84   struct protoent *proto;
85
86   struct addrinfo *in, hints;
87
88   char *hostname = NULL, *service = "ircd";
89   int family, port;
90   fd_set *readfds, *writefds;
91   int server, emacsIn = fileno (stdin), emacsOut = fileno (stdout); 
92   char buffer[1024], *retry;
93   int nbuffer, wret, false = 0;
94   int c;
95   
96   progname = (char *) basename (argv[0]);
97
98   while (1) {
99     int this_option_optind = optind ? optind : 1;
100     int option_index = 0;
101     static struct option long_options[] =       {
102       {"version", 0, 0, 'v'},
103       {"help", 0, 0, 'h'},
104       {0, 0, 0, 0}
105     };
106     
107     c = getopt_long (argc, argv, "vh", long_options, &option_index);
108     if (c == -1)
109       break;
110     
111     switch (c) {
112     case 'v':
113       version();
114       exit(1);
115       break;
116     case 'h':
117       usage();
118       exit(1);
119       break;
120     default:
121       break;
122     }
123   }
124   
125   if (argc < 2)
126     {
127       usage();
128       exit (1);
129     }
130   if (argc >= 2)
131     hostname = argv[1];
132   if (argc >= 3)
133     service = argv[2];
134   
135   if ((proto = getprotobyname ("tcp")) == NULL) {
136     perror ("getprotobyname");
137     exit (1);
138   }
139   
140   memset (&hints, 0, sizeof (hints));
141   hints.ai_family = AF_UNSPEC;
142   hints.ai_socktype = SOCK_STREAM;
143   hints.ai_protocol = proto->p_proto;
144   if (getaddrinfo (hostname, service, &hints, &in) < 0) {
145     perror ("getaddrinfo");
146     exit (1);
147   }
148
149   if ((server = socket (in->ai_family, in->ai_socktype, 0)) < 0) {
150     perror ("socket");
151     exit (1);
152   }
153
154   if (setsockopt (server, SOL_SOCKET, SO_REUSEADDR, 
155                   (const char *) &false, sizeof (false))) {
156     perror ("setsockopt");
157     exit (1);
158   }
159
160   if (connect (server, in->ai_addr, in->ai_addrlen) < 0) {
161     perror ("connect");
162     close (server);
163     exit (1);
164   }
165
166 #ifdef O_NDELAY
167   fcntl (server, F_SETFL, O_NDELAY);
168 #endif /* O_NDELAY */
169
170   /* Connection established. */
171
172   readfds = (fd_set *) calloc(server + 1, sizeof (fd_mask));
173   writefds = (fd_set *) calloc(server + 1, sizeof (fd_mask));
174
175   while (1)
176     {
177       FD_SET (server, readfds);
178       FD_SET (emacsIn, readfds);
179       if (select (server+1, readfds, NULL, NULL, NULL) == -1)
180         {
181           perror ("select");
182           exit (1);
183         }
184       if (FD_ISSET (emacsIn, readfds))
185         {
186           /* From Emacs */
187           nbuffer = read (emacsIn, buffer, sizeof buffer -1);
188
189           if (nbuffer == 0)
190             goto finish;
191           for (retry = buffer; nbuffer > 0; nbuffer -= wret, retry += wret)
192             {
193               FD_SET (server, writefds);
194               if (select (server+1, NULL, writefds, NULL, NULL) == -1)
195                 {
196                   perror ("select");
197                   exit (1);
198                 }
199               wret = write (server, retry, nbuffer);
200               if (wret < 0) goto finish;
201             }
202         }
203       if (FD_ISSET (server, readfds))
204         {
205           /* From NNTP server */
206           nbuffer = read (server, buffer, sizeof buffer -1);
207           if (nbuffer == 0)
208             goto finish;
209           for (retry = buffer; nbuffer > 0; nbuffer -= wret, retry += wret)
210             {
211               FD_SET (emacsOut, writefds);
212               if (select (emacsOut+1, NULL, writefds, NULL, NULL) == -1)
213                 {
214                   perror ("select");
215                   exit (1);
216                 }
217               wret = write (emacsOut, retry, nbuffer);
218               if (wret < 0) goto finish;
219             }
220         }
221     }
222
223   /* End of communication. */
224  finish:
225   close (server);
226   close (emacsIn);
227   close (emacsOut);
228   exit (0);
229 }