Derek,
are you interested in a series of patches which extract various parts out
of the (messy) client.c and server.c?
Goals are: reduce those two beasts; move similar stuff together; help me
keep cvs-nserver merges manageable. Not a rocket science, but my
experience w/cvs-nserver shows that some parts are really becoming clearer
that way.
2003-04-24 Alexey Mahotkin <alexm@hsys.msk.ru>
Moved most of the socket stuff to separate socket-client.[ch];
in particular, GSSAPI split depends on this
src/Makefile.am | 1
src/Makefile.in | 20 ++-
src/client.c | 264 ----------------------------------------------------
src/socket-client.c | 246 ++++++++++++++++++++++++++++++++++++++++++++++++
src/socket-client.h | 55 ++++++++++
5 files changed, 315 insertions(+), 271 deletions(-)
--- ccvs/src/client.c~socket-client Thu Apr 24 02:07:42 2003
+++ ccvs-alexm/src/client.c Thu Apr 24 02:18:47 2003
@@ -26,39 +26,7 @@
# include "md5.h"
-# if defined(AUTH_CLIENT_SUPPORT) || defined(HAVE_KERBEROS) ||
defined(HAVE_GSSAPI) || defined(SOCK_ERRNO) || defined(SOCK_STRERROR)
-# ifdef HAVE_WINSOCK_H
-# include <winsock.h>
-# else /* No winsock.h */
-# include <sys/socket.h>
-# include <netinet/in.h>
-# include <arpa/inet.h>
-# include <netdb.h>
-# endif /* No winsock.h */
-# endif
-
-/* If SOCK_ERRNO is defined, then send()/recv() and other socket calls
- do not set errno, but that this macro should be used to obtain an
- error code. This probably doesn't make sense unless
- NO_SOCKET_TO_FD is also defined. */
-# ifndef SOCK_ERRNO
-# define SOCK_ERRNO errno
-# endif
-
-/* If SOCK_STRERROR is defined, then the error codes returned by
- socket operations are not known to strerror, and this macro must be
- used instead to convert those error codes to strings. */
-# ifndef SOCK_STRERROR
-# define SOCK_STRERROR strerror
-
-# if STDC_HEADERS
-# include <string.h>
-# endif
-
-# ifndef strerror
-extern char *strerror ();
-# endif
-# endif /* ! SOCK_STRERROR */
+#include "socket-client.h"
# if HAVE_KERBEROS
@@ -602,236 +570,6 @@ log_buffer_shutdown (buf)
error (0, errno, "closing log file");
return retval;
}
-
-#ifdef NO_SOCKET_TO_FD
-
-/* 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;
-};
-
-static struct buffer *socket_buffer_initialize
- PROTO ((int, int, void (*) (struct buffer *)));
-static int socket_buffer_input PROTO((void *, char *, int, int, int *));
-static int socket_buffer_output PROTO((void *, const char *, int, int *));
-static int socket_buffer_flush PROTO((void *));
-static int socket_buffer_shutdown PROTO((struct buffer *));
-
-
-
-/* Create a buffer based on a socket. */
-
-static struct buffer *
-socket_buffer_initialize (socket, input, memory)
- int socket;
- int input;
- void (*memory) PROTO((struct buffer *));
-{
- struct socket_buffer *n;
-
- n = (struct socket_buffer *) xmalloc (sizeof *n);
- n->socket = socket;
- return buf_initialize (input ? socket_buffer_input : NULL,
- input ? NULL : socket_buffer_output,
- input ? NULL : socket_buffer_flush,
- (int (*) PROTO((void *, int))) NULL,
- socket_buffer_shutdown,
- memory,
- n);
-}
-
-
-
-/* The buffer input function for a buffer built on a socket. */
-
-static int
-socket_buffer_input (closure, data, need, size, got)
- void *closure;
- char *data;
- int need;
- int size;
- int *got;
-{
- struct socket_buffer *sb = (struct socket_buffer *) 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. */
-
- *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, size, 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;
- }
- need -= nbytes;
- size -= nbytes;
- data += nbytes;
- *got += nbytes;
- }
- while (need > 0);
-
- return 0;
-}
-
-
-
-/* The buffer output function for a buffer built on a socket. */
-
-static int
-socket_buffer_output (closure, data, have, wrote)
- void *closure;
- const char *data;
- int have;
- int *wrote;
-{
- struct socket_buffer *sb = (struct socket_buffer *) 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 (closure)
- void *closure;
-{
- /* Nothing to do. Sockets are always flushed. */
- return 0;
-}
-
-
-
-static int
-socket_buffer_shutdown (buf)
- struct buffer *buf;
-{
- struct socket_buffer *n = (struct socket_buffer *) 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;
-}
-
-#endif /* NO_SOCKET_TO_FD */
/*
* Read a line from the server. Result does not include the terminating \n.
--- ccvs/src/Makefile.am~socket-client Thu Apr 24 02:07:42 2003
+++ ccvs-alexm/src/Makefile.am Thu Apr 24 02:17:24 2003
@@ -73,6 +73,7 @@ cvs_SOURCES = \
run.c \
scramble.c \
server.c \
+ socket-client.c socket-client.h \
status.c \
subr.c \
tag.c \
--- ccvs/src/Makefile.in~socket-client Thu Apr 24 02:07:42 2003
+++ ccvs-alexm/src/Makefile.in Thu Apr 24 02:17:24 2003
@@ -164,6 +164,7 @@ cvs_SOURCES = \
run.c \
scramble.c \
server.c \
+ socket-client.c socket-client.h \
status.c \
subr.c \
tag.c \
@@ -226,9 +227,10 @@ am_cvs_OBJECTS = add.$(OBJEXT) admin.$(O
patch.$(OBJEXT) rcs.$(OBJEXT) rcscmds.$(OBJEXT) \
recurse.$(OBJEXT) release.$(OBJEXT) remove.$(OBJEXT) \
repos.$(OBJEXT) root.$(OBJEXT) run.$(OBJEXT) scramble.$(OBJEXT) \
- server.$(OBJEXT) status.$(OBJEXT) subr.$(OBJEXT) tag.$(OBJEXT) \
- update.$(OBJEXT) version.$(OBJEXT) vers_ts.$(OBJEXT) \
- watch.$(OBJEXT) wrapper.$(OBJEXT) zlib.$(OBJEXT)
+ server.$(OBJEXT) socket-client.$(OBJEXT) status.$(OBJEXT) \
+ subr.$(OBJEXT) tag.$(OBJEXT) update.$(OBJEXT) version.$(OBJEXT) \
+ vers_ts.$(OBJEXT) watch.$(OBJEXT) wrapper.$(OBJEXT) \
+ zlib.$(OBJEXT)
cvs_OBJECTS = $(am_cvs_OBJECTS)
cvs_DEPENDENCIES = ../diff/libdiff.a ../lib/libcvs.a ../zlib/libz.a
cvs_LDFLAGS =
@@ -264,11 +266,12 @@ am__depfiles_maybe = depfiles
@AMDEP_TRUE@ ./$(DEPDIR)/release.Po ./$(DEPDIR)/remove.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/repos.Po ./$(DEPDIR)/root.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/run.Po ./$(DEPDIR)/scramble.Po \
-@AMDEP_TRUE@ ./$(DEPDIR)/server.Po ./$(DEPDIR)/status.Po \
-@AMDEP_TRUE@ ./$(DEPDIR)/subr.Po ./$(DEPDIR)/tag.Po \
-@AMDEP_TRUE@ ./$(DEPDIR)/update.Po ./$(DEPDIR)/vers_ts.Po \
-@AMDEP_TRUE@ ./$(DEPDIR)/version.Po ./$(DEPDIR)/watch.Po \
-@AMDEP_TRUE@ ./$(DEPDIR)/wrapper.Po ./$(DEPDIR)/zlib.Po
+@AMDEP_TRUE@ ./$(DEPDIR)/server.Po ./$(DEPDIR)/socket-client.Po \
+@AMDEP_TRUE@ ./$(DEPDIR)/status.Po ./$(DEPDIR)/subr.Po \
+@AMDEP_TRUE@ ./$(DEPDIR)/tag.Po ./$(DEPDIR)/update.Po \
+@AMDEP_TRUE@ ./$(DEPDIR)/vers_ts.Po ./$(DEPDIR)/version.Po \
+@AMDEP_TRUE@ ./$(DEPDIR)/watch.Po ./$(DEPDIR)/wrapper.Po \
+@AMDEP_TRUE@ ./$(DEPDIR)/zlib.Po
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
CCLD = $(CC)
@@ -391,6 +394,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/scramble.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/server.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/socket-client.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/status.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/subr.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tag.Po@am__quote@
--- /dev/null Wed Jan 1 02:48:46 2003
+++ ccvs-alexm/src/socket-client.c Thu Apr 24 02:07:42 2003
@@ -0,0 +1,246 @@
+/* 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 <config.h>
+
+#include "cvs.h"
+
+#include "socket-client.h"
+
+#ifdef NO_SOCKET_TO_FD
+
+/* 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;
+};
+
+static int socket_buffer_input PROTO((void *, char *, int, int, int *));
+static int socket_buffer_output PROTO((void *, const char *, int, int *));
+static int socket_buffer_flush PROTO((void *));
+static int socket_buffer_shutdown PROTO((struct buffer *));
+
+
+
+/* Create a buffer based on a socket. */
+
+static struct buffer *
+socket_buffer_initialize (socket, input, memory)
+ int socket;
+ int input;
+ void (*memory) PROTO((struct buffer *));
+{
+ struct socket_buffer *n;
+
+ n = (struct socket_buffer *) xmalloc (sizeof *n);
+ n->socket = socket;
+ return buf_initialize (input ? socket_buffer_input : NULL,
+ input ? NULL : socket_buffer_output,
+ input ? NULL : socket_buffer_flush,
+ (int (*) PROTO((void *, int))) NULL,
+ socket_buffer_shutdown,
+ memory,
+ n);
+}
+
+
+
+/* The buffer input function for a buffer built on a socket. */
+
+static int
+socket_buffer_input (closure, data, need, size, got)
+ void *closure;
+ char *data;
+ int need;
+ int size;
+ int *got;
+{
+ struct socket_buffer *sb = (struct socket_buffer *) 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. */
+
+ *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, size, 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;
+ }
+ need -= nbytes;
+ size -= nbytes;
+ data += nbytes;
+ *got += nbytes;
+ }
+ while (need > 0);
+
+ return 0;
+}
+
+
+
+/* The buffer output function for a buffer built on a socket. */
+
+static int
+socket_buffer_output (closure, data, have, wrote)
+ void *closure;
+ const char *data;
+ int have;
+ int *wrote;
+{
+ struct socket_buffer *sb = (struct socket_buffer *) 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 (closure)
+ void *closure;
+{
+ /* Nothing to do. Sockets are always flushed. */
+ return 0;
+}
+
+
+
+static int
+socket_buffer_shutdown (buf)
+ struct buffer *buf;
+{
+ struct socket_buffer *n = (struct socket_buffer *) 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;
+}
+
+#endif /* NO_SOCKET_TO_FD */
+
--- /dev/null Wed Jan 1 02:48:46 2003
+++ ccvs-alexm/src/socket-client.h Thu Apr 24 02:18:54 2003
@@ -0,0 +1,55 @@
+/* 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. */
+
+#ifndef SOCKET_CLIENT_H__
+#define SOCKET_CLIENT_H__ 1
+
+#include <config.h>
+
+struct buffer *socket_buffer_initialize
+ PROTO ((int, int, void (*) (struct buffer *)));
+
+# if defined(AUTH_CLIENT_SUPPORT) || defined(HAVE_KERBEROS) ||
defined(HAVE_GSSAPI) || defined(SOCK_ERRNO) || defined(SOCK_STRERROR)
+# ifdef HAVE_WINSOCK_H
+# include <winsock.h>
+# else /* No winsock.h */
+# include <sys/socket.h>
+# include <netinet/in.h>
+# include <arpa/inet.h>
+# include <netdb.h>
+# endif /* No winsock.h */
+# endif
+
+/* If SOCK_ERRNO is defined, then send()/recv() and other socket calls
+ do not set errno, but that this macro should be used to obtain an
+ error code. This probably doesn't make sense unless
+ NO_SOCKET_TO_FD is also defined. */
+# ifndef SOCK_ERRNO
+# define SOCK_ERRNO errno
+# endif
+
+/* If SOCK_STRERROR is defined, then the error codes returned by
+ socket operations are not known to strerror, and this macro must be
+ used instead to convert those error codes to strings. */
+# ifndef SOCK_STRERROR
+# define SOCK_STRERROR strerror
+
+# if STDC_HEADERS
+# include <string.h>
+# endif
+
+# ifndef strerror
+extern char *strerror ();
+# endif
+# endif /* ! SOCK_STRERROR */
+
+#endif SOCKET_CLIENT_H__
_
--alexm