[JGIT PATCH 13/13] Add basic git daemon support to publish receive-pack

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



The git:// daemon service receives anonymous TCP connections and runs
commands as they are received.

Currently we only support the server portion of send-pack/receive-pack,
so that is the only service registered in our Daemon class.

Signed-off-by: Shawn O. Pearce <spearce@xxxxxxxxxxx>
---
 .../services/org.spearce.jgit.pgm.TextBuiltin      |    1 +
 .../src/org/spearce/jgit/pgm/Daemon.java           |  125 ++++++++
 .../src/org/spearce/jgit/transport/Daemon.java     |  309 ++++++++++++++++++++
 .../org/spearce/jgit/transport/DaemonClient.java   |  106 +++++++
 .../org/spearce/jgit/transport/DaemonService.java  |  120 ++++++++
 .../spearce/jgit/transport/TransportGitAnon.java   |    3 +-
 6 files changed, 662 insertions(+), 2 deletions(-)
 create mode 100644 org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Daemon.java
 create mode 100644 org.spearce.jgit/src/org/spearce/jgit/transport/Daemon.java
 create mode 100644 org.spearce.jgit/src/org/spearce/jgit/transport/DaemonClient.java
 create mode 100644 org.spearce.jgit/src/org/spearce/jgit/transport/DaemonService.java

diff --git a/org.spearce.jgit.pgm/src/META-INF/services/org.spearce.jgit.pgm.TextBuiltin b/org.spearce.jgit.pgm/src/META-INF/services/org.spearce.jgit.pgm.TextBuiltin
index e2e7938..5fb0953 100644
--- a/org.spearce.jgit.pgm/src/META-INF/services/org.spearce.jgit.pgm.TextBuiltin
+++ b/org.spearce.jgit.pgm/src/META-INF/services/org.spearce.jgit.pgm.TextBuiltin
@@ -1,4 +1,5 @@
 org.spearce.jgit.pgm.Branch
+org.spearce.jgit.pgm.Daemon
 org.spearce.jgit.pgm.DiffTree
 org.spearce.jgit.pgm.Fetch
 org.spearce.jgit.pgm.Glog
diff --git a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Daemon.java b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Daemon.java
new file mode 100644
index 0000000..aafc82e
--- /dev/null
+++ b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Daemon.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2008, Google Inc.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Git Development Community nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.spearce.jgit.pgm;
+
+import java.io.File;
+import java.net.InetSocketAddress;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.kohsuke.args4j.Argument;
+import org.kohsuke.args4j.Option;
+import org.spearce.jgit.lib.Repository;
+import org.spearce.jgit.transport.DaemonService;
+
+@Command(common = true, usage = "Export repositories over git://")
+class Daemon extends TextBuiltin {
+	@Option(name = "--port", metaVar = "PORT", usage = "port number to listen on")
+	int port = org.spearce.jgit.transport.Daemon.DEFAULT_PORT;
+
+	@Option(name = "--listen", metaVar = "HOSTNAME", usage = "hostname (or ip) to listen on")
+	String host;
+
+	@Option(name = "--enable", metaVar = "SERVICE", usage = "enable the service in all repositories", multiValued = true)
+	final List<String> enable = new ArrayList<String>();
+
+	@Option(name = "--disable", metaVar = "SERVICE", usage = "disable the service in all repositories", multiValued = true)
+	final List<String> disable = new ArrayList<String>();
+
+	@Option(name = "--allow-override", metaVar = "SERVICE", usage = "configure the service in daemon.servicename", multiValued = true)
+	final List<String> canOverride = new ArrayList<String>();
+
+	@Option(name = "--forbid-override", metaVar = "SERVICE", usage = "configure the service in daemon.servicename", multiValued = true)
+	final List<String> forbidOverride = new ArrayList<String>();
+
+	@Argument(metaVar = "DIRECTORY", usage = "directories to export")
+	final List<File> directory = new ArrayList<File>();
+
+	@Override
+	protected void run() throws Exception {
+		final org.spearce.jgit.transport.Daemon d;
+
+		d = new org.spearce.jgit.transport.Daemon(
+				host != null ? new InetSocketAddress(host, port)
+						: new InetSocketAddress(port));
+
+		for (final String n : enable)
+			service(d, n).setEnabled(true);
+		for (final String n : disable)
+			service(d, n).setEnabled(false);
+
+		for (final String n : canOverride)
+			service(d, n).setOverridable(true);
+		for (final String n : forbidOverride)
+			service(d, n).setOverridable(false);
+
+		if (directory.isEmpty()) {
+			export(d, db);
+		} else {
+			for (final File f : directory) {
+				out.println("Exporting " + f.getAbsolutePath());
+				d.exportDirectory(f);
+			}
+		}
+		d.start();
+		out.println("Listening on " + d.getAddress());
+	}
+
+	private DaemonService service(final org.spearce.jgit.transport.Daemon d,
+			final String n) {
+		final DaemonService svc = d.getService(n);
+		if (svc == null)
+			throw die("Service '" + n + "' not supported");
+		return svc;
+	}
+
+	private void export(final org.spearce.jgit.transport.Daemon daemon,
+			final Repository repo) {
+		File d = repo.getDirectory();
+		String name = d.getName();
+		while (name.equals(".git") || name.equals(".")) {
+			d = d.getParentFile();
+			name = d.getName();
+		}
+		if (!name.endsWith(".git"))
+			name += ".git";
+
+		out.println("Exporting current repository as \"" + name + "\"");
+		daemon.exportRepository(name, repo);
+	}
+}
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/Daemon.java b/org.spearce.jgit/src/org/spearce/jgit/transport/Daemon.java
new file mode 100644
index 0000000..c225740
--- /dev/null
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/Daemon.java
@@ -0,0 +1,309 @@
+/*
+ * Copyright (C) 2008, Google Inc.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Git Development Community nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.spearce.jgit.transport;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketAddress;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+import org.spearce.jgit.lib.Repository;
+
+/** Basic daemon for the anonymous <code>git://</code> transport protocol. */
+public class Daemon {
+	/** 9418: IANA assigned port number for Git. */
+	public static final int DEFAULT_PORT = 9418;
+
+	private static final int BACKLOG = 5;
+
+	private static final Pattern SAFE_REPOSITORY_NAME = Pattern
+			.compile("^[A-Za-z][A-Za-z0-9/_ -]+(\\.git)?$");
+
+	private InetSocketAddress myAddress;
+
+	private final DaemonService[] services;
+
+	private final ThreadGroup processors;
+
+	private Map<String, Repository> exports;
+
+	private Collection<File> exportBase;
+
+	private boolean run;
+
+	private Thread acceptThread;
+
+	/** Configure a daemon to listen on any available network port. */
+	public Daemon() {
+		this(null);
+	}
+
+	/**
+	 * Configure a new daemon for the specified network address.
+	 * 
+	 * @param addr
+	 *            address to listen for connections on. If null, any available
+	 *            port will be chosen on all network interfaces.
+	 */
+	public Daemon(final InetSocketAddress addr) {
+		myAddress = addr;
+		exports = new HashMap<String, Repository>();
+		exportBase = new ArrayList<File>();
+		processors = new ThreadGroup("Git-Daemon");
+
+		services = new DaemonService[] { new DaemonService("receive-pack",
+				"receivepack") {
+			@Override
+			protected void execute(final DaemonClient dc, final Repository db)
+					throws IOException {
+				final ReceivePack rp = new ReceivePack(db);
+				rp.receive(dc.getInputStream(), dc.getOutputStream(), null);
+			}
+		} };
+	}
+
+	/** @return the address connections are received on. */
+	public synchronized InetSocketAddress getAddress() {
+		return myAddress;
+	}
+
+	/**
+	 * Lookup a supported service so it can be reconfigured.
+	 * 
+	 * @param name
+	 *            name of the service; e.g. "receive-pack"/"git-receive-pack" or
+	 *            "upload-pack"/"git-upload-pack".
+	 * @return the service; null if this daemon implementation doesn't support
+	 *         the requested service type.
+	 */
+	public synchronized DaemonService getService(String name) {
+		if (!name.startsWith("git-"))
+			name = "git-" + name;
+		for (final DaemonService s : services) {
+			if (s.getCommandName().equals(name))
+				return s;
+		}
+		return null;
+	}
+
+	/**
+	 * Add a single repository to the set that is exported by this daemon.
+	 * <p>
+	 * The existence (or lack-thereof) of <code>git-daemon-export-ok</code> is
+	 * ignored by this method. The repository is always published.
+	 * 
+	 * @param name
+	 *            name the repository will be published under.
+	 * @param db
+	 *            the repository instance.
+	 */
+	public void exportRepository(final String name, final Repository db) {
+		synchronized (exports) {
+			exports.put(name, db);
+		}
+	}
+
+	/**
+	 * Recursively export all Git repositories within a directory.
+	 * 
+	 * @param dir
+	 *            the directory to export. This directory must not itself be a
+	 *            git repository, but any directory below it which has a file
+	 *            named <code>git-daemon-export-ok</code> will be published.
+	 */
+	public void exportDirectory(final File dir) {
+		synchronized (exportBase) {
+			exportBase.add(dir);
+		}
+	}
+
+	/**
+	 * Start this daemon on a background thread.
+	 * 
+	 * @throws IOException
+	 *             the server socket could not be opened.
+	 * @throws IllegalStateException
+	 *             the daemon is already running.
+	 */
+	public synchronized void start() throws IOException {
+		if (acceptThread != null)
+			throw new IllegalStateException("Daemon already running");
+
+		final ServerSocket listenSock = new ServerSocket(
+				myAddress != null ? myAddress.getPort() : 0, BACKLOG,
+				myAddress != null ? myAddress.getAddress() : null);
+		myAddress = (InetSocketAddress) listenSock.getLocalSocketAddress();
+
+		run = true;
+		acceptThread = new Thread(processors, "Git-Daemon-Accept") {
+			public void run() {
+				while (isRunning()) {
+					try {
+						startClient(listenSock.accept());
+					} catch (InterruptedIOException e) {
+						// Test again to see if we should keep accepting.
+					} catch (IOException e) {
+						break;
+					}
+				}
+
+				try {
+					listenSock.close();
+				} catch (IOException err) {
+					//
+				} finally {
+					synchronized (Daemon.this) {
+						acceptThread = null;
+					}
+				}
+			}
+		};
+		acceptThread.start();
+	}
+
+	/** @return true if this daemon is receiving connections. */
+	public synchronized boolean isRunning() {
+		return run;
+	}
+
+	/** Stop this daemon. */
+	public synchronized void stop() {
+		if (acceptThread != null) {
+			run = false;
+			acceptThread.interrupt();
+		}
+	}
+
+	private void startClient(final Socket s) {
+		final DaemonClient dc = new DaemonClient(this);
+
+		final SocketAddress peer = s.getRemoteSocketAddress();
+		if (peer instanceof InetSocketAddress)
+			dc.setRemoteAddress(((InetSocketAddress) peer).getAddress());
+
+		new Thread(processors, "Git-Daemon-Client " + peer.toString()) {
+			public void run() {
+				try {
+					dc.execute(new BufferedInputStream(s.getInputStream()),
+							new BufferedOutputStream(s.getOutputStream()));
+				} catch (IOException e) {
+					// Ignore unexpected IO exceptions from clients
+					e.printStackTrace();
+				} finally {
+					try {
+						s.getInputStream().close();
+					} catch (IOException e) {
+						// Ignore close exceptions
+					}
+					try {
+						s.getOutputStream().close();
+					} catch (IOException e) {
+						// Ignore close exceptions
+					}
+				}
+			}
+		}.start();
+	}
+
+	synchronized DaemonService matchService(final String cmd) {
+		for (final DaemonService d : services) {
+			if (d.handles(cmd))
+				return d;
+		}
+		return null;
+	}
+
+	Repository openRepository(String name) {
+		if (!name.startsWith("/"))
+			return null;
+		name = name.substring(1);
+
+		Repository db;
+		synchronized (exports) {
+			db = exports.get(name);
+			if (db != null)
+				return db;
+
+			db = exports.get(name + ".git");
+			if (db != null)
+				return db;
+		}
+
+		if (SAFE_REPOSITORY_NAME.matcher(name).matches()) {
+			final File[] search;
+			synchronized (exportBase) {
+				search = exportBase.toArray(new File[exportBase.size()]);
+			}
+			for (final File f : search) {
+				db = openRepository(new File(f, name));
+				if (db != null)
+					return db;
+
+				db = openRepository(new File(f, name + ".git"));
+				if (db != null)
+					return db;
+
+				db = openRepository(new File(f, name + "/.git"));
+				if (db != null)
+					return db;
+			}
+		}
+		return null;
+	}
+
+	private Repository openRepository(final File d) {
+		if (d.isDirectory() && new File(d, "git-daemon-export-ok").exists()) {
+			try {
+				return new Repository(d);
+			} catch (IOException err) {
+				// Ignore
+			}
+		}
+		return null;
+	}
+}
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/DaemonClient.java b/org.spearce.jgit/src/org/spearce/jgit/transport/DaemonClient.java
new file mode 100644
index 0000000..636cf22
--- /dev/null
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/DaemonClient.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2008, Google Inc.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Git Development Community nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.spearce.jgit.transport;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.InetAddress;
+
+/** Active network client of {@link Daemon}. */
+public class DaemonClient {
+	private final Daemon daemon;
+
+	private InetAddress peer;
+
+	private InputStream rawIn;
+
+	private OutputStream rawOut;
+
+	DaemonClient(final Daemon d) {
+		daemon = d;
+	}
+
+	void setRemoteAddress(final InetAddress ia) {
+		peer = ia;
+	}
+
+	/** @return the daemon which spawned this client. */
+	public Daemon getDaemon() {
+		return daemon;
+	}
+
+	/** @return Internet address of the remote client. */
+	public InetAddress getRemoteAddress() {
+		return peer;
+	}
+
+	/** @return input stream to read from the connected client. */
+	public InputStream getInputStream() {
+		return rawIn;
+	}
+
+	/** @return output stream to send data to the connected client. */
+	public OutputStream getOutputStream() {
+		return rawOut;
+	}
+
+	void execute(final InputStream in, final OutputStream out)
+			throws IOException {
+		rawIn = in;
+		rawOut = out;
+
+		String cmd = new PacketLineIn(rawIn).readStringNoLF();
+		if (cmd == null || cmd.length() == 0)
+			return;
+
+		final int nul = cmd.indexOf('\0');
+		if (nul >= 0) {
+			// Newer clients hide a "host" header behind this byte.
+			// Currently we don't use it for anything, so we ignore
+			// this portion of the command.
+			//
+			cmd = cmd.substring(0, nul);
+		}
+
+		final DaemonService srv = getDaemon().matchService(cmd);
+		if (srv == null)
+			return;
+		srv.execute(this, cmd);
+	}
+}
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/DaemonService.java b/org.spearce.jgit/src/org/spearce/jgit/transport/DaemonService.java
new file mode 100644
index 0000000..775a506
--- /dev/null
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/DaemonService.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2008, Google Inc.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Git Development Community nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.spearce.jgit.transport;
+
+import java.io.IOException;
+
+import org.spearce.jgit.lib.Repository;
+
+/** A service exposed by {@link Daemon} over anonymous <code>git://</code>. */
+public abstract class DaemonService {
+	private final String command;
+
+	private final String config;
+
+	private boolean enabled;
+
+	private boolean overridable;
+
+	protected DaemonService(final String cmdName, final String cfgName) {
+		command = cmdName.startsWith("git-") ? cmdName : "git-" + cmdName;
+		config = cfgName;
+		overridable = true;
+	}
+
+	/** @return is this service enabled for invocation? */
+	public boolean isEnabled() {
+		return enabled;
+	}
+
+	/**
+	 * @param on
+	 *            true to allow this service to be used; false to deny it.
+	 */
+	public void setEnabled(final boolean on) {
+		enabled = on;
+	}
+
+	/** @return can this service be configured in the repository config file? */
+	public boolean isOverridable() {
+		return overridable;
+	}
+
+	/**
+	 * @param on
+	 *            true to permit repositories to override this service's enabled
+	 *            state with the <code>daemon.servicename</code> config setting.
+	 */
+	public void setOverridable(final boolean on) {
+		overridable = on;
+	}
+
+	/** @return name of the command requested by clients. */
+	public String getCommandName() {
+		return command;
+	}
+
+	/**
+	 * Determine if this service can handle the requested command.
+	 * 
+	 * @param commandLine
+	 *            input line from the client.
+	 * @return true if this command can accept the given command line.
+	 */
+	public boolean handles(final String commandLine) {
+		return command.length() + 1 < commandLine.length()
+				&& commandLine.charAt(command.length()) == ' '
+				&& commandLine.startsWith(command);
+	}
+
+	void execute(final DaemonClient client, final String commandLine)
+			throws IOException {
+		final String name = commandLine.substring(command.length() + 1);
+		final Repository db = client.getDaemon().openRepository(name);
+		if (db == null)
+			return;
+		boolean on = isEnabled();
+		if (isOverridable())
+			on = db.getConfig().getBoolean("daemon", config, on);
+		if (on)
+			execute(client, db);
+	}
+
+	protected abstract void execute(DaemonClient client, Repository db)
+			throws IOException;
+}
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitAnon.java b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitAnon.java
index a80c335..a11f293 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitAnon.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitAnon.java
@@ -56,8 +56,7 @@
  * source projects, as there are no authentication or authorization overheads.
  */
 class TransportGitAnon extends PackTransport {
-	/** IANA assigned port number for Git. */
-	static final int GIT_PORT = 9418;
+	static final int GIT_PORT = Daemon.DEFAULT_PORT;
 
 	static boolean canHandle(final URIish uri) {
 		return "git".equals(uri.getScheme());
-- 
1.6.1.rc4.301.g5497a

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]

  Powered by Linux