001/* ***** BEGIN LICENSE BLOCK *****
002 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
003 *
004 * The contents of this file are subject to the Mozilla Public License Version
005 * 1.1 (the "License"); you may not use this file except in compliance with
006 * the License. You may obtain a copy of the License at
007 * http://www.mozilla.org/MPL/
008 *
009 * Software distributed under the License is distributed on an "AS IS" basis,
010 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
011 * for the specific language governing rights and limitations under the
012 * License.
013 *
014 * The Original Code is part of dcm4che, an implementation of DICOM(TM) in
015 * Java(TM), hosted at https://github.com/gunterze/dcm4che.
016 *
017 * The Initial Developer of the Original Code is
018 * Agfa Healthcare.
019 * Portions created by the Initial Developer are Copyright (C) 2013
020 * the Initial Developer. All Rights Reserved.
021 *
022 * Contributor(s):
023 * See @authors listed below
024 *
025 * Alternatively, the contents of this file may be used under the terms of
026 * either the GNU General Public License Version 2 or later (the "GPL"), or
027 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
028 * in which case the provisions of the GPL or the LGPL are applicable instead
029 * of those above. If you wish to allow use of your version of this file only
030 * under the terms of either the GPL or the LGPL, and not to allow others to
031 * use your version of this file under the terms of the MPL, indicate your
032 * decision by deleting the provisions above and replace them with the notice
033 * and other provisions required by the GPL or the LGPL. If you do not delete
034 * the provisions above, a recipient may use your version of this file under
035 * the terms of any one of the MPL, the GPL or the LGPL.
036 *
037 * ***** END LICENSE BLOCK ***** */
038
039package org.dcm4che3.net;
040
041import java.io.IOException;
042import java.net.*;
043import java.security.GeneralSecurityException;
044
045/**
046 * @author Gunter Zeilinger <gunterze@gmail.com>
047 *
048 */
049class UDPListener implements Listener {
050
051    private static final int MAX_PACKAGE_LEN = 0x10000;
052
053    private final Connection conn;
054    private final UDPProtocolHandler handler;
055    private final DatagramSocket ds;
056
057    public UDPListener(Connection conn, UDPProtocolHandler handler)
058            throws IOException, GeneralSecurityException {
059        this.conn = conn;
060        this.handler = handler;
061        try {
062            ds = new DatagramSocket(conn.getBindPoint());
063        } catch (BindException e) {
064            throw new IOException("Cannot start UDP listener on "+conn.getBindPoint().getHostName()+":"+conn.getBindPoint().getPort(),e);
065        }
066        conn.setReceiveBufferSize(ds);
067        conn.getDevice().execute(new Runnable(){
068
069            @Override
070            public void run() { listen(); }
071        });
072    }
073
074
075    private void listen() {
076        SocketAddress sockAddr = ds.getLocalSocketAddress();
077        Connection.LOG.info("Start UDP listener on {}", sockAddr);
078        byte[] data = new byte[MAX_PACKAGE_LEN];
079        try {
080            while (!ds.isClosed()) {
081                Connection.LOG.debug("Wait for UDP datagram package on {}", sockAddr);
082                DatagramPacket dp = new DatagramPacket(data, MAX_PACKAGE_LEN);
083                ds.receive(dp);
084                InetAddress senderAddr = dp.getAddress();
085                if (conn.isBlackListed(dp.getAddress())) {
086                    Connection.LOG.info(
087                            "Ignore UDP datagram package received from blacklisted {}", senderAddr);
088                } else {
089                    Connection.LOG.info(
090                            "Received UDP datagram package from {}", senderAddr);
091                    try {
092                        handler.onReceive(conn, dp);
093                    } catch (Throwable e) {
094                        Connection.LOG.warn(
095                                "Exception processing UDP received from {}:", senderAddr, e);
096                    }
097                }
098            }
099        } catch (Throwable e) {
100            if (!ds.isClosed()) // ignore exception caused by close()
101                Connection.LOG.error("Exception on listing on {}:", sockAddr, e);
102        }
103        Connection.LOG.info("Stop UDP listener on {}", sockAddr);
104    }
105
106
107    @Override
108    public SocketAddress getEndPoint()  {
109        return ds.getLocalSocketAddress();
110    }
111
112    @Override
113    public void close() throws IOException {
114         try {
115            ds.close();
116        } catch (Throwable e) {
117            // Ignore errors when closing the datagram socket.
118        }
119    }
120}