xref: /dflybsd-src/contrib/cvs-1.12/src/socket-client.c (revision 86d7f5d305c6adaa56ff4582ece9859d73106103)
1*86d7f5d3SJohn Marino /* CVS socket client stuff.
2*86d7f5d3SJohn Marino 
3*86d7f5d3SJohn Marino    This program is free software; you can redistribute it and/or modify
4*86d7f5d3SJohn Marino    it under the terms of the GNU General Public License as published by
5*86d7f5d3SJohn Marino    the Free Software Foundation; either version 2, or (at your option)
6*86d7f5d3SJohn Marino    any later version.
7*86d7f5d3SJohn Marino 
8*86d7f5d3SJohn Marino    This program is distributed in the hope that it will be useful,
9*86d7f5d3SJohn Marino    but WITHOUT ANY WARRANTY; without even the implied warranty of
10*86d7f5d3SJohn Marino    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11*86d7f5d3SJohn Marino    GNU General Public License for more details.  */
12*86d7f5d3SJohn Marino 
13*86d7f5d3SJohn Marino /***
14*86d7f5d3SJohn Marino  *** THIS FILE SHOULD NEVER BE COMPILED UNLESS NO_SOCKET_TO_FD IS DEFINED.
15*86d7f5d3SJohn Marino  ***/
16*86d7f5d3SJohn Marino 
17*86d7f5d3SJohn Marino #ifdef HAVE_CONFIG_H
18*86d7f5d3SJohn Marino # include <config.h>
19*86d7f5d3SJohn Marino #endif
20*86d7f5d3SJohn Marino 
21*86d7f5d3SJohn Marino #ifdef CLIENT_SUPPORT
22*86d7f5d3SJohn Marino 
23*86d7f5d3SJohn Marino #include "cvs.h"
24*86d7f5d3SJohn Marino #include "buffer.h"
25*86d7f5d3SJohn Marino 
26*86d7f5d3SJohn Marino #include "socket-client.h"
27*86d7f5d3SJohn Marino 
28*86d7f5d3SJohn Marino 
29*86d7f5d3SJohn Marino /* Under certain circumstances, we must communicate with the server
30*86d7f5d3SJohn Marino    via a socket using send() and recv().  This is because under some
31*86d7f5d3SJohn Marino    operating systems (OS/2 and Windows 95 come to mind), a socket
32*86d7f5d3SJohn Marino    cannot be converted to a file descriptor -- it must be treated as a
33*86d7f5d3SJohn Marino    socket and nothing else.
34*86d7f5d3SJohn Marino 
35*86d7f5d3SJohn Marino    We may also need to deal with socket routine error codes differently
36*86d7f5d3SJohn Marino    in these cases.  This is handled through the SOCK_ERRNO and
37*86d7f5d3SJohn Marino    SOCK_STRERROR macros. */
38*86d7f5d3SJohn Marino 
39*86d7f5d3SJohn Marino /* These routines implement a buffer structure which uses send and
40*86d7f5d3SJohn Marino    recv.  The buffer is always in blocking mode so we don't implement
41*86d7f5d3SJohn Marino    the block routine.  */
42*86d7f5d3SJohn Marino 
43*86d7f5d3SJohn Marino /* Note that it is important that these routines always handle errors
44*86d7f5d3SJohn Marino    internally and never return a positive errno code, since it would in
45*86d7f5d3SJohn Marino    general be impossible for the caller to know in general whether any
46*86d7f5d3SJohn Marino    error code came from a socket routine (to decide whether to use
47*86d7f5d3SJohn Marino    SOCK_STRERROR or simply strerror to print an error message). */
48*86d7f5d3SJohn Marino 
49*86d7f5d3SJohn Marino /* We use an instance of this structure as the closure field.  */
50*86d7f5d3SJohn Marino 
51*86d7f5d3SJohn Marino struct socket_buffer
52*86d7f5d3SJohn Marino {
53*86d7f5d3SJohn Marino     /* The socket number.  */
54*86d7f5d3SJohn Marino     int socket;
55*86d7f5d3SJohn Marino };
56*86d7f5d3SJohn Marino 
57*86d7f5d3SJohn Marino 
58*86d7f5d3SJohn Marino 
59*86d7f5d3SJohn Marino /* The buffer input function for a buffer built on a socket.  */
60*86d7f5d3SJohn Marino 
61*86d7f5d3SJohn Marino static int
socket_buffer_input(void * closure,char * data,size_t need,size_t size,size_t * got)62*86d7f5d3SJohn Marino socket_buffer_input (void *closure, char *data, size_t need, size_t size,
63*86d7f5d3SJohn Marino 		     size_t *got)
64*86d7f5d3SJohn Marino {
65*86d7f5d3SJohn Marino     struct socket_buffer *sb = closure;
66*86d7f5d3SJohn Marino     int nbytes;
67*86d7f5d3SJohn Marino 
68*86d7f5d3SJohn Marino     /* I believe that the recv function gives us exactly the semantics
69*86d7f5d3SJohn Marino        we want.  If there is a message, it returns immediately with
70*86d7f5d3SJohn Marino        whatever it could get.  If there is no message, it waits until
71*86d7f5d3SJohn Marino        one comes in.  In other words, it is not like read, which in
72*86d7f5d3SJohn Marino        blocking mode normally waits until all the requested data is
73*86d7f5d3SJohn Marino        available.  */
74*86d7f5d3SJohn Marino 
75*86d7f5d3SJohn Marino     assert (size >= need);
76*86d7f5d3SJohn Marino 
77*86d7f5d3SJohn Marino     *got = 0;
78*86d7f5d3SJohn Marino 
79*86d7f5d3SJohn Marino     do
80*86d7f5d3SJohn Marino     {
81*86d7f5d3SJohn Marino 
82*86d7f5d3SJohn Marino 	/* Note that for certain (broken?) networking stacks, like
83*86d7f5d3SJohn Marino 	   VMS's UCX (not sure what version, problem reported with
84*86d7f5d3SJohn Marino 	   recv() in 1997), and (according to windows-NT/config.h)
85*86d7f5d3SJohn Marino 	   Windows NT 3.51, we must call recv or send with a
86*86d7f5d3SJohn Marino 	   moderately sized buffer (say, less than 200K or something),
87*86d7f5d3SJohn Marino 	   or else there may be network errors (somewhat hard to
88*86d7f5d3SJohn Marino 	   produce, e.g. WAN not LAN or some such).  buf_read_data
89*86d7f5d3SJohn Marino 	   makes sure that we only recv() BUFFER_DATA_SIZE bytes at
90*86d7f5d3SJohn Marino 	   a time.  */
91*86d7f5d3SJohn Marino 
92*86d7f5d3SJohn Marino 	nbytes = recv (sb->socket, data + *got, size - *got, 0);
93*86d7f5d3SJohn Marino 	if (nbytes < 0)
94*86d7f5d3SJohn Marino 	    error (1, 0, "reading from server: %s",
95*86d7f5d3SJohn Marino 		   SOCK_STRERROR (SOCK_ERRNO));
96*86d7f5d3SJohn Marino 	if (nbytes == 0)
97*86d7f5d3SJohn Marino 	{
98*86d7f5d3SJohn Marino 	    /* End of file (for example, the server has closed
99*86d7f5d3SJohn Marino 	       the connection).  If we've already read something, we
100*86d7f5d3SJohn Marino 	       just tell the caller about the data, not about the end of
101*86d7f5d3SJohn Marino 	       file.  If we've read nothing, we return end of file.  */
102*86d7f5d3SJohn Marino 	    if (*got == 0)
103*86d7f5d3SJohn Marino 		return -1;
104*86d7f5d3SJohn Marino 	    else
105*86d7f5d3SJohn Marino 		return 0;
106*86d7f5d3SJohn Marino 	}
107*86d7f5d3SJohn Marino 	*got += nbytes;
108*86d7f5d3SJohn Marino     }
109*86d7f5d3SJohn Marino     while (*got < need);
110*86d7f5d3SJohn Marino 
111*86d7f5d3SJohn Marino     return 0;
112*86d7f5d3SJohn Marino }
113*86d7f5d3SJohn Marino 
114*86d7f5d3SJohn Marino 
115*86d7f5d3SJohn Marino 
116*86d7f5d3SJohn Marino /* The buffer output function for a buffer built on a socket.  */
117*86d7f5d3SJohn Marino 
118*86d7f5d3SJohn Marino static int
socket_buffer_output(void * closure,const char * data,size_t have,size_t * wrote)119*86d7f5d3SJohn Marino socket_buffer_output (void *closure, const char *data, size_t have,
120*86d7f5d3SJohn Marino 		      size_t *wrote)
121*86d7f5d3SJohn Marino {
122*86d7f5d3SJohn Marino     struct socket_buffer *sb = closure;
123*86d7f5d3SJohn Marino 
124*86d7f5d3SJohn Marino     *wrote = have;
125*86d7f5d3SJohn Marino 
126*86d7f5d3SJohn Marino     /* See comment in socket_buffer_input regarding buffer size we pass
127*86d7f5d3SJohn Marino        to send and recv.  */
128*86d7f5d3SJohn Marino 
129*86d7f5d3SJohn Marino # ifdef SEND_NEVER_PARTIAL
130*86d7f5d3SJohn Marino     /* If send() never will produce a partial write, then just do it.  This
131*86d7f5d3SJohn Marino        is needed for systems where its return value is something other than
132*86d7f5d3SJohn Marino        the number of bytes written.  */
133*86d7f5d3SJohn Marino     if (send (sb->socket, data, have, 0) < 0)
134*86d7f5d3SJohn Marino 	error (1, 0, "writing to server socket: %s",
135*86d7f5d3SJohn Marino 	       SOCK_STRERROR (SOCK_ERRNO));
136*86d7f5d3SJohn Marino # else
137*86d7f5d3SJohn Marino     while (have > 0)
138*86d7f5d3SJohn Marino     {
139*86d7f5d3SJohn Marino 	int nbytes;
140*86d7f5d3SJohn Marino 
141*86d7f5d3SJohn Marino 	nbytes = send (sb->socket, data, have, 0);
142*86d7f5d3SJohn Marino 	if (nbytes < 0)
143*86d7f5d3SJohn Marino 	    error (1, 0, "writing to server socket: %s",
144*86d7f5d3SJohn Marino 		   SOCK_STRERROR (SOCK_ERRNO));
145*86d7f5d3SJohn Marino 
146*86d7f5d3SJohn Marino 	have -= nbytes;
147*86d7f5d3SJohn Marino 	data += nbytes;
148*86d7f5d3SJohn Marino     }
149*86d7f5d3SJohn Marino # endif
150*86d7f5d3SJohn Marino 
151*86d7f5d3SJohn Marino     return 0;
152*86d7f5d3SJohn Marino }
153*86d7f5d3SJohn Marino 
154*86d7f5d3SJohn Marino 
155*86d7f5d3SJohn Marino 
156*86d7f5d3SJohn Marino /* The buffer flush function for a buffer built on a socket.  */
157*86d7f5d3SJohn Marino 
158*86d7f5d3SJohn Marino /*ARGSUSED*/
159*86d7f5d3SJohn Marino static int
socket_buffer_flush(void * closure)160*86d7f5d3SJohn Marino socket_buffer_flush (void *closure)
161*86d7f5d3SJohn Marino {
162*86d7f5d3SJohn Marino     /* Nothing to do.  Sockets are always flushed.  */
163*86d7f5d3SJohn Marino     return 0;
164*86d7f5d3SJohn Marino }
165*86d7f5d3SJohn Marino 
166*86d7f5d3SJohn Marino 
167*86d7f5d3SJohn Marino 
168*86d7f5d3SJohn Marino static int
socket_buffer_shutdown(struct buffer * buf)169*86d7f5d3SJohn Marino socket_buffer_shutdown (struct buffer *buf)
170*86d7f5d3SJohn Marino {
171*86d7f5d3SJohn Marino     struct socket_buffer *n = buf->closure;
172*86d7f5d3SJohn Marino     char tmp;
173*86d7f5d3SJohn Marino 
174*86d7f5d3SJohn Marino     /* no need to flush children of an endpoint buffer here */
175*86d7f5d3SJohn Marino 
176*86d7f5d3SJohn Marino     if (buf->input)
177*86d7f5d3SJohn Marino     {
178*86d7f5d3SJohn Marino 	int err = 0;
179*86d7f5d3SJohn Marino 	if (! buf_empty_p (buf)
180*86d7f5d3SJohn Marino 	    || (err = recv (n->socket, &tmp, 1, 0)) > 0)
181*86d7f5d3SJohn Marino 	    error (0, 0, "dying gasps from %s unexpected",
182*86d7f5d3SJohn Marino 		   current_parsed_root->hostname);
183*86d7f5d3SJohn Marino 	else if (err == -1)
184*86d7f5d3SJohn Marino 	    error (0, 0, "reading from %s: %s", current_parsed_root->hostname,
185*86d7f5d3SJohn Marino 		   SOCK_STRERROR (SOCK_ERRNO));
186*86d7f5d3SJohn Marino 
187*86d7f5d3SJohn Marino 	/* shutdown() socket */
188*86d7f5d3SJohn Marino # ifdef SHUTDOWN_SERVER
189*86d7f5d3SJohn Marino 	if (current_parsed_root->method != server_method)
190*86d7f5d3SJohn Marino # endif
191*86d7f5d3SJohn Marino 	if (shutdown (n->socket, 0) < 0)
192*86d7f5d3SJohn Marino 	{
193*86d7f5d3SJohn Marino 	    error (1, 0, "shutting down server socket: %s",
194*86d7f5d3SJohn Marino 		   SOCK_STRERROR (SOCK_ERRNO));
195*86d7f5d3SJohn Marino 	}
196*86d7f5d3SJohn Marino 
197*86d7f5d3SJohn Marino 	buf->input = NULL;
198*86d7f5d3SJohn Marino     }
199*86d7f5d3SJohn Marino     else if (buf->output)
200*86d7f5d3SJohn Marino     {
201*86d7f5d3SJohn Marino 	/* shutdown() socket */
202*86d7f5d3SJohn Marino # ifdef SHUTDOWN_SERVER
203*86d7f5d3SJohn Marino 	/* FIXME:  Should have a SHUTDOWN_SERVER_INPUT &
204*86d7f5d3SJohn Marino 	 * SHUTDOWN_SERVER_OUTPUT
205*86d7f5d3SJohn Marino 	 */
206*86d7f5d3SJohn Marino 	if (current_parsed_root->method == server_method)
207*86d7f5d3SJohn Marino 	    SHUTDOWN_SERVER (n->socket);
208*86d7f5d3SJohn Marino 	else
209*86d7f5d3SJohn Marino # endif
210*86d7f5d3SJohn Marino 	if (shutdown (n->socket, 1) < 0)
211*86d7f5d3SJohn Marino 	{
212*86d7f5d3SJohn Marino 	    error (1, 0, "shutting down server socket: %s",
213*86d7f5d3SJohn Marino 		   SOCK_STRERROR (SOCK_ERRNO));
214*86d7f5d3SJohn Marino 	}
215*86d7f5d3SJohn Marino 
216*86d7f5d3SJohn Marino 	buf->output = NULL;
217*86d7f5d3SJohn Marino     }
218*86d7f5d3SJohn Marino 
219*86d7f5d3SJohn Marino     return 0;
220*86d7f5d3SJohn Marino }
221*86d7f5d3SJohn Marino 
222*86d7f5d3SJohn Marino 
223*86d7f5d3SJohn Marino 
224*86d7f5d3SJohn Marino /* Create a buffer based on a socket.  */
225*86d7f5d3SJohn Marino 
226*86d7f5d3SJohn Marino struct buffer *
socket_buffer_initialize(int socket,int input,void (* memory)(struct buffer *))227*86d7f5d3SJohn Marino socket_buffer_initialize (int socket, int input,
228*86d7f5d3SJohn Marino                           void (*memory) (struct buffer *))
229*86d7f5d3SJohn Marino {
230*86d7f5d3SJohn Marino     struct socket_buffer *sbuf = xmalloc (sizeof *sbuf);
231*86d7f5d3SJohn Marino     sbuf->socket = socket;
232*86d7f5d3SJohn Marino     return buf_initialize (input ? socket_buffer_input : NULL,
233*86d7f5d3SJohn Marino 			   input ? NULL : socket_buffer_output,
234*86d7f5d3SJohn Marino 			   input ? NULL : socket_buffer_flush,
235*86d7f5d3SJohn Marino 			   NULL, NULL,
236*86d7f5d3SJohn Marino 			   socket_buffer_shutdown,
237*86d7f5d3SJohn Marino 			   memory,
238*86d7f5d3SJohn Marino 			   sbuf);
239*86d7f5d3SJohn Marino }
240*86d7f5d3SJohn Marino 
241*86d7f5d3SJohn Marino #endif /* CLIENT_SUPPORT */
242