anchor.diff:      });
     }
   
  -  async.Future<DeleteAllPortMapResult> deleteAllPortMap(List<int> deleteExternalPortList) {
  -    return UpnpDeviceSearcher.createInstance(this.builder).then((UpnpDeviceSearcher searcher) {
  -      return searcher.searchWanPPPDevice().then((int e) {
  -        if (searcher.deviceInfoList.length <= 0) {
  -          throw {"failed": "not found router"};
  -        }
  -        List<async.Future> futures = [];
  -        UpnpDeviceInfo info = searcher.deviceInfoList.first;
  +  async.Future<List<UpnpDeviceInfo>> searchRoutder({bool reuseRouter: false}) {
  +    return new async.Future(() {
  +      if (reuseRouter == true && _currentUpnpDeviceInfo.length > 0) {
  +        return _currentUpnpDeviceInfo[0];
  +      } else {
  +        return UpnpDeviceSearcher.createInstance(this.builder).then((UpnpDeviceSearcher searcher) {
  +          return searcher.searchWanPPPDevice().then((int e) {
  +            if (searcher.deviceInfoList.length <= 0) {
  +              throw {"failed": "not found router"};
  +            }
  +            _currentUpnpDeviceInfo.clear();
  +            _currentUpnpDeviceInfo.addAll(searcher.deviceInfoList);
  +            return searcher.deviceInfoList;
  +          }).whenComplete(() {
  +            try {
  +              searcher.close();
  +            } catch (e) {}
  +          });
  +        });
  +      }
  +    });
  +  }
  +
  +  void clearSearchedRouterInfo() {
  +    _currentUpnpDeviceInfo.clear();
  +  }
  +
  +  async.Future<DeleteAllPortMapResult> deleteAllPortMap(List<int> deleteExternalPortList, {bool reuseRouter: false}) {
  +    return searchRoutder(reuseRouter: reuseRouter).then((List<UpnpDeviceInfo> deviceInfoList) {
  +      List<async.Future> futures = [];
  +      UpnpDeviceInfo info = deviceInfoList.first;
  +      UpnpPPPDevice pppDevice = new UpnpPPPDevice(info);
  +      for (int port in deleteExternalPortList) {
  +        futures.add(pppDevice.requestDeletePortMapping(port, UpnpPPPDevice.VALUE_PORT_MAPPING_PROTOCOL_TCP));
  +      }
  +      return async.Future.wait(futures).then((List<dynamic> d) {
  +        return new DeleteAllPortMapResult();
  +      });
  +    });
  +  }
  +
  +  async.Future<GetPortMapInfoResult> getPortMapInfo({String target: null, bool reuseRouter: false}) {
  +    return searchRoutder(reuseRouter: reuseRouter).then((List<UpnpDeviceInfo> deviceInfoList) {
  +      UpnpDeviceInfo info = deviceInfoList.first;
  +
  +      int index = 0;
  +      GetPortMapInfoResult result = new GetPortMapInfoResult();
  +
  +      tryGetPortMapInfo() {
           UpnpPPPDevice pppDevice = new UpnpPPPDevice(info);
  -        for (int port in deleteExternalPortList) {
  -          futures.add(pppDevice.requestDeletePortMapping(port, UpnpPPPDevice.VALUE_PORT_MAPPING_PROTOCOL_TCP));
  -        }
  -        return async.Future.wait(futures).then((List<dynamic> d) {
  -          searcher.close();
  -          return new DeleteAllPortMapResult();
  +        return pppDevice.requestGetGenericPortMapping(index++).then((UpnpGetGenericPortMappingResponse res) {
  +          if (res.resultCode != 200) {
  +            return result;
  +          }
  +          String description = res.getValue(UpnpGetGenericPortMappingResponse.KEY_NewPortMappingDescription, "");
  +          String externalPort = res.getValue(UpnpGetGenericPortMappingResponse.KEY_NewExternalPort, "");
  +          String internalPort = res.getValue(UpnpGetGenericPortMappingResponse.KEY_NewInternalPort, "");
  +          String ip = res.getValue(UpnpGetGenericPortMappingResponse.KEY_NewInternalClient, "");
  +          String type = res.getValue(UpnpGetGenericPortMappingResponse.KEY_NewProtocol, "");
  +          if (target == null || description.contains(target)) {
  +            //"hetim(${appid})") {
  +            result.add(ip, internalPort, externalPort, description, type);
  +          }
  +          if (externalPort.replaceAll(" |\t|\r|\n", "") == "" && ip.replaceAll(" |\t|\r|\n", "") == "") {
  +            return result;
  +          }
  +          return tryGetPortMapInfo();
  +        }).catchError((e) {
  +          throw e;
           });
  -      });
  -    });
  -  }
  -
  -  async.Future<GetPortMapInfoResult> getPortMapInfo([String target = null]) {
  -    return UpnpDeviceSearcher.createInstance(this.builder).then((UpnpDeviceSearcher searcher) {
  -      return searcher.searchWanPPPDevice().then((int e) {
  -        if (searcher.deviceInfoList.length <= 0) {
  -          throw {"failed": "not found router"};
  -        }
  -
  -        int index = 0;
  -        GetPortMapInfoResult result = new GetPortMapInfoResult();
  -
  -        tryGetPortMapInfo() {
  -          UpnpDeviceInfo info = searcher.deviceInfoList.first;
  -          UpnpPPPDevice pppDevice = new UpnpPPPDevice(info);
  -          return pppDevice.requestGetGenericPortMapping(index++).then((UpnpGetGenericPortMappingResponse res) {
  -            if (res.resultCode != 200) {
  -              return result;
  -            }
  -            String description = res.getValue(UpnpGetGenericPortMappingResponse.KEY_NewPortMappingDescription, "");
  -            String externalPort = res.getValue(UpnpGetGenericPortMappingResponse.KEY_NewExternalPort, "");
  -            String internalPort = res.getValue(UpnpGetGenericPortMappingResponse.KEY_NewInternalPort, "");
  -            String ip = res.getValue(UpnpGetGenericPortMappingResponse.KEY_NewInternalClient, "");
  -            String type = res.getValue(UpnpGetGenericPortMappingResponse.KEY_NewProtocol, "");
  -            if (target == null || description.contains(target)) {
  -              //"hetim(${appid})") {
  -              result.add(ip, internalPort, externalPort, description, type);
  -            }
  -            if (externalPort.replaceAll(" |\t|\r|\n", "") == "" && ip.replaceAll(" |\t|\r|\n", "") == "") {
  -              return result;
  -            }
  -            return tryGetPortMapInfo();
  -          }).catchError((e) {
  -            searcher.close();
  -            throw e;
  -          });
  -        }
  -        return tryGetPortMapInfo();
  -      });
  +      }
  +      return tryGetPortMapInfo();
       });
     }
   
  
positive.code: }
  class GetPortMapInfoResult {
    List<PortMapInfo> infos = [];
    add(String ip, String internalPort, String externalPort,String description, String type) {
      infos.add(new PortMapInfo()..description=description..externalPort=externalPort..ip=ip..type=type..internalPort=internalPort);
    }
  }
  
  
negative.code:   //
    //
    // ####
    async.Future<StartGetExternalIp> startGetExternalIp({bool reuseRouter: false}) {
      _externalPort = basePort;
      return searchRoutder(reuseRouter: reuseRouter).then((List<UpnpDeviceInfo> deviceInfoList) {
        UpnpDeviceInfo info = deviceInfoList.first;
        UpnpPPPDevice pppDevice = new UpnpPPPDevice(info);
        return pppDevice.requestGetExternalIPAddress().then((UpnpGetExternalIPAddressResponse res) {
          _externalAddress = res.externalIp;
          _controllerUpdateGlobalIp.add(res.externalIp);
          return new StartGetExternalIp(res.externalIp);
        });
      }).catchError((e) {
        throw e;
      });
    }
  
    async.Future<StartPortMapResult> startPortMap({bool reuseRouter: false}) {
      _externalPort = basePort;
      return searchRoutder(reuseRouter: reuseRouter).then((List<UpnpDeviceInfo> deviceInfoList) {
        UpnpDeviceInfo info = deviceInfoList.first;
        UpnpPPPDevice pppDevice = new UpnpPPPDevice(info);
        int maxRetryExternalPort = _externalPort + numOfRetry;
  
        tryAddPortMap() {
          print("############### ${this.localPort} ${this.localAddress}");
          return pppDevice
              .requestAddPortMapping(_externalPort, UpnpPPPDevice.VALUE_PORT_MAPPING_PROTOCOL_TCP, localPort, localAddress, UpnpPPPDevice.VALUE_ENABLE, appIdDesc, 0)
              .then((UpnpAddPortMappingResponse res) {
            if (200 == res.resultCode) {
              _controllerUpdateGlobalPort.add("${_externalPort}");
              return new StartPortMapResult();
            } else if (500 == res.resultCode) {
              _externalPort++;
              if (_externalPort < maxRetryExternalPort) {
                return tryAddPortMap();
              } else {
                throw {"failed": "redirect max"};
              }
            } else {
              throw {"failed": "unexpected error code ${res.resultCode}"};
            }
          });
        }
  
        return tryAddPortMap();
      }).catchError((e) {
        throw e;
      });
    }
  
    async.Future<DeleteAllPortMapResult> deletePortMapFromAppIdDesc({bool reuseRouter: false}) {
      return getPortMapInfo(target: appIdDesc, reuseRouter: reuseRouter).then((GetPortMapInfoResult result) {
        List<int> externalPortList = [];
        for (PortMapInfo info in result.infos) {
          try {
            externalPortList.add(int.parse(info.externalPort));
          } catch (e) {
            ;
          }
        }
  