aboutsummaryrefslogtreecommitdiffstats
path: root/libgsm0710mux/gsm0710mux/channel.vala
diff options
context:
space:
mode:
Diffstat (limited to 'libgsm0710mux/gsm0710mux/channel.vala')
-rw-r--r--libgsm0710mux/gsm0710mux/channel.vala216
1 files changed, 216 insertions, 0 deletions
diff --git a/libgsm0710mux/gsm0710mux/channel.vala b/libgsm0710mux/gsm0710mux/channel.vala
new file mode 100644
index 00000000..5c55cdf0
--- /dev/null
+++ b/libgsm0710mux/gsm0710mux/channel.vala
@@ -0,0 +1,216 @@
+/*
+ * This file is part of libgsm0710mux
+ *
+ * (C) 2009-2010 Michael 'Mickey' Lauer <mlauer@vanille-media.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+//===========================================================================
+using GLib;
+using CONST;
+using Gsm0710;
+
+//===========================================================================
+// The Channel class
+//
+internal class Channel
+{
+ public enum Status
+ {
+ Requested, /* requested on 07.10 layer, but not acknowledged by modem */
+ Acked, /* acknowledged by modem, but not opened by any client */
+ Open, /* acknowledged and opened by a client */
+ Denied, /* denied by the modem. this status is persistent */
+ Shutdown, /* shutting down, will no longer be openable */
+ }
+
+ // FIXME: Do we really want to expose the whole multiplexer object to the channel? Consider only using the relevant delegates.
+ Multiplexer _multiplexer;
+ Status _status;
+ FsoFramework.Transport transport;
+ FsoFramework.Logger logger;
+
+ string _name;
+ int _number;
+ int _serial_status;
+
+ SourceFunc ackCallback;
+ uint ackTimeoutWatch;
+
+ public Channel( Multiplexer? multiplexer,
+ Gsm0710mux.ChannelInfo info,
+ SourceFunc? ackCallback = null,
+ uint ackTimeout = 0 )
+ {
+ logger = FsoFramework.Logger.createFromKeyFile( FsoFramework.theConfig, LIBGSM0710MUX_CONFIG_SECTION, LIBGSM0710MUX_LOGGING_DOMAIN );
+ logger.setReprDelegate( repr );
+
+ _multiplexer = multiplexer;
+ _status = Status.Requested;
+ _name = info.consumer;
+ _number = info.number;
+
+ info.tspec.create();
+ transport = info.tspec.transport;
+ transport.setPriorities( TRANSPORT_READ_PRIORITY, TRANSPORT_WRITE_PRIORITY );
+ transport.setDelegates( onRead, onHup );
+ info.tspec.transport = transport;
+ assert( logger.debug( "Constructed" ) );
+
+ if ( ackTimeout > 0 )
+ {
+ ackTimeoutWatch = Timeout.add_seconds( ackTimeout, ackCallback );
+ }
+ this.ackCallback = ackCallback;
+ }
+
+ ~Channel()
+ {
+ assert( logger.debug( "Destructed" ) );
+ }
+
+ public string repr()
+ {
+ return "<%d (%s) connected via %s>".printf( _number, _name, transport != null? transport.getName() : "(none)" );
+ }
+
+ public string acked()
+ {
+ if ( ackTimeoutWatch > 0 )
+ {
+ Source.remove( ackTimeoutWatch );
+ }
+
+ assert( logger.debug( "Acked" ) );
+
+ if ( !transport.open() )
+ {
+ logger.error( "Could not open transport: %s".printf( Posix.strerror( Posix.errno ) ) );
+ return "";
+ }
+
+ _status = Status.Acked;
+
+ if ( ackCallback != null )
+ {
+ assert( logger.debug( "AckCallback is set, calling" ) );
+ ackCallback();
+ }
+ else
+ {
+ assert( logger.debug( "AckCallback NOT set" ) );
+ }
+
+ return transport.getName();
+ }
+
+ public void close()
+ {
+ assert( logger.debug( "Closing" ) );
+ var oldstatus = _status;
+ _status = Status.Shutdown;
+
+ if ( oldstatus != Status.Requested )
+ {
+ if (_multiplexer != null )
+ _multiplexer.channel_closed( _number );
+ }
+
+ if ( transport != null )
+ {
+ transport.close();
+ transport = null;
+ }
+ }
+
+ public string name()
+ {
+ return _name;
+ }
+
+ public string path()
+ {
+ return transport.getName();
+ }
+
+ public bool isAcked()
+ {
+ return _status != Status.Requested;
+ }
+
+ public void setSerialStatus( int newstatus )
+ {
+ assert( logger.debug( "setSerialStatus()" ) );
+
+ var oldstatus = _serial_status;
+ _serial_status = newstatus;
+
+ if ( Gsm0710mux.Manager.leave_fc_alone )
+ {
+ return;
+ }
+
+ // check whether the FC bit has been set
+ if ( ( ( oldstatus & SerialStatus.FC ) == 0 ) &&
+ ( ( newstatus & SerialStatus.FC ) == SerialStatus.FC ) )
+ {
+ logger.warning( "FC has been set. Disabling read from PTY" );
+ transport.freeze();
+ }
+
+ // check whether the FC bit has been cleared
+ if ( ( ( oldstatus & SerialStatus.FC ) == SerialStatus.FC ) &&
+ ( ( newstatus & SerialStatus.FC ) == 0 ) )
+ {
+ logger.warning( "FC has been cleared. Reenabling read from PTY" );
+ transport.thaw();
+ }
+ }
+
+ public void deliverData( void* data, int len )
+ {
+ transport.write( data, len );
+ MainContext.default().iteration( false ); // give other channels a chance (round-robin)
+ }
+
+ //
+ // delegates from Pty object
+ //
+ public void onRead( FsoFramework.Transport transport )
+ {
+ assert( logger.debug( "onRead() from Transport; reading." ) );
+ assert( _multiplexer != null );
+
+ if ( ( _serial_status & SerialStatus.FC ) == SerialStatus.FC )
+ {
+ logger.warning( "FC active... reading anyways..." );
+ }
+
+ var buffer = new char[8192];
+ int bytesread = transport.read( buffer, 8192 );
+ assert( logger.debug( @"Read $bytesread bytes" ) );
+
+ _multiplexer.submit_data( _number, buffer, (int)bytesread );
+ }
+
+ public void onHup( FsoFramework.Transport transport )
+ {
+ assert( logger.debug( "onHup() from Transport; closing." ) );
+ close();
+ }
+
+}