def trim_connections(self):
     for k, v in self.peers.iteritems():
         # Trim TinCan link if the peer is offline
         if "fpr" in v and v["status"] == "offline":
             if v["last_time"] > CONFIG["wait_time"] * 2:
                 il.do_send_msg(self.sock, "send_msg", 1, k,
                             "destroy" + self.ipop_state["_uid"])
                 il.do_trim_link(self.sock, k)
         # Trim TinCan link if the On Demand Inactive Timeout occurs        
         if CONFIG["on-demand_connection"] and v["status"] == "online": 
             if v["last_active"] + CONFIG["on-demand_inactive_timeout"]\
                                                           < time.time():
                 logging.debug("Inactive, trimming node:{0}".format(k))
                 il.do_send_msg(self.sock, 1, "send_msg", k,
                             "destroy" + self.ipop_state["_uid"])
                 il.do_trim_link(self.sock, k)
    def serve(self):
        # select.select returns a triple of lists of objects that are 
        # ready: subsets of the first three arguments. When the time-out,
        # given as the last argument, is reached without a file descriptor
        # becoming ready, three empty lists are returned.
        socks, _, _ = select.select(self.sock_list, [], [], CONFIG["wait_time"])
        for sock in socks:
            if sock == self.sock or sock == self.sock_svr:
                #---------------------------------------------------------------
                #| offset(byte) |                                              |
                #---------------------------------------------------------------
                #|      0       | ipop version                                 |
                #|      1       | message type                                 |
                #|      2       | Payload (JSON formatted control message)     |
                #---------------------------------------------------------------
                data, addr = sock.recvfrom(CONFIG["buf_size"])
                if data[0] != il.ipop_ver:
                    logging.debug("ipop version mismatch: tincan:{0} controller"
                                  ":{1}" "".format(data[0].encode("hex"), \
                                   ipop_ver.encode("hex")))
                    sys.exit()
                if data[1] == il.tincan_control:
                    msg = json.loads(data[2:])
                    logging.debug("recv %s %s" % (addr, data[2:]))
                    msg_type = msg.get("type", None)
                    if msg_type == "echo_request":
                        make_remote_call(self.sock_svr, m_type=tincan_control,\
                          dest_addr=addr[0], dest_port=addr[1], payload=None,\
                          type="echo_reply") # Reply to the echo_request 
                    if msg_type == "local_state":
                        self.ipop_state = msg
                    elif msg_type == "peer_state": 
                        if msg["status"] == "offline" or "stats" not in msg:
                            self.peers[msg["uid"]] = msg
                            self.trigger_conn_request(msg)
                            continue
                        stats = msg["stats"]
                        total_byte = 0
                        global REMOTE_UID
                        REMOTE_UID = msg["uid"]
                        for stat in stats:
                            total_byte += stat["sent_total_bytes"]
                            total_byte += stat["recv_total_bytes"]
                        msg["total_byte"]=total_byte
                        logging.debug("?? {0} {1} {2}".format(stats[0]["best_conn"], stats[0]["local_type"] , stats[0]["rem_type"]))
                        #if stats[0]["best_conn"] and stats[0]["local_type"] == "local" and stats[0]["rem_type"] == "local":
                        # Amazon AWS instance does not find itself as "local"
                        if stats[0]["best_conn"]:
                            ryu_msg = {}
                            ryu_msg["type"] = "tincan_notify"
			    ryu_msg["local_addr"] = stats[0]["local_addr"].split(":")[0]
                            ryu_msg["rem_addr"] = stats[0]["rem_addr"].split(":")[0]
                            # sock.sendto(json.dumps(ryu_msg),("::1", 30001))
                            global LOCAL_HOST_IPv4
                            global REMOTE_HOST_IPv4
                            LOCAL_HOST_IPv4 = stats[0]["local_addr"].split(":")[0]
                            REMOTE_HOST_IPv4 = stats[0]["rem_addr"].split(":")[0]
                            logging.debug("REMOTE_HOST_IPv4:{0}".format(REMOTE_HOST_IPv4))
                        logging.debug("self.peers:{0}".format(self.peers))
                        if not msg["uid"] in self.peers:
                            msg["last_active"]=time.time()
                        elif not "total_byte" in self.peers[msg["uid"]]:
                            msg["last_active"]=time.time()
                        else:
                            if msg["total_byte"] > \
                                         self.peers[msg["uid"]]["total_byte"]:
                                msg["last_active"]=time.time()
                            else:
                                msg["last_active"]=\
                                        self.peers[msg["uid"]]["last_active"]
                        self.peers[msg["uid"]] = msg
    
                    # we ignore connection status notification for now
                    elif msg_type == "con_stat": pass
                    elif msg_type == "con_req": 
                        if CONFIG["on-demand_connection"]: 
                            self.idle_peers[msg["uid"]]=msg
                        else:
                            if self.check_collision(msg_type,msg["uid"]): 
                                continue
                            fpr_len = len(self.ipop_state["_fpr"])
                            fpr = msg["data"][:fpr_len]
                            cas = msg["data"][fpr_len + 1:]
                            ip4 = self.uid_ip_table[msg["uid"]]
                            self.create_connection(msg["uid"], fpr, 1, 
                                                   CONFIG["sec"], cas, ip4)
                    elif msg_type == "con_resp":
                        if self.check_collision(msg_type, msg["uid"]): continue
                        fpr_len = len(self.ipop_state["_fpr"])
                        fpr = msg["data"][:fpr_len]
                        cas = msg["data"][fpr_len + 1:]
                        ip4 = self.uid_ip_table[msg["uid"]]
                        self.create_connection(msg["uid"], fpr, 1, 
                                               CONFIG["sec"], cas, ip4)
    
                    # send message is used as "request for start mutual 
                    # connection"
                    elif msg_type == "send_msg": 
                        if CONFIG["on-demand_connection"]:
                            if msg["data"].startswith("destroy"):
                                il.do_trim_link(self.sock, msg["uid"])
                            else:
                                self.ondemand_create_connection(msg["uid"], 
                                                                False)
                    elif msg_type == "packet_notify":
                        if msg["nw_proto"] == 6:
                            if msg["ack"] != 0:
                                continue
                        if msg["src_port"] == 68:
                            continue #Ignore BOOTP
                        if msg["src_port"] == 5353:
                            continue #Ignore Multicast DNS
                        if msg["src_port"] == 30000:
                            continue #Ignore ICC packet 
                        if msg["nw_proto"] == 17:
                            continue # Let's ignore UDP for the time being

                        #ryu_msg = {}
                        #ryu_msg["type"] = "packet_notify"
                        #ryu_msg["protocol"] = msg["data"].split(',')[0]
                        #msg["remote_ipop_ipv4"] = REMOTE_IPOP_IPv4
                        # TODO I'm just using the src_port to differentiate the
                        # stream. so if the src_port is the same I consider it 
                        # as the same TCP/UDp stream. For correct implementation
                        # I have to use src_port dst_port src_ipv4 and dst_ipv4. 
                        random.seed(msg["src_port"])
                        src_random_port = random.randint(49125, 65535)
                        dst_random_port = random.randint(49125, 65535)
                        msg_id = random.randint(1, 65535)
                        msg["msg_id"] = msg_id
                        msg["src_host_ipv4"] = REMOTE_HOST_IPv4
                        msg["local_host_ipv4"] = LOCAL_HOST_IPv4
                        msg["remote_host_ipv4"] = REMOTE_HOST_IPv4
                        msg["src_random_port"] = src_random_port
                        msg["dst_random_port"] = dst_random_port
                        #ryu_msg["src_mac"] = msg["src_mac"]
                        #ryu_msg["dst_mac"] = msg["data"].split(',')[2]
                        #ryu_msg["src_ipv4"] = msg["data"].split(',')[3] 
                        #ryu_msg["dst_ipv4"] = msg["data"].split(',')[4]
                        #logging.debug("Try sending message to {0}".format(REMOTE_IPOP_IPv4))
                        #logging.debug("Try sending message to {0}".format("::1 / 30001"))
                        #msg["type"] = "packet_notify_remote"
                        logging.debug("sending message to retmoe and local --- {0}".format(msg))
                        msg["type"] = "packet_notify_remote"
                        self.icc_sendto_control(REMOTE_UID, json.dumps(msg))
                        #ret1 = self.cc_sock.sendto(json.dumps(msg), (REMOTE_IPOP_IPv4, 30002))
                        #ret1 = self.cc_sock.sendto(json.dumps(msg), (REMOTE_IPOP_IPv6, 30002))
                        #time.sleep(5)
                        #msg["type"] = "packet_notify_local"
                        msg["type"] = "packet_notify_local_inbound"
                        PENDING_MSG[msg_id] = msg
                        self.observable.send_msg("ocs", "control", msg)

                        #ret0 = self.sock.sendto(json.dumps(msg),("::1", 30001))
                        #logging.debug("Sent {0} {1} byte".format(ret0, ret1))

                   
                # If a packet that is destined to yet no p2p connection 
                # established node, the packet as a whole is forwarded to 
                # controller
                #|-------------------------------------------------------------|
                #| offset(byte) |                                              |
                #|-------------------------------------------------------------|
                #|      0       | ipop version                                 |
                #|      1       | message type                                 |
                #|      2       | source uid                                   |
                #|     22       | destination uid                              |
                #|     42       | Payload (Ethernet frame)                     |
                #|-------------------------------------------------------------|
                elif data[1] == il.tincan_packet:
 
                    # Ignore IPv6 packets for log readability. Most of them are
                    # Multicast DNS packets
                    if data[54:56] == "\x86\xdd":
                        logging.debug("Ignoring IPv6 packet")
                        continue
                    # Ignore IPv4 Multicast Packets
                    if data[42:45] == "\x01\x00\x5e":
                        logging.debug("Ignoring IPv4 multicast")
                        continue
                    logging.debug("IP packet forwarded \nversion:{0}\nmsg_type:"
                        "{1}\nsrc_uid:{2}\ndest_uid:{3}\nsrc_mac:{4}\ndst_mac:{"
                        "5}\neth_type:{6}".format(data[0].encode("hex"), \
                        data[1].encode("hex"), data[2:22].encode("hex"), \
                        data[22:42].encode("hex"), data[42:48].encode("hex"),\
                        data[48:54].encode("hex"), data[54:56].encode("hex")))
 
                    if not CONFIG["on-demand_connection"]:
                        continue
                    if len(data) < 16:
                        continue
                    self.create_connection_req(data[2:])

                elif data[1] == "\x03":
                    logging.debug("ICC control")
                    #for i in range(0, len(data)):
                    #  logging.debug("ICC control:{0} {1}".format(i, data[i]))
                    # TODO i don't know why but there is some trailing null characters
                    msglist = data[56:].split("\x00")
                    #print msglist
                    rawmsg = msglist[0] 
                    #print rawmsg
                    msg = json.loads(rawmsg)
                    #print msg
                    if msg["type"] == "ack": 
                        pending_msg = PENDING_MSG[msg["msg_id"]]
                        pending_msg["type"] = "packet_notify_local_outbound"
                        self.observable.send_msg("ocs", "control", pending_msg)
                    else :
                        self.observable.send_msg("ocs", "control", msg)
                        ack = {}
                        ack["msg_id"] = msg["msg_id"] 
                        ack["type"] = "ack"
                        src_uid = il.uid_b2a(data[2:22])
                        self.icc_sendto_control(src_uid, json.dumps(ack))

                elif data[1] == "\x04":
                    logging.debug("ICC packet")
     
                else:
                    logging.error("Unknown type message")
                    logging.debug("{0}".format(data[0:].encode("hex")))
                    sys.exit()

            else:
                logging.error("Unknown type socket")
                sys.exit()