Initial git import
[sxemacs] / lib-src / 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
6  * Maintainer: umerin@mse.kyutech.ac.jp
7
8 This file is part of SXEmacs.
9
10 SXEmacs 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 3 of the License, or
13 (at your option) any later version.
14
15 SXEmacs 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 this program.  If not, see <http://www.gnu.org/licenses/>.
22
23  *
24  * Yasunari, Itoh at PFU limited contributed for Fujitsu UTS and SX/A.
25  *
26  * Thu Apr  6 13:47:37 JST 1989
27  * USG fixes by Sakaeda <saka@mickey.trad.pf.fujitsu.junet>
28  *
29  * For Fujitsu UTS compile with:
30  *      cc -O -o tcp tcp.c -DFUJITSU_UTS -lu -lsocket
31  */
32
33 #include <stdio.h>
34 #include <fcntl.h>
35 #include <ctype.h>
36 #include <sys/types.h>
37
38 #ifdef FUJITSU_UTS
39 #define USG
40 #include <sys/ucbtypes.h>
41 #include <sys/tisp/socket.h>
42 #include <netdb.h>
43 #include <sys/tisp/in.h>
44 #else
45 #include <sys/socket.h>
46 #include <netdb.h>
47 #include <netinet/in.h>
48 #endif
49
50 #ifdef USG
51 #include <sys/stat.h>
52 #include <signal.h>
53 #endif
54
55 #ifdef USG
56 int selectable = 1;
57
58 sigout()
59 {
60         fcntl(fileno(stdin), F_SETFL, 0);
61         exit(-1);
62 }
63 #endif
64
65 main(argc, argv)
66 int argc;
67 char *argv[];
68 {
69         struct hostent *host;
70         struct sockaddr_in sockin, sockme;
71         struct servent *serv;
72         char *hostname = NULL;
73         char *service = "nntp";
74         int port;
75         int readfds;
76         int writefds;
77         int server;             /* NNTP Server */
78         int emacsIn = fileno(stdin);    /* Emacs intput */
79         int emacsOut = fileno(stdout);  /* Emacs output */
80         char buffer[1024];
81         int nbuffer;            /* Number of bytes in buffer */
82         int wret;
83         char *retry;            /* retry bufferp */
84         int false = 0;          /* FALSE flag for setsockopt () */
85
86         if (argc < 2) {
87                 fprintf(stderr, "Usage: %s HOST [SERVICE]\n", argv[0]);
88                 exit(1);
89         }
90         if (argc >= 2)
91                 hostname = argv[1];
92         if (argc >= 3)
93                 service = argv[2];
94
95         if ((host = gethostbyname(hostname)) == NULL) {
96                 perror("gethostbyname");
97                 exit(1);
98         }
99         if (isdigit(service[0]))
100                 port = atoi(service);
101         else {
102                 serv = getservbyname(service, "tcp");
103                 if (serv == NULL) {
104                         perror("getservbyname");
105                         exit(1);
106                 }
107                 port = serv->s_port;
108         }
109
110         memset(&sockin, 0, sizeof(sockin));
111         sockin.sin_family = host->h_addrtype;
112         memcpy(&sockin.sin_addr, host->h_addr, host->h_length);
113         sockin.sin_port = port;
114         if ((server = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
115                 perror("socket");
116                 exit(1);
117         }
118         if (setsockopt(server, SOL_SOCKET, SO_REUSEADDR, &false, sizeof(false))) {
119                 perror("setsockopt");
120                 exit(1);
121         }
122         memset(&sockme, 0, sizeof(sockme));
123         sockme.sin_family = sockin.sin_family;
124         sockme.sin_addr.s_addr = INADDR_ANY;
125         if (bind(server, &sockme, sizeof(sockme)) < 0) {
126                 perror("bind");
127                 exit(1);
128         }
129         if (connect(server, &sockin, sizeof(sockin)) < 0) {
130                 perror("connect");
131                 close(server);
132                 exit(1);
133         }
134 #ifdef O_NDELAY
135         fcntl(server, F_SETFL, O_NDELAY);
136
137 #ifdef USG
138         /* USG pipe cannot not select emacsIn */
139         {
140                 struct stat statbuf;
141                 fstat(emacsIn, &statbuf);
142                 if (statbuf.st_mode & 010000)
143                         selectable = 0;
144                 if (!selectable) {
145                         signal(SIGINT, sigout);
146                         fcntl(emacsIn, F_SETFL, O_NDELAY);
147                 }
148         }
149 #endif
150 #endif
151
152         /* Connection established. */
153         while (1) {
154                 readfds = (1 << server) | (1 << emacsIn);
155                 if (select(32, &readfds, NULL, NULL, (struct timeval *)NULL) ==
156                     -1) {
157                         perror("select");
158                         exit(1);
159                 }
160                 if (readfds & (1 << emacsIn)) {
161                         /* From Emacs */
162                         nbuffer = read(emacsIn, buffer, sizeof buffer - 1);
163
164 #ifdef USG
165                         if (selectable && nbuffer == 0) {
166                                 goto finish;
167                         } else if (!(readfds & (1 << server)) && nbuffer == 0) {
168                                 sleep(1);
169                         } else
170 #else
171                         if (nbuffer == 0)
172                                 goto finish;
173 #endif
174                         for (retry = buffer; nbuffer > 0;
175                              nbuffer -= wret, retry += wret) {
176                                 writefds = 1 << server;
177                                 if (select
178                                     (server + 1, NULL, &writefds, NULL,
179                                      (struct timeval *)NULL) == -1) {
180                                         perror("select");
181                                         exit(1);
182                                 }
183                                 wret = write(server, retry, nbuffer);
184                                 if (wret < 0)
185                                         goto finish;
186                         }
187                 }
188                 if (readfds & (1 << server)) {
189                         /* From NNTP server */
190                         nbuffer = read(server, buffer, sizeof buffer - 1);
191                         if (nbuffer == 0)
192                                 goto finish;
193                         for (retry = buffer; nbuffer > 0;
194                              nbuffer -= wret, retry += wret) {
195                                 writefds = 1 << emacsOut;
196 #ifdef USG
197                                 if (selectable)
198 #endif
199                                         if (select
200                                             (emacsOut + 1, NULL, &writefds,
201                                              NULL,
202                                              (struct timeval *)NULL) == -1) {
203                                                 perror("select");
204                                                 exit(1);
205                                         }
206                                 wret = write(emacsOut, retry, nbuffer);
207                                 if (wret < 0)
208                                         goto finish;
209                         }
210                 }
211         }
212
213         /* End of communication. */
214       finish:
215         close(server);
216 #ifdef USG
217         if (!selectable)
218                 fcntl(emacsIn, F_SETFL, 0);
219 #endif
220         close(emacsIn);
221         close(emacsOut);
222         exit(0);
223 }