tcputil.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. /* Server for the Midnight Commander Virtual File System.
  2. Routines for the tcp connection, includes the primitive rpc routines.
  3. Copyright (C) 1995, 1996 Miguel de Icaza
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU Library General Public License
  6. as published by the Free Software Foundation; either version 2 of
  7. the License, or (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU Library General Public License for more details.
  12. You should have received a copy of the GNU Library General Public
  13. License along with this program; if not, write to the Free Software
  14. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
  15. #include <config.h>
  16. #include <unistd.h>
  17. #include <stdlib.h>
  18. #include <stdarg.h>
  19. #include <stdio.h>
  20. #include <signal.h>
  21. #include <pwd.h>
  22. #include <sys/types.h>
  23. #include <netdb.h>
  24. #include <sys/socket.h>
  25. #include <netinet/in.h>
  26. #ifdef HAVE_ARPA_INET_H
  27. #include <arpa/inet.h>
  28. #endif
  29. #ifdef HAVE_PMAP_SET
  30. #include <rpc/rpc.h>
  31. #include <rpc/pmap_prot.h>
  32. #ifdef HAVE_RPC_PMAP_CLNT_H
  33. #include <rpc/pmap_clnt.h>
  34. #endif
  35. #endif
  36. #include <errno.h>
  37. #include "tcputil.h"
  38. #include "../src/dialog.h" /* for message () */
  39. #include "utilvfs.h"
  40. #include "mcfs.h" /* for mcserver_port definition */
  41. #define CHECK_SIG_PIPE(sock) if (got_sigpipe) \
  42. { tcp_invalidate_socket (sock); return got_sigpipe = 0; }
  43. extern void tcp_invalidate_socket (int);
  44. extern void vfs_die (char *);
  45. int got_sigpipe;
  46. #ifdef WITH_MCFS
  47. /* Reads a block on dest for len bytes from sock */
  48. /* Returns a boolean indicating the success status */
  49. int socket_read_block (int sock, char *dest, int len)
  50. {
  51. int nread, n;
  52. for (nread = 0; nread < len;){
  53. n = read (sock, dest+nread, len-nread);
  54. if (n <= 0){
  55. tcp_invalidate_socket (sock);
  56. return 0;
  57. }
  58. nread += n;
  59. }
  60. return 1;
  61. }
  62. int socket_write_block (int sock, char *buffer, int len)
  63. {
  64. int left, status;
  65. for (left = len; left > 0;){
  66. status = write (sock, buffer, left);
  67. CHECK_SIG_PIPE (sock);
  68. if (status < 0)
  69. return 0;
  70. left -= status;
  71. buffer += status;
  72. }
  73. return 1;
  74. }
  75. int send_string (int sock, char *string)
  76. {
  77. return socket_write_block (sock, string, strlen (string));
  78. }
  79. int rpc_send (int sock, ...)
  80. {
  81. long int tmp, len, cmd;
  82. char *text;
  83. va_list ap;
  84. va_start (ap, sock);
  85. for (;;){
  86. cmd = va_arg (ap, int);
  87. switch (cmd){
  88. case RPC_END:
  89. va_end (ap);
  90. return 1;
  91. case RPC_INT:
  92. tmp = htonl (va_arg (ap, int));
  93. write (sock, &tmp, sizeof (tmp));
  94. CHECK_SIG_PIPE (sock);
  95. break;
  96. case RPC_STRING:
  97. text = va_arg (ap, char *);
  98. len = strlen (text);
  99. tmp = htonl (len);
  100. write (sock, &tmp, sizeof (tmp));
  101. CHECK_SIG_PIPE (sock);
  102. write (sock, text, len);
  103. CHECK_SIG_PIPE (sock);
  104. break;
  105. case RPC_BLOCK:
  106. len = va_arg (ap, int);
  107. text = va_arg (ap, char *);
  108. tmp = htonl (len);
  109. write (sock, text, len);
  110. CHECK_SIG_PIPE (sock);
  111. break;
  112. default:
  113. vfs_die ("Unknown rpc message\n");
  114. }
  115. }
  116. }
  117. typedef struct sock_callback_t {
  118. int sock;
  119. void (*cback)(int);
  120. struct sock_callback_t *link;
  121. } sock_callback_t;
  122. sock_callback_t *sock_callbacks = 0;
  123. static void check_hooks (int sock)
  124. {
  125. sock_callback_t *callback, *prev;
  126. for (prev=callback = sock_callbacks; callback; callback = callback->link){
  127. if (callback->sock != sock){
  128. prev = callback;
  129. continue;
  130. }
  131. callback->sock = -1;
  132. (callback->cback)(sock);
  133. if (callback == sock_callbacks){
  134. sock_callbacks = callback->link;
  135. } else {
  136. prev->link = callback->link;
  137. }
  138. g_free (callback);
  139. return;
  140. }
  141. }
  142. int rpc_get (int sock, ...)
  143. {
  144. long int tmp, len;
  145. char *text, **str_dest;
  146. int *dest, cmd;
  147. va_list ap;
  148. va_start (ap, sock);
  149. check_hooks (sock);
  150. for (;;){
  151. cmd = va_arg (ap, int);
  152. switch (cmd){
  153. case RPC_END:
  154. va_end (ap);
  155. return 1;
  156. case RPC_INT:
  157. if (socket_read_block (sock, (char *) &tmp, sizeof (tmp)) == 0){
  158. va_end (ap);
  159. return 0;
  160. }
  161. dest = va_arg (ap, int *);
  162. *dest = ntohl (tmp);
  163. break;
  164. /* returns an allocated string */
  165. case RPC_LIMITED_STRING:
  166. case RPC_STRING:
  167. if (socket_read_block (sock, (char *)&tmp, sizeof (tmp)) == 0){
  168. va_end (ap);
  169. return 0;
  170. }
  171. len = ntohl (tmp);
  172. if (cmd == RPC_LIMITED_STRING)
  173. if (len > 16*1024){
  174. /* silently die */
  175. abort ();
  176. }
  177. if (len > 128*1024)
  178. abort ();
  179. text = g_new0 (char, len+1);
  180. if (socket_read_block (sock, text, len) == 0){
  181. g_free (text);
  182. va_end (ap);
  183. return 0;
  184. }
  185. str_dest = va_arg (ap, char **);
  186. *str_dest = text;
  187. text [len] = '\0';
  188. break;
  189. case RPC_BLOCK:
  190. len = va_arg (ap, int);
  191. text = va_arg (ap, char *);
  192. if (socket_read_block (sock, text, len) == 0){
  193. va_end (ap);
  194. return 0;
  195. }
  196. break;
  197. default:
  198. vfs_die ("Unknown rpc message\n");
  199. }
  200. }
  201. }
  202. void rpc_add_get_callback (int sock, void (*cback)(int))
  203. {
  204. sock_callback_t *new;
  205. new = g_new (sock_callback_t, 1);
  206. new->cback = cback;
  207. new->sock = sock;
  208. new->link = sock_callbacks;
  209. sock_callbacks = new;
  210. }
  211. #endif /* WITH_MCFS */
  212. static void sig_pipe (int unused)
  213. {
  214. got_sigpipe = 1;
  215. }
  216. void tcp_init (void)
  217. {
  218. struct sigaction sa;
  219. got_sigpipe = 0;
  220. sa.sa_handler = sig_pipe;
  221. sa.sa_flags = 0;
  222. sigemptyset (&sa.sa_mask);
  223. sigaction (SIGPIPE, &sa, NULL);
  224. }
  225. #ifdef WITH_MCFS
  226. int get_remote_port (struct sockaddr_in *sin, int *version)
  227. {
  228. #ifdef HAVE_PMAP_GETMAPS
  229. int port;
  230. struct pmaplist *pl;
  231. *version = 1;
  232. port = mcserver_port;
  233. for (pl = pmap_getmaps (sin); pl; pl = pl->pml_next)
  234. if (pl->pml_map.pm_prog == RPC_PROGNUM &&
  235. pl->pml_map.pm_prot == IPPROTO_TCP &&
  236. pl->pml_map.pm_vers >= *version) {
  237. *version = pl->pml_map.pm_vers;
  238. port = pl->pml_map.pm_port;
  239. }
  240. return port;
  241. #else
  242. #ifdef HAVE_PMAP_GETPORT
  243. int port;
  244. for (*version = RPC_PROGVER; *version >= 1; (*version)--)
  245. if (port = pmap_getport (sin, RPC_PROGNUM, *version, IPPROTO_TCP))
  246. return port;
  247. #endif /* HAVE_PMAP_GETPORT */
  248. #endif /* HAVE_PMAP_GETMAPS */
  249. *version = 1;
  250. return mcserver_port;
  251. }
  252. #endif /* WITH_MCFS */