Communicate the client's timezone to the server during the authentication
process and keep that information around in case the server ever wants to know. git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@4356 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
@@ -21,6 +21,8 @@
|
|||||||
|
|
||||||
package com.threerings.presents.net;
|
package com.threerings.presents.net;
|
||||||
|
|
||||||
|
import java.util.TimeZone;
|
||||||
|
|
||||||
public class AuthRequest extends UpstreamMessage
|
public class AuthRequest extends UpstreamMessage
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
@@ -39,6 +41,7 @@ public class AuthRequest extends UpstreamMessage
|
|||||||
{
|
{
|
||||||
_creds = creds;
|
_creds = creds;
|
||||||
_version = version;
|
_version = version;
|
||||||
|
_zone = TimeZone.getDefault().getID();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -58,6 +61,14 @@ public class AuthRequest extends UpstreamMessage
|
|||||||
return _version;
|
return _version;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the timezone in which this client is operating.
|
||||||
|
*/
|
||||||
|
public TimeZone getTimeZone ()
|
||||||
|
{
|
||||||
|
return TimeZone.getTimeZone(_zone);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates a string representation of this instance.
|
* Generates a string representation of this instance.
|
||||||
*/
|
*/
|
||||||
@@ -72,4 +83,7 @@ public class AuthRequest extends UpstreamMessage
|
|||||||
|
|
||||||
/** The version information associated with the client code. */
|
/** The version information associated with the client code. */
|
||||||
protected String _version;
|
protected String _version;
|
||||||
|
|
||||||
|
/** The timezone in which this client is operating. */
|
||||||
|
protected String _zone;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -349,7 +349,7 @@ public class ClientManager
|
|||||||
", conn=" + conn + "].");
|
", conn=" + conn + "].");
|
||||||
// create a new client and stick'em in the table
|
// create a new client and stick'em in the table
|
||||||
client = _factory.createClient(req);
|
client = _factory.createClient(req);
|
||||||
client.startSession(this, creds, conn, rsp.authdata);
|
client.startSession(this, req, conn, rsp.authdata);
|
||||||
|
|
||||||
// map their client instance
|
// map their client instance
|
||||||
_usermap.put(username, client);
|
_usermap.put(username, client);
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import java.io.IOException;
|
|||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
import java.util.TimeZone;
|
||||||
|
|
||||||
import com.samskivert.util.HashIntMap;
|
import com.samskivert.util.HashIntMap;
|
||||||
import com.samskivert.util.Throttle;
|
import com.samskivert.util.Throttle;
|
||||||
@@ -39,6 +40,7 @@ import com.threerings.presents.dobj.DObject;
|
|||||||
import com.threerings.presents.dobj.ObjectAccessException;
|
import com.threerings.presents.dobj.ObjectAccessException;
|
||||||
import com.threerings.presents.dobj.ProxySubscriber;
|
import com.threerings.presents.dobj.ProxySubscriber;
|
||||||
|
|
||||||
|
import com.threerings.presents.net.AuthRequest;
|
||||||
import com.threerings.presents.net.BootstrapData;
|
import com.threerings.presents.net.BootstrapData;
|
||||||
import com.threerings.presents.net.BootstrapNotification;
|
import com.threerings.presents.net.BootstrapNotification;
|
||||||
import com.threerings.presents.net.Credentials;
|
import com.threerings.presents.net.Credentials;
|
||||||
@@ -105,7 +107,15 @@ public class PresentsClient
|
|||||||
*/
|
*/
|
||||||
public Credentials getCredentials ()
|
public Credentials getCredentials ()
|
||||||
{
|
{
|
||||||
return _creds;
|
return _areq.getCredentials();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the time zone in which this client is operating.
|
||||||
|
*/
|
||||||
|
public TimeZone getTimeZone ()
|
||||||
|
{
|
||||||
|
return _areq.getTimeZone();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -269,25 +279,6 @@ public class PresentsClient
|
|||||||
_cmgr.resolveClientObject(username, clr);
|
_cmgr.resolveClientObject(username, clr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when {@link #setUsername} has been called and the new client
|
|
||||||
* object is about to be applied to this client. The old client object
|
|
||||||
* will not yet have been destroyed, so any final events can be sent
|
|
||||||
* along prior to the new object being put into effect.
|
|
||||||
*/
|
|
||||||
protected void clientObjectWillChange (
|
|
||||||
ClientObject oldClobj, ClientObject newClobj)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called after the new client object has been committed to this
|
|
||||||
* client due to a call to {@link #setUsername}.
|
|
||||||
*/
|
|
||||||
protected void clientObjectDidChange (ClientObject newClobj)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the client object that is associated with this client.
|
* Returns the client object that is associated with this client.
|
||||||
*/
|
*/
|
||||||
@@ -297,38 +288,89 @@ public class PresentsClient
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes this client instance with the specified username,
|
* Forcibly terminates a client's session. This must be called from
|
||||||
* connection instance and client object and begins a client session.
|
* the dobjmgr thread.
|
||||||
*/
|
*/
|
||||||
protected void startSession (
|
public void endSession ()
|
||||||
ClientManager cmgr, Credentials creds, Connection conn, Object authdata)
|
|
||||||
{
|
{
|
||||||
_cmgr = cmgr;
|
// queue up a request for our connection to be closed (if we have
|
||||||
_creds = creds;
|
// a connection, that is)
|
||||||
_authdata = authdata;
|
Connection conn = getConnection();
|
||||||
setConnection(conn);
|
if (conn != null) {
|
||||||
|
// go ahead and clear out our connection now to prevent
|
||||||
|
// funniness
|
||||||
|
setConnection(null);
|
||||||
|
// have the connection manager close our connection when it is
|
||||||
|
// next convenient
|
||||||
|
PresentsServer.conmgr.closeConnection(conn);
|
||||||
|
}
|
||||||
|
|
||||||
// obtain our starting username
|
// if we don't have a client object, we failed to resolve in the
|
||||||
assignStartingUsername();
|
// first place, in which case we have to cope as best we can
|
||||||
|
if (_clobj != null) {
|
||||||
|
// and clean up after ourselves
|
||||||
|
try {
|
||||||
|
sessionDidEnd();
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.warning("Choked in sessionDidEnd [client=" + this + "].");
|
||||||
|
Log.logStackTrace(e);
|
||||||
|
}
|
||||||
|
|
||||||
// resolve our client object before we get fully underway
|
// release (and destroy) our client object
|
||||||
cmgr.resolveClientObject(_username, this);
|
_cmgr.releaseClientObject(_username);
|
||||||
|
}
|
||||||
|
|
||||||
// make a note of our session start time
|
// let the client manager know that we're audi 5000
|
||||||
_sessionStamp = System.currentTimeMillis();
|
_cmgr.clientSessionDidEnd(this);
|
||||||
|
|
||||||
|
// clear out the client object so that we know the session is over
|
||||||
|
_clobj = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is factored out to allow derived classes to use a different
|
* This is called when the server is shut down in the middle of a
|
||||||
* starting username than the one supplied in the user's credentials.
|
* client session. In this circumstance, {@link #endSession} will
|
||||||
* Generally one only wants to munge the starting username if the user
|
* <em>not</em> be called and so any persistent data that might
|
||||||
* will subsequently choose a "screen name" and it is desirable to
|
* normally be flushed at the end of a client's session should likely
|
||||||
* avoid collision between the authentication user namespace and the
|
* be flushed here.
|
||||||
* screen namespace.
|
|
||||||
*/
|
*/
|
||||||
protected void assignStartingUsername ()
|
public void shutdown ()
|
||||||
{
|
{
|
||||||
_username = _creds.getUsername();
|
// if the client is connected, we need to fake the computation of
|
||||||
|
// their final connect time because we won't be closing their
|
||||||
|
// socket normally
|
||||||
|
if (getConnection() != null) {
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
_connectTime += ((now - _networkStamp) / 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes a note that this client is subscribed to this object so that
|
||||||
|
* we can clean up after ourselves if and when the client goes
|
||||||
|
* away. This is called by the client internals and needn't be called
|
||||||
|
* by code outside the client.
|
||||||
|
*/
|
||||||
|
public synchronized void mapSubscrip (DObject object)
|
||||||
|
{
|
||||||
|
_subscrips.put(object.getOid(), object);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes a note that this client is no longer subscribed to this
|
||||||
|
* object. The subscription map is used to clean up after the client
|
||||||
|
* when it goes away. This is called by the client internals and
|
||||||
|
* needn't be called by code outside the client.
|
||||||
|
*/
|
||||||
|
public synchronized void unmapSubscrip (int oid)
|
||||||
|
{
|
||||||
|
DObject object = _subscrips.remove(oid);
|
||||||
|
if (object != null) {
|
||||||
|
object.removeSubscriber(this);
|
||||||
|
} else {
|
||||||
|
Log.warning("Requested to unmap non-existent subscription " +
|
||||||
|
"[oid=" + oid + "].");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// documentation inherited from interface
|
// documentation inherited from interface
|
||||||
@@ -356,6 +398,123 @@ public class PresentsClient
|
|||||||
endSession();
|
endSession();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// documentation inherited from interface
|
||||||
|
public void handleMessage (UpstreamMessage message)
|
||||||
|
{
|
||||||
|
_messagesIn++; // count 'em up!
|
||||||
|
|
||||||
|
// if the client has been getting crazy with the cheeze whiz,
|
||||||
|
// stick a fork in them; the first time through we end our
|
||||||
|
// session, subsequently _throttle is null and we just drop any
|
||||||
|
// messages that come in until we've fully shutdown
|
||||||
|
if (_throttle == null) {
|
||||||
|
// Log.info("Dropping message from force-quit client " +
|
||||||
|
// "[conn=" + _conn +
|
||||||
|
// ", msg=" + message + "].");
|
||||||
|
return;
|
||||||
|
} else if (_throttle.throttleOp(message.received)) {
|
||||||
|
Log.warning("Client sent more than 100 messages in 10 seconds, " +
|
||||||
|
"forcing disconnect " + this + ".");
|
||||||
|
safeEndSession();
|
||||||
|
_throttle = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we dispatch to a message dispatcher that is specialized for the
|
||||||
|
// particular class of message that we received
|
||||||
|
MessageDispatcher disp = _disps.get(message.getClass());
|
||||||
|
if (disp == null) {
|
||||||
|
Log.warning("No dispatcher for message [msg=" + message + "].");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// otherwise pass the message on to the dispatcher
|
||||||
|
disp.dispatch(this, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
// documentation inherited from interface
|
||||||
|
public void objectAvailable (DObject object)
|
||||||
|
{
|
||||||
|
if (postMessage(new ObjectResponse<DObject>(object))) {
|
||||||
|
// make a note of this new subscription
|
||||||
|
mapSubscrip(object);
|
||||||
|
} else {
|
||||||
|
// if we failed to send the object response, unsubscribe
|
||||||
|
object.removeSubscriber(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// documentation inherited from interface
|
||||||
|
public void requestFailed (int oid, ObjectAccessException cause)
|
||||||
|
{
|
||||||
|
postMessage(new FailureResponse(oid));
|
||||||
|
}
|
||||||
|
|
||||||
|
// documentation inherited from interface
|
||||||
|
public void eventReceived (DEvent event)
|
||||||
|
{
|
||||||
|
if (event instanceof PresentsDObjectMgr.AccessObjectEvent) {
|
||||||
|
Log.warning("Ignoring event that shouldn't be forwarded " +
|
||||||
|
event + ".");
|
||||||
|
Thread.dumpStack();
|
||||||
|
} else {
|
||||||
|
postMessage(new EventNotification(event));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when {@link #setUsername} has been called and the new client
|
||||||
|
* object is about to be applied to this client. The old client object
|
||||||
|
* will not yet have been destroyed, so any final events can be sent
|
||||||
|
* along prior to the new object being put into effect.
|
||||||
|
*/
|
||||||
|
protected void clientObjectWillChange (
|
||||||
|
ClientObject oldClobj, ClientObject newClobj)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called after the new client object has been committed to this
|
||||||
|
* client due to a call to {@link #setUsername}.
|
||||||
|
*/
|
||||||
|
protected void clientObjectDidChange (ClientObject newClobj)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes this client instance with the specified username, connection
|
||||||
|
* instance and client object and begins a client session.
|
||||||
|
*/
|
||||||
|
protected void startSession (
|
||||||
|
ClientManager cmgr, AuthRequest req, Connection conn, Object authdata)
|
||||||
|
{
|
||||||
|
_cmgr = cmgr;
|
||||||
|
_areq = req;
|
||||||
|
_authdata = authdata;
|
||||||
|
setConnection(conn);
|
||||||
|
|
||||||
|
// obtain our starting username
|
||||||
|
assignStartingUsername();
|
||||||
|
|
||||||
|
// resolve our client object before we get fully underway
|
||||||
|
cmgr.resolveClientObject(_username, this);
|
||||||
|
|
||||||
|
// make a note of our session start time
|
||||||
|
_sessionStamp = System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is factored out to allow derived classes to use a different
|
||||||
|
* starting username than the one supplied in the user's credentials.
|
||||||
|
* Generally one only wants to munge the starting username if the user
|
||||||
|
* will subsequently choose a "screen name" and it is desirable to
|
||||||
|
* avoid collision between the authentication user namespace and the
|
||||||
|
* screen namespace.
|
||||||
|
*/
|
||||||
|
protected void assignStartingUsername ()
|
||||||
|
{
|
||||||
|
_username = getCredentials().getUsername();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called by the client manager when a new connection arrives that
|
* Called by the client manager when a new connection arrives that
|
||||||
* authenticates as this already established client. This must only be
|
* authenticates as this already established client. This must only be
|
||||||
@@ -418,46 +577,6 @@ public class PresentsClient
|
|||||||
Log.info("Session resumed " + this + ".");
|
Log.info("Session resumed " + this + ".");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Forcibly terminates a client's session. This must be called from
|
|
||||||
* the dobjmgr thread.
|
|
||||||
*/
|
|
||||||
public void endSession ()
|
|
||||||
{
|
|
||||||
// queue up a request for our connection to be closed (if we have
|
|
||||||
// a connection, that is)
|
|
||||||
Connection conn = getConnection();
|
|
||||||
if (conn != null) {
|
|
||||||
// go ahead and clear out our connection now to prevent
|
|
||||||
// funniness
|
|
||||||
setConnection(null);
|
|
||||||
// have the connection manager close our connection when it is
|
|
||||||
// next convenient
|
|
||||||
PresentsServer.conmgr.closeConnection(conn);
|
|
||||||
}
|
|
||||||
|
|
||||||
// if we don't have a client object, we failed to resolve in the
|
|
||||||
// first place, in which case we have to cope as best we can
|
|
||||||
if (_clobj != null) {
|
|
||||||
// and clean up after ourselves
|
|
||||||
try {
|
|
||||||
sessionDidEnd();
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.warning("Choked in sessionDidEnd [client=" + this + "].");
|
|
||||||
Log.logStackTrace(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
// release (and destroy) our client object
|
|
||||||
_cmgr.releaseClientObject(_username);
|
|
||||||
}
|
|
||||||
|
|
||||||
// let the client manager know that we're audi 5000
|
|
||||||
_cmgr.clientSessionDidEnd(this);
|
|
||||||
|
|
||||||
// clear out the client object so that we know the session is over
|
|
||||||
_clobj = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Queues up a runnable on the object manager thread where we can
|
* Queues up a runnable on the object manager thread where we can
|
||||||
* safely end the session.
|
* safely end the session.
|
||||||
@@ -479,52 +598,6 @@ public class PresentsClient
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* This is called when the server is shut down in the middle of a
|
|
||||||
* client session. In this circumstance, {@link #endSession} will
|
|
||||||
* <em>not</em> be called and so any persistent data that might
|
|
||||||
* normally be flushed at the end of a client's session should likely
|
|
||||||
* be flushed here.
|
|
||||||
*/
|
|
||||||
public void shutdown ()
|
|
||||||
{
|
|
||||||
// if the client is connected, we need to fake the computation of
|
|
||||||
// their final connect time because we won't be closing their
|
|
||||||
// socket normally
|
|
||||||
if (getConnection() != null) {
|
|
||||||
long now = System.currentTimeMillis();
|
|
||||||
_connectTime += ((now - _networkStamp) / 1000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Makes a note that this client is subscribed to this object so that
|
|
||||||
* we can clean up after ourselves if and when the client goes
|
|
||||||
* away. This is called by the client internals and needn't be called
|
|
||||||
* by code outside the client.
|
|
||||||
*/
|
|
||||||
public synchronized void mapSubscrip (DObject object)
|
|
||||||
{
|
|
||||||
_subscrips.put(object.getOid(), object);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Makes a note that this client is no longer subscribed to this
|
|
||||||
* object. The subscription map is used to clean up after the client
|
|
||||||
* when it goes away. This is called by the client internals and
|
|
||||||
* needn't be called by code outside the client.
|
|
||||||
*/
|
|
||||||
public synchronized void unmapSubscrip (int oid)
|
|
||||||
{
|
|
||||||
DObject object = _subscrips.remove(oid);
|
|
||||||
if (object != null) {
|
|
||||||
object.removeSubscriber(this);
|
|
||||||
} else {
|
|
||||||
Log.warning("Requested to unmap non-existent subscription " +
|
|
||||||
"[oid=" + oid + "].");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clears out the tracked client subscriptions. Called when the client
|
* Clears out the tracked client subscriptions. Called when the client
|
||||||
* goes away and shouldn't be called otherwise.
|
* goes away and shouldn't be called otherwise.
|
||||||
@@ -731,69 +804,6 @@ public class PresentsClient
|
|||||||
return _conn;
|
return _conn;
|
||||||
}
|
}
|
||||||
|
|
||||||
// documentation inherited from interface
|
|
||||||
public void handleMessage (UpstreamMessage message)
|
|
||||||
{
|
|
||||||
_messagesIn++; // count 'em up!
|
|
||||||
|
|
||||||
// if the client has been getting crazy with the cheeze whiz,
|
|
||||||
// stick a fork in them; the first time through we end our
|
|
||||||
// session, subsequently _throttle is null and we just drop any
|
|
||||||
// messages that come in until we've fully shutdown
|
|
||||||
if (_throttle == null) {
|
|
||||||
// Log.info("Dropping message from force-quit client " +
|
|
||||||
// "[conn=" + _conn +
|
|
||||||
// ", msg=" + message + "].");
|
|
||||||
return;
|
|
||||||
} else if (_throttle.throttleOp(message.received)) {
|
|
||||||
Log.warning("Client sent more than 100 messages in 10 seconds, " +
|
|
||||||
"forcing disconnect " + this + ".");
|
|
||||||
safeEndSession();
|
|
||||||
_throttle = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// we dispatch to a message dispatcher that is specialized for the
|
|
||||||
// particular class of message that we received
|
|
||||||
MessageDispatcher disp = _disps.get(message.getClass());
|
|
||||||
if (disp == null) {
|
|
||||||
Log.warning("No dispatcher for message [msg=" + message + "].");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// otherwise pass the message on to the dispatcher
|
|
||||||
disp.dispatch(this, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
// documentation inherited from interface
|
|
||||||
public void objectAvailable (DObject object)
|
|
||||||
{
|
|
||||||
if (postMessage(new ObjectResponse<DObject>(object))) {
|
|
||||||
// make a note of this new subscription
|
|
||||||
mapSubscrip(object);
|
|
||||||
} else {
|
|
||||||
// if we failed to send the object response, unsubscribe
|
|
||||||
object.removeSubscriber(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// documentation inherited from interface
|
|
||||||
public void requestFailed (int oid, ObjectAccessException cause)
|
|
||||||
{
|
|
||||||
postMessage(new FailureResponse(oid));
|
|
||||||
}
|
|
||||||
|
|
||||||
// documentation inherited from interface
|
|
||||||
public void eventReceived (DEvent event)
|
|
||||||
{
|
|
||||||
if (event instanceof PresentsDObjectMgr.AccessObjectEvent) {
|
|
||||||
Log.warning("Ignoring event that shouldn't be forwarded " +
|
|
||||||
event + ".");
|
|
||||||
Thread.dumpStack();
|
|
||||||
} else {
|
|
||||||
postMessage(new EventNotification(event));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Callable from non-dobjmgr thread, this queues up a runnable on the
|
/** Callable from non-dobjmgr thread, this queues up a runnable on the
|
||||||
* dobjmgr thread to post the supplied message to this client. */
|
* dobjmgr thread to post the supplied message to this client. */
|
||||||
protected final void safePostMessage (final DownstreamMessage msg)
|
protected final void safePostMessage (final DownstreamMessage msg)
|
||||||
@@ -954,7 +964,7 @@ public class PresentsClient
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected ClientManager _cmgr;
|
protected ClientManager _cmgr;
|
||||||
protected Credentials _creds;
|
protected AuthRequest _areq;
|
||||||
protected Object _authdata;
|
protected Object _authdata;
|
||||||
protected Name _username;
|
protected Name _username;
|
||||||
protected Connection _conn;
|
protected Connection _conn;
|
||||||
|
|||||||
Reference in New Issue
Block a user