Added cs to the list of languages
[midnight-commander.git] / vfs / tcputil.c
blob80ad8c5036fd8cd784186417715adc610b34e842
1 /* Server for the Midnight Commander Virtual File System.
2 Routines for the tcp connection, includes the primitive rpc routines.
4 Copyright (C) 1995, 1996 Miguel de Icaza
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public License
8 as published by the Free Software Foundation; either version 2 of
9 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 Library General Public License for more details.
16 You should have received a copy of the GNU Library General Public
17 License along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
20 #include <config.h>
21 #include <unistd.h>
22 #include <stdlib.h>
23 #include <stdarg.h>
24 #include <stdio.h>
25 #include <signal.h>
26 #include <pwd.h>
27 #include <sys/types.h>
28 #include <netdb.h>
29 #include <sys/socket.h>
30 #include <netinet/in.h>
31 #include <arpa/inet.h>
33 #ifdef HAVE_PMAP_SET
34 #include <rpc/rpc.h>
35 #include <rpc/pmap_prot.h>
36 #ifdef HAVE_RPC_PMAP_CLNT_H
37 #include <rpc/pmap_clnt.h>
38 #endif
39 #endif
41 #ifdef USE_TERMNET
42 #include <termnet.h>
43 #endif
45 #include <errno.h>
46 #include "tcputil.h"
47 #include "../src/dialog.h" /* for message () */
49 #include "utilvfs.h"
51 #include "mcfs.h" /* for mcserver_port definition */
53 #define CHECK_SIG_PIPE(sock) if (got_sigpipe) \
54 { tcp_invalidate_socket (sock); return got_sigpipe = 0; }
56 extern void tcp_invalidate_socket (int);
57 extern void vfs_die (char *);
59 int got_sigpipe;
61 /* Reads a block on dest for len bytes from sock */
62 /* Returns a boolean indicating the success status */
63 int socket_read_block (int sock, char *dest, int len)
65 int nread, n;
67 for (nread = 0; nread < len;){
68 n = read (sock, dest+nread, len-nread);
69 if (n <= 0){
70 tcp_invalidate_socket (sock);
71 return 0;
73 nread += n;
75 return 1;
78 int socket_write_block (int sock, char *buffer, int len)
80 int left, status;
82 for (left = len; left > 0;){
83 status = write (sock, buffer, left);
84 CHECK_SIG_PIPE (sock);
85 if (status < 0)
86 return 0;
87 left -= status;
88 buffer += status;
90 return 1;
93 int send_string (int sock, char *string)
95 return socket_write_block (sock, string, strlen (string));
98 int rpc_send (int sock, ...)
100 long int tmp, len, cmd;
101 char *text;
102 va_list ap;
104 va_start (ap, sock);
106 for (;;){
107 cmd = va_arg (ap, int);
108 switch (cmd){
109 case RPC_END:
110 va_end (ap);
111 return 1;
113 case RPC_INT:
114 tmp = htonl (va_arg (ap, int));
115 write (sock, &tmp, sizeof (tmp));
116 CHECK_SIG_PIPE (sock);
117 break;
119 case RPC_STRING:
120 text = va_arg (ap, char *);
121 len = strlen (text);
122 tmp = htonl (len);
123 write (sock, &tmp, sizeof (tmp));
124 CHECK_SIG_PIPE (sock);
125 write (sock, text, len);
126 CHECK_SIG_PIPE (sock);
127 break;
129 case RPC_BLOCK:
130 len = va_arg (ap, int);
131 text = va_arg (ap, char *);
132 tmp = htonl (len);
133 write (sock, text, len);
134 CHECK_SIG_PIPE (sock);
135 break;
137 default:
138 vfs_die ("Unknown rpc message\n");
143 typedef struct sock_callback_t {
144 int sock;
145 void (*cback)(int);
146 struct sock_callback_t *link;
147 } sock_callback_t;
149 sock_callback_t *sock_callbacks = 0;
151 static void check_hooks (int sock)
153 sock_callback_t *callback, *prev;
155 for (prev=callback = sock_callbacks; callback; callback = callback->link){
156 if (callback->sock != sock){
157 prev = callback;
158 continue;
160 callback->sock = -1;
161 (callback->cback)(sock);
162 if (callback == sock_callbacks){
163 sock_callbacks = callback->link;
164 } else {
165 prev->link = callback->link;
167 g_free (callback);
168 return;
172 int rpc_get (int sock, ...)
174 long int tmp, len;
175 char *text, **str_dest;
176 int *dest, cmd;
177 va_list ap;
179 va_start (ap, sock);
181 check_hooks (sock);
183 for (;;){
184 cmd = va_arg (ap, int);
185 switch (cmd){
186 case RPC_END:
187 va_end (ap);
188 return 1;
190 case RPC_INT:
191 if (socket_read_block (sock, (char *) &tmp, sizeof (tmp)) == 0)
192 return 0;
193 dest = va_arg (ap, int *);
194 *dest = ntohl (tmp);
195 break;
197 /* returns an allocated string */
198 case RPC_LIMITED_STRING:
199 case RPC_STRING:
200 if (socket_read_block (sock, (char *)&tmp, sizeof (tmp)) == 0)
201 return 0;
202 len = ntohl (tmp);
203 if (cmd == RPC_LIMITED_STRING)
204 if (len > 16*1024){
205 /* silently die */
206 abort ();
208 if (len > 128*1024)
209 abort ();
210 text = g_new0 (char, len+1);
211 if (socket_read_block (sock, text, len) == 0)
212 return 0;
213 str_dest = va_arg (ap, char **);
214 *str_dest = text;
215 text [len] = '\0';
216 break;
218 case RPC_BLOCK:
219 len = va_arg (ap, int);
220 text = va_arg (ap, char *);
221 if (socket_read_block (sock, text, len) == 0)
222 return 0;
223 break;
225 default:
226 vfs_die ("Unknown rpc message\n");
231 void rpc_add_get_callback (int sock, void (*cback)(int))
233 sock_callback_t *new;
235 new = g_new (sock_callback_t, 1);
236 new->cback = cback;
237 new->sock = sock;
238 new->link = sock_callbacks;
239 sock_callbacks = new;
242 #if defined(IS_AIX) || defined(linux) || defined(SCO_FLAVOR) \
243 || defined(__QNX__) || defined(__FreeBSD__) || defined(__bsdi__)
244 static void sig_pipe (int unused)
245 #else
246 static void sig_pipe (void)
247 #endif
249 got_sigpipe = 1;
252 void tcp_init (void)
254 struct sigaction sa;
256 got_sigpipe = 0;
257 sa.sa_handler = sig_pipe;
258 sa.sa_flags = 0;
259 sigemptyset (&sa.sa_mask);
260 sigaction (SIGPIPE, &sa, NULL);
263 int get_remote_port (struct sockaddr_in *sin, int *version)
265 #ifdef HAVE_PMAP_GETMAPS
266 int port;
267 struct pmaplist *pl;
269 *version = 1;
270 port = mcserver_port;
271 for (pl = pmap_getmaps (sin); pl; pl = pl->pml_next)
272 if (pl->pml_map.pm_prog == RPC_PROGNUM &&
273 pl->pml_map.pm_prot == IPPROTO_TCP &&
274 pl->pml_map.pm_vers >= *version) {
275 *version = pl->pml_map.pm_vers;
276 port = pl->pml_map.pm_port;
278 return port;
279 #else
280 #ifdef HAVE_PMAP_GETPORT
281 int port;
282 for (*version = RPC_PROGVER; *version >= 1; (*version)--)
283 if (port = pmap_getport (sin, RPC_PROGNUM, *version, IPPROTO_TCP))
284 return port;
285 #endif /* HAVE_PMAP_GETPORT */
286 #endif /* HAVE_PMAP_GETMAPS */
287 *version = 1;
288 return mcserver_port;