5

I'm having the following problem: When I try to createTcpServer with my external IP address (the PC's IP and not my local IP = the one we see as an output after running ipconfig in cmd.exe) the following error occurs:

Error with Server: Exception opening port "9092" (port may be in use), cause: "java.net.BindException: Cannot assign requested address: JVM_Bind" [90061-169]

However, the port is not in use. I've checked that using netstat -a -n . I have enabled my external IP and I have disabled the firewall from the router. My external IP can now be pinged.

Please help me.

Update: Here is my code to start the tcp server.

package businessApp;

import org.h2.tools.Server; //imports the server utility

public class startTcpServerForH2 {

    Server server; //the server's instance variable

    private static final String SERVER_IP = "192.168.1.101"; //fixed IP of the server
    private static final String SERVER_PORT = "9092"; //fixed port the server is listening to

    public void tcpServer() { //method responsible to create the tcp server

        optionPane optPane = new optionPane(); //option pane for debugging purposes, shows the server's status

        try { //catches any server related errors, if the connection is broken etc.

            //server uses the IP and port defined earlier, allows other computers in the LAN to connect and implements the secure socket layer (SSL) feature
            server = Server.createTcpServer( //create tcp server
                new String[] { "-tcpPort" , SERVER_PORT , "-tcpAllowOthers" , "-tcpSSL" }).start();

            System.out.println(server.getStatus()); //prints out the server's status
            optPane.checkServerStatus(server.getStatus()); //prints out the server's status on the option pane as well

        } catch(Exception ex){
            System.out.println("Error with Server: " + ex.getMessage());
        }
    }

    public static void main(String[] args){

        startTcpServerForH2 tcpServ = new startTcpServerForH2(); //create a new server object
        tcpServ.tcpServer(); //starts the tcp server
    }
}

Second Update: here is the h2Connection code.

package businessApp;

import java.sql.*; //imports sql features

//Class responsible for connection with H2 Database Engine public class h2Connection {

Connection conn;        //connection variable
DatabaseMetaData dbmd;  /** Metadata variable which include methods such as the following:
                         * 1) Database Product Name
                         * 2) Database Product Version
                         * 3) URL where the database files are located (in TCP mode)
                        */
Statement stm;          //statements variable
ResultSet rst;          //result sets variable

private static final String SERVER_IP = "..."; //here I enter my WAN_IP
private static final String SERVER_PORT = "9092";

public Connection connectionToH2(Connection connt) {

    optionPane optPane = new optionPane(); //create new option pane object
    String outputConn = null; //declare & initialize string which will hold important messages

    try {

        Class.forName("org.h2.Driver"); //Driver's name
        /** The String URL is pertained of the following:
         *  1) jdbc which java implements so that it can take advantage of the SQL features
         *  2) Which Database Engine will be used
         *  3) URL where the files will be stored (as this is a TCP connection)
         *  4) Schema: businessApp
         *  5) Auto server is true means that other computers can connect with the same databse at any time
         *  6) Port number of the server is also defined
         */

        String url = "jdbc:h2:tcp://" + SERVER_IP + ":" + SERVER_PORT + "/C:/Databases/businessApp;IFEXISTS=TRUE";
        System.out.println(url); //prints out the url the database files are located as well as the h2 features used (SSL)
        connt = DriverManager.getConnection(url, "sa", ""); //Driver Manager defines the username & password of the database
        System.out.println(connt.getCatalog()); //prints out the database schema
        optPane.checkServerStatus(connt.getCatalog()); //prints out the database schema on the option pane as well
        connt.setAutoCommit(false); //set AutoCommit to false to control commit actions manually

        //outputs H2 version and the URL of the database files which H2 is reading from, for confirmation
        dbmd = connt.getMetaData(); //get MetaData to confirm connection

        outputConn = "Connection to "+dbmd.getDatabaseProductName()+" "+
                   dbmd.getDatabaseProductVersion()+ " with the URL " + dbmd.getURL()+" was successful.\n";
        System.out.println(outputConn);  //outputs the message on the system (NetBeans compiler)
        optPane.checkH2Connection(outputConn); //outputs the message on top of the frame


    } catch (ClassNotFoundException ex){ //In case there is an error for creating the class for the Driver to be used
        System.out.println("Error creating class: " + ex.getMessage());
    } catch(SQLException ex){ //Any error associated with the Database Engine
        System.out.println("SQL error: " + ex.getMessage());
        optPane.checkServerStatus("SQL error: " + ex.getMessage());
    }
    return connt; //As the method is not void, a connection variable must be returned
}

}

When I want to connect to the h2 database, I make a new h2Connection object and use it to connect. I have followed the H2 manual word by word. What more do you need?

Nadeem Saad
  • 65
  • 1
  • 1
  • 8

1 Answers1

8

As suggested in the command line help shown below, Protection against Remote Access advises the following:

By default this database does not allow connections from other machines when starting the H2 Console, the TCP server, or the PG server. Remote access can be enabled using the command line options -webAllowOthers, -tcpAllowOthers, -pgAllowOthers.

See the documentation for important caveats regarding these options.

Addendum: Works for me, as long as I restart the Server after opening the firewall; you don't need the setProperty() line at all; the LAN IP to which your WAN_IP forwards port 9092 should be your host IP address; then you can open a shell via your WAN_IP:

java -cp h2.jar org.h2.tools.Shell -url 
    jdbc:h2:tcp://WAN_IP/~/path/to/test;ifexists=true"

Command line help:

$ java -cp .:/opt/h2/bin/h2.jar org.h2.tools.Shell -?
Interactive command line tool to access a database using JDBC.
Usage: java org.h2.tools.Shell 
Options are case sensitive. Supported options are:
[-help] or [-?]        Print the list of options
[-url ""]         The database URL (jdbc:h2:...)
[-user ]         The user name
[-password ]      The password
[-driver ]      The JDBC driver class to use (not required in most cases)
[-sql ""]  Execute the SQL statements and exit
[-properties ""]  Load the server properties from this directory
If special characters don't work as expected, you may need to use
 -Dfile.encoding=UTF-8 (Mac OS X) or CP850 (Windows).
See also http://h2database.com/javadoc/org/h2/tools/Shell.html

$ java -cp /opt/h2/bin/h2.jar org.h2.tools.Server -?
Starts the H2 Console (web-) server, TCP, and PG server.
Usage: java org.h2.tools.Server 
When running without options, -tcp, -web, -browser and -pg are started.
Options are case sensitive. Supported options are:
[-help] or [-?]         Print the list of options
[-web]                  Start the web server with the H2 Console
[-webAllowOthers]       Allow other computers to connect - see below
[-webDaemon]            Use a daemon thread
[-webPort ]       The port (default: 8082)
[-webSSL]               Use encrypted (HTTPS) connections
[-browser]              Start a browser connecting to the web server
[-tcp]                  Start the TCP server
[-tcpAllowOthers]       Allow other computers to connect - see below
[-tcpDaemon]            Use a daemon thread
[-tcpPort ]       The port (default: 9092)
[-tcpSSL]               Use encrypted (SSL) connections
[-tcpPassword ]    The password for shutting down a TCP server
[-tcpShutdown ""]  Stop the TCP server; example: tcp://localhost
[-tcpShutdownForce]     Do not wait until all connections are closed
[-pg]                   Start the PG server
[-pgAllowOthers]        Allow other computers to connect - see below
[-pgDaemon]             Use a daemon thread
[-pgPort ]        The port (default: 5435)
[-properties ""]   Server properties (default: ~, disable: null)
[-baseDir ]        The base directory for H2 databases (all servers)
[-ifExists]             Only existing databases may be opened (all servers)
[-trace]                Print additional trace information (all servers)
The options -xAllowOthers are potentially risky.
For details, see Advanced Topics / Protection against Remote Access.
See also http://h2database.com/javadoc/org/h2/tools/Server.html
trashgod
  • 203,806
  • 29
  • 246
  • 1,045
  • Kindly check my updated question above, I have included the code which starts the tcp server. My problem is that I cannot bind my external IP with the server for remote access. Maybe I'm doing it the wrong way. With my internal IP, everything is working fine but only for computers that are connected to my LAN. – Nadeem Saad Jan 14 '13 at 12:22
  • I'm not sure that you need `h2.bindAddress`. Is your border router forwarding `9092`? – trashgod Jan 14 '13 at 13:14
  • My router is based on 3G mobile broadband technology. Under its settings, I have created a new Virtual Server with the LAN IP address being 192.168.1.101 and both LAN & WAN ports were entered as "9092". I then changed the SERVER_IP above to my external IP and ran the code. I have also switched off the firewall settings on my router. It still does not work. – Nadeem Saad Jan 14 '13 at 15:28
  • Thank you for your help. I just have one last question: I've tried what you've stated above from my PC and it didn't work! Did you try it on your PC? Can you be the server and the client connecting to the WAN IP at the same time? – Nadeem Saad Jan 19 '13 at 06:24
  • Yes to both; here's an [example](http://stackoverflow.com/a/3245805/230513). Use `netstat` to verify that your server is listening on port 9092; use `localhost` in the URL to verify that you can connect to it; then use your external ip address. – trashgod Jan 19 '13 at 07:46
  • I'm asking this only because I want to you know what to expect from my tests. Thanks again. – Nadeem Saad Jan 19 '13 at 08:02
  • Thank you very much trashgod! I will try it once I go home! I will notify you of the outcomes. Thanks again! – Nadeem Saad Jan 19 '13 at 08:03
  • I've tried with my localhost and it worked like a charm. I tried with my WAN IP and the following error occurred: SQL Exception: Connection is broken: "java.net.ConnectException: Connection refused: connect: (my WAN IP:9092)" [90067-169]. My TCP server (as per the code above) is on, FYI. – Nadeem Saad Jan 19 '13 at 18:47
  • Yes, I got a similar error until I (1) set the border router to forward 9092 from my WAN IP address to my private, fixed IP address, and (2) enabled 9092 on the firewall. – trashgod Jan 19 '13 at 19:13
  • I have also checked the firewall log and it was as follows: 2013-01-19 21:19:06 ALLOW TCP 127.0.0.1 127.0.0.1 52922 9092 0 - 0 0 0 - - - SEND 2013-01-19 21:19:06 ALLOW TCP 127.0.0.1 127.0.0.1 52922 9092 0 - 0 0 0 - - - RECEIVE This is when connecting to the localhost of course. When I chenge the IP to my WAN IP there is no entry in the firewall log at all. I'm very sorry for the headache... – Nadeem Saad Jan 19 '13 at 19:23
  • That makes me think the router is not forwarding the request. You might re-check the port mapping. – trashgod Jan 19 '13 at 19:31
  • Ok, I've found the following: I start the server from the command line. WebServer, PGServer and TCPServer (which allow others) are all enabled. After running netstat -a -n I can see in the foreign address TCP 192.168.1.101:9092 indicated as "TIME_WAIT" and not listening. The local one is "LISTENING". Does this say anything to you? – Nadeem Saad Jan 19 '13 at 19:50
  • Is your local IP address `192.168.1.101`? – trashgod Jan 19 '13 at 19:55
  • Sorry sorry. My localhost is 127.0.0.1 . The IP 192.168.1.101 is the LAN IP provided by the ISP. – Nadeem Saad Jan 19 '13 at 20:06
  • `192.168.1.101` looks like a DHCP address provided by your router. You're looking for the IP address specified in your network control panel. – trashgod Jan 19 '13 at 20:09
  • If I run ipconfig the IPv4 address is 192.168.1.101. My localhost however is 127.0.0.1. If I don't use the h2.bindAdress, the tcp Server will use 192.168.1.101 by default. Which one should I use? – Nadeem Saad Jan 19 '13 at 20:14
  • Oh, you're on Windows. If the DHCP address assigned by your router is `192.168.1.101`, you want your router to forward 9092 from your ISP assigned WAN IP address to your internal address, `192.168.1.101`. You might change your network configuration to use an unused, fixed IP address like `192.168.1.10` just to see if it helps. – trashgod Jan 19 '13 at 20:23
  • I have made my IP 192.168.1.10 from my router's settings and opened the TCP server under this IP and still when I insert my WAN_IP it still doesn't work.I have disabled the router's firewall and windows firewall completely before starting the TCP server. – Nadeem Saad Jan 20 '13 at 10:59
  • I would like to ask something at this point: from netstat should the port be appearing in both the local and foreign addresses lists or just in the local one? – Nadeem Saad Jan 20 '13 at 11:06
  • Please update your question to show your current code, i.e. no `setProperty`. Starting the server should show a port on the local address, `*.9092`, anybody on the remote address, `*.*`, and the `LISTEN` state. – trashgod Jan 20 '13 at 12:03
  • I don't think I used `-tcpSSL`; you might try omitting that. Also, try forwarding a well known port, e.g. 22/ssh, and verify that forwarding works. If so, you can forward 9092 to remote host using `ssh -fNL`. – trashgod Jan 20 '13 at 20:22
  • Hello again. After starting the TCP server on 192... and asking a friend from an another network to connect through telnet giving my WAN IP and the PORT, he was able to connect. We tried the opposite and it worked too. Hence, the TCP server and firewalls are defined correctly. My question is this: the remote client (using Java) should connect to the server using the WAN_IP, the 192.. IP or the localhost IP (127.0.0.1)? – Nadeem Saad Mar 07 '13 at 10:09
  • [`127.0.0.1`](http://superuser.com/questions/31824/why-is-localhost-ip-127-0-0-1) is only accessible locally. – trashgod Mar 07 '13 at 10:21
  • Ok so the string URL should be: String url = "jdbc:h2:tcp://" + SERVER_IP + ":" + SERVER_PORT + "/C:/Databases/businessApp;IFEXISTS=TRUE"; where SERVER_IP is the WAN_IP? I tried this on my computer and it does not work! Maybe you cannot remotely connect to your computer!!! I will try it today with my friend, unless you have other suggestions!! Thank you! – Nadeem Saad Mar 07 '13 at 15:19
  • Trashgod, I have great news. I've sent the client app to a friend of mine and he was able to connect to my database remotely. Solution is: configure port forwarding on the router, create an inbound rule in the firewall to accept the specific port you have defined in the code, and use the following for the client URL: A) System.setProperty("h2.bindAddress", SERVER_IP); B) String url = "jdbc:h2:tcp://" + SERVER_IP + ":" + ACTIVE_PORT + "/C:/Databases/businessApp;IFEXISTS=TRUE"; SERVER_IP is: Server's WAN_IP. – Nadeem Saad Mar 07 '13 at 19:27
  • To get the WAN_IP the best site that I could find is http://icanhazip.com/ . Other sites might not provide the correct WAN_IP, for some unknown reason so be careful. Trashgod, your advises have been valuable to me. Thank you very much. – Nadeem Saad Mar 07 '13 at 19:30