package org.red5.server; /* * RED5 Open Source Flash Server - http://www.osflash.org/red5 * * Copyright (c) 2006-2009 by respective authors (see below). All rights reserved. * * This library is free software; you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free Software * Foundation; either version 2.1 of the License, or (at your option) any later * version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along * with this library; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.concurrent.locks.Lock; import java.util.concurrent.atomic.AtomicLong; import org.red5.server.api.IBasicScope; import org.red5.server.api.IClient; import org.red5.server.api.IConnection; import org.red5.server.api.IScope; import org.red5.server.api.event.IEvent; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Base abstract class for connections. Adds connection specific functionality like work with clients * to AttributeStore. */ public abstract class BaseConnection extends AttributeStore implements IConnection { /** * Logger */ private static final Logger log = LoggerFactory.getLogger(BaseConnection.class); /** * Connection type */ protected final String type; /** * Connection host */ protected volatile String host; /** * Connection remote address */ protected volatile String remoteAddress; /** * Connection remote addresses */ protected volatile List<String> remoteAddresses; /** * Remote port */ protected volatile int remotePort; /** * Path of scope client connected to */ protected volatile String path; /** * Connection session identifier */ protected volatile String sessionId; /** * Number of read messages */ protected AtomicLong readMessages = new AtomicLong(0); /** * Number of written messages */ protected AtomicLong writtenMessages = new AtomicLong(0); /** * Number of dropped messages */ protected AtomicLong droppedMessages = new AtomicLong(0); /** * Connection params passed from client with NetConnection.connect call * * @see <a href='http://livedocs.adobe.com/fms/2/docs/00000570.html'>NetConnection in Flash Media Server docs (external)</a> */ @SuppressWarnings("all") protected volatile Map<String, Object> params = null; /** * Client bound to connection */ protected volatile IClient client; /** * Scope that connection belongs to */ protected volatile Scope scope; /** * Set of basic scopes. */ protected Set<IBasicScope> basicScopes = new CopyOnWriteArraySet<IBasicScope>(); /** * Is the connection closed? */ protected volatile boolean closed; private final ReadWriteLock lock = new ReentrantReadWriteLock(); /** * * @param type Connection type * @param host Host * @param remoteAddress Remote address * @param remotePort Remote port * @param path Scope path on server * @param sessionId Session id * @param params Params passed from client */ public BaseConnection(String type, String host, String remoteAddress, int remotePort, String path, String sessionId, Map<String, Object> params) { this.type = type; this.host = host; this.remoteAddress = remoteAddress; this.remoteAddresses = new ArrayList<String>(); this.remoteAddresses.add(remoteAddress); this.remoteAddresses = Collections .unmodifiableList(this.remoteAddresses); this.remotePort = remotePort; this.path = path; this.sessionId = sessionId; this.params = params; } /** * @return lock for read only operations */ public Lock getReadLock() { return lock.readLock(); } /** * @return lock for changing state operations */ public Lock getWriteLock() { return lock.writeLock(); } /** * Initializes client * @param client Client bound to connection */ public void initialize(IClient client) { getWriteLock().lock(); try { if (this.client != null && this.client instanceof Client) { // Unregister old client ((Client) this.client).unregister(this); } this.client = client; if (this.client instanceof Client) { // Register new client ((Client) this.client).register(this); } } finally { getWriteLock().unlock(); } } /** * * @return type */ public String getType() { return type; } /** * * @return host */ public String getHost() { return host; } /** * * @return remote address */ public String getRemoteAddress() { return remoteAddress; } /** * @return remote address */ public List<String> getRemoteAddresses() { return remoteAddresses; } /** * * @return remote port */ public int getRemotePort() { return remotePort; } /** * * @return path */ public String getPath() { return path; } /** * * @return session id */ public String getSessionId() { return sessionId; } /** * Return connection parameters * @return connection parameters */ public Map<String, Object> getConnectParams() { return Collections.unmodifiableMap(params); } /** * * @return client */ public IClient getClient() { return client; } /** * Check whether connection is alive * @return true if connection is bound to scope, false otherwise */ public boolean isConnected() { return scope != null; } /** * Connect to another scope on server * @param newScope New scope * @return true on success, false otherwise */ public boolean connect(IScope newScope) { return connect(newScope, null); } /** * Connect to another scope on server with given parameters * @param newScope New scope * @param params Parameters to connect with * @return true on success, false otherwise */ public boolean connect(IScope newScope, Object[] params) { getWriteLock().lock(); try { final Scope oldScope = scope; scope = (Scope) newScope; if (scope.connect(this, params)) { if (oldScope != null) { oldScope.disconnect(this); } return true; } else { scope = oldScope; return false; } } finally { getWriteLock().unlock(); } } /** * * @return scope */ public IScope getScope() { return scope; } /** * Closes connection */ public void close() { getWriteLock().lock(); try { if (closed || scope == null) { log.debug("Close, not connected nothing to do."); return; } closed = true; } finally { getWriteLock().unlock(); } log.debug("Close, disconnect from scope, and children"); try { // Unregister all child scopes first for (IBasicScope basicScope : basicScopes) { unregisterBasicScope(basicScope); } } catch (Exception err) { log.error("Error while unregistering basic scopes.", err); } // Disconnect try { scope.disconnect(this); } catch (Exception err) { log.error("Error while disconnecting from scope " + scope, err); } // Unregister client if (client != null && client instanceof Client) { ((Client) client).unregister(this); client = null; } scope = null; } /** * Notified on event * @param event Event */ public void notifyEvent(IEvent event) { } /** * Dispatches event * @param event Event */ public void dispatchEvent(IEvent event) { } /** * Handles event * @param event Event * @return true if associated scope was able to handle event, false otherwise */ public boolean handleEvent(IEvent event) { return getScope().handleEvent(event); } /** * * @return basic scopes */ public Iterator<IBasicScope> getBasicScopes() { return basicScopes.iterator(); } /** * Registers basic scope * @param basicScope Basic scope to register */ public void registerBasicScope(IBasicScope basicScope) { basicScopes.add(basicScope); basicScope.addEventListener(this); } /** * Unregister basic scope * * @param basicScope Unregister basic scope */ public void unregisterBasicScope(IBasicScope basicScope) { basicScopes.remove(basicScope); basicScope.removeEventListener(this); } /** * * @return bytes read */ public abstract long getReadBytes(); /** * * @return bytes written */ public abstract long getWrittenBytes(); /** * * @return messages read */ public long getReadMessages() { return readMessages.get(); } /** * * @return messages written */ public long getWrittenMessages() { return writtenMessages.get(); } /** * * @return dropped messages */ public long getDroppedMessages() { return droppedMessages.get(); } /** * * @return pending messages */ public long getPendingMessages() { return 0; } /** * * @param streamId the id you want to know about * @return pending messages for this streamId */ public long getPendingVideoMessages(int streamId) { return 0; } /** {@inheritDoc} */ public long getClientBytesRead() { return 0; } }