示例#1
0
文件: ISconf.py 项目: stevegt/isconf4
 def fork(self,migrate=False):
     debug("fork args",self.args)
     if self.volume.wip(): 
         error("local changes not checked in")
         return 
     if len(self.args) < 1:
         error("missing new branch name")
         return
     newbranch = self.args[0]
     debug("newbranch",newbranch)
     if migrate and newbranch == self.volname:
         error("%s is already on %s branch" % (
                 os.environ['HOSTNAME'], newbranch)
                 )
         return
     newvolume = ISFS.Volume(
             newbranch,logname=self.logname,outpin=self.outpin,
             histfile=self.histfile)
     yield kernel.wait(self.volume.pull(bg=True))
     yield kernel.wait(newvolume.pull(bg=True))
     if not migrate:
         if not newvolume.journal.copy(self.volume.journal):
             error("%s already exists -- did you mean 'migrate'?" % newbranch)
             return
         info("branch %s created" % (newbranch))
     else:
         if not self.volume.journal.migrate(newvolume.journal):
             error("migration of this host to %s failed: conflicting changes: %s is not a superset of %s" % (newbranch,newbranch,self.volname))
             return
     branch(newbranch)
     self.volname = newbranch
     self.volume = newvolume
     info("%s migrated to %s" % (os.environ['HOSTNAME'], newbranch))
示例#2
0
 def pull(self, bg=False):
     files = (self.mkrelative(self.p.journal), self.mkrelative(self.p.lock))
     yield kernel.wait(self.pullfiles(files))
     files = self.pendingfiles()
     if bg:
         kernel.spawn(self.pullfiles(files))
     else:
         yield kernel.wait(self.pullfiles(files))
示例#3
0
 def pull(self,bg=False):
     files = (
             self.mkrelative(self.p.journal),
             self.mkrelative(self.p.lock)
             )
     yield kernel.wait(self.pullfiles(files))
     files = self.pendingfiles()
     if bg:
         kernel.spawn(self.pullfiles(files))
     else:
         yield kernel.wait(self.pullfiles(files))
示例#4
0
 def ci(self):
     wipdata = self.wip()
     if not wipdata:
         if not self.cklock():
             return
         info("no outstanding updates")
         self.unlock()
         return
     if not self.cklock(): return
     jtime = self.journal.mtime()
     yield kernel.wait(self.pull())
     if not self.cklock(): return
     # if jtime and jtime != self.journal.mtime():
     if jtime != self.journal.mtime():
         error(
             "someone else checked in conflicting changes -- repair wip and retry"
         )
         return
     if self.journal.mtime() > getmtime_int(self.p.wip):
         error("journal is newer than wip -- repair and retry")
         return
     self.journal.addraw(wipdata)
     # XXX announce all new block files here (rather than in addwip)
     os.unlink(self.p.wip)
     self.announce(self.p.journal)
     info("changes checked in")
     self.unlock()
示例#5
0
 def ihaveRx(self,msg,ip):
     yield None
     scheme = msg['scheme']
     port = msg['port']
     path = msg['file']
     mtime = msg.head.mtime
     # XXX is python's pseudo-random good enough here?  
     #
     # probably, but for other cases, use 'gpg --gen-random 2 16'
     # to generate 128 bits of random data from entropy
     #
     challenge = str(random.random())
     url = "%s://%s:%s/%s?challenge=%s" % (scheme,ip,port,path,challenge)
     path = path.lstrip('/')
     # simple check to ignore foreign domains 
     # XXX probably want to make this a list of domains
     domain  = os.environ['IS_DOMAIN']
     if not path.startswith(domain + '/'):
         debug("foreign domain, ignoring: %s" % path)
         return
     fullpath = os.path.join(self.p.cache,path)
     mymtime = 0
     debug("checking",url)
     if os.path.exists(fullpath):
         mymtime = getmtime_int(fullpath)
     if mtime > mymtime:
         debug("remote is newer:",url)
         if self.req.has_key(path):
             self.req[path]['state'] = SENDME
         yield kernel.wait(self.wget(path,url,challenge))
     elif mtime < mymtime:
         debug("remote is older:",url)
         self.ihaveTx(path)
     else:
         debug("remote and local times are the same:",path,mtime,mymtime)
示例#6
0
文件: ISconf.py 项目: stevegt/isconf4
 def Exec(self):
     yield None
     cwd = self.opt['cwd']
     if not len(self.data):
         error(iserrno.EINVAL,"missing exec command")
         return
     yield kernel.wait(self.volume.Exec(self.data,cwd))
示例#7
0
 def Exec(self, argdata, cwd):
     # XXX what about when cwd != volroot?
     if not self.cklock(): return
     msg = FBP.mkmsg('exec', argdata + "\n", cwd=cwd)
     yield kernel.wait(self.addwip(msg))
     argv = argdata.split("\n")
     info("exec done:", str(argv))
示例#8
0
 def Exec(self,argdata,cwd):
     # XXX what about when cwd != volroot?
     if not self.cklock(): return 
     msg = FBP.mkmsg('exec', argdata + "\n", cwd=cwd)
     yield kernel.wait(self.addwip(msg))
     argv = argdata.split("\n")
     info("exec done:", str(argv))
示例#9
0
 def close(self):
     # XXX this whole File class is a kludge, and really needs to
     # be gotten rid of and the useful bits moved into ISconf as part
     # of the refactoring to turn ISFS into ISDM
     #
     # build journal transaction message
     os.close(self.tmp)
     fbp = fbp822()
     parent = os.path.dirname(self.path)
     pathmodes = []
     while True:
         pstat = os.stat(parent)
         mug = "%d:%d:%d" % (pstat.st_mode, pstat.st_uid, pstat.st_gid)
         pathmodes.insert(0, mug)
         if len(parent) == 1:
             assert parent == '/'
             break
         parent = os.path.dirname(parent)
         assert len(parent) >= 1
     # XXX pathname needs to be relative to volroot
     msg = fbp.mkmsg('snap',
                     '',
                     pathname=self.path,
                     st_mode=self.st.st_mode,
                     st_uid=self.st.st_uid,
                     st_gid=self.st.st_gid,
                     st_atime=self.st.st_atime,
                     st_mtime=self.st.st_mtime,
                     pathmodes=','.join(pathmodes))
     debug("calling addwip")
     yield kernel.wait(self.volume.addwip(msg=msg, tmpfn=self.tmpfn))
     self.volume.closefile(self)
     info("snapshot done:", self.path)
示例#10
0
 def close(self):
     # XXX this whole File class is a kludge, and really needs to
     # be gotten rid of and the useful bits moved into ISconf as part
     # of the refactoring to turn ISFS into ISDM
     #
     # build journal transaction message
     os.close(self.tmp)
     fbp = fbp822()
     parent = os.path.dirname(self.path)
     pathmodes = []
     while True:
         pstat = os.stat(parent)
         mug = "%d:%d:%d" % (pstat.st_mode,pstat.st_uid,pstat.st_gid)
         pathmodes.insert(0,mug)
         if len(parent) == 1:
             assert parent == '/'
             break
         parent = os.path.dirname(parent)
         assert len(parent) >= 1
     # XXX pathname needs to be relative to volroot
     msg = fbp.mkmsg('snap','',
             pathname=self.path,
             st_mode = self.st.st_mode,
             st_uid = self.st.st_uid,
             st_gid = self.st.st_gid,
             st_atime = self.st.st_atime,
             st_mtime = self.st.st_mtime,
             pathmodes = ','.join(pathmodes)
             )
     debug("calling addwip")
     yield kernel.wait(self.volume.addwip(msg=msg,tmpfn=self.tmpfn))
     self.volume.closefile(self)
     info("snapshot done:", self.path)
示例#11
0
 def ci(self):
     wipdata = self.wip()
     if not wipdata:
         if not self.cklock(): 
             return 
         info("no outstanding updates")
         self.unlock()
         return 
     if not self.cklock(): return 
     jtime = self.journal.mtime()
     yield kernel.wait(self.pull())
     if not self.cklock(): return
     # if jtime and jtime != self.journal.mtime():
     if jtime != self.journal.mtime():
         error("someone else checked in conflicting changes -- repair wip and retry")
         return
     if self.journal.mtime() > getmtime_int(self.p.wip):
         error("journal is newer than wip -- repair and retry")
         return
     self.journal.addraw(wipdata)
     # XXX announce all new block files here (rather than in addwip)
     os.unlink(self.p.wip)
     self.announce(self.p.journal)
     info("changes checked in")
     self.unlock()
示例#12
0
文件: ISconf.py 项目: stevegt/isconf4
 def snap(self):
     debug("starting snap")
     yield None
     if not len(self.args):
         error(iserrno.EINVAL,"missing snapshot pathname")
         return
     if len(self.args) > 1:
         error(iserrno.EINVAL,
                 "can only snapshot one file at a time (for now)")
         return
     path = self.args[0]
     cwd = self.opt['cwd']
     path = os.path.join(cwd,path)
     if not os.path.exists(path):
         error(iserrno.ENOENT,path)
         return
     if not os.path.isfile(path):
         error(iserrno.EINVAL,"%s is not a file" % path)
         return
     st = os.stat(path)
     src = open(path,'r')
     debug("calling open")
     dst = self.volume.open(path,'w')
     if not dst:
         return
     dst.setstat(st)
     while True:
         yield kernel.sigbusy
         data = src.read(1024 * 1024 * 1)
         if not len(data):
             break
         dst.write(data)
     src.close()
     debug("calling close")
     yield kernel.wait(dst.close())
示例#13
0
文件: ISconf.py 项目: stevegt/isconf4
 def lock(self):
     message = ''
     if self.opt['message']:
         message = self.opt['message']
     if self.args:
         message = "%s %s" % (message,' '.join(self.args))
     message = message.strip()
     if not len(message):
         error(iserrno.NEEDMSG,'did not lock %s' % self.volname)
         return
     yield kernel.wait(self.volume.lock(message))
示例#14
0
文件: ISconf.py 项目: stevegt/isconf4
 def process(self,transport,outpin):
     while True:
         yield None
         # read messages from client
         mlist = FBP.fromFile(stream=transport)
         for msg in mlist:
             if msg in (kernel.eagain,None):
                 continue
             if outpin.state == 'down':
                 return
             if msg is kernel.eof:
                 # outpin.close()
                 return
             debug("from client:", str(msg))
             rectype = msg.type()
             if rectype != 'cmd':
                 error(iserrno.EINVAL, 
                     "first message must be cmd, got %s" % rectype)
                 return
             self.verbose = msg.head.verbose
             self.debug = msg.head.debug
             data = msg.payload()
             opt = dict(msg.items())
             if opt['message'] == 'None':
                 opt['message'] = None
             # XXX why don't we just pass the whole message to Ops()?
             opt['reboot_ok'] = msg.head.reboot_ok
             debug(opt)
             verb = msg['verb']
             debug("verb in process",verb)
             if verb != 'lock' and opt['message'] != None:
                 error(iserrno.EINVAL, "-m is only valid on lock")
             if verb == 'exec': verb = 'Exec' # sigh
             if verb == 'shutdown': 
                 kernel.shutdown()
                 return
             args=[]
             if len(data):
                 data = data.strip()
                 args = data.split('\n')
             ops = Ops(opt=opt,args=args,data=data,outpin=outpin)
             try:
                 func = getattr(ops,verb)
             except AttributeError:
                 error(outpin,iserrno.EINVAL,verb)
                 return
             # start command processor, wait for it to finish
             debug("process calling",verb)
             yield kernel.wait(func())
             return # XXX can't handle stdin yet
示例#15
0
 def update(self, reboot_ok=False):
     fbp = fbp822()
     if self.wip():
         error("local changes not checked in")
         return
     info("checking for updates")
     yield kernel.wait(self.pull())
     pending = self.pending()
     if not len(pending):
         info("no new updates")
         return
     for msg in pending:
         debug(msg['pathname'], time.time())
         # XXX XXX XXX OUCH!!!  using 'wait' here keeps us from
         # XXX XXX XXX checking return codes; execution of journal
         # XXX XXX XXX will always continue on error
         if msg.type() == 'snap':
             yield kernel.wait(self.updateSnap(msg))
         if msg.type() == 'exec':
             yield kernel.wait(self.updateExec(msg))
         if msg.type() == 'reboot':
             yield kernel.wait(self.updateReboot(msg, reboot_ok))
     info("update done")
示例#16
0
 def update(self,reboot_ok=False):
     fbp = fbp822()
     if self.wip():
         error("local changes not checked in")
         return 
     info("checking for updates")
     yield kernel.wait(self.pull())
     pending = self.pending()
     if not len(pending):
         info("no new updates")
         return
     for msg in pending:
         debug(msg['pathname'],time.time())
         # XXX XXX XXX OUCH!!!  using 'wait' here keeps us from
         # XXX XXX XXX checking return codes; execution of journal
         # XXX XXX XXX will always continue on error
         if msg.type() == 'snap': 
             yield kernel.wait(self.updateSnap(msg))
         if msg.type() == 'exec': 
             yield kernel.wait(self.updateExec(msg))
         if msg.type() == 'reboot': 
             yield kernel.wait(self.updateReboot(msg,reboot_ok))
     info("update done")
示例#17
0
 def lock(self,message):
     logname = self.logname
     message = "%s@%s: %s" % (logname,os.environ['HOSTNAME'],str(message))
     yield kernel.wait(self.pull())
     if self.locked() and not self.cklock():
         return 
     pending = self.pending()
     if len(pending):
         error("local node is out of date -- try 'isconf up' first")
         return
     open(self.p.lock,'w').write(message)
     self.announce(self.p.lock)
     info("%s locked" % self.volname)
     if not self.locked():
         error(iserrno.NOTLOCKED,'attempt to lock %s failed' % self.volname) 
示例#18
0
 def lock(self, message):
     logname = self.logname
     message = "%s@%s: %s" % (logname, os.environ['HOSTNAME'], str(message))
     yield kernel.wait(self.pull())
     if self.locked() and not self.cklock():
         return
     pending = self.pending()
     if len(pending):
         error("local node is out of date -- try 'isconf up' first")
         return
     open(self.p.lock, 'w').write(message)
     self.announce(self.p.lock)
     info("%s locked" % self.volname)
     if not self.locked():
         error(iserrno.NOTLOCKED,
               'attempt to lock %s failed' % self.volname)
示例#19
0
 def ihaveRx(self, msg, ip):
     yield None
     scheme = msg['scheme']
     port = msg['port']
     path = msg['file']
     mtime = msg.head.mtime
     # XXX is python's pseudo-random good enough here?
     #
     # probably, but for other cases, use 'gpg --gen-random 2 16'
     # to generate 128 bits of random data from entropy
     #
     challenge = str(random.random())
     url = "%s://%s:%s/%s?challenge=%s" % (scheme, ip, port, path,
                                           challenge)
     path = path.lstrip('/')
     # simple check to ignore foreign domains
     # XXX probably want to make this a list of domains
     domain = os.environ['IS_DOMAIN']
     if not path.startswith(domain + '/'):
         debug("foreign domain, ignoring: %s" % path)
         return
     fullpath = os.path.join(self.p.cache, path)
     mymtime = 0
     debug("checking", url)
     if os.path.exists(fullpath):
         mymtime = getmtime_int(fullpath)
     if mtime > mymtime:
         debug("remote is newer:", url)
         if self.req.has_key(path):
             self.req[path]['state'] = SENDME
         yield kernel.wait(self.wget(path, url, challenge))
     elif mtime < mymtime:
         debug("remote is older:", url)
         self.ihaveTx(path)
     else:
         debug("remote and local times are the same:", path, mtime, mymtime)
示例#20
0
 def updateSnap(self,msg):
     blk = msg['blk']
     src = self.blk2path(blk)
     relsrc = self.mkrelative(src)
     match = re.match("(\w+)-(\w+)-(\d+)",blk)
     if not match:
         error("unable to parse block id", blk)
         yield False
         return
     sha1sum = match.group(1)
     md5sum = match.group(2)
     for retry in range(3):
         while not os.path.exists(src):
             info("pull", relsrc)
             yield kernel.wait(self.pullfiles([relsrc]))
         sumtask = kernel.spawn(self.sums(src),itermode=True)
         sums = None
         for sums in sumtask: yield kernel.sigbusy
         if not sums: 
             error("unable to checksum",tmpfn)
             yield False
             return
         if sums['sha'] == sha1sum and sums['md5'] == md5sum:
             break
         debug("re-fetching corrupt block:", src)
         os.unlink(src)
     if not os.path.exists(src):
         error("missing block:", src)
         yield False
         return
     # XXX volroot
     dst = msg['pathname']
     dstdir = os.path.dirname(dst)
     dstpath = dstdir.split('/')
     pathmodes = msg['pathmodes'].split(',')
     debug("dstpath %s" % repr(dstpath))
     debug("pathmodes %s" % repr(pathmodes))
     assert len(dstpath) == len(pathmodes)
     # create any missing parent dirs
     for i in range(len(pathmodes)):
         pathmode = pathmodes[i]
         (st_mode,st_uid,st_gid) = pathmode.split(':')
         curpath = '/'.join(dstpath[:i+1]) + '/'
         assert curpath[0] == '/'
         debug("checking %s" % curpath)
         if not os.path.isdir(curpath):
             debug('creating path %s as %s' % (curpath,pathmode))
             os.mkdir(curpath,int(st_mode))
             os.chown(curpath,int(st_uid),int(st_gid))
     tmpdst = dst + ".IS.snap.tmp~"
     # security: create and setstat first
     open(tmpdst,'w')
     class St: pass
     st = St()
     for attr in "st_mode st_uid st_gid st_atime st_mtime".split():
         setattr(st,attr,getattr(msg.head,attr))
     self.setstat(tmpdst,st)
     # integrity: copy to tmpdst first, then rename
     shutil.copyfile(src,tmpdst)
     os.rename(tmpdst,dst)
     # update history
     self.history.add(msg)
     info("updated", dst)
     yield True
     debug("updateSnap done")
示例#21
0
文件: ISconf.py 项目: stevegt/isconf4
 def migrate(self):
     yield None
     debug("migrate calling fork")
     yield kernel.wait(self.fork(migrate=True))
示例#22
0
 def reboot(self):
     if not self.cklock(): return 
     msg = FBP.mkmsg('reboot')
     yield kernel.wait(self.addwip(msg))
示例#23
0
文件: ISconf.py 项目: stevegt/isconf4
 def reboot(self):
     yield None
     debug("calling reboot")
     yield kernel.wait(self.volume.reboot())
示例#24
0
文件: ISconf.py 项目: stevegt/isconf4
 def up(self):
     reboot_ok = bool(self.opt.get('reboot_ok',False))
     if reboot_ok:
         debug("reboot_ok", repr(self.opt['reboot_ok']))
         info("may reboot...")
     yield kernel.wait(self.volume.update(reboot_ok=reboot_ok))
示例#25
0
    def updateSnap(self, msg):
        blk = msg['blk']
        src = self.blk2path(blk)
        relsrc = self.mkrelative(src)
        match = re.match("(\w+)-(\w+)-(\d+)", blk)
        if not match:
            error("unable to parse block id", blk)
            yield False
            return
        sha1sum = match.group(1)
        md5sum = match.group(2)
        for retry in range(3):
            while not os.path.exists(src):
                info("pull", relsrc)
                yield kernel.wait(self.pullfiles([relsrc]))
            sumtask = kernel.spawn(self.sums(src), itermode=True)
            sums = None
            for sums in sumtask:
                yield kernel.sigbusy
            if not sums:
                error("unable to checksum", tmpfn)
                yield False
                return
            if sums['sha'] == sha1sum and sums['md5'] == md5sum:
                break
            debug("re-fetching corrupt block:", src)
            os.unlink(src)
        if not os.path.exists(src):
            error("missing block:", src)
            yield False
            return
        # XXX volroot
        dst = msg['pathname']
        dstdir = os.path.dirname(dst)
        dstpath = dstdir.split('/')
        pathmodes = msg['pathmodes'].split(',')
        debug("dstpath %s" % repr(dstpath))
        debug("pathmodes %s" % repr(pathmodes))
        assert len(dstpath) == len(pathmodes)
        # create any missing parent dirs
        for i in range(len(pathmodes)):
            pathmode = pathmodes[i]
            (st_mode, st_uid, st_gid) = pathmode.split(':')
            curpath = '/'.join(dstpath[:i + 1]) + '/'
            assert curpath[0] == '/'
            debug("checking %s" % curpath)
            if not os.path.isdir(curpath):
                debug('creating path %s as %s' % (curpath, pathmode))
                os.mkdir(curpath, int(st_mode))
                os.chown(curpath, int(st_uid), int(st_gid))
        tmpdst = dst + ".IS.snap.tmp~"
        # security: create and setstat first
        open(tmpdst, 'w')

        class St:
            pass

        st = St()
        for attr in "st_mode st_uid st_gid st_atime st_mtime".split():
            setattr(st, attr, getattr(msg.head, attr))
        self.setstat(tmpdst, st)
        # integrity: copy to tmpdst first, then rename
        shutil.copyfile(src, tmpdst)
        os.rename(tmpdst, dst)
        # update history
        self.history.add(msg)
        info("updated", dst)
        yield True
        debug("updateSnap done")
示例#26
0
    def run(self):
        from SocketServer import UDPServer
        from isconf.fbp822 import fbp822, Error822

        kernel.spawn(self.puller())
        kernel.spawn(self.sender())

        # XXX most of the following should be broken out into a receiver() task

        dir = self.p.cache
        udpport = self.udpport

        debug("UDP server serving %s on port %d" % (dir, udpport))
        sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self.sock = sock
        sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
        sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, True)
        sock.setblocking(0)
        sock.bind(('', udpport))
        # laddr = sock.getsockname()
        # localip = os.environ['HOSTNAME']
        while True:
            yield None
            self.flush()
            yield None
            try:
                data, addr = sock.recvfrom(8192)
                # XXX check against addrs or nets
                debug("from %s: %s" % (addr, data))
                factory = fbp822()
                msg = factory.parse(data)
                type = msg.type().strip()
                if msg.head.tuid == self.tuid:
                    # debug("one of ours -- ignore",str(msg))
                    continue
                if not HMAC.msgck(msg):
                    debug("HMAC failed, dropping: %s" % msg)
                    continue
                if type == 'whohas':
                    path = msg['file']
                    path = path.lstrip('/')
                    fullpath = os.path.join(dir, path)
                    fullpath = os.path.normpath(fullpath)
                    newer = int(msg.get('newer', None))
                    # security checks
                    bad = 0
                    if fullpath != os.path.normpath(fullpath):
                        bad += 1
                    if dir != os.path.commonprefix(
                        (dir, os.path.abspath(fullpath))):
                        print dir, os.path.commonprefix(
                            (dir, os.path.abspath(fullpath)))
                        bad += 2
                    if bad:
                        warn("unsafe request %d from %s: %s" %
                             (bad, addr, fullpath))
                        continue
                    if not os.path.isfile(fullpath):
                        debug("ignoring whohas from %s: not found: %s" %
                              (addr, fullpath))
                        continue
                    if newer is not None and newer >= getmtime_int(fullpath):
                        debug("ignoring whohas from %s: not newer: %s" %
                              (addr, fullpath))
                        continue
                    # url = "http://%s:%d/%s" % (localip,httpport,path)
                    self.ihaveTx(path)
                    continue
                if type == 'ihave':
                    debug("gotihave:", str(msg))
                    ip = addr[0]
                    yield kernel.wait(self.ihaveRx(msg, ip))
                    continue
                warn("unsupported message type from %s: %s" % (addr, type))
            except socket.error:
                yield kernel.sigsleep, 1
                continue
            except Exception, e:
                warn("%s from %s: %s" % (e, addr, str(msg)))
                continue
示例#27
0
 def reboot(self):
     if not self.cklock(): return
     msg = FBP.mkmsg('reboot')
     yield kernel.wait(self.addwip(msg))
示例#28
0
    def run(self):
        from SocketServer import UDPServer
        from isconf.fbp822 import fbp822, Error822

        kernel.spawn(self.puller())
        kernel.spawn(self.sender())

        # XXX most of the following should be broken out into a receiver() task

        dir = self.p.cache
        udpport = self.udpport

        debug("UDP server serving %s on port %d" % (dir,udpport))
        sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self.sock = sock
        sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
        sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, True)
        sock.setblocking(0)
        sock.bind(('',udpport))     
        # laddr = sock.getsockname()
        # localip = os.environ['HOSTNAME']
        while True:
            yield None
            self.flush()
            yield None
            try:
                data,addr = sock.recvfrom(8192)
                # XXX check against addrs or nets
                debug("from %s: %s" % (addr,data))
                factory = fbp822()
                msg = factory.parse(data)
                type = msg.type().strip()
                if msg.head.tuid == self.tuid:
                    # debug("one of ours -- ignore",str(msg))
                    continue
                if not HMAC.msgck(msg):
                    debug("HMAC failed, dropping: %s" % msg)
                    continue
                if type == 'whohas':
                    path = msg['file']
                    path = path.lstrip('/')
                    fullpath = os.path.join(dir,path)
                    fullpath = os.path.normpath(fullpath)
                    newer = int(msg.get('newer',None))
                    # security checks
                    bad=0
                    if fullpath != os.path.normpath(fullpath): 
                        bad += 1
                    if dir != os.path.commonprefix(
                            (dir,os.path.abspath(fullpath))):
                        print dir,os.path.commonprefix(
                            (dir,os.path.abspath(fullpath)))
                        bad += 2
                    if bad:
                        warn("unsafe request %d from %s: %s" % (
                            bad,addr,fullpath))
                        continue
                    if not os.path.isfile(fullpath):
                        debug("ignoring whohas from %s: not found: %s" % (addr,fullpath))
                        continue
                    if newer is not None and newer >= getmtime_int(
                            fullpath):
                        debug("ignoring whohas from %s: not newer: %s" % (addr,fullpath))
                        continue
                    # url = "http://%s:%d/%s" % (localip,httpport,path)
                    self.ihaveTx(path)
                    continue
                if type == 'ihave':
                    debug("gotihave:",str(msg))
                    ip = addr[0]
                    yield kernel.wait(self.ihaveRx(msg,ip))
                    continue
                warn("unsupported message type from %s: %s" % (addr,type))
            except socket.error:
                yield kernel.sigsleep, 1
                continue
            except Exception, e:
                warn("%s from %s: %s" % (e,addr,str(msg)))
                continue
示例#29
0
文件: ISconf.py 项目: stevegt/isconf4
 def ci(self):
     yield kernel.wait(self.volume.ci())