tcputil.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  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., 675 Mass Ave, Cambridge, MA 02139, 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. #include <arpa/inet.h>
  27. #include <malloc.h>
  28. #ifdef HAVE_PMAP_SET
  29. #include <rpc/rpc.h>
  30. #include <rpc/pmap_prot.h>
  31. #ifdef HAVE_RPC_PMAP_CLNT_H
  32. #include <rpc/pmap_clnt.h>
  33. #endif
  34. #endif
  35. #ifdef USE_TERMNET
  36. #include <termnet.h>
  37. #endif
  38. #include <errno.h>
  39. #include "tcputil.h"
  40. #include "../src/dialog.h" /* for message () */
  41. #include "../src/mem.h" /* for bcopy */
  42. #include "../src/util.h" /* for unix_error_string */
  43. #include "../src/mad.h"
  44. #include "mcfs.h" /* for mcserver_port definition */
  45. #define CHECK_SIG_PIPE(sock) if (got_sigpipe) \
  46. { tcp_invalidate_socket (sock); return got_sigpipe = 0; }
  47. extern void tcp_invalidate_socket (int);
  48. extern void vfs_die (char *);
  49. int got_sigpipe;
  50. /* Reads a block on dest for len bytes from sock */
  51. /* Returns a boolean indicating the success status */
  52. int socket_read_block (int sock, char *dest, int len)
  53. {
  54. int nread, n;
  55. for (nread = 0; nread < len;){
  56. n = read (sock, dest+nread, len-nread);
  57. if (n <= 0){
  58. tcp_invalidate_socket (sock);
  59. return 0;
  60. }
  61. nread += n;
  62. }
  63. return 1;
  64. }
  65. int socket_write_block (int sock, char *buffer, int len)
  66. {
  67. int left, status;
  68. for (left = len; left > 0;){
  69. status = write (sock, buffer, left);
  70. CHECK_SIG_PIPE (sock);
  71. if (status < 0)
  72. return 0;
  73. left -= status;
  74. buffer += status;
  75. }
  76. return 1;
  77. }
  78. int send_string (int sock, char *string)
  79. {
  80. return socket_write_block (sock, string, strlen (string));
  81. }
  82. int rpc_send (int sock, ...)
  83. {
  84. long int tmp, len, cmd;
  85. char *text;
  86. va_list ap;
  87. va_start (ap, sock);
  88. for (;;){
  89. cmd = va_arg (ap, int);
  90. switch (cmd){
  91. case RPC_END:
  92. va_end (ap);
  93. return 1;
  94. case RPC_INT:
  95. tmp = htonl (va_arg (ap, int));
  96. write (sock, &tmp, sizeof (tmp));
  97. CHECK_SIG_PIPE (sock);
  98. break;
  99. case RPC_STRING:
  100. text = va_arg (ap, char *);
  101. len = strlen (text);
  102. tmp = htonl (len);
  103. write (sock, &tmp, sizeof (tmp));
  104. CHECK_SIG_PIPE (sock);
  105. write (sock, text, len);
  106. CHECK_SIG_PIPE (sock);
  107. break;
  108. case RPC_BLOCK:
  109. len = va_arg (ap, int);
  110. text = va_arg (ap, char *);
  111. tmp = htonl (len);
  112. write (sock, text, len);
  113. CHECK_SIG_PIPE (sock);
  114. break;
  115. default:
  116. vfs_die ("Unknown rpc message\n");
  117. }
  118. }
  119. }
  120. typedef struct sock_callback_t {
  121. int sock;
  122. void (*cback)(int);
  123. struct sock_callback_t *link;
  124. } sock_callback_t;
  125. sock_callback_t *sock_callbacks = 0;
  126. static void check_hooks (int sock)
  127. {
  128. sock_callback_t *callback, *prev;
  129. for (prev=callback = sock_callbacks; callback; callback = callback->link){
  130. if (callback->sock != sock){
  131. prev = callback;
  132. continue;
  133. }
  134. callback->sock = -1;
  135. (callback->cback)(sock);
  136. if (callback == sock_callbacks){
  137. sock_callbacks = callback->link;
  138. } else {
  139. prev->link = callback->link;
  140. }
  141. free (callback);
  142. return;
  143. }
  144. }
  145. int rpc_get (int sock, ...)
  146. {
  147. long int tmp, len;
  148. char *text, **str_dest;
  149. int *dest, cmd;
  150. va_list ap;
  151. va_start (ap, sock);
  152. check_hooks (sock);
  153. for (;;){
  154. cmd = va_arg (ap, int);
  155. switch (cmd){
  156. case RPC_END:
  157. va_end (ap);
  158. return 1;
  159. case RPC_INT:
  160. if (socket_read_block (sock, (char *) &tmp, sizeof (tmp)) == 0)
  161. return 0;
  162. dest = va_arg (ap, int *);
  163. *dest = ntohl (tmp);
  164. break;
  165. /* returns an allocated string */
  166. case RPC_LIMITED_STRING:
  167. case RPC_STRING:
  168. if (socket_read_block (sock, (char *)&tmp, sizeof (tmp)) == 0)
  169. return 0;
  170. len = ntohl (tmp);
  171. if (cmd == RPC_LIMITED_STRING)
  172. if (len > 16*1024){
  173. /* silently die */
  174. abort ();
  175. }
  176. if (len > 128*1024)
  177. abort ();
  178. text = malloc (len+1);
  179. if (socket_read_block (sock, text, len) == 0)
  180. return 0;
  181. str_dest = va_arg (ap, char **);
  182. *str_dest = text;
  183. text [len] = 0;
  184. break;
  185. case RPC_BLOCK:
  186. len = va_arg (ap, int);
  187. text = va_arg (ap, char *);
  188. if (socket_read_block (sock, text, len) == 0)
  189. return 0;
  190. break;
  191. default:
  192. vfs_die ("Unknown rpc message\n");
  193. }
  194. }
  195. }
  196. void rpc_add_get_callback (int sock, void (*cback)(int))
  197. {
  198. sock_callback_t *new;
  199. new = malloc (sizeof (sock_callback_t));
  200. new->cback = cback;
  201. new->sock = sock;
  202. new->link = sock_callbacks;
  203. sock_callbacks = new;
  204. }
  205. #if defined(IS_AIX) || defined(linux) || defined(SCO_FLAVOR) || defined(__QNX__)
  206. static void sig_pipe (int unused)
  207. #else
  208. static void sig_pipe (void)
  209. #endif
  210. {
  211. got_sigpipe = 1;
  212. }
  213. void tcp_init (void)
  214. {
  215. struct sigaction sa;
  216. got_sigpipe = 0;
  217. sa.sa_handler = sig_pipe;
  218. sa.sa_flags = 0;
  219. sigemptyset (&sa.sa_mask);
  220. sigaction (SIGPIPE, &sa, NULL);
  221. }
  222. int get_remote_port (struct sockaddr_in *sin, int *version)
  223. {
  224. #ifdef HAVE_PMAP_GETMAPS
  225. int port;
  226. struct pmaplist *pl;
  227. *version = 1;
  228. port = mcserver_port;
  229. for (pl = pmap_getmaps (sin); pl; pl = pl->pml_next)
  230. if (pl->pml_map.pm_prog == RPC_PROGNUM &&
  231. pl->pml_map.pm_prot == IPPROTO_TCP &&
  232. pl->pml_map.pm_vers >= *version) {
  233. *version = pl->pml_map.pm_vers;
  234. port = pl->pml_map.pm_port;
  235. }
  236. return port;
  237. #else
  238. #ifdef HAVE_PMAP_GETPORT
  239. int port;
  240. for (*version = RPC_PROGVER; *version >= 1; (*version)--)
  241. if (port = pmap_getport (sin, RPC_PROGNUM, *version, IPPROTO_TCP))
  242. return port;
  243. #endif /* HAVE_PMAP_GETPORT */
  244. #endif /* HAVE_PMAP_GETMAPS */
  245. *version = 1;
  246. return mcserver_port;
  247. }