KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > jonathan > libs > resources > tcpip > IPv4ConnectionFactory


1 /***
2  * Jonathan: an Open Distributed Processing Environment
3  * Copyright (C) 1999-2000 France Telecom R&D
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18  *
19  * Release: 3.0
20  *
21  * Contact: jonathan@objectweb.org
22  *
23  * Author: Bruno Dumant
24  *
25  */

26
27
28 package org.objectweb.jonathan.libs.resources.tcpip;
29
30 import java.io.EOFException JavaDoc;
31 import java.io.IOException JavaDoc;
32 import java.io.InputStream JavaDoc;
33 import java.io.OutputStream JavaDoc;
34 import java.net.ConnectException JavaDoc;
35 import java.net.InetAddress JavaDoc;
36 import java.net.ServerSocket JavaDoc;
37 import java.net.Socket JavaDoc;
38 import java.net.UnknownHostException JavaDoc;
39 import java.net.NetworkInterface JavaDoc;
40 import java.util.Enumeration JavaDoc;
41
42 import org.objectweb.jonathan.apis.binding.ExportException;
43 import org.objectweb.jonathan.apis.kernel.InternalException;
44 import org.objectweb.jonathan.apis.kernel.JonathanException;
45 import org.objectweb.jonathan.apis.protocols.ip.IpConnection;
46 import org.objectweb.jonathan.apis.protocols.ip.IpSession;
47 import org.objectweb.jonathan.apis.protocols.ip.TcpIpConnectionMgr;
48 import org.objectweb.jonathan.apis.protocols.ip.TcpIpSrvConnectionFactory;
49 import org.objectweb.jonathan.apis.resources.Chunk;
50
51 import org.objectweb.util.monolog.api.BasicLevel;
52
53 /**
54  * Implementation of an IP V4 connection factory.
55  */

56 public class IPv4ConnectionFactory implements TcpIpConnectionMgr {
57
58    static String JavaDoc default_localhost_name;
59    static String JavaDoc default_localhost_address;
60    static InetAddress JavaDoc default_localhost;
61
62    static {
63       // look for a valid IP address among local network interfaces
64
try {
65          Enumeration JavaDoc interfaces = NetworkInterface.getNetworkInterfaces();
66          while (default_localhost == null && interfaces.hasMoreElements()) {
67             Enumeration JavaDoc addresses =
68                ((NetworkInterface JavaDoc)interfaces.nextElement()).getInetAddresses();
69             while (default_localhost == null && addresses.hasMoreElements()) {
70                InetAddress JavaDoc address = (InetAddress JavaDoc)addresses.nextElement();
71                if (!address.isLoopbackAddress() && address.isSiteLocalAddress()) {
72                   default_localhost = address;
73                }
74             }
75          }
76       } catch (Exception JavaDoc ignored) {
77          if ((LoggerProvider.logger != null)
78             &&(LoggerProvider.logger.isLoggable(BasicLevel.WARN))) {
79             LoggerProvider.logger.log(BasicLevel.WARN,"Could not determine local host address.");
80          }
81       }
82       if (default_localhost != null) {
83          default_localhost_name = default_localhost.getHostName();
84          default_localhost_address = default_localhost.getHostAddress();
85       }
86    }
87
88    InetAddress JavaDoc localhost;
89    public String JavaDoc localhost_name;
90
91    /**
92     * Indicates whether warning messages should be printed to stderr.
93     */

94    public boolean verbose;
95
96    /**
97     * Indicates whether the names used to identify endpoints should be
98     * host names or host addresses.
99     */

100    public boolean use_address_as_name;
101
102    /**
103     * If >= 0, enables the SO_LINGER option with the specified linger time.
104     */

105    public int SO_LINGER;
106
107    /**
108     * If >= 0, enables the SO_TIMEOUT option with the specified timeout (in
109     * ms). 0 means infinity (no timeout).
110     */

111    public int SO_TIMEOUT;
112
113    /**
114     * If true, enables the TCP_NODELAY option.
115     */

116    public boolean TCP_NODELAY;
117
118    /**
119     * Maximum length of the queue on incoming connect requests.
120     */

121    public int backlog;
122
123    int max_retries;
124
125
126    
127    /**
128     * Returns a new IPv4ConnectionFactory with default parameters.
129     *
130     * @exception JonathanException if something goes wrong.
131     */

132    public IPv4ConnectionFactory() throws JonathanException {
133       this(null,false,100,0,true,50,10,true);
134    }
135    
136
137    /**
138     * Returns a new IPv4 connection factory
139     * @param localhost_value string representing the local machine (may be null)
140     * @param verbose indicates whether warning messages should be output on stderr
141     * @param SO_LINGER SO_LINGER parameter used to create sockets
142     * @param SO_TIMEOUT SO_TIMEOUT parameter used to create sockets
143     * @param TCP_NODELAY TCP_NODELAY parameter used to create sockets
144     * @param backlog backlog parameter used to create sockets
145     * @param max_retries maximum number of retries when creating a socket
146     * @param use_address_as_name use a.b.c.d adresses instead of DNS names
147     * @exception JonathanException if something goes wrong
148     */

149    public IPv4ConnectionFactory(String JavaDoc localhost_value,
150                                 boolean verbose,
151                                 int SO_LINGER, int SO_TIMEOUT,
152                                 boolean TCP_NODELAY, int backlog,
153                                 int max_retries, boolean use_address_as_name)
154       throws JonathanException {
155       
156       this.verbose = verbose;
157       this.SO_LINGER = SO_LINGER;
158       this.SO_TIMEOUT = SO_TIMEOUT;
159       this.TCP_NODELAY = TCP_NODELAY;
160       this.backlog = backlog;
161       this.max_retries = max_retries;
162       if (max_retries <= 0) {
163          this.max_retries = 1;
164       }
165       this.use_address_as_name = use_address_as_name;
166       
167       try{
168          if (localhost_value != null &&
169              (localhost_value.equals("localhost") ||
170               localhost_value.equals("127.0.0.1"))) {
171             localhost_value = null;
172          }
173          if (localhost_value != null) {
174             localhost = InetAddress.getByName(localhost_value);
175             if (use_address_as_name) {
176                localhost_name = localhost.getHostAddress();
177             } else {
178                localhost_name = localhost.getHostName();
179             }
180          } else {
181             localhost = default_localhost;
182             if (use_address_as_name) {
183                localhost_name = default_localhost_address;
184             } else {
185                localhost_name = default_localhost_name;
186             }
187          }
188       } catch(UnknownHostException JavaDoc e){
189          throw new JonathanException(e);
190       }
191    }
192
193    public void setVerbose(boolean verbose) {
194       this.verbose = verbose;
195    }
196
197    /**
198     * Builds a new client-side connection with the provided parameters.
199     *
200     * @param host a host name;
201     * @param port a port number;
202     * @param session a TCP/IP session;
203     * @return a new client-side connection.
204     * @exception JonathanException if something goes wrong.
205     */

206    public IpConnection newCltConnection(String JavaDoc host,int port,
207                                         IpSession session)
208       throws JonathanException {
209       try {
210          if (host == null || host.equals("localhost") || host.equals("127.0.0.1")) {
211             host = default_localhost_name;
212          }
213 // if (verbose) {
214
// System.err.println("Trying to connect to " + host +
215
// " on port " + (port & 0xFFFF) + ".");
216
// }
217
// begin log
218
if ((LoggerProvider.bind_logger != null)
219             &&(LoggerProvider.bind_logger.isLoggable(BasicLevel.INFO))) {
220             LoggerProvider.bind_logger.log(BasicLevel.INFO,"Trying to connect to " + host +
221                                " on port " + (port & 0xFFFF) + ".");
222          }
223          // end log
224
Socket JavaDoc socket = null;
225          for (int i = 0; i < max_retries; i++) {
226             try {
227                socket = new Socket JavaDoc(host,port & 0xFFFF);
228                break;
229             } catch (ConnectException JavaDoc e) {
230                if (i == (max_retries - 1)) {
231                   throw new JonathanException(e);
232 // } else if (verbose) {
233
// System.err.println("Re-trying to connect to " + host +
234
// " on port " + (port & 0xFFFF) + ".");
235
// }
236
// begin log
237
} else if ((LoggerProvider.bind_logger != null)
238                   &&(LoggerProvider.bind_logger.isLoggable(BasicLevel.INFO))) {
239                   LoggerProvider.bind_logger.log(BasicLevel.INFO,"Re-trying to connect to " + host +
240                                      " on port " + (port & 0xFFFF) + ".");
241                }
242                // end log
243
}
244          }
245          if (SO_LINGER >= 0) {
246             socket.setSoLinger(true,SO_LINGER);
247          }
248          if (SO_TIMEOUT >= 0) {
249             socket.setSoTimeout(SO_TIMEOUT);
250          }
251          socket.setTcpNoDelay(TCP_NODELAY);
252 // port = (short) socket.getPort();
253
port = socket.getPort() & 0xFFFF ;
254
255 // if (verbose) {
256
// System.err.println("Connected to " + socket);
257
// }
258
// begin log
259
if ((LoggerProvider.bind_logger != null)
260             &&(LoggerProvider.bind_logger.isLoggable(BasicLevel.INFO))) {
261             LoggerProvider.bind_logger.log(BasicLevel.INFO,"Connected to " + socket);
262          }
263          // end log
264
return new Connection(socket,session,host,port);
265       } catch (IOException JavaDoc e) {
266          throw new JonathanException(e);
267       }
268    }
269
270    /**
271     * Returns a new server connection factory encapsulating a server socket on the
272     * provided port. If port = 0, an anonymous server socket is opened.
273     * @param port the expected port of the server socket;
274     * @return a server connection factory.
275     * @exception JonathanException if an error occurs.
276     */

277    public TcpIpSrvConnectionFactory newSrvConnectionFactory(int port)
278       throws JonathanException {
279       return new SrvConnectionFactory(localhost,port,backlog);
280    }
281
282    /**
283     * Returns the canonical host name corresponding to hostname.
284     *
285     * If use_address_as_name is true, the canonical host name is the
286     * string corresponding to the IP address, else it is the machine name.
287     *
288     * @param hostname a host name.
289     * @return the canonical host name corresponding to hostname.
290     */

291    public String JavaDoc getCanonicalHostName(String JavaDoc hostname) {
292       if (hostname != null && hostname.length() > 0) {
293          if (use_address_as_name) {
294             if (! Character.isDigit(hostname.charAt(0))) {
295                if (hostname.equals("localhost")) {
296                   return default_localhost_address;
297                } else {
298                   try {
299                      return InetAddress.getByName(hostname).getHostAddress();
300                   } catch (Exception JavaDoc ignored) {
301                   }
302                }
303             } else if (hostname.equals("127.0.0.1")) {
304                return default_localhost_address;
305             }
306          } else {
307             if (Character.isDigit(hostname.charAt(0))) {
308                if (hostname.equals("127.0.0.1")) {
309                   return default_localhost_name;
310                } else {
311                   try {
312                      return InetAddress.getByName(hostname).getHostName();
313                   } catch (Exception JavaDoc ignored) {
314                   }
315                }
316             } else if (hostname.equals("localhost")) {
317                return default_localhost_name;
318             }
319          }
320       }
321       return hostname;
322    }
323
324    /**
325     * Builds a new server-side connection with the provided parameters.
326     *
327     * @param socket a TCP/IP socket;
328     * @param session a TCP/IP session;
329     * @param host a host name;
330     * @param port a port number;
331     * @return a new server-side connection.
332     * @exception JonathanException if something goes wrong.
333     */

334    protected Connection newSrvConnection(Socket JavaDoc socket,IpSession session,
335                                          String JavaDoc host, int port)
336
337       throws JonathanException {
338       return new Connection(socket,session,host,port);
339    }
340
341    /**
342     * Implementation of TcpIpConnection.
343     */

344    class Connection implements IpConnection {
345
346       /** The encapsulated socket. */
347       Socket JavaDoc socket;
348       String JavaDoc host;
349       int port;
350       InputStream JavaDoc is;
351       OutputStream JavaDoc os;
352
353       /** The related session. */
354       IpSession session;
355
356       /**
357        * Builds a new connection.
358        *
359        * @param socket a socket;
360        * @param session a session;
361        * @param host a host name;
362        * @param port a tcp port;
363        * @exception JonathanException if something goes wrong.
364        */

365       protected Connection(Socket JavaDoc socket, IpSession session,
366                            String JavaDoc host, int port)
367
368          throws JonathanException {
369          if (socket != null) {
370             try {
371                is = socket.getInputStream();
372                os = socket.getOutputStream();
373             } catch (IOException JavaDoc e) {
374                try {
375                   socket.close();
376                } catch (IOException JavaDoc ignored) {
377                }
378                throw new JonathanException(e);
379             }
380          } else {
381             throw new InternalException("Null socket to create connection");
382          }
383          this.socket = socket;
384          this.session = session;
385          this.host = host;
386          this.port = port;
387       }
388
389       public int available() throws IOException JavaDoc {
390          return is.available();
391       }
392
393       public void emit(Chunk c) throws IOException JavaDoc {
394          synchronized (os) {
395 // byte[] data = c.data;
396
// int len = c.top - c.offset;
397
// String str = "OUT: ";
398
// for (int i = c.offset; i < len; i++) {
399
// str = str + data[i] + " ";
400
// }
401
// System.out.println(str);
402
// begin log
403
if ((LoggerProvider.send_logger != null)
404                &&(LoggerProvider.send_logger.isLoggable(BasicLevel.DEBUG))) {
405                byte[] data = c.data;
406                int len = c.top - c.offset;
407                String JavaDoc str = "OUT: ";
408                for (int i = c.offset; i < len; i++) {
409                   str = str + data[i] + " ";
410                }
411                LoggerProvider.send_logger.log(BasicLevel.DEBUG,str);
412             }
413             // end log
414
os.write(c.data,c.offset,c.top);
415          }
416       }
417
418       public void receive(Chunk c,int sz) throws IOException JavaDoc {
419          byte[] data = c.data;
420          int top = c.top;
421 // System.err.println(Thread.currentThread() +
422
// " trying to read " + sz + " bytes from " +
423
// socket.getPort());
424
while (sz > 0) {
425             int a = is.read(data,top,sz);
426 // String str = "IN: ";
427
// for (int i = top; i < top + sz; i++) {
428
// str = str + data[i] + " ";
429
// }
430
// System.out.println(str);
431
// begin log
432
if ((LoggerProvider.receive_logger != null)
433                &&(LoggerProvider.receive_logger.isLoggable(BasicLevel.DEBUG))) {
434                String JavaDoc str = "IN: ";
435                for (int i = top; i < top + sz; i++) {
436                   str = str + data[i] + " ";
437                }
438                LoggerProvider.receive_logger.log(BasicLevel.DEBUG,str);
439             }
440             // end log
441
if (a > 0) {
442                top += a;
443                sz -= a;
444             } else {
445                throw new EOFException JavaDoc();
446             }
447          }
448 // System.err.println(Thread.currentThread() +
449
// " read " + (top - c.top) + " bytes from " +
450
// socket.getPort());
451

452          c.top = top;
453       }
454
455
456       /**
457        * Returns the port number of the underlying socket.
458        * @return the port number of the underlying socket.
459        */

460       public int getPort() {
461          return port;
462       }
463
464       /**
465        * Returns the host name of the underlying socket.
466        * @return the host name of the underlying socket.
467        */

468       public String JavaDoc getHostName() {
469          return host;
470       }
471
472       /**
473        * Returns the session attached to this connection.
474        * @return the session attached to this connection.
475        */

476       public IpSession getSession() {
477          return session;
478       }
479
480       /**
481        * Attaches a new session to this connection.
482        * @param session the session to be attached to the target connection.
483        */

484       public void setSession(IpSession session) {
485          this.session = session;
486       }
487
488       /**
489        * Deletes this connection, removing it from the connection manager, and
490        * closing the socket. This method should not be used by a socket user unless
491        * a problem occurs on the connection, like an exception when trying to read
492        * or to write data.
493        */

494       public synchronized void delete() {
495          if (socket != null) {
496             try {
497 // if (verbose) {
498
// System.err.println("Connection with host " + host +
499
// " on port " +
500
// (port & 0xFFFF) + " closed.");
501
// }
502
// begin log
503
if ((LoggerProvider.logger != null)
504                   &&(LoggerProvider.logger.isLoggable(BasicLevel.INFO))) {
505                   LoggerProvider.logger.log(BasicLevel.INFO,"Connection with host " + host +
506                                      " on port " +
507                                      (port & 0xFFFF) + " closed.");
508                }
509                // end log
510
socket.close();
511             } catch (IOException JavaDoc ignored) {}
512             socket = null;
513             session = null;
514          }
515       }
516
517       /**
518        * Releases this connection. This is to indicate to the connection manager
519        * that the target connection is no longer used.
520        */

521       public void release() {
522          delete();
523       }
524
525       public String JavaDoc toString() {
526          return "IPv4Connection[" + socket + "]";
527       }
528
529    }
530
531    class SrvConnectionFactory implements TcpIpSrvConnectionFactory {
532       int port;
533       String JavaDoc hostname;
534       ServerSocket JavaDoc server_socket;
535
536       SrvConnectionFactory(InetAddress JavaDoc localhost,int port,int backlog)
537          throws JonathanException {
538          if (use_address_as_name) {
539             this.hostname = localhost.getHostAddress();
540          } else {
541             this.hostname = localhost.getHostName();
542          }
543          try {
544             server_socket = new ServerSocket JavaDoc(port & 0xFFFF,backlog,localhost);
545             if (server_socket != null) {
546                this.port = server_socket.getLocalPort() & 0xFFFF;
547 // if (verbose) {
548
// System.err.println("Opened a server connection on host " +
549
// hostname +
550
// "\n on port " +
551
// (this.port & 0xFFFF));
552
// }
553
// begin log
554
if ((LoggerProvider.export_logger != null)
555                   &&(LoggerProvider.export_logger.isLoggable(BasicLevel.INFO))) {
556                   LoggerProvider.export_logger.log(BasicLevel.INFO,"Opened a server connection on host " +
557                                      hostname + " on port " +
558                                      (this.port & 0xFFFF));
559                }
560                // end log
561
} else {
562                throw new ExportException("Can't create server socket.");
563             }
564          } catch (IOException JavaDoc e) {
565             throw new ExportException(e);
566          }
567       }
568
569       public IpConnection newSrvConnection(IpSession session)
570          throws JonathanException {
571          try {
572             ServerSocket JavaDoc current = null;
573             synchronized (this) {
574                if (server_socket != null) {
575                   current = server_socket;
576                } else {
577                   throw new ExportException("Server Connection Factory has been closed");
578                }
579             }
580
581             Socket JavaDoc socket = current.accept();
582             if (SO_LINGER >= 0) {
583                socket.setSoLinger(true,SO_LINGER);
584             }
585             if (SO_TIMEOUT >= 0) {
586                socket.setSoTimeout(SO_TIMEOUT);
587             }
588             socket.setTcpNoDelay(TCP_NODELAY);
589             int port = socket.getPort() & 0xFFFF;
590             String JavaDoc hostname = socket.getInetAddress().getHostName();
591 // if (verbose) {
592
// System.err.println("Accepted connection with host: " +
593
// hostname +
594
// "\n on port: " +
595
// port);
596
// }
597
// begin log
598
if ((LoggerProvider.bind_logger != null)
599                &&(LoggerProvider.bind_logger.isLoggable(BasicLevel.INFO))) {
600                LoggerProvider.bind_logger.log(BasicLevel.INFO,"Accepted connection with host: " +
601                                   hostname + " on port: " + port);
602             }
603             // end log
604
return
605                IPv4ConnectionFactory.this.newSrvConnection(socket,session,hostname,
606                                                            port);
607          } catch (IOException JavaDoc e) {
608             throw new ExportException(e);
609          }
610       }
611
612       public int getPort() {
613          return port;
614       }
615
616       public String JavaDoc getHostName() {
617          return hostname;
618       }
619
620       public synchronized void close() {
621          if (server_socket != null) {
622             try {
623                server_socket.close();
624             } catch (IOException JavaDoc ignored) {}
625             server_socket = null;
626          }
627       }
628    }
629 }
630
631
632
633
634
Popular Tags