Just a fuzzy trim...
[midnight-commander.git] / vfs / tcputil.c
blob951643394ae4726f4740af23304ef4682ce92ad8
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 #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 va_end (ap);
193 return 0;
195 dest = va_arg (ap, int *);
196 *dest = ntohl (tmp);
197 break;
199 /* returns an allocated string */
200 case RPC_LIMITED_STRING:
201 case RPC_STRING:
202 if (socket_read_block (sock, (char *)&tmp, sizeof (tmp)) == 0){
203 va_end (ap);
204 return 0;
206 len = ntohl (tmp);
207 if (cmd == RPC_LIMITED_STRING)
208 if (len > 16*1024){
209 /* silently die */
210 abort ();
212 if (len > 128*1024)
213 abort ();
214 text = g_new0 (char, len+1);
215 if (socket_read_block (sock, text, len) == 0){
216 g_free (text);
217 va_end (ap);
218 return 0;
220 str_dest = va_arg (ap, char **);
221 *str_dest = text;
222 text [len] = '\0';
223 break;
225 case RPC_BLOCK:
226 len = va_arg (ap, int);
227 text = va_arg (ap, char *);
228 if (socket_read_block (sock, text, len) == 0){
229 va_end (ap);
230 return 0;
232 break;
234 default:
235 vfs_die ("Unknown rpc message\n");
240 void rpc_add_get_callback (int sock, void (*cback)(int))
242 sock_callback_t *new;
244 new = g_new (sock_callback_t, 1);
245 new->cback = cback;
246 new->sock = sock;
247 new->link = sock_callbacks;
248 sock_callbacks = new;
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 int get_remote_port (struct sockaddr_in *sin, int *version)
269 #ifdef HAVE_PMAP_GETMAPS
270 int port;
271 struct pmaplist *pl;
273 *version = 1;
274 port = mcserver_port;
275 for (pl = pmap_getmaps (sin); pl; pl = pl->pml_next)
276 if (pl->pml_map.pm_prog == RPC_PROGNUM &&
277 pl->pml_map.pm_prot == IPPROTO_TCP &&
278 pl->pml_map.pm_vers >= *version) {
279 *version = pl->pml_map.pm_vers;
280 port = pl->pml_map.pm_port;
282 return port;
283 #else
284 #ifdef HAVE_PMAP_GETPORT
285 int port;
286 for (*version = RPC_PROGVER; *version >= 1; (*version)--)
287 if (port = pmap_getport (sin, RPC_PROGNUM, *version, IPPROTO_TCP))
288 return port;
289 #endif /* HAVE_PMAP_GETPORT */
290 #endif /* HAVE_PMAP_GETMAPS */
291 *version = 1;
292 return mcserver_port;