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