root/usr/src/lib/libslp/javalib/com/sun/slp/SLPV1Manager.java
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright (c) 2001 by Sun Microsystems, Inc.
 * All rights reserved.
 *
 */

//  SLPV1Manager.java: Manages V1 Compatibility
//  Author:           James Kempf
//  Created On:       Wed Sep  9 09:51:40 1998
//  Last Modified By: James Kempf
//  Last Modified On: Thu Mar  4 10:39:11 1999
//  Update Count:     46
//

package com.sun.slp;

import java.io.*;
import java.util.*;
import java.net.*;


/**
 * The SLPV1Manager manages access between the DA and the V1 compatibility
 * framework. The DA calls into the SLPV1Manager to initialize
 * active and passive DA advertising, and to decode an incoming V1
 * message. However, the ServiceTable does *not* call into SLPV1Manager
 * to handle an outgoing message, since each individual message type is
 * handled separately. SLPV1Manager also handles V1 defaults.
 *
 * @author James Kempf
 */

abstract class SLPV1Manager extends Object {

    // V1 Header class.

    static final String V1_HEADER_CLASS = "com.sun.slp.SLPHeaderV1";

    // V1 multicast addresses.

    static final String sGeneralSLPMCAddress = "224.0.1.22";
    static final String sDADiscSLPMCAddress  = "224.0.1.35";

    static InetAddress v1SLPGSAddr = null;
    static InetAddress v1SLPDAAddr = null;

    /**
     * The SLPV1Advertiser implements the SLPv1 DAAdvert xid incrementing
     * algorithm. In SLPv1, the xid of an unsolicited DAAdvert is only
     * 0 if it came up stateless. If it comes up with preexisting state,
     * it sets the counter to 0x100. Also, when the xid counter wraps,
     * it must wrap to 0x100 and not 0x0.
     */

    static class SLPV1Advertiser extends DAAdvertiser {

        // For implementing the V1 xid algorithm.

        private short xid = 0;

        private static final short STATEFUL_XID = 0x100;

        private static final long STATEFUL_TIME_BOUND = 300L;

        // Service table.

        private ServiceTable table = null;

        // Scopes to use. We need to map from V2, so default corresponds to
        //  the empty scope.

        Vector useScopes = new Vector();

        // Create an SLPv1 Advertiser and start it running.

        SLPV1Advertiser(InetAddress interfac,
                        InetAddress maddr,
                        ServiceTable table)
            throws ServiceLocationException {
            super();

            this.table = table;

            initialize();

            //  There will be NO listener on this multicast address,
            //  so the superclass will simply create a scoket for it.
            //  We don't want to create a new Listener
            //  because we are not interested in multicast requests since
            //  only SAs answer multicast requests.

            initializeNetworking(interfac, maddr);
        }

        // Initialize the xid for passive advertising. We need to determine
        //  whether we came up stateless or not. We do this by asking the
        //  the service store for the stateless reboot time. If the
        //  stateless reboot time is within the last 5 minutes, we
        //  assume we came up stateless. Otherwise, we're stateful.
        //  We also initialize the URL and scopes.

        private void initialize() throws ServiceLocationException {

            // Initialize the xid.

            ServiceStore store = ServiceTable.getServiceTable().store;
            long timestamp = store.getStateTimestamp();
            long currentTime = SLPConfig.currentSLPTime();

            if ((currentTime - timestamp) > STATEFUL_TIME_BOUND) {
                xid = STATEFUL_XID;

            }

            // Initialize the scopes.

            useScopes = config.getSAConfiguredScopes();

        }

        // Return the output buffer for a passive advert. We need to create
        //  the advert, rolling over the xid if necessary for the next one.

        protected byte[] getOutbuf() {

            SDAAdvert daadvert = null;

            try {

                SLPHeaderV1 hdr = new SLPHeaderV1();
                hdr.functionCode = SrvLocHeader.DAAdvert;
                hdr.locale = config.getLocale();

                daadvert = (SDAAdvert)table.makeDAAdvert(hdr,
                                                         interfac,
                                                         xid,
                                                         useScopes,
                                                         config);
                hdr = (SLPHeaderV1)daadvert.getHeader();

                ByteArrayOutputStream baos = new ByteArrayOutputStream();

                hdr.externalize(baos, true, false);
                byte[] outbuf = baos.toByteArray();

                bumpXid();

                return outbuf;

            } catch (ServiceLocationException ex) {
                Assert.slpassert(false,
                              "v1_advert_error",
                              new Object[0]);

            }

            return null;
        }

        private void bumpXid() {

            int newXID = (int)xid + 1;

            if (newXID > Short.MAX_VALUE) {
                xid = STATEFUL_XID;

            } else {
                xid = (short)newXID;

            }
        }
    }


    // Start up listener, active and passive listeners for SLPv1.

    static public void
        start(SLPConfig config, ServerDATable table, ServiceTable stable) {

        // We do not handle SLPv1 if security is enabled, because SLPv1
        //  security is not implemented.

        if (config.getHasSecurity()) {

            if (config.regTest() ||
                config.traceMsg() ||
                config.traceDrop() ||
                config.traceDATraffic()) {

                config.writeLog("v1_security_enabled",
                                new Object[0]);
            }

            return;

        }

        Vector interfaces = config.getInterfaces();
        int i = 0, n = interfaces.size();
        Vector advs = new Vector();

        try {

            InetAddress v1SLPDAAddr = null;

            // Get address for DA discovery multicast.

            v1SLPDAAddr = InetAddress.getByName(sDADiscSLPMCAddress);
            v1SLPGSAddr = InetAddress.getByName(sGeneralSLPMCAddress);

            // Add all listeners onto the SLPv1 DA multicast address and
            //  create a DAAdvertiser on all network interfaces for the
            //  general multicast group.

            for (i = 0; i < n; i++) {
                InetAddress interfac = (InetAddress)interfaces.elementAt(i);

                // Listen for SLPv1 multicast DA service requests. Only DA
                //  service requests are multicast on this address.

                Listener.addListenerToMulticastGroup(interfac, v1SLPDAAddr);

                // We don't need to listen to the SLPv1 general multicast
                //  address because we never want any multicast service
                //  requests. But we do need to advertise as an SLPv1 DA.
                //  So we have a special DAAdvertiser subclass to do it.

                DAAdvertiser ad =
                    new SLPV1Advertiser(interfac, v1SLPGSAddr, stable);
                ad.start();

                advs.addElement(ad);

            }

            // Let admin know we are running in SLPv1 compatibility mode
            //  if tracing is on

            if (config.regTest() ||
                config.traceMsg() ||
                config.traceDrop() ||
                config.traceDATraffic()) {

                config.writeLog("v1_hello",
                                new Object[] {config.getSAConfiguredScopes()});
            }

            return;

        } catch (ServiceLocationException ex) {

            config.writeLog("v1_init_error",
                            new Object[] {ex.getMessage()});

        }  catch (UnknownHostException ex) {

            config.writeLog("v1_init_error",
                            new Object[] {ex.getMessage()});

        }

        // Remove Listeners from multicast group, stop DAAdvertisers.
        // An error occured.

        int j;

        for (j = 0; j < i; i++) {
            InetAddress interfac = (InetAddress)interfaces.elementAt(i);
            DatagramSocket dss =
                Listener.returnListenerSocketOnInterface(interfac);

            if (dss instanceof MulticastSocket) {
                MulticastSocket mss = (MulticastSocket)dss;

                try {
                    mss.leaveGroup(v1SLPDAAddr);

                } catch (IOException ex) {

                    // Ignore it.

                }

                DAAdvertiser ad = (DAAdvertiser)advs.elementAt(j);

                ad.stopThread();
            }
        }
    }

    // Initialize CSrvReg, CSrvDereg, CSrvMsg, and SDAAdvert classes for SLPv1,
    //  also V1 header class.

    static {

        SrvLocHeader.addHeaderClass(V1_HEADER_CLASS, SLPHeaderV1.VERSION);

    }
}