]>
Commit | Line | Data |
---|---|---|
28f540f4 RM |
1 | /* @(#)svc_tcp.c 2.2 88/08/01 4.0 RPCSRC */ |
2 | /* | |
3 | * Sun RPC is a product of Sun Microsystems, Inc. and is provided for | |
4 | * unrestricted use provided that this legend is included on all tape | |
5 | * media and as a part of the software program in whole or part. Users | |
6 | * may copy or modify Sun RPC without charge, but are not authorized | |
7 | * to license or distribute it to anyone else except as part of a product or | |
8 | * program developed by the user. | |
cbd3dceb | 9 | * |
28f540f4 RM |
10 | * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE |
11 | * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR | |
12 | * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. | |
cbd3dceb | 13 | * |
28f540f4 RM |
14 | * Sun RPC is provided with no support and without any obligation on the |
15 | * part of Sun Microsystems, Inc. to assist in its use, correction, | |
16 | * modification or enhancement. | |
cbd3dceb | 17 | * |
28f540f4 RM |
18 | * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE |
19 | * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC | |
20 | * OR ANY PART THEREOF. | |
cbd3dceb | 21 | * |
28f540f4 RM |
22 | * In no event will Sun Microsystems, Inc. be liable for any lost revenue |
23 | * or profits or other special, indirect and consequential damages, even if | |
24 | * Sun has been advised of the possibility of such damages. | |
cbd3dceb | 25 | * |
28f540f4 RM |
26 | * Sun Microsystems, Inc. |
27 | * 2550 Garcia Avenue | |
28 | * Mountain View, California 94043 | |
29 | */ | |
30 | #if !defined(lint) && defined(SCCSIDS) | |
31 | static char sccsid[] = "@(#)svc_tcp.c 1.21 87/08/11 Copyr 1984 Sun Micro"; | |
32 | #endif | |
33 | ||
34 | /* | |
cbd3dceb | 35 | * svc_tcp.c, Server side for TCP/IP based RPC. |
28f540f4 RM |
36 | * |
37 | * Copyright (C) 1984, Sun Microsystems, Inc. | |
38 | * | |
39 | * Actually implements two flavors of transporter - | |
6d52618b | 40 | * a tcp rendezvouser (a listener and connection establisher) |
28f540f4 RM |
41 | * and a record/tcp stream. |
42 | */ | |
43 | ||
44 | #include <stdio.h> | |
e7fd8a39 UD |
45 | #include <unistd.h> |
46 | #include <string.h> | |
28f540f4 RM |
47 | #include <rpc/rpc.h> |
48 | #include <sys/socket.h> | |
49 | #include <errno.h> | |
e7fd8a39 | 50 | #include <stdlib.h> |
28f540f4 RM |
51 | |
52 | /* | |
53 | * Ops vector for TCP/IP based rpc service handle | |
54 | */ | |
e7fd8a39 UD |
55 | static bool_t svctcp_recv (SVCXPRT *, struct rpc_msg *); |
56 | static enum xprt_stat svctcp_stat (SVCXPRT *); | |
57 | static bool_t svctcp_getargs (SVCXPRT *, xdrproc_t, caddr_t); | |
58 | static bool_t svctcp_reply (SVCXPRT *, struct rpc_msg *); | |
59 | static bool_t svctcp_freeargs (SVCXPRT *, xdrproc_t, caddr_t); | |
60 | static void svctcp_destroy (SVCXPRT *); | |
61 | ||
62 | static const struct xp_ops svctcp_op = | |
63 | { | |
64 | svctcp_recv, | |
65 | svctcp_stat, | |
66 | svctcp_getargs, | |
67 | svctcp_reply, | |
68 | svctcp_freeargs, | |
69 | svctcp_destroy | |
28f540f4 RM |
70 | }; |
71 | ||
72 | /* | |
73 | * Ops vector for TCP/IP rendezvous handler | |
74 | */ | |
e7fd8a39 UD |
75 | static bool_t rendezvous_request (SVCXPRT *, struct rpc_msg *); |
76 | static enum xprt_stat rendezvous_stat (SVCXPRT *); | |
77 | ||
78 | static const struct xp_ops svctcp_rendezvous_op = | |
79 | { | |
80 | rendezvous_request, | |
81 | rendezvous_stat, | |
82 | (bool_t (*) (SVCXPRT *, xdrproc_t, caddr_t)) abort, | |
83 | (bool_t (*) (SVCXPRT *, struct rpc_msg *)) abort, | |
84 | (bool_t (*) (SVCXPRT *, xdrproc_t, caddr_t)) abort, | |
85 | svctcp_destroy | |
28f540f4 RM |
86 | }; |
87 | ||
e7fd8a39 UD |
88 | static int readtcp (char*, char *, int); |
89 | static int writetcp (char *, char *, int); | |
90 | static SVCXPRT *makefd_xprt (int, u_int, u_int); | |
28f540f4 | 91 | |
e7fd8a39 UD |
92 | struct tcp_rendezvous |
93 | { /* kept in xprt->xp_p1 */ | |
94 | u_int sendsize; | |
95 | u_int recvsize; | |
96 | }; | |
28f540f4 | 97 | |
e7fd8a39 UD |
98 | struct tcp_conn |
99 | { /* kept in xprt->xp_p1 */ | |
100 | enum xprt_stat strm_stat; | |
101 | u_long x_id; | |
102 | XDR xdrs; | |
103 | char verf_body[MAX_AUTH_BYTES]; | |
104 | }; | |
28f540f4 RM |
105 | |
106 | /* | |
107 | * Usage: | |
e7fd8a39 | 108 | * xprt = svctcp_create(sock, send_buf_size, recv_buf_size); |
28f540f4 RM |
109 | * |
110 | * Creates, registers, and returns a (rpc) tcp based transporter. | |
111 | * Once *xprt is initialized, it is registered as a transporter | |
112 | * see (svc.h, xprt_register). This routine returns | |
113 | * a NULL if a problem occurred. | |
114 | * | |
115 | * If sock<0 then a socket is created, else sock is used. | |
116 | * If the socket, sock is not bound to a port then svctcp_create | |
117 | * binds it to an arbitrary port. The routine then starts a tcp | |
118 | * listener on the socket's associated port. In any (successful) case, | |
119 | * xprt->xp_sock is the registered socket number and xprt->xp_port is the | |
120 | * associated port number. | |
121 | * | |
122 | * Since tcp streams do buffered io similar to stdio, the caller can specify | |
123 | * how big the send and receive buffers are via the second and third parms; | |
124 | * 0 => use the system default. | |
125 | */ | |
126 | SVCXPRT * | |
e7fd8a39 | 127 | svctcp_create (int sock, u_int sendsize, u_int recvsize) |
28f540f4 | 128 | { |
e7fd8a39 UD |
129 | bool_t madesock = FALSE; |
130 | SVCXPRT *xprt; | |
131 | struct tcp_rendezvous *r; | |
132 | struct sockaddr_in addr; | |
f671aeab | 133 | size_t len = sizeof (struct sockaddr_in); |
e7fd8a39 UD |
134 | |
135 | if (sock == RPC_ANYSOCK) | |
136 | { | |
137 | if ((sock = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) | |
138 | { | |
139 | perror (_("svctcp_.c - udp socket creation problem")); | |
140 | return (SVCXPRT *) NULL; | |
28f540f4 | 141 | } |
e7fd8a39 UD |
142 | madesock = TRUE; |
143 | } | |
144 | bzero ((char *) &addr, sizeof (addr)); | |
145 | addr.sin_family = AF_INET; | |
146 | if (bindresvport (sock, &addr)) | |
147 | { | |
148 | addr.sin_port = 0; | |
149 | (void) bind (sock, (struct sockaddr *) &addr, len); | |
150 | } | |
151 | if ((getsockname (sock, (struct sockaddr *) &addr, &len) != 0) || | |
152 | (listen (sock, 2) != 0)) | |
153 | { | |
154 | perror (_("svctcp_.c - cannot getsockname or listen")); | |
155 | if (madesock) | |
156 | (void) close (sock); | |
157 | return (SVCXPRT *) NULL; | |
158 | } | |
159 | r = (struct tcp_rendezvous *) mem_alloc (sizeof (*r)); | |
160 | if (r == NULL) | |
161 | { | |
162 | (void) fputs (_("svctcp_create: out of memory\n"), stderr); | |
163 | return NULL; | |
164 | } | |
165 | r->sendsize = sendsize; | |
166 | r->recvsize = recvsize; | |
167 | xprt = (SVCXPRT *) mem_alloc (sizeof (SVCXPRT)); | |
168 | if (xprt == NULL) | |
169 | { | |
170 | (void) fputs (_("svctcp_create: out of memory\n"), stderr); | |
171 | return NULL; | |
172 | } | |
173 | xprt->xp_p2 = NULL; | |
174 | xprt->xp_p1 = (caddr_t) r; | |
175 | xprt->xp_verf = _null_auth; | |
176 | xprt->xp_ops = &svctcp_rendezvous_op; | |
177 | xprt->xp_port = ntohs (addr.sin_port); | |
178 | xprt->xp_sock = sock; | |
179 | xprt_register (xprt); | |
180 | return xprt; | |
28f540f4 RM |
181 | } |
182 | ||
183 | /* | |
184 | * Like svtcp_create(), except the routine takes any *open* UNIX file | |
185 | * descriptor as its first input. | |
186 | */ | |
187 | SVCXPRT * | |
e7fd8a39 | 188 | svcfd_create (int fd, u_int sendsize, u_int recvsize) |
28f540f4 | 189 | { |
e7fd8a39 | 190 | return makefd_xprt (fd, sendsize, recvsize); |
28f540f4 RM |
191 | } |
192 | ||
193 | static SVCXPRT * | |
e7fd8a39 | 194 | makefd_xprt (int fd, u_int sendsize, u_int recvsize) |
28f540f4 | 195 | { |
e7fd8a39 UD |
196 | SVCXPRT *xprt; |
197 | struct tcp_conn *cd; | |
198 | ||
199 | xprt = (SVCXPRT *) mem_alloc (sizeof (SVCXPRT)); | |
200 | if (xprt == (SVCXPRT *) NULL) | |
201 | { | |
202 | (void) fputs (_("svc_tcp: makefd_xprt: out of memory\n"), stderr); | |
203 | goto done; | |
204 | } | |
205 | cd = (struct tcp_conn *) mem_alloc (sizeof (struct tcp_conn)); | |
206 | if (cd == (struct tcp_conn *) NULL) | |
207 | { | |
208 | (void) fputs (_("svc_tcp: makefd_xprt: out of memory\n"), stderr); | |
209 | mem_free ((char *) xprt, sizeof (SVCXPRT)); | |
210 | xprt = (SVCXPRT *) NULL; | |
211 | goto done; | |
212 | } | |
213 | cd->strm_stat = XPRT_IDLE; | |
214 | xdrrec_create (&(cd->xdrs), sendsize, recvsize, | |
215 | (caddr_t) xprt, readtcp, writetcp); | |
216 | xprt->xp_p2 = NULL; | |
217 | xprt->xp_p1 = (caddr_t) cd; | |
218 | xprt->xp_verf.oa_base = cd->verf_body; | |
219 | xprt->xp_addrlen = 0; | |
220 | xprt->xp_ops = &svctcp_op; /* truly deals with calls */ | |
221 | xprt->xp_port = 0; /* this is a connection, not a rendezvouser */ | |
222 | xprt->xp_sock = fd; | |
223 | xprt_register (xprt); | |
224 | done: | |
225 | return xprt; | |
28f540f4 RM |
226 | } |
227 | ||
228 | static bool_t | |
e7fd8a39 | 229 | rendezvous_request (SVCXPRT *xprt, struct rpc_msg *errmsg) |
28f540f4 | 230 | { |
e7fd8a39 UD |
231 | int sock; |
232 | struct tcp_rendezvous *r; | |
233 | struct sockaddr_in addr; | |
f671aeab | 234 | size_t len; |
e7fd8a39 UD |
235 | |
236 | r = (struct tcp_rendezvous *) xprt->xp_p1; | |
237 | again: | |
238 | len = sizeof (struct sockaddr_in); | |
239 | if ((sock = accept (xprt->xp_sock, (struct sockaddr *) &addr, | |
240 | &len)) < 0) | |
241 | { | |
242 | if (errno == EINTR) | |
243 | goto again; | |
244 | return FALSE; | |
245 | } | |
246 | /* | |
247 | * make a new transporter (re-uses xprt) | |
248 | */ | |
249 | xprt = makefd_xprt (sock, r->sendsize, r->recvsize); | |
250 | xprt->xp_raddr = addr; | |
251 | xprt->xp_addrlen = len; | |
252 | return FALSE; /* there is never an rpc msg to be processed */ | |
28f540f4 RM |
253 | } |
254 | ||
255 | static enum xprt_stat | |
e7fd8a39 | 256 | rendezvous_stat (SVCXPRT *xprt) |
28f540f4 | 257 | { |
e7fd8a39 | 258 | return XPRT_IDLE; |
28f540f4 RM |
259 | } |
260 | ||
261 | static void | |
e7fd8a39 | 262 | svctcp_destroy (SVCXPRT *xprt) |
28f540f4 | 263 | { |
e7fd8a39 UD |
264 | struct tcp_conn *cd = (struct tcp_conn *) xprt->xp_p1; |
265 | ||
266 | xprt_unregister (xprt); | |
267 | (void) close (xprt->xp_sock); | |
268 | if (xprt->xp_port != 0) | |
269 | { | |
270 | /* a rendezvouser socket */ | |
271 | xprt->xp_port = 0; | |
272 | } | |
273 | else | |
274 | { | |
275 | /* an actual connection socket */ | |
276 | XDR_DESTROY (&(cd->xdrs)); | |
277 | } | |
278 | mem_free ((caddr_t) cd, sizeof (struct tcp_conn)); | |
279 | mem_free ((caddr_t) xprt, sizeof (SVCXPRT)); | |
28f540f4 RM |
280 | } |
281 | ||
282 | /* | |
283 | * All read operations timeout after 35 seconds. | |
284 | * A timeout is fatal for the connection. | |
285 | */ | |
e7fd8a39 UD |
286 | static struct timeval wait_per_try = |
287 | {35, 0}; | |
28f540f4 RM |
288 | |
289 | /* | |
6d52618b | 290 | * reads data from the tcp connection. |
28f540f4 RM |
291 | * any error is fatal and the connection is closed. |
292 | * (And a read of zero bytes is a half closed stream => error.) | |
293 | */ | |
294 | static int | |
e7fd8a39 | 295 | readtcp (char *xprtptr, char *buf, int len) |
28f540f4 | 296 | { |
e7fd8a39 UD |
297 | SVCXPRT *xprt = (SVCXPRT *)xprtptr; |
298 | int sock = xprt->xp_sock; | |
28f540f4 | 299 | #ifdef FD_SETSIZE |
e7fd8a39 UD |
300 | fd_set mask; |
301 | fd_set readfds; | |
28f540f4 | 302 | |
e7fd8a39 UD |
303 | FD_ZERO (&mask); |
304 | FD_SET (sock, &mask); | |
28f540f4 | 305 | #else |
e7fd8a39 UD |
306 | int mask = 1 << sock; |
307 | int readfds; | |
28f540f4 | 308 | #endif /* def FD_SETSIZE */ |
e7fd8a39 UD |
309 | do |
310 | { | |
311 | struct timeval timeout = wait_per_try; | |
312 | readfds = mask; | |
313 | if (select (_rpc_dtablesize (), &readfds, (fd_set *) NULL, | |
314 | (fd_set *) NULL, &timeout) <= 0) | |
315 | { | |
316 | if (errno == EINTR) | |
317 | { | |
318 | continue; | |
319 | } | |
320 | goto fatal_err; | |
321 | } | |
28f540f4 | 322 | #ifdef FD_SETSIZE |
e7fd8a39 UD |
323 | } |
324 | while (!FD_ISSET (sock, &readfds)); | |
28f540f4 | 325 | #else |
e7fd8a39 UD |
326 | } |
327 | while (readfds != mask); | |
28f540f4 | 328 | #endif /* def FD_SETSIZE */ |
e7fd8a39 UD |
329 | if ((len = read (sock, buf, len)) > 0) |
330 | { | |
331 | return len; | |
332 | } | |
28f540f4 | 333 | fatal_err: |
e7fd8a39 UD |
334 | ((struct tcp_conn *) (xprt->xp_p1))->strm_stat = XPRT_DIED; |
335 | return -1; | |
28f540f4 RM |
336 | } |
337 | ||
338 | /* | |
339 | * writes data to the tcp connection. | |
340 | * Any error is fatal and the connection is closed. | |
341 | */ | |
342 | static int | |
e7fd8a39 | 343 | writetcp (char *xprtptr, char * buf, int len) |
28f540f4 | 344 | { |
e7fd8a39 UD |
345 | SVCXPRT *xprt = (SVCXPRT *)xprtptr; |
346 | int i, cnt; | |
347 | ||
348 | for (cnt = len; cnt > 0; cnt -= i, buf += i) | |
349 | { | |
350 | if ((i = write (xprt->xp_sock, buf, cnt)) < 0) | |
351 | { | |
352 | ((struct tcp_conn *) (xprt->xp_p1))->strm_stat = | |
353 | XPRT_DIED; | |
354 | return (-1); | |
28f540f4 | 355 | } |
e7fd8a39 UD |
356 | } |
357 | return (len); | |
28f540f4 RM |
358 | } |
359 | ||
360 | static enum xprt_stat | |
e7fd8a39 | 361 | svctcp_stat (SVCXPRT *xprt) |
28f540f4 | 362 | { |
e7fd8a39 UD |
363 | struct tcp_conn *cd = |
364 | (struct tcp_conn *) (xprt->xp_p1); | |
365 | ||
366 | if (cd->strm_stat == XPRT_DIED) | |
367 | return (XPRT_DIED); | |
368 | if (!xdrrec_eof (&(cd->xdrs))) | |
369 | return (XPRT_MOREREQS); | |
370 | return (XPRT_IDLE); | |
28f540f4 RM |
371 | } |
372 | ||
373 | static bool_t | |
e7fd8a39 UD |
374 | svctcp_recv (xprt, msg) |
375 | SVCXPRT *xprt; | |
376 | struct rpc_msg *msg; | |
28f540f4 | 377 | { |
e7fd8a39 UD |
378 | struct tcp_conn *cd = |
379 | (struct tcp_conn *) (xprt->xp_p1); | |
380 | XDR *xdrs = &(cd->xdrs); | |
381 | ||
382 | xdrs->x_op = XDR_DECODE; | |
383 | (void) xdrrec_skiprecord (xdrs); | |
384 | if (xdr_callmsg (xdrs, msg)) | |
385 | { | |
386 | cd->x_id = msg->rm_xid; | |
387 | return (TRUE); | |
388 | } | |
389 | return (FALSE); | |
28f540f4 RM |
390 | } |
391 | ||
392 | static bool_t | |
e7fd8a39 UD |
393 | svctcp_getargs (xprt, xdr_args, args_ptr) |
394 | SVCXPRT *xprt; | |
395 | xdrproc_t xdr_args; | |
396 | caddr_t args_ptr; | |
28f540f4 RM |
397 | { |
398 | ||
e7fd8a39 | 399 | return ((*xdr_args) (&(((struct tcp_conn *) (xprt->xp_p1))->xdrs), args_ptr)); |
28f540f4 RM |
400 | } |
401 | ||
402 | static bool_t | |
e7fd8a39 UD |
403 | svctcp_freeargs (xprt, xdr_args, args_ptr) |
404 | SVCXPRT *xprt; | |
405 | xdrproc_t xdr_args; | |
406 | caddr_t args_ptr; | |
28f540f4 | 407 | { |
e7fd8a39 UD |
408 | XDR *xdrs = |
409 | &(((struct tcp_conn *) (xprt->xp_p1))->xdrs); | |
28f540f4 | 410 | |
e7fd8a39 UD |
411 | xdrs->x_op = XDR_FREE; |
412 | return ((*xdr_args) (xdrs, args_ptr)); | |
28f540f4 RM |
413 | } |
414 | ||
415 | static bool_t | |
e7fd8a39 UD |
416 | svctcp_reply (xprt, msg) |
417 | SVCXPRT *xprt; | |
418 | struct rpc_msg *msg; | |
28f540f4 | 419 | { |
e7fd8a39 UD |
420 | struct tcp_conn *cd = |
421 | (struct tcp_conn *) (xprt->xp_p1); | |
422 | XDR *xdrs = &(cd->xdrs); | |
423 | bool_t stat; | |
424 | ||
425 | xdrs->x_op = XDR_ENCODE; | |
426 | msg->rm_xid = cd->x_id; | |
427 | stat = xdr_replymsg (xdrs, msg); | |
428 | (void) xdrrec_endofrecord (xdrs, TRUE); | |
429 | return (stat); | |
28f540f4 | 430 | } |