*** empty log message ***
[midnight-commander.git] / vfs / tcputil.c
blob0aa7b64837e80e19c655c5e09682828a9a9c7215
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 #ifdef HAVE_ARPA_INET_H
32 #include <arpa/inet.h>
33 #endif
35 #ifdef HAVE_PMAP_SET
36 #include <rpc/rpc.h>
37 #include <rpc/pmap_prot.h>
38 #ifdef HAVE_RPC_PMAP_CLNT_H
39 #include <rpc/pmap_clnt.h>
40 #endif
41 #endif
43 #include <errno.h>
44 #include "tcputil.h"
45 #include "../src/dialog.h" /* for message () */
47 #include "utilvfs.h"
49 #include "mcfs.h" /* for mcserver_port definition */
51 #define CHECK_SIG_PIPE(sock) if (got_sigpipe) \
52 { tcp_invalidate_socket (sock); return got_sigpipe = 0; }
54 extern void tcp_invalidate_socket (int);
55 extern void vfs_die (char *);
57 int got_sigpipe;
59 #ifdef WITH_MCFS
60 /* Reads a block on dest for len bytes from sock */
61 /* Returns a boolean indicating the success status */
62 int socket_read_block (int sock, char *dest, int len)
64 int nread, n;
66 for (nread = 0; nread < len;){
67 n = read (sock, dest+nread, len-nread);
68 if (n <= 0){
69 tcp_invalidate_socket (sock);
70 return 0;
72 nread += n;
74 return 1;
77 int socket_write_block (int sock, char *buffer, int len)
79 int left, status;
81 for (left = len; left > 0;){
82 status = write (sock, buffer, left);
83 CHECK_SIG_PIPE (sock);
84 if (status < 0)
85 return 0;
86 left -= status;
87 buffer += status;
89 return 1;
92 int send_string (int sock, char *string)
94 return socket_write_block (sock, string, strlen (string));
97 int rpc_send (int sock, ...)
99 long int tmp, len, cmd;
100 char *text;
101 va_list ap;
103 va_start (ap, sock);
105 for (;;){
106 cmd = va_arg (ap, int);
107 switch (cmd){
108 case RPC_END:
109 va_end (ap);
110 return 1;
112 case RPC_INT:
113 tmp = htonl (va_arg (ap, int));
114 write (sock, &tmp, sizeof (tmp));
115 CHECK_SIG_PIPE (sock);
116 break;
118 case RPC_STRING:
119 text = va_arg (ap, char *);
120 len = strlen (text);
121 tmp = htonl (len);
122 write (sock, &tmp, sizeof (tmp));
123 CHECK_SIG_PIPE (sock);
124 write (sock, text, len);
125 CHECK_SIG_PIPE (sock);
126 break;
128 case RPC_BLOCK:
129 len = va_arg (ap, int);
130 text = va_arg (ap, char *);
131 tmp = htonl (len);
132 write (sock, text, len);
133 CHECK_SIG_PIPE (sock);
134 break;
136 default:
137 vfs_die ("Unknown rpc message\n");
142 typedef struct sock_callback_t {
143 int sock;
144 void (*cback)(int);
145 struct sock_callback_t *link;
146 } sock_callback_t;
148 sock_callback_t *sock_callbacks = 0;
150 static void check_hooks (int sock)
152 sock_callback_t *callback, *prev;
154 for (prev=callback = sock_callbacks; callback; callback = callback->link){
155 if (callback->sock != sock){
156 prev = callback;
157 continue;
159 callback->sock = -1;
160 (callback->cback)(sock);
161 if (callback == sock_callbacks){
162 sock_callbacks = callback->link;
163 } else {
164 prev->link = callback->link;
166 g_free (callback);
167 return;
171 int rpc_get (int sock, ...)
173 long int tmp, len;
174 char *text, **str_dest;
175 int *dest, cmd;
176 va_list ap;
178 va_start (ap, sock);
180 check_hooks (sock);
182 for (;;){
183 cmd = va_arg (ap, int);
184 switch (cmd){
185 case RPC_END:
186 va_end (ap);
187 return 1;
189 case RPC_INT:
190 if (socket_read_block (sock, (char *) &tmp, sizeof (tmp)) == 0){
191 va_end (ap);
192 return 0;
194 dest = va_arg (ap, int *);
195 *dest = ntohl (tmp);
196 break;
198 /* returns an allocated string */
199 case RPC_LIMITED_STRING:
200 case RPC_STRING:
201 if (socket_read_block (sock, (char *)&tmp, sizeof (tmp)) == 0){
202 va_end (ap);
203 return 0;
205 len = ntohl (tmp);
206 if (cmd == RPC_LIMITED_STRING)
207 if (len > 16*1024){
208 /* silently die */
209 abort ();
211 if (len > 128*1024)
212 abort ();
213 text = g_new0 (char, len+1);
214 if (socket_read_block (sock, text, len) == 0){
215 g_free (text);
216 va_end (ap);
217 return 0;
219 str_dest = va_arg (ap, char **);
220 *str_dest = text;
221 text [len] = '\0';
222 break;
224 case RPC_BLOCK:
225 len = va_arg (ap, int);
226 text = va_arg (ap, char *);
227 if (socket_read_block (sock, text, len) == 0){
228 va_end (ap);
229 return 0;
231 break;
233 default:
234 vfs_die ("Unknown rpc message\n");
239 void rpc_add_get_callback (int sock, void (*cback)(int))
241 sock_callback_t *new;
243 new = g_new (sock_callback_t, 1);
244 new->cback = cback;
245 new->sock = sock;
246 new->link = sock_callbacks;
247 sock_callbacks = new;
249 #endif /* WITH_MCFS */
251 static void sig_pipe (int unused)
253 got_sigpipe = 1;
256 void tcp_init (void)
258 struct sigaction sa;
260 got_sigpipe = 0;
261 sa.sa_handler = sig_pipe;
262 sa.sa_flags = 0;
263 sigemptyset (&sa.sa_mask);
264 sigaction (SIGPIPE, &sa, NULL);
267 #ifdef WITH_MCFS
268 int get_remote_port (struct sockaddr_in *sin, int *version)
270 #ifdef HAVE_PMAP_GETMAPS
271 int port;
272 struct pmaplist *pl;
274 *version = 1;
275 port = mcserver_port;
276 for (pl = pmap_getmaps (sin); pl; pl = pl->pml_next)
277 if (pl->pml_map.pm_prog == RPC_PROGNUM &&
278 pl->pml_map.pm_prot == IPPROTO_TCP &&
279 pl->pml_map.pm_vers >= *version) {
280 *version = pl->pml_map.pm_vers;
281 port = pl->pml_map.pm_port;
283 return port;
284 #else
285 #ifdef HAVE_PMAP_GETPORT
286 int port;
287 for (*version = RPC_PROGVER; *version >= 1; (*version)--)
288 if (port = pmap_getport (sin, RPC_PROGNUM, *version, IPPROTO_TCP))
289 return port;
290 #endif /* HAVE_PMAP_GETPORT */
291 #endif /* HAVE_PMAP_GETMAPS */
292 *version = 1;
293 return mcserver_port;
295 #endif /* WITH_MCFS */