001    /**
002     * Jetrix TetriNET Server
003     * Copyright (C) 2001-2004  Emmanuel Bourg
004     *
005     * This program is free software; you can redistribute it and/or
006     * modify it under the terms of the GNU General Public License
007     * as published by the Free Software Foundation; either version 2
008     * of the License, or (at your option) any later version.
009     *
010     * This program is distributed in the hope that it will be useful,
011     * but WITHOUT ANY WARRANTY; without even the implied warranty of
012     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
013     * GNU General Public License for more details.
014     *
015     * You should have received a copy of the GNU General Public License
016     * along with this program; if not, write to the Free Software
017     * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
018     */
019    
020    package net.jetrix.services;
021    
022    import java.io.BufferedReader;
023    import java.io.IOException;
024    import java.io.InputStreamReader;
025    import java.io.OutputStreamWriter;
026    import java.io.Writer;
027    import java.net.HttpURLConnection;
028    import java.net.InetAddress;
029    import java.net.NetworkInterface;
030    import java.net.SocketException;
031    import java.net.URL;
032    import java.util.Enumeration;
033    import java.util.HashMap;
034    import java.util.Iterator;
035    import java.util.Map;
036    import java.util.logging.Level;
037    import java.util.logging.Logger;
038    
039    import net.jetrix.Server;
040    
041    /**
042     * A service publishing the address of the server on public server lists
043     * (tetrinet.org and tsrv.com). The <tt>host</tt> parameter can be
044     * specified if not explicitely defined in the config.xml file (with the host
045     * attribute on the tetrinet-server element), if no hostname is provided the
046     * service will try to guess the address automatically. The name of the server
047     * is used as the description. The address is published once a day by default.
048     *
049     * @author Emmanuel Bourg
050     * @version $Revision: 794 $, $Date: 2009-02-17 20:08:39 +0100 (Tue, 17 Feb 2009) $
051     * @since 0.2
052     */
053    public class PublishingService extends ScheduledService
054    {
055    
056        private Logger log = Logger.getLogger("net.jetrix");
057    
058        private String host;
059    
060        public PublishingService()
061        {
062            setDelay(1000);
063            setPeriod(24 * 3600 * 1000); // 24 hours
064        }
065    
066        public void setHost(String host)
067        {
068            this.host = host;
069        }
070    
071        public String getHost()
072        {
073            return host;
074        }
075    
076        public String getName()
077        {
078            return "Publishing service";
079        }
080    
081        protected void run()
082        {
083            // get the server address
084            String host = getPublishedAddress();
085    
086            if (host == null)
087            {
088                log.warning("The server address cannot be published, please specify the hostname in the server configuration.");
089                return;
090            }
091    
092            log.info("Publishing server address to online directories... (" + host + ")");
093    
094            // publishing to servers.tetrinet.fr
095            try
096            {
097                String url = "http://servers.tetrinet.fr/server-add.jsp";
098                Map<String, String> params = new HashMap<String, String>();
099                params.put("hostname", host);
100                params.put("description", Server.getInstance().getConfig().getName());
101                post(url, params);
102            }
103            catch (IOException e)
104            {
105                log.log(Level.WARNING, "Unable to publish the server on http://servers.tetrinet.fr", e);
106            }
107        }
108    
109        /**
110         * Send a POST http request to the specified URL.
111         *
112         * @param url        the URL
113         * @param parameters the parameters of the request
114         */
115        protected void post(String url, Map<String, String> parameters) throws IOException
116        {
117            if (log.isLoggable(Level.FINE))
118            {
119                log.fine("posting to: " + url);
120            }
121    
122            URL location = new URL(url);
123            HttpURLConnection conn = (HttpURLConnection) location.openConnection();
124            conn.setDoOutput(true);
125            conn.setRequestMethod("POST");
126    
127            // prepare the request body
128            StringBuilder params = new StringBuilder();
129            Iterator<String> keys = parameters.keySet().iterator();
130            while (keys.hasNext())
131            {
132                String key = keys.next();
133                params.append(key);
134                params.append("=");
135                params.append(parameters.get(key));
136                if (keys.hasNext())
137                {
138                    params.append("&");
139                }
140            }
141    
142            // prepare the request header
143            conn.addRequestProperty("Content-Type", "application/x-www-form-urlencoded");
144            conn.addRequestProperty("Content-Length", String.valueOf(params.length()));
145    
146            // write the request body
147            Writer out = new OutputStreamWriter(conn.getOutputStream());
148            out.write(params.toString());
149            out.flush();
150            out.close();
151    
152            try
153            {
154                // send the request
155                conn.connect();
156    
157                if (log.isLoggable(Level.FINE) && conn.getResponseCode() >= 400)
158                {
159                    log.fine("Response: " + conn.getResponseCode() + " - " + conn.getResponseMessage());
160    
161                    // read the response
162                    BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
163                    String line = null;
164                    while ((line = in.readLine()) != null)
165                    {
166                        log.fine(line);
167                    }
168    
169                    in.close();
170                }
171            }
172            finally
173            {
174                conn.disconnect();
175            }
176        }
177    
178        /**
179         * Find the address to publish by looking at the service host parameter, the
180         * server host attribute in the config.xml file, and the IP associated to
181         * the network interfaces.
182         */
183        protected String getPublishedAddress()
184        {
185            // try the service host parameter
186            if (host != null)
187            {
188                return host;
189            }
190    
191            // try the server host parameter
192            InetAddress address = Server.getInstance().getConfig().getHost();
193            if (address != null)
194            {
195                return address.getHostName();
196            }
197    
198            // search through the network interfaces
199            address = findInetAddress();
200            if (address != null)
201            {
202                return address.getHostName();
203            }
204    
205            return null;
206        }
207    
208        /**
209         * Search through the available network interfaces and return the first
210         * global internet address found.
211         */
212        protected InetAddress findInetAddress()
213        {
214            InetAddress address = null;
215    
216            try
217            {
218                Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
219                while (interfaces.hasMoreElements() && address == null)
220                {
221                    NetworkInterface network = interfaces.nextElement();
222    
223                    Enumeration<InetAddress> addresses = network.getInetAddresses();
224                    while (addresses.hasMoreElements() && address == null)
225                    {
226                        InetAddress addr = addresses.nextElement();
227                        if (!addr.isLoopbackAddress()
228                                && !addr.isLinkLocalAddress()
229                                && !addr.isSiteLocalAddress())
230                        {
231                            address = addr;
232                        }
233                    }
234                }
235            }
236            catch (SocketException e)
237            {
238                log.log(Level.WARNING, e.getMessage(), e);
239            }
240    
241            return address;
242        }
243    
244    }