Changeset 3a8ce64


Ignore:
Timestamp:
Mar 27, 2015 2:16:41 PM (6 years ago)
Author:
zzz <zzz@…>
Branches:
master
Children:
188bd6d
Parents:
d7c3ffa4
Message:

I2PTunnel client-side locking fixes (ticket #815)
Checkin of patches from Oct. 2013, based on 0.9.8.1.
Had some issues back then, and not tested recently.
Prop from i2p.i2p to follow.

Location:
apps/i2ptunnel/java/src/net/i2p/i2ptunnel
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java

    rd7c3ffa4 r3a8ce64  
    708708                throw new IllegalArgumentException(getPrefix() + "Bad port " + args[0]);
    709709
    710             I2PTunnelTask task;
    711710            ownDest = !isShared;
    712711            try {
     
    714713                if (args.length >= 4)
    715714                    privateKeyFile = args[3];
    716                 task = new I2PTunnelClient(portNum, args[1], l, ownDest, this, this, privateKeyFile);
     715                I2PTunnelClientBase task = new I2PTunnelClient(portNum, args[1], l, ownDest, this, this, privateKeyFile);
     716                task.startRunning();
    717717                addtask(task);
    718718                notifyEvent("clientTaskId", Integer.valueOf(task.getId()));
     
    787787            }
    788788
    789             I2PTunnelTask task;
    790789            ownDest = !isShared;
    791790            try {
    792                 task = new I2PTunnelHTTPClient(clientPort, l, ownDest, proxy, this, this);
     791                I2PTunnelClientBase task = new I2PTunnelHTTPClient(clientPort, l, ownDest, proxy, this, this);
     792                task.startRunning();
    793793                addtask(task);
    794794                notifyEvent("httpclientTaskId", Integer.valueOf(task.getId()));
     
    856856            }
    857857
    858             I2PTunnelTask task;
    859858            ownDest = !isShared;
    860859            try {
    861                 task = new I2PTunnelConnectClient(_port, l, ownDest, proxy, this, this);
     860                I2PTunnelClientBase task = new I2PTunnelConnectClient(_port, l, ownDest, proxy, this, this);
     861                task.startRunning();
    862862                addtask(task);
    863863            } catch (IllegalArgumentException iae) {
     
    918918            }
    919919
    920             I2PTunnelTask task;
    921920            ownDest = !isShared;
    922921            try {
     
    924923                if (args.length >= 4)
    925924                    privateKeyFile = args[3];
    926                 task = new I2PTunnelIRCClient(_port, args[1], l, ownDest, this, this, privateKeyFile);
     925                I2PTunnelClientBase task = new I2PTunnelIRCClient(_port, args[1], l, ownDest, this, this, privateKeyFile);
     926                task.startRunning();
    927927                addtask(task);
    928928                notifyEvent("ircclientTaskId", Integer.valueOf(task.getId()));
     
    978978            ownDest = !isShared;
    979979            try {
    980                 I2PTunnelTask task = new I2PSOCKSTunnel(_port, l, ownDest, this, this, null);
     980                I2PTunnelClientBase task = new I2PSOCKSTunnel(_port, l, ownDest, this, this, null);
     981                task.startRunning();
    981982                addtask(task);
    982983                notifyEvent("sockstunnelTaskId", Integer.valueOf(task.getId()));
     
    10251026                privateKeyFile = args[2];
    10261027            try {
    1027                 I2PTunnelTask task = new I2PSOCKSIRCTunnel(_port, l, ownDest, this, this, privateKeyFile);
     1028                I2PTunnelClientBase task = new I2PSOCKSIRCTunnel(_port, l, ownDest, this, this, privateKeyFile);
     1029                task.startRunning();
    10281030                addtask(task);
    10291031                notifyEvent("sockstunnelTaskId", Integer.valueOf(task.getId()));
     
    14381440    private void runPing(String allargs, Logging l) {
    14391441        if (allargs.length() != 0) {
    1440             I2PTunnelTask task;
    14411442            // pings always use the main destination
    1442             task = new I2Ping(allargs, l, false, this, this);
     1443            I2PTunnelTask task = new I2Ping(allargs, l, false, this, this);
     1444            // TODO
     1445            //I2PTunnelClientBase task = new I2Ping(allargs, l, false, this, this);
     1446            //task.startRunning();
    14431447            addtask(task);
    14441448            notifyEvent("pingTaskId", Integer.valueOf(task.getId()));
  • apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClient.java

    rd7c3ffa4 r3a8ce64  
    3232              "Standard client on " + tunnel.listenHost + ':' + localPort,
    3333              tunnel, pkf);
    34 
    35         if (waitEventValue("openBaseClientResult").equals("error")) {
    36             notifyEvent("openClientResult", "error");
    37             return;
    38         }
    3934
    4035        StringTokenizer tok = new StringTokenizer(destinations, ", ");
  • apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java

    rd7c3ffa4 r3a8ce64  
    2727import net.i2p.I2PException;
    2828import net.i2p.client.I2PSession;
     29import net.i2p.client.I2PSessionException;
    2930import net.i2p.client.streaming.I2PSocket;
    3031import net.i2p.client.streaming.I2PSocketManager;
     
    5354    protected Destination dest = null;
    5455    private int localPort;
     56    private final String _handlerName;
    5557
    5658    private boolean listenerReady = false;
     
    9799        sockMgr = sktMgr;
    98100        _clientId = clientId;
     101        _handlerName = "chained";
    99102        this.localPort = localPort;
    100103        this.l = l;
     
    112115        }
    113116
    114         Thread t = new I2PAppThread(this, "Client " + tunnel.listenHost + ':' + localPort);
    115         t.start();
    116         open = true;
    117         synchronized (this) {
    118             while (!listenerReady && open) {
    119                 try {
    120                     wait();
    121                 } catch (InterruptedException e) {
    122                     // ignore
    123                 }
    124             }
    125         }
    126 
    127         if (open && listenerReady) {
    128             l.log("Client ready, listening on " + tunnel.listenHost + ':' + localPort);
    129             notifyEvent("openBaseClientResult", "ok");
    130         } else {
    131             l.log("Client error for " + tunnel.listenHost + ':' + localPort + ", check logs");
    132             notifyEvent("openBaseClientResult", "error");
    133         }
     117        startup();
    134118    }
    135119
    136120    /**
    137121     * The main constructor.
    138      * This may take a LONG time if building and starting a new manager.
     122     *
     123     * As of 0.9.20 this is fast, and does NOT connect the manager to the router,
     124     * or open the local socket. You MUST call startRunning() for that.
    139125     *
    140126     * @param localPort if 0, use any port, get actual port selected with getLocalPort()
     
    150136    /**
    151137     * Use this to build a client with a persistent private key.
    152      * This may take a LONG time if building and starting a new manager.
     138     *
     139     * As of 0.9.20 this is fast, and does NOT connect the manager to the router,
     140     * or open the local socket. You MUST call startRunning() for that.
    153141     *
    154142     * @param localPort if 0, use any port, get actual port selected with getLocalPort()
     
    166154        this.l = l;
    167155        _ownDest = ownDest; // == ! shared client
    168 
     156        _handlerName = handlerName;
    169157
    170158        _context = tunnel.getContext();
     
    195183            tunnel.getClientOptions().setProperty("i2cp.dontPublishLeaseSet", "true");
    196184       
    197         boolean openNow = !Boolean.parseBoolean(tunnel.getClientOptions().getProperty("i2cp.delayOpen"));
    198         if (openNow) {
    199             while (sockMgr == null) {
    200                 verifySocketManager();
    201                 if (sockMgr == null) {
    202                     _log.error("Unable to connect to router and build tunnels for " + handlerName);
    203                     // FIXME there is a loop in buildSocketManager(), do we really need another one here?
    204                     // no matter, buildSocketManager() now throws an IllegalArgumentException
    205                     try { Thread.sleep(10*1000); } catch (InterruptedException ie) {}
    206                 }
    207             }
    208             // can't be null unless we limit the loop above
    209             //if (sockMgr == null) {
    210             //    l.log("Invalid I2CP configuration");
    211             //    throw new IllegalArgumentException("Socket manager could not be created");
    212             //}
    213             l.log("Tunnels ready for client: " + handlerName);
    214 
    215         } // else delay creating session until createI2PSocket() is called
    216        
    217         Thread t = new I2PAppThread(this);
    218         t.setName("Client " + _clientId);
    219         t.start();
    220         open = true;
    221         synchronized (this) {
    222             while (!listenerReady && open) {
    223                 try {
    224                     wait();
    225                 } catch (InterruptedException e) {
    226                     // ignore
    227                 }
    228             }
    229         }
    230 
    231         if (open && listenerReady) {
    232             if (openNow)
    233                 l.log("Client ready, listening on " + tunnel.listenHost + ':' + localPort);
    234             else
    235                 l.log("Client ready, listening on " + tunnel.listenHost + ':' + localPort + ", delaying tunnel open until required");
    236             notifyEvent("openBaseClientResult", "ok");
    237         } else {
    238             l.log("Client error for " + tunnel.listenHost + ':' + localPort + ", check logs");
    239             notifyEvent("openBaseClientResult", "error");
    240         }
    241185    }
    242186   
    243187    /**
     188     * Create the manager if it doesn't exist, AND connect it to the router and
     189     * build tunnels.
     190     *
    244191     * Sets the this.sockMgr field if it is null, or if we want a new one.
    245192     * This may take a LONG time if building a new manager.
     
    273220            }
    274221        }
     222        connectManager();
    275223    }
    276224
     
    281229    /**
    282230     * This is ONLY for shared clients.
    283      * This may take a LONG time if building a new manager.
     231     * As of 0.9.20 this is fast, and does NOT connect the manager to the router.
     232     * Call verifySocketManager() for that.
    284233     *
    285234     * @return non-null
     
    293242    /**
    294243     * This is ONLY for shared clients.
    295      * This may take a LONG time if building a new manager.
     244     * As of 0.9.20 this is fast, and does NOT connect the manager to the router.
     245     * Call verifySocketManager() for that.
    296246     *
    297247     * @return non-null
     
    305255    /**
    306256     * This is ONLY for shared clients.
    307      * This may take a LONG time if building a new manager.
     257     * As of 0.9.20 this is fast, and does NOT connect the manager to the router.
     258     * Call verifySocketManager() for that.
    308259     *
    309260     * @return non-null
     
    336287
    337288    /**
    338      * This may take a LONG time.
     289     * For NON-SHARED clients (ownDest = true).
     290     *
     291     * As of 0.9.20 this is fast, and does NOT connect the manager to the router.
     292     * Call verifySocketManager() for that.
    339293     *
    340294     * @return non-null
     
    346300    }
    347301    /**
    348      * This may take a LONG time.
     302     * As of 0.9.20 this is fast, and does NOT connect the manager to the router.
     303     * Call verifySocketManager() for that.
    349304     *
    350305     * @return non-null
     
    360315
    361316    /**
    362      * This may take a LONG time.
     317     * As of 0.9.20 this is fast, and does NOT connect the manager to the router.
     318     * Call verifySocketManager() for that.
    363319     *
    364320     * @param pkf absolute path or null
     
    372328
    373329    /**
    374      * This may take a LONG time.
     330     * As of 0.9.20 this is fast, and does NOT connect the manager to the router.
     331     * Call verifySocketManager() for that.
    375332     *
    376333     * @param pkf absolute path or null
     
    389346                portNum = Integer.parseInt(tunnel.port);
    390347            } catch (NumberFormatException nfe) {
    391                 _log.log(Log.CRIT, "Invalid port specified [" + tunnel.port + "], reverting to " + portNum);
     348                throw new IllegalArgumentException("Invalid port specified [" + tunnel.port + "]", nfe);
    392349            }
    393350        }
    394351       
    395352        I2PSocketManager sockManager = null;
    396         // FIXME: Can't stop a tunnel from the UI while it's in this loop (no session yet)
    397         int retries = 0;
    398         while (sockManager == null) {
     353        FileInputStream fis = null;
     354        try {
    399355            if (pkf != null) {
    400356                // Persistent client dest
    401                 FileInputStream fis = null;
    402                 try {
    403                     fis = new FileInputStream(pkf);
    404                     sockManager = I2PSocketManagerFactory.createManager(fis, tunnel.host, portNum, props);
    405                 } catch (IOException ioe) {
    406                     if (log != null)
    407                         log.log("Error opening key file " + ioe);
    408                     _log.error("Error opening key file", ioe);
    409                     throw new IllegalArgumentException("Error opening key file " + ioe);
    410                 } finally {
    411                     if (fis != null)
    412                         try { fis.close(); } catch (IOException ioe) {}
    413                 }
     357                fis = new FileInputStream(pkf);
     358                sockManager = I2PSocketManagerFactory.createDisconnectedManager(fis, tunnel.host, portNum, props);
    414359            } else {
    415                 sockManager = I2PSocketManagerFactory.createManager(tunnel.host, portNum, props);
    416             }
    417            
    418             if (sockManager == null) {
    419                 // try to make this error sensible as it will happen... sadly we can't get to the listenPort, only the listenHost
    420                 String msg = "Unable to connect to the router at " + tunnel.host + ':' + portNum +
     360                sockManager = I2PSocketManagerFactory.createDisconnectedManager(null, tunnel.host, portNum, props);
     361            }
     362        } catch (I2PSessionException ise) {
     363            throw new IllegalArgumentException("Can't create socket manager", ise);
     364        } catch (IOException ioe) {
     365            if (log != null)
     366                log.log("Error opening key file " + ioe);
     367            _log.error("Error opening key file", ioe);
     368            throw new IllegalArgumentException("Error opening key file " + ioe);
     369        } finally {
     370            if (fis != null)
     371                try { fis.close(); } catch (IOException ioe) {}
     372        }
     373        sockManager.setName("Client");
     374        if (_log.shouldLog(Log.INFO))
     375            _log.info(tunnel.getClientOptions().getProperty("inbound.nickname") + ": Built a new socket manager [s=" + sockManager.getSession() + "]");
     376        tunnel.addSession(sockManager.getSession());
     377        return sockManager;
     378    }
     379
     380
     381    /**
     382     * Warning, blocks while connecting to router and building tunnels;
     383     * This may take a LONG time.
     384     *
     385     * @throws IllegalArgumentException if the I2CP configuration is b0rked so
     386     *                                  badly that we cant create a socketManager
     387     * @since 0.9.20
     388     */
     389    private void connectManager() {
     390        // shadows instance _log
     391        Log _log = getTunnel().getContext().logManager().getLog(I2PTunnelClientBase.class);
     392        Logging log = this.l;
     393        int retries = 0;
     394        while (sockMgr.getSession().isClosed()) {
     395            try {
     396                sockMgr.getSession().connect();
     397            } catch (I2PSessionException ise) {
     398                // try to make this error sensible as it will happen...
     399                String portNum = getTunnel().port;
     400                if (portNum == null)
     401                    portNum = "7654";
     402                String msg = "Unable to connect to the router at " + getTunnel().host + ':' + portNum +
    421403                             " and build tunnels for the client";
    422404                if (++retries < MAX_RETRIES) {
     
    435417            }
    436418        }
    437         sockManager.setName("Client");
    438         if (_log.shouldLog(Log.INFO))
    439             _log.info(tunnel.getClientOptions().getProperty("inbound.nickname") + ": Built a new socket manager [s=" + sockManager.getSession() + "]");
    440         tunnel.addSession(sockManager.getSession());
    441         return sockManager;
    442419    }
    443420
     
    458435
    459436    /**
    460      * Actually start working on incoming connections.  *Must* be
     437     * Actually open the local socket and start working on incoming connections.  *Must* be
    461438     * called by derived classes after initialization.
    462439     *
     440     * (this wasn't actually true until 0.9.20)
     441     *
     442     * This will be fast if i2cp.delayOpen is true, but could take
     443     * a LONG TIME if it is false, as it connects to the router and builds tunnels.
     444     *
    463445     */
    464446    public void startRunning() {
     447        boolean openNow = !Boolean.parseBoolean(getTunnel().getClientOptions().getProperty("i2cp.delayOpen"));
     448        if (openNow) {
     449            while (sockMgr == null) {
     450                verifySocketManager();
     451                if (sockMgr == null) {
     452                    _log.error("Unable to connect to router and build tunnels for " + _handlerName);
     453                    // FIXME there is a loop in buildSocketManager(), do we really need another one here?
     454                    // no matter, buildSocketManager() now throws an IllegalArgumentException
     455                    try { Thread.sleep(10*1000); } catch (InterruptedException ie) {}
     456                }
     457            }
     458            // can't be null unless we limit the loop above
     459            //if (sockMgr == null) {
     460            //    l.log("Invalid I2CP configuration");
     461            //    throw new IllegalArgumentException("Socket manager could not be created");
     462            //}
     463            l.log("Tunnels ready for client: " + _handlerName);
     464
     465        } // else delay creating session until createI2PSocket() is called
     466        startup();
     467    }
     468       
     469    private void startup() {
     470        // prevent JVM exit when running outside the router
     471        boolean isDaemon = getTunnel().getContext().isRouterContext();
     472        Thread t = new I2PAppThread(this, "Client " + _clientId, isDaemon);
     473        t.start();
     474        open = true;
     475        synchronized (this) {
     476            while (!listenerReady && open) {
     477                try {
     478                    wait();
     479                } catch (InterruptedException e) {
     480                    // ignore
     481                }
     482            }
     483        }
     484
     485        if (open && listenerReady) {
     486            boolean openNow = !Boolean.parseBoolean(getTunnel().getClientOptions().getProperty("i2cp.delayOpen"));
     487            if (openNow)
     488                l.log("Client ready, listening on " + getTunnel().listenHost + ':' + localPort);
     489            else
     490                l.log("Client ready, listening on " + getTunnel().listenHost + ':' + localPort + ", delaying tunnel open until required");
     491            notifyEvent("openBaseClientResult", "ok");
     492        } else {
     493            l.log("Client error for " + getTunnel().listenHost + ':' + localPort + ", check logs");
     494            notifyEvent("openBaseClientResult", "error");
     495        }
    465496        synchronized (startLock) {
    466497            startRunning = true;
     
    522553     */
    523554    public I2PSocket createI2PSocket(Destination dest) throws I2PException, ConnectException, NoRouteToHostException, InterruptedIOException {
     555        return createI2PSocket(dest, 0);
     556    }
     557
     558    /**
     559     * Create a new I2PSocket towards to the specified destination,
     560     * adding it to the list of connections actually managed by this
     561     * tunnel.
     562     *
     563     * @param dest The destination to connect to
     564     * @param port The destination port to connect to 0 - 65535
     565     * @return a new I2PSocket
     566     * @since 0.9.20
     567     */
     568    public I2PSocket createI2PSocket(Destination dest, int port)
     569                throws I2PException, ConnectException, NoRouteToHostException, InterruptedIOException {
    524570        verifySocketManager();
    525         return createI2PSocket(dest, getDefaultOptions());
     571        I2PSocketOptions opts = getDefaultOptions();
     572        opts.setPort(port);
     573        return createI2PSocket(dest, opts);
    526574    }
    527575
  • apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelConnectClient.java

    rd7c3ffa4 r3a8ce64  
    106106                               I2PTunnel tunnel) throws IllegalArgumentException {
    107107        super(localPort, ownDest, l, notifyThis, "HTTPS Proxy on " + tunnel.listenHost + ':' + localPort + " #" + (++__clientId), tunnel);
    108 
    109         if (waitEventValue("openBaseClientResult").equals("error")) {
    110             notifyEvent("openConnectClientResult", "error");
    111             return;
    112         }
    113108
    114109        if (wwwProxy != null) {
  • apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java

    rd7c3ffa4 r3a8ce64  
    207207
    208208        //proxyList = new ArrayList(); // We won't use outside of i2p
    209         if(waitEventValue("openBaseClientResult").equals("error")) {
    210             notifyEvent("openHTTPClientResult", "error");
    211             return;
    212         }
    213209
    214210        if(wwwProxy != null) {
  • apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelControllerGroup.java

    rd7c3ffa4 r3a8ce64  
    247247                    TunnelController controller = _controllers.get(i);
    248248                    if (controller.getStartOnLoad())
    249                         controller.startTunnel();
     249                        controller.startTunnelBackground();
    250250                }
    251251            }
Note: See TracChangeset for help on using the changeset viewer.