##// END OF EJS Templates
zeroconf: don't allow ipv6 addresses
Alexander Solovyov -
r7777:e3425726 default
parent child Browse files
Show More
@@ -1,159 +1,159 b''
1 # zeroconf.py - zeroconf support for Mercurial
1 # zeroconf.py - zeroconf support for Mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of
5 # This software may be used and distributed according to the terms of
6 # the GNU General Public License (version 2), incorporated herein by
6 # the GNU General Public License (version 2), incorporated herein by
7 # reference.
7 # reference.
8
8
9 '''zeroconf support for mercurial repositories
9 '''zeroconf support for mercurial repositories
10
10
11 Zeroconf enabled repositories will be announced in a network without the need
11 Zeroconf enabled repositories will be announced in a network without the need
12 to configure a server or a service. They can be discovered without knowing
12 to configure a server or a service. They can be discovered without knowing
13 their actual IP address.
13 their actual IP address.
14
14
15 To use the zeroconf extension add the following entry to your hgrc file:
15 To use the zeroconf extension add the following entry to your hgrc file:
16
16
17 [extensions]
17 [extensions]
18 hgext.zeroconf =
18 hgext.zeroconf =
19
19
20 To allow other people to discover your repository using run "hg serve" in your
20 To allow other people to discover your repository using run "hg serve" in your
21 repository.
21 repository.
22
22
23 $ cd test
23 $ cd test
24 $ hg serve
24 $ hg serve
25
25
26 You can discover zeroconf enabled repositories by running "hg paths".
26 You can discover zeroconf enabled repositories by running "hg paths".
27
27
28 $ hg paths
28 $ hg paths
29 zc-test = http://example.com:8000/test
29 zc-test = http://example.com:8000/test
30 '''
30 '''
31
31
32 import Zeroconf, socket, time, os
32 import Zeroconf, socket, time, os
33 from mercurial import ui
33 from mercurial import ui
34 from mercurial import extensions
34 from mercurial import extensions
35 from mercurial.hgweb import hgweb_mod
35 from mercurial.hgweb import hgweb_mod
36 from mercurial.hgweb import hgwebdir_mod
36 from mercurial.hgweb import hgwebdir_mod
37
37
38 # publish
38 # publish
39
39
40 server = None
40 server = None
41 localip = None
41 localip = None
42
42
43 def getip():
43 def getip():
44 # finds external-facing interface without sending any packets (Linux)
44 # finds external-facing interface without sending any packets (Linux)
45 try:
45 try:
46 s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
46 s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
47 s.connect(('1.0.0.1', 0))
47 s.connect(('1.0.0.1', 0))
48 ip = s.getsockname()[0]
48 ip = s.getsockname()[0]
49 return ip
49 return ip
50 except:
50 except:
51 pass
51 pass
52
52
53 # Generic method, sometimes gives useless results
53 # Generic method, sometimes gives useless results
54 dumbip = socket.gethostbyaddr(socket.gethostname())[2][0]
54 dumbip = socket.gethostbyaddr(socket.gethostname())[2][0]
55 if not dumbip.startswith('127.'):
55 if not dumbip.startswith('127.') and ':' not in dumbip:
56 return dumbip
56 return dumbip
57
57
58 # works elsewhere, but actually sends a packet
58 # works elsewhere, but actually sends a packet
59 try:
59 try:
60 s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
60 s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
61 s.connect(('1.0.0.1', 1))
61 s.connect(('1.0.0.1', 1))
62 ip = s.getsockname()[0]
62 ip = s.getsockname()[0]
63 return ip
63 return ip
64 except:
64 except:
65 pass
65 pass
66
66
67 return dumbip
67 return dumbip
68
68
69 def publish(name, desc, path, port):
69 def publish(name, desc, path, port):
70 global server, localip
70 global server, localip
71 if not server:
71 if not server:
72 try:
72 try:
73 server = Zeroconf.Zeroconf()
73 server = Zeroconf.Zeroconf()
74 except socket.gaierror:
74 except socket.gaierror:
75 # if we have no internet connection, this can happen.
75 # if we have no internet connection, this can happen.
76 return
76 return
77 ip = getip()
77 ip = getip()
78 localip = socket.inet_aton(ip)
78 localip = socket.inet_aton(ip)
79
79
80 parts = socket.gethostname().split('.')
80 parts = socket.gethostname().split('.')
81 host = parts[0] + ".local"
81 host = parts[0] + ".local"
82
82
83 # advertise to browsers
83 # advertise to browsers
84 svc = Zeroconf.ServiceInfo('_http._tcp.local.',
84 svc = Zeroconf.ServiceInfo('_http._tcp.local.',
85 name + '._http._tcp.local.',
85 name + '._http._tcp.local.',
86 server = host,
86 server = host,
87 port = port,
87 port = port,
88 properties = {'description': desc,
88 properties = {'description': desc,
89 'path': "/" + path},
89 'path': "/" + path},
90 address = localip, weight = 0, priority = 0)
90 address = localip, weight = 0, priority = 0)
91 server.registerService(svc)
91 server.registerService(svc)
92
92
93 # advertise to Mercurial clients
93 # advertise to Mercurial clients
94 svc = Zeroconf.ServiceInfo('_hg._tcp.local.',
94 svc = Zeroconf.ServiceInfo('_hg._tcp.local.',
95 name + '._hg._tcp.local.',
95 name + '._hg._tcp.local.',
96 server = host,
96 server = host,
97 port = port,
97 port = port,
98 properties = {'description': desc,
98 properties = {'description': desc,
99 'path': "/" + path},
99 'path': "/" + path},
100 address = localip, weight = 0, priority = 0)
100 address = localip, weight = 0, priority = 0)
101 server.registerService(svc)
101 server.registerService(svc)
102
102
103 class hgwebzc(hgweb_mod.hgweb):
103 class hgwebzc(hgweb_mod.hgweb):
104 def __init__(self, repo, name=None):
104 def __init__(self, repo, name=None):
105 super(hgwebzc, self).__init__(repo, name)
105 super(hgwebzc, self).__init__(repo, name)
106 name = self.reponame or os.path.basename(repo.root)
106 name = self.reponame or os.path.basename(repo.root)
107 desc = self.repo.ui.config("web", "description", name)
107 desc = self.repo.ui.config("web", "description", name)
108 publish(name, desc, name, int(repo.ui.config("web", "port", 8000)))
108 publish(name, desc, name, int(repo.ui.config("web", "port", 8000)))
109
109
110 class hgwebdirzc(hgwebdir_mod.hgwebdir):
110 class hgwebdirzc(hgwebdir_mod.hgwebdir):
111 def run(self):
111 def run(self):
112 for r, p in self.repos:
112 for r, p in self.repos:
113 u = ui.ui(parentui=self.parentui)
113 u = ui.ui(parentui=self.parentui)
114 u.readconfig(os.path.join(p, '.hg', 'hgrc'))
114 u.readconfig(os.path.join(p, '.hg', 'hgrc'))
115 n = os.path.basename(r)
115 n = os.path.basename(r)
116 publish(n, "hgweb", p, int(u.config("web", "port", 8000)))
116 publish(n, "hgweb", p, int(u.config("web", "port", 8000)))
117 return super(hgwebdirzc, self).run()
117 return super(hgwebdirzc, self).run()
118
118
119 # listen
119 # listen
120
120
121 class listener(object):
121 class listener(object):
122 def __init__(self):
122 def __init__(self):
123 self.found = {}
123 self.found = {}
124 def removeService(self, server, type, name):
124 def removeService(self, server, type, name):
125 if repr(name) in self.found:
125 if repr(name) in self.found:
126 del self.found[repr(name)]
126 del self.found[repr(name)]
127 def addService(self, server, type, name):
127 def addService(self, server, type, name):
128 self.found[repr(name)] = server.getServiceInfo(type, name)
128 self.found[repr(name)] = server.getServiceInfo(type, name)
129
129
130 def getzcpaths():
130 def getzcpaths():
131 server = Zeroconf.Zeroconf()
131 server = Zeroconf.Zeroconf()
132 l = listener()
132 l = listener()
133 browser = Zeroconf.ServiceBrowser(server, "_hg._tcp.local.", l)
133 browser = Zeroconf.ServiceBrowser(server, "_hg._tcp.local.", l)
134 time.sleep(1)
134 time.sleep(1)
135 server.close()
135 server.close()
136 for v in l.found.values():
136 for v in l.found.values():
137 n = v.name[:v.name.index('.')]
137 n = v.name[:v.name.index('.')]
138 n.replace(" ", "-")
138 n.replace(" ", "-")
139 u = "http://%s:%s%s" % (socket.inet_ntoa(v.address), v.port,
139 u = "http://%s:%s%s" % (socket.inet_ntoa(v.address), v.port,
140 v.properties.get("path", "/"))
140 v.properties.get("path", "/"))
141 yield "zc-" + n, u
141 yield "zc-" + n, u
142
142
143 def config(orig, self, section, key, default=None, untrusted=False):
143 def config(orig, self, section, key, default=None, untrusted=False):
144 if section == "paths" and key.startswith("zc-"):
144 if section == "paths" and key.startswith("zc-"):
145 for n, p in getzcpaths():
145 for n, p in getzcpaths():
146 if n == key:
146 if n == key:
147 return p
147 return p
148 return orig(self, section, key, default, untrusted)
148 return orig(self, section, key, default, untrusted)
149
149
150 def configitems(orig, self, section, untrusted=False):
150 def configitems(orig, self, section, untrusted=False):
151 r = orig(self, section, untrusted)
151 r = orig(self, section, untrusted)
152 if section == "paths":
152 if section == "paths":
153 r += getzcpaths()
153 r += getzcpaths()
154 return r
154 return r
155
155
156 extensions.wrapfunction(ui.ui, 'config', config)
156 extensions.wrapfunction(ui.ui, 'config', config)
157 extensions.wrapfunction(ui.ui, 'configitems', configitems)
157 extensions.wrapfunction(ui.ui, 'configitems', configitems)
158 hgweb_mod.hgweb = hgwebzc
158 hgweb_mod.hgweb = hgwebzc
159 hgwebdir_mod.hgwebdir = hgwebdirzc
159 hgwebdir_mod.hgwebdir = hgwebdirzc
General Comments 0
You need to be logged in to leave comments. Login now