xref: /dragonfly/contrib/cvs-1.12/src/socket-client.c (revision 86d7f5d305c6adaa56ff4582ece9859d73106103)
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 
51 struct 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 
61 static int
socket_buffer_input(void * closure,char * data,size_t need,size_t size,size_t * got)62 socket_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 
118 static int
socket_buffer_output(void * closure,const char * data,size_t have,size_t * wrote)119 socket_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*/
159 static int
socket_buffer_flush(void * closure)160 socket_buffer_flush (void *closure)
161 {
162     /* Nothing to do.  Sockets are always flushed.  */
163     return 0;
164 }
165 
166 
167 
168 static int
socket_buffer_shutdown(struct buffer * buf)169 socket_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 
226 struct buffer *
socket_buffer_initialize(int socket,int input,void (* memory)(struct buffer *))227 socket_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