xref: /dflybsd-src/contrib/cvs-1.12/src/socket-client.c (revision 86d7f5d305c6adaa56ff4582ece9859d73106103)
186d7f5d3SJohn Marino /* CVS socket client stuff.
286d7f5d3SJohn Marino 
386d7f5d3SJohn Marino    This program is free software; you can redistribute it and/or modify
486d7f5d3SJohn Marino    it under the terms of the GNU General Public License as published by
586d7f5d3SJohn Marino    the Free Software Foundation; either version 2, or (at your option)
686d7f5d3SJohn Marino    any later version.
786d7f5d3SJohn Marino 
886d7f5d3SJohn Marino    This program is distributed in the hope that it will be useful,
986d7f5d3SJohn Marino    but WITHOUT ANY WARRANTY; without even the implied warranty of
1086d7f5d3SJohn Marino    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1186d7f5d3SJohn Marino    GNU General Public License for more details.  */
1286d7f5d3SJohn Marino 
1386d7f5d3SJohn Marino /***
1486d7f5d3SJohn Marino  *** THIS FILE SHOULD NEVER BE COMPILED UNLESS NO_SOCKET_TO_FD IS DEFINED.
1586d7f5d3SJohn Marino  ***/
1686d7f5d3SJohn Marino 
1786d7f5d3SJohn Marino #ifdef HAVE_CONFIG_H
1886d7f5d3SJohn Marino # include <config.h>
1986d7f5d3SJohn Marino #endif
2086d7f5d3SJohn Marino 
2186d7f5d3SJohn Marino #ifdef CLIENT_SUPPORT
2286d7f5d3SJohn Marino 
2386d7f5d3SJohn Marino #include "cvs.h"
2486d7f5d3SJohn Marino #include "buffer.h"
2586d7f5d3SJohn Marino 
2686d7f5d3SJohn Marino #include "socket-client.h"
2786d7f5d3SJohn Marino 
2886d7f5d3SJohn Marino 
2986d7f5d3SJohn Marino /* Under certain circumstances, we must communicate with the server
3086d7f5d3SJohn Marino    via a socket using send() and recv().  This is because under some
3186d7f5d3SJohn Marino    operating systems (OS/2 and Windows 95 come to mind), a socket
3286d7f5d3SJohn Marino    cannot be converted to a file descriptor -- it must be treated as a
3386d7f5d3SJohn Marino    socket and nothing else.
3486d7f5d3SJohn Marino 
3586d7f5d3SJohn Marino    We may also need to deal with socket routine error codes differently
3686d7f5d3SJohn Marino    in these cases.  This is handled through the SOCK_ERRNO and
3786d7f5d3SJohn Marino    SOCK_STRERROR macros. */
3886d7f5d3SJohn Marino 
3986d7f5d3SJohn Marino /* These routines implement a buffer structure which uses send and
4086d7f5d3SJohn Marino    recv.  The buffer is always in blocking mode so we don't implement
4186d7f5d3SJohn Marino    the block routine.  */
4286d7f5d3SJohn Marino 
4386d7f5d3SJohn Marino /* Note that it is important that these routines always handle errors
4486d7f5d3SJohn Marino    internally and never return a positive errno code, since it would in
4586d7f5d3SJohn Marino    general be impossible for the caller to know in general whether any
4686d7f5d3SJohn Marino    error code came from a socket routine (to decide whether to use
4786d7f5d3SJohn Marino    SOCK_STRERROR or simply strerror to print an error message). */
4886d7f5d3SJohn Marino 
4986d7f5d3SJohn Marino /* We use an instance of this structure as the closure field.  */
5086d7f5d3SJohn Marino 
5186d7f5d3SJohn Marino struct socket_buffer
5286d7f5d3SJohn Marino {
5386d7f5d3SJohn Marino     /* The socket number.  */
5486d7f5d3SJohn Marino     int socket;
5586d7f5d3SJohn Marino };
5686d7f5d3SJohn Marino 
5786d7f5d3SJohn Marino 
5886d7f5d3SJohn Marino 
5986d7f5d3SJohn Marino /* The buffer input function for a buffer built on a socket.  */
6086d7f5d3SJohn Marino 
6186d7f5d3SJohn Marino static int
socket_buffer_input(void * closure,char * data,size_t need,size_t size,size_t * got)6286d7f5d3SJohn Marino socket_buffer_input (void *closure, char *data, size_t need, size_t size,
6386d7f5d3SJohn Marino 		     size_t *got)
6486d7f5d3SJohn Marino {
6586d7f5d3SJohn Marino     struct socket_buffer *sb = closure;
6686d7f5d3SJohn Marino     int nbytes;
6786d7f5d3SJohn Marino 
6886d7f5d3SJohn Marino     /* I believe that the recv function gives us exactly the semantics
6986d7f5d3SJohn Marino        we want.  If there is a message, it returns immediately with
7086d7f5d3SJohn Marino        whatever it could get.  If there is no message, it waits until
7186d7f5d3SJohn Marino        one comes in.  In other words, it is not like read, which in
7286d7f5d3SJohn Marino        blocking mode normally waits until all the requested data is
7386d7f5d3SJohn Marino        available.  */
7486d7f5d3SJohn Marino 
7586d7f5d3SJohn Marino     assert (size >= need);
7686d7f5d3SJohn Marino 
7786d7f5d3SJohn Marino     *got = 0;
7886d7f5d3SJohn Marino 
7986d7f5d3SJohn Marino     do
8086d7f5d3SJohn Marino     {
8186d7f5d3SJohn Marino 
8286d7f5d3SJohn Marino 	/* Note that for certain (broken?) networking stacks, like
8386d7f5d3SJohn Marino 	   VMS's UCX (not sure what version, problem reported with
8486d7f5d3SJohn Marino 	   recv() in 1997), and (according to windows-NT/config.h)
8586d7f5d3SJohn Marino 	   Windows NT 3.51, we must call recv or send with a
8686d7f5d3SJohn Marino 	   moderately sized buffer (say, less than 200K or something),
8786d7f5d3SJohn Marino 	   or else there may be network errors (somewhat hard to
8886d7f5d3SJohn Marino 	   produce, e.g. WAN not LAN or some such).  buf_read_data
8986d7f5d3SJohn Marino 	   makes sure that we only recv() BUFFER_DATA_SIZE bytes at
9086d7f5d3SJohn Marino 	   a time.  */
9186d7f5d3SJohn Marino 
9286d7f5d3SJohn Marino 	nbytes = recv (sb->socket, data + *got, size - *got, 0);
9386d7f5d3SJohn Marino 	if (nbytes < 0)
9486d7f5d3SJohn Marino 	    error (1, 0, "reading from server: %s",
9586d7f5d3SJohn Marino 		   SOCK_STRERROR (SOCK_ERRNO));
9686d7f5d3SJohn Marino 	if (nbytes == 0)
9786d7f5d3SJohn Marino 	{
9886d7f5d3SJohn Marino 	    /* End of file (for example, the server has closed
9986d7f5d3SJohn Marino 	       the connection).  If we've already read something, we
10086d7f5d3SJohn Marino 	       just tell the caller about the data, not about the end of
10186d7f5d3SJohn Marino 	       file.  If we've read nothing, we return end of file.  */
10286d7f5d3SJohn Marino 	    if (*got == 0)
10386d7f5d3SJohn Marino 		return -1;
10486d7f5d3SJohn Marino 	    else
10586d7f5d3SJohn Marino 		return 0;
10686d7f5d3SJohn Marino 	}
10786d7f5d3SJohn Marino 	*got += nbytes;
10886d7f5d3SJohn Marino     }
10986d7f5d3SJohn Marino     while (*got < need);
11086d7f5d3SJohn Marino 
11186d7f5d3SJohn Marino     return 0;
11286d7f5d3SJohn Marino }
11386d7f5d3SJohn Marino 
11486d7f5d3SJohn Marino 
11586d7f5d3SJohn Marino 
11686d7f5d3SJohn Marino /* The buffer output function for a buffer built on a socket.  */
11786d7f5d3SJohn Marino 
11886d7f5d3SJohn Marino static int
socket_buffer_output(void * closure,const char * data,size_t have,size_t * wrote)11986d7f5d3SJohn Marino socket_buffer_output (void *closure, const char *data, size_t have,
12086d7f5d3SJohn Marino 		      size_t *wrote)
12186d7f5d3SJohn Marino {
12286d7f5d3SJohn Marino     struct socket_buffer *sb = closure;
12386d7f5d3SJohn Marino 
12486d7f5d3SJohn Marino     *wrote = have;
12586d7f5d3SJohn Marino 
12686d7f5d3SJohn Marino     /* See comment in socket_buffer_input regarding buffer size we pass
12786d7f5d3SJohn Marino        to send and recv.  */
12886d7f5d3SJohn Marino 
12986d7f5d3SJohn Marino # ifdef SEND_NEVER_PARTIAL
13086d7f5d3SJohn Marino     /* If send() never will produce a partial write, then just do it.  This
13186d7f5d3SJohn Marino        is needed for systems where its return value is something other than
13286d7f5d3SJohn Marino        the number of bytes written.  */
13386d7f5d3SJohn Marino     if (send (sb->socket, data, have, 0) < 0)
13486d7f5d3SJohn Marino 	error (1, 0, "writing to server socket: %s",
13586d7f5d3SJohn Marino 	       SOCK_STRERROR (SOCK_ERRNO));
13686d7f5d3SJohn Marino # else
13786d7f5d3SJohn Marino     while (have > 0)
13886d7f5d3SJohn Marino     {
13986d7f5d3SJohn Marino 	int nbytes;
14086d7f5d3SJohn Marino 
14186d7f5d3SJohn Marino 	nbytes = send (sb->socket, data, have, 0);
14286d7f5d3SJohn Marino 	if (nbytes < 0)
14386d7f5d3SJohn Marino 	    error (1, 0, "writing to server socket: %s",
14486d7f5d3SJohn Marino 		   SOCK_STRERROR (SOCK_ERRNO));
14586d7f5d3SJohn Marino 
14686d7f5d3SJohn Marino 	have -= nbytes;
14786d7f5d3SJohn Marino 	data += nbytes;
14886d7f5d3SJohn Marino     }
14986d7f5d3SJohn Marino # endif
15086d7f5d3SJohn Marino 
15186d7f5d3SJohn Marino     return 0;
15286d7f5d3SJohn Marino }
15386d7f5d3SJohn Marino 
15486d7f5d3SJohn Marino 
15586d7f5d3SJohn Marino 
15686d7f5d3SJohn Marino /* The buffer flush function for a buffer built on a socket.  */
15786d7f5d3SJohn Marino 
15886d7f5d3SJohn Marino /*ARGSUSED*/
15986d7f5d3SJohn Marino static int
socket_buffer_flush(void * closure)16086d7f5d3SJohn Marino socket_buffer_flush (void *closure)
16186d7f5d3SJohn Marino {
16286d7f5d3SJohn Marino     /* Nothing to do.  Sockets are always flushed.  */
16386d7f5d3SJohn Marino     return 0;
16486d7f5d3SJohn Marino }
16586d7f5d3SJohn Marino 
16686d7f5d3SJohn Marino 
16786d7f5d3SJohn Marino 
16886d7f5d3SJohn Marino static int
socket_buffer_shutdown(struct buffer * buf)16986d7f5d3SJohn Marino socket_buffer_shutdown (struct buffer *buf)
17086d7f5d3SJohn Marino {
17186d7f5d3SJohn Marino     struct socket_buffer *n = buf->closure;
17286d7f5d3SJohn Marino     char tmp;
17386d7f5d3SJohn Marino 
17486d7f5d3SJohn Marino     /* no need to flush children of an endpoint buffer here */
17586d7f5d3SJohn Marino 
17686d7f5d3SJohn Marino     if (buf->input)
17786d7f5d3SJohn Marino     {
17886d7f5d3SJohn Marino 	int err = 0;
17986d7f5d3SJohn Marino 	if (! buf_empty_p (buf)
18086d7f5d3SJohn Marino 	    || (err = recv (n->socket, &tmp, 1, 0)) > 0)
18186d7f5d3SJohn Marino 	    error (0, 0, "dying gasps from %s unexpected",
18286d7f5d3SJohn Marino 		   current_parsed_root->hostname);
18386d7f5d3SJohn Marino 	else if (err == -1)
18486d7f5d3SJohn Marino 	    error (0, 0, "reading from %s: %s", current_parsed_root->hostname,
18586d7f5d3SJohn Marino 		   SOCK_STRERROR (SOCK_ERRNO));
18686d7f5d3SJohn Marino 
18786d7f5d3SJohn Marino 	/* shutdown() socket */
18886d7f5d3SJohn Marino # ifdef SHUTDOWN_SERVER
18986d7f5d3SJohn Marino 	if (current_parsed_root->method != server_method)
19086d7f5d3SJohn Marino # endif
19186d7f5d3SJohn Marino 	if (shutdown (n->socket, 0) < 0)
19286d7f5d3SJohn Marino 	{
19386d7f5d3SJohn Marino 	    error (1, 0, "shutting down server socket: %s",
19486d7f5d3SJohn Marino 		   SOCK_STRERROR (SOCK_ERRNO));
19586d7f5d3SJohn Marino 	}
19686d7f5d3SJohn Marino 
19786d7f5d3SJohn Marino 	buf->input = NULL;
19886d7f5d3SJohn Marino     }
19986d7f5d3SJohn Marino     else if (buf->output)
20086d7f5d3SJohn Marino     {
20186d7f5d3SJohn Marino 	/* shutdown() socket */
20286d7f5d3SJohn Marino # ifdef SHUTDOWN_SERVER
20386d7f5d3SJohn Marino 	/* FIXME:  Should have a SHUTDOWN_SERVER_INPUT &
20486d7f5d3SJohn Marino 	 * SHUTDOWN_SERVER_OUTPUT
20586d7f5d3SJohn Marino 	 */
20686d7f5d3SJohn Marino 	if (current_parsed_root->method == server_method)
20786d7f5d3SJohn Marino 	    SHUTDOWN_SERVER (n->socket);
20886d7f5d3SJohn Marino 	else
20986d7f5d3SJohn Marino # endif
21086d7f5d3SJohn Marino 	if (shutdown (n->socket, 1) < 0)
21186d7f5d3SJohn Marino 	{
21286d7f5d3SJohn Marino 	    error (1, 0, "shutting down server socket: %s",
21386d7f5d3SJohn Marino 		   SOCK_STRERROR (SOCK_ERRNO));
21486d7f5d3SJohn Marino 	}
21586d7f5d3SJohn Marino 
21686d7f5d3SJohn Marino 	buf->output = NULL;
21786d7f5d3SJohn Marino     }
21886d7f5d3SJohn Marino 
21986d7f5d3SJohn Marino     return 0;
22086d7f5d3SJohn Marino }
22186d7f5d3SJohn Marino 
22286d7f5d3SJohn Marino 
22386d7f5d3SJohn Marino 
22486d7f5d3SJohn Marino /* Create a buffer based on a socket.  */
22586d7f5d3SJohn Marino 
22686d7f5d3SJohn Marino struct buffer *
socket_buffer_initialize(int socket,int input,void (* memory)(struct buffer *))22786d7f5d3SJohn Marino socket_buffer_initialize (int socket, int input,
22886d7f5d3SJohn Marino                           void (*memory) (struct buffer *))
22986d7f5d3SJohn Marino {
23086d7f5d3SJohn Marino     struct socket_buffer *sbuf = xmalloc (sizeof *sbuf);
23186d7f5d3SJohn Marino     sbuf->socket = socket;
23286d7f5d3SJohn Marino     return buf_initialize (input ? socket_buffer_input : NULL,
23386d7f5d3SJohn Marino 			   input ? NULL : socket_buffer_output,
23486d7f5d3SJohn Marino 			   input ? NULL : socket_buffer_flush,
23586d7f5d3SJohn Marino 			   NULL, NULL,
23686d7f5d3SJohn Marino 			   socket_buffer_shutdown,
23786d7f5d3SJohn Marino 			   memory,
23886d7f5d3SJohn Marino 			   sbuf);
23986d7f5d3SJohn Marino }
24086d7f5d3SJohn Marino 
24186d7f5d3SJohn Marino #endif /* CLIENT_SUPPORT */
242