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