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
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()