Exemplo n.º 1
0
    def perform_call(self, msg, peerIDs, peerIPs):
        """Only the controller should invoke this method -> Called from main thread
        both peerIDs and peerIPs should be sets
        Used also by start_lunchinator to send messages without initializing
        the whole lunch server."""     
        msg = convert_string(msg) # make sure, msg is unicode
        target = []
        
        if len(peerIDs) == 0 and len(peerIPs) == 0:
            target = self._peers.getFirstPeerIP()
        else:
            target = peerIPs
            for pID in peerIDs:
                pIPs = self._peers.getFirstPeerIP(pID=pID)
                if len(pIPs):
                    target = target.union(pIPs)
                else:
                    getCoreLogger().warning("While calling: I do not know a peer with ID %s, ignoring ", pID)
    
        if 0 == len(target):            
            getCoreLogger().warning("Cannot send message (%s), there is no peer given or none found", msg)
            
        if lunchinator_has_gui() and \
           get_settings().get_warn_if_members_not_ready() and \
           not msg.startswith(u"HELO") and \
           get_settings().get_lunch_trigger().upper() in msg.upper():
            # check if everyone is ready
            notReadyMembers = [self._peers.getDisplayedPeerName(pID=peerID) for peerID in peerIDs if not self._peers.isPeerReady(pID=peerID)]
            
            if notReadyMembers:
                    
                if len(notReadyMembers) == 1:
                    warn = "%s is not ready for lunch." % iter(notReadyMembers).next()
                elif len(notReadyMembers) == 2:
                    it = iter(notReadyMembers)
                    warn = "%s and %s are not ready for lunch." % (it.next(), it.next())
                else:
                    warn = "%s and %d others are not ready for lunch." % (random.sample(notReadyMembers, 1)[0], len(notReadyMembers) - 1)
                try:
                    from PyQt4.QtGui import QMessageBox
                    warn = "WARNING: %s Send lunch call anyways?" % warn
                    result = QMessageBox.warning(None,
                                                 "Members not ready",
                                                 warn,
                                                 QMessageBox.Yes | QMessageBox.No,
                                                 QMessageBox.No)
                    if result == QMessageBox.No:
                        return
                except ImportError:
                    print warn

        i = 0
        s = lunchSocket(self._peers)
        try:                  
            self._send_logger.info(msg)
            for ip in target:
                try:
                    short = msg if len(msg)<15 else msg[:14]+"..."
                    self._send_logger.debug("To %s: %s", ip.strip(), short)
                    s.sendto(msg, ip.strip())
                    i += 1                    
                except socket.error as e:
                    if e.errno in [64,65]:
                        getCoreLogger().debug("lunch_socket: Removing IP because host is down or there is no route")
                        self._peers.removePeerIPs([ip])
                    else:
                        getCoreLogger().warning("The following message could not be delivered to %s: %s", ip, msg, exc_info=1)
                except Exception as e:
                    getCoreLogger().warning("The following message could not be delivered to %s: %s", ip, msg, exc_info=1)
        finally:
            s.close() 
        return i
Exemplo n.º 2
0
    def start_server(self):
        '''listening method - should be started in its own thread''' 
        
        getCoreLogger().info("%s - Starting the lunch notifier service", strftime("%a, %d %b %Y %H:%M:%S", localtime()).decode("utf-8"))
        
        self.my_master = -1  # the peer i use as master
        
        is_in_broadcast_mode = False
        
        self._recv_socket = lunchSocket(self._peers)
        try: 
            self._recv_socket.bind()
            self.running = True
            self._cleanupLock = loggingMutex("cleanup", logging=get_settings().get_verbose())
            self._startCleanupTimer()
            self.controller.initDone()
            
            #first thing to do: ask stored peers for their info:
            if len(self._peers) == 0:
                requests = self._peers.initPeersFromFile()
                self.call_request_info(requests)
            
            while self.running:
                try:
                    xmsg, ip = self._recv_socket.recv()
                    try:
                        plainMsg = xmsg.getPlainMessage()                        
                        self._recv_logger.info("From %s: %s",ip,plainMsg)
                    except:
                        getCoreLogger().exception("There was an error when trying to parse a message from %s", ip)
                        continue
                     
                    # check for local address: only stop command allowed, else ignore
                    if ip.startswith("127."):
                        if xmsg.getCommand() == "STOP":
                            getCoreLogger().info("Got Stop Command from localhost: %s", plainMsg)
                            self.running = False
                            self.exitCode = EXIT_CODE_STOP
                        elif xmsg.getCommand() == "OPEN_WINDOW" and lunchinator_has_gui():
                            self.controller._openWindow.emit()
                        elif xmsg.getCommand() == "LOCAL_PIPE":
                            getCoreLogger().debug("Relaying LOCAL_PIPE call")
                            self.call_all_members("HELO_PIPE "+xmsg.getCommandPayload())
                        continue
                    
                    # first we save the timestamp of this contact, no matter what
                    self._peers.seenIP(ip)

                    # check if we know this peer          
                    isNewPeer = self._peers.getPeerInfo(pIP=ip) == None          
                    if isNewPeer and self._should_call_info_on_event(plainMsg):
                        #this is a new member - we ask for info right away
                        self.call_request_info([ip])
                    
                    self._handle_event(xmsg, ip, time(), isNewPeer, False)
                except splitCall as e:
                    getCoreLogger().debug(e.value)
                except socket.timeout:                    
                    if len(self._peers) > 1:                     
                        if is_in_broadcast_mode:
                            is_in_broadcast_mode = False
                            getCoreLogger().info("ending broadcast")       
                    else:
                        if not self._disable_broadcast:
                            if not is_in_broadcast_mode:
                                is_in_broadcast_mode = True
                                getCoreLogger().info("seems like you are alone - broadcasting for others")
                            s_broad = lunchSocket(self._peers)
                            msg = 'HELO_REQUEST_INFO ' + self._build_info_string()
                            self._send_logger.info(msg)
                            s_broad.broadcast(msg)
                            s_broad.close()
                            #forgotten peers may be on file
                            requests = self._peers.initPeersFromFile()
                            self.call_request_info(requests)
                            
        except socket.error as e:
            # socket error messages may contain special characters, which leads to crashes on old python versions
            getCoreLogger().error(u"stopping lunchinator because of socket error: %s", convert_string(str(e)))
        except KeyboardInterrupt:
            getCoreLogger().info("Received keyboard interrupt, stopping.")
        except:
            getCoreLogger().exception("stopping - Critical error: %s", str(sys.exc_info())) 
        finally: 
            self.running = False
            try:
                #make sure to close the cleanup thread first
                with self._cleanupLock:
                    self._cleanupTimer.cancel()
                
                self.call("HELO_LEAVE bye")
                self._recv_socket.close()
                self._recv_socket = None 
            except:
                getCoreLogger().warning("Wasn't able to send the leave call and close the socket...")
            self._finish()