Click here to Skip to main content
Click here to Skip to main content
Articles » Languages » C# » General » Downloads
 
Add your own
alternative version

SIP Stack with SIP Proxy - (VOIP)

, 11 Jun 2007 CPOL
C# implementation of SIP
SIP_Proxy_demo.zip
SIP_Proxy_demo
SIP_Proxy_demo.suo
SIP_Proxy_demo
bin
Debug
LumiSoft.Net.dll
SIP_Proxy_demo.exe
SIP_Proxy_demo.vshost.exe
dep
LumiSoft.Net.dll
LumiSoft.Net.pdb
Properties
Settings.settings
Resources
add.ico
app.ico
delete.ico
edit.ico
error.ico
info.ico
refresh.ico
rule.ico
server_running.ico
server_stopped.ico
viewmessages.ico
Stack.zip
Net
docs
dns
dns_records.jpg
dns_records.vsd
Net
_junk
_Obsolete
AUTH
bin
Release
LumiSoft.Net.dll
Data
Dns
Client
FTP
Client
Server
HTTP
Server
ICMP
IMAP
Client
Server
IO
Log
LumiSoft.Net
Mime
vCard
Net.csproj.user
Net.suo
NNTP
Client
POP3
Client
Server
RTP
SDP
ServersCore
SIP
Client
Message
Proxy
Stack
SMTP
Client
Server
STUN
Client
Message
URI
using System;
using System.IO;
using System.Collections.Generic;
using System.Text;

using LumiSoft.Net;

namespace LumiSoft.Data.lsDB
{
    /// <summary>
    /// Table what all columns are with fixed length.
    /// </summary>
    public class lsDB_FixedLengthTable : IDisposable
    {
        private LDB_DataColumnCollection m_pColumns           = null;
		private FileStream               m_pDbFile            = null;
		private string                   m_DbFileName         = "";
		private bool                     m_TableLocked        = false;
        private long                     m_RowsStartOffset    = -1;
        private long                     m_ColumnsStartOffset = -1;
        private int                      m_RowLength          = -1;
        private byte[]                   m_RowDataBuffer      = null;
        private lsDB_FixedLengthRecord   m_pCurrentRecord     = null;
        private long                     m_FileLength         = 0;
		private long                     m_FilePosition       = 0;

        /// <summary>
        /// Default constructor.
        /// </summary>
        public lsDB_FixedLengthTable()
        {
            m_pColumns = new LDB_DataColumnCollection(this);
        }

		#region method Dispose

		/// <summary>
		/// Clean up any resources being used.
		/// </summary>
		public void Dispose()
		{
			Close();
		}

		#endregion


        #region method Open

         /// <summary>
		/// Opens specified data file.
		/// </summary>
		/// <param name="fileName">File name.</param>
        public void Open(string fileName)
        {
            Open(fileName,0);
        }

        /// <summary>
		/// Opens specified data file.
		/// </summary>
		/// <param name="fileName">File name.</param>
		/// <param name="waitTime">If data base file is exclusively locked, then how many seconds to wait file to unlock before raising a error.</param>
		public void Open(string fileName,int waitTime)
		{            
			DateTime lockExpireTime = DateTime.Now.AddSeconds(waitTime);
			while(true){
				try{
					m_pDbFile = File.Open(fileName,FileMode.Open,FileAccess.ReadWrite,FileShare.ReadWrite);

					break;
				}
				catch(IOException x){
                    if(!File.Exists(fileName)){
                        throw new Exception("Specified database file '" + fileName + "' does not exists !");
                    }

					// Make this because to get rid of "The variable 'x' is declared but never used"
					string dummy = x.Message;

					System.Threading.Thread.Sleep(15);

					// Lock wait time timed out
                    if(DateTime.Now > lockExpireTime){
						throw new Exception("Database file is locked and lock wait time expired !");
					}
				}
			}

			/* Table structure:
				50    bytes         - version
				2     bytes         - CRLF
                4     bytes         - Free rows count
                2     bytes         - CRLF
				100 x 500 bytes     - 100 columns info store
				2     bytes         - CRLF
				... data pages
			*/

			m_DbFileName = fileName;

			// TODO: check if LDB file

			// Read version line (50 bytes + CRLF)	
			byte[] version = new byte[52];
            ReadFromFile(0,version,0,version.Length);

            // Read free rows count
            byte[] freeRows = new byte[6];
            ReadFromFile(0,freeRows,0,freeRows.Length);

            long currentColumnOffset = 58;
			// Read 100 column lines (500 + CRLF bytes each)
			for(int i=0;i<100;i++){
				byte[] columnInfo = new byte[102];                
				if(ReadFromFile(currentColumnOffset,columnInfo,0,columnInfo.Length) != columnInfo.Length){
					throw new Exception("Invalid columns data area length !");
				}

				if(columnInfo[0] != '\0'){					
					m_pColumns.Parse(columnInfo);
				}

                currentColumnOffset += 102;
			}

			// Header terminator \0
			m_pDbFile.Position++;
	
			// No we have rows start offset
			m_RowsStartOffset = m_pDbFile.Position;

			// Store file length and position
			m_FileLength = m_pDbFile.Length;
			m_FilePosition = m_pDbFile.Position;

            // Calculate row length
            m_RowLength = 1 + 2;
            for(int i = 0;i < m_pColumns.Count;i++){
                m_RowLength += m_pColumns[i].ColumnSize;
            }

            m_RowDataBuffer = new byte[m_RowLength];
		}

		#endregion

        #region method Close

		/// <summary>
		/// Closes database file.
		/// </summary>
		public void Close()
		{
			if(m_pDbFile != null){
				m_pDbFile.Close();
				m_pDbFile = null;
				m_DbFileName = "";
				m_FileLength = 0;
				m_FilePosition = 0;
                m_RowLength = 0;
                m_ColumnsStartOffset = 0;
                m_RowsStartOffset = 0;
                m_TableLocked = false;
                m_RowDataBuffer = null;
                m_pCurrentRecord = null;
			}
		}

		#endregion

        #region method Create

        /// <summary>
		/// Creates new database file.
		/// </summary>
		/// <param name="fileName">File name.</param>
        public void Create(string fileName)
        {
            m_pDbFile = new FileStream(fileName,FileMode.CreateNew,FileAccess.ReadWrite,FileShare.None);

			/* Table structure:
				50    bytes         - version
				2     bytes         - CRLF
                4     bytes         - Free rows count
                2     bytes         - CRLF
				100 x 500 bytes     - 100 columns info store
				2     bytes         - CRLF
				... data pages
			*/

			// Version 50 + CRLF bytes
			byte[] versionData = new byte[52];
			versionData[0] = (byte)'1';
			versionData[1] = (byte)'.';
			versionData[2] = (byte)'0';
			versionData[50] = (byte)'\r';
			versionData[51] = (byte)'\n';
			m_pDbFile.Write(versionData,0,versionData.Length);

            // Free rows count
            byte[] freeRows = new byte[6];
            freeRows[4] = (byte)'\r';
            freeRows[5] = (byte)'\n';
            m_pDbFile.Write(freeRows,0,freeRows.Length);

            m_ColumnsStartOffset = m_pDbFile.Position;

			// 100 x 100 + CRLF bytes header lines
			for(int i=0;i<100;i++){
				byte[] data = new byte[100];
				m_pDbFile.Write(data,0,data.Length);
				m_pDbFile.Write(new byte[]{(int)'\r',(int)'\n'},0,2);
			}

			// Headers terminator char(0)
			m_pDbFile.WriteByte((int)'\0');

			// Rows start pointer
			m_RowsStartOffset = m_pDbFile.Position - 1;

			m_DbFileName = fileName;

			// Store file length and position
			m_FileLength = m_pDbFile.Length;
			m_FilePosition = m_pDbFile.Position;
          
            // Calculate row length
            m_RowLength = 1 + 2;
            for(int i = 0;i < m_pColumns.Count;i++){
                m_RowLength += m_pColumns[i].ColumnSize;
            }

            m_RowDataBuffer = new byte[m_RowLength];
        }

        #endregion


        #region method LockTable
		
		/// <summary>
		/// Locks table.
		/// </summary>
		/// <param name="waitTime">If table is locked, then how many sconds to wait table to unlock, before teturning error.</param>
		public void LockTable(int waitTime)
		{
			if(!this.IsDatabaseOpen){
				throw new Exception("Database isn't open, please open database first !");
			}
			// Table is locked already, just skip locking
			if(m_TableLocked){
				return;
			}

			DateTime lockExpireTime = DateTime.Now.AddSeconds(waitTime);
			while(true){
				try{
					// We just lock first byte
					m_pDbFile.Lock(0,1);
					m_TableLocked = true;

					break;
				}
				// Catch the IOException generated if the 
				// specified part of the file is locked.
				catch(IOException x){
					// Make this because to get rid of "The variable 'x' is declared but never used"
					string dummy = x.Message;

					System.Threading.Thread.Sleep(15);

					// Lock wait time timed out
                    if(DateTime.Now > lockExpireTime){
						throw new Exception("Table is locked and lock wait time expired !");
					}
				}
			}
		}

		#endregion

		#region method UnlockTable

		/// <summary>
		/// Unlock table.
		/// </summary>
		public void UnlockTable()
		{
			if(!this.IsDatabaseOpen){
				throw new Exception("Database isn't open, please open database first !");
			}

			if(m_TableLocked){
				// We just unlock first byte
				m_pDbFile.Unlock(0,1);
			}
		}

		#endregion


        #region method MoveFirstRecord

        /// <summary>
        /// Moves to first record.
        /// </summary>
        public void MoveFirstRecord()
        {
            m_pCurrentRecord = null;
        //    NextRecord();
        }

        #endregion

        #region method NextRecord

        /// <summary>
		/// Gets next record. Returns true if end of file reached and there are no more records.
		/// </summary>
		/// <returns>Returns true if end of file reached and there are no more records.</returns>
		public bool NextRecord()
		{
			if(!this.IsDatabaseOpen){
				throw new Exception("Database isn't open, please open database first !");
			}
                        
			//--- Find next record ---------------------------------------------------//
			long nextRowStartOffset = 0;
			if(m_pCurrentRecord == null){
				nextRowStartOffset = m_RowsStartOffset;
			}
			else{                
                nextRowStartOffset = m_pCurrentRecord.Pointer + m_RowLength;                
			}

			while(true){
				if(m_FileLength > nextRowStartOffset){
                    ReadFromFile(nextRowStartOffset,m_RowDataBuffer,0,m_RowLength);

                    // We want used row
                    if(m_RowDataBuffer[0] == 'u'){
                        if(m_pCurrentRecord == null){
                            m_pCurrentRecord = new lsDB_FixedLengthRecord(this,nextRowStartOffset,m_RowDataBuffer);
                        }
                        else{
                            m_pCurrentRecord.ReuseRecord(this,nextRowStartOffset,m_RowDataBuffer);
                        }
                        break;
                    }
				}
				else{
					return true;
				}
				
				nextRowStartOffset += m_RowLength;
			}
			//-------------------------------------------------------------------------//
			
			return false;
		}

		#endregion


        #region method AppendRecord

		/// <summary>
		/// Appends new record to table.
		/// </summary>
		public void AppendRecord(object[] values)
		{
			if(!this.IsDatabaseOpen){
				throw new Exception("Database isn't open, please open database first !");
			}
			if(m_pColumns.Count != values.Length){
				throw new Exception("Each column must have corresponding value !");
			}

			bool unlock = true;
			// Table is already locked, don't lock it
			if(this.TableLocked){
				unlock = false;
			}
			else{
				LockTable(15);
			}

            /* Fixed record structure:
                1 byte     - specified is row is used or free space
                             u - used
                             f - free space
                x bytes    - columns data
                2 bytes    - CRLF
            */

            int rowLength = 1 + 2;
            for(int i = 0;i < m_pColumns.Count;i++){
                rowLength += m_pColumns[i].ColumnSize;
            }

            int position = 1;
            byte[] record = new byte[rowLength];
            record[0] = (int)'u';
            record[rowLength - 2] = (int)'\r';
            record[rowLength - 1] = (int)'\n';
            for(int i = 0;i < values.Length;i++){
                byte[] columnData = LDB_Record.ConvertToInternalData(m_pColumns[i],values[i]);
                // Check that column won't exceed maximum length.
                if(columnData.Length > m_pColumns[i].ColumnSize){
                    throw new Exception("Column '" + m_pColumns[i] + "' exceeds maximum value length !");
                }

                Array.Copy(columnData,0,record,position,columnData.Length);
                position += columnData.Length; 
            }

            // Find free row
            byte[] freeRowsBuffer = new byte[4];
            ReadFromFile(52,freeRowsBuffer,0,freeRowsBuffer.Length);
            int freeRows = ldb_Utils.ByteToInt(freeRowsBuffer,0);
            // There are plenty free rows, find first
            
            if(freeRows > 100){
                //--- Find free record ---------------------------------------------------//
			    long nextRowStartOffset = m_RowsStartOffset;
                long rowOffset = 0;

                byte[] rowData = new byte[m_RowLength];
	    		while(true){
                    ReadFromFile(nextRowStartOffset,rowData,0,m_RowLength);

                    // We want used row
                    if(rowData[0] == 'f'){
                        rowOffset = nextRowStartOffset;
                        break;
                    }
				
				    nextRowStartOffset += m_RowLength;
			    }
			    //-------------------------------------------------------------------------//

                // Write new record to file
                WriteToFile(rowOffset,record,0,record.Length);

                // Update free rows count
                WriteToFile(52,ldb_Utils.IntToByte(freeRows - 1),0,4);
            }
            // There are few empty rows, just append it
            else{
                AppendToFile(record,0,record.Length);
            }

			if(unlock){
				UnlockTable();
			}
		}
	
		#endregion

        #region method DeleteRecord

		/// <summary>
		/// Deletes current record.
		/// </summary>
        public void DeleteCurrentRecord()
        {
            if(!this.IsDatabaseOpen){
				throw new Exception("Database isn't open, please open database first !");
			}
			if(m_pCurrentRecord == null){
				throw new Exception("There is no current record !");
			}

			bool unlock = true;
			// Table is already locked, don't lock it
			if(this.TableLocked){
				unlock = false;
			}
			else{
				LockTable(15);
			}
                        
            byte[] data = new byte[m_RowLength];
            data[0] = (byte)'f';
            data[m_RowLength - 2] = (byte)'\r';
            data[m_RowLength - 1] = (byte)'\n';
            WriteToFile(m_pCurrentRecord.Pointer,data,0,data.Length);

            // Update free rows count
            byte[] freeRowsBuffer = new byte[4];
            ReadFromFile(52,freeRowsBuffer,0,freeRowsBuffer.Length);
            int freeRows = ldb_Utils.ByteToInt(freeRowsBuffer,0);
            WriteToFile(52,ldb_Utils.IntToByte(freeRows + 1),0,4);

            if(unlock){
				UnlockTable();
			}

			// Activate next record **** Change it ???
			NextRecord();
        }

        #endregion


        #region method AddColumn

        /// <summary>
		/// Adds column to db file.
		/// </summary>
		/// <param name="column"></param>
		internal void AddColumn(LDB_DataColumn column)
		{
            if(column.ColumnSize < 1){
                throw new Exception("Invalid column size '" + column.ColumnSize + "' for column '" + column.ColumnName + "' !");
            }

			// Find free column data area

            long currentColumnOffset = m_ColumnsStartOffset;
			long freeColumnPosition = -1;
			// Loop all columns data areas, see it there any free left
			for(int i=0;i<100;i++){
                byte[] columnInfo = new byte[102];                
				if(ReadFromFile(currentColumnOffset,columnInfo,0,columnInfo.Length) != columnInfo.Length){
					throw new Exception("Invalid columns data area length !");
				}

				// We found unused column data area
				if(columnInfo[0] == '\0'){
					freeColumnPosition = currentColumnOffset - 102;
					break;
				}

                currentColumnOffset += 102;
			}

			if(freeColumnPosition != -1){
				// TODO: If there is data ???

				// Store column
				byte[] columnData = column.ToColumnInfo();
				WriteToFile(currentColumnOffset,columnData,0,columnData.Length);
			}
			else{
				throw new Exception("Couldn't find free column space ! ");
			}
		}

		#endregion

		#region method RemoveColumn

		/// <summary>
		/// Removes specified column from database file.
		/// </summary>
		/// <param name="column"></param>
		internal void RemoveColumn(LDB_DataColumn column)
		{
			throw new Exception("TODO:");
		}

		#endregion


        #region method ReadFromFile

		/// <summary>
		/// Reads data from file.
		/// </summary>
        /// <param name="readOffset">Offset in database file from where to start reading data.</param>
		/// <param name="data">Buffer where to store readed data.</param>
		/// <param name="offset">Offset in array to where to start storing readed data.</param>
		/// <param name="count">Number of bytes to read.</param>
		/// <returns></returns>
		internal int ReadFromFile(long readOffset,byte[] data,int offset,int count)
		{
            SetFilePosition(readOffset);

			int readed = m_pDbFile.Read(data,offset,count);
			m_FilePosition += readed;

			return readed;
		}

		#endregion

		#region method WriteToFile

		/// <summary>
		/// Writes data to file.
		/// </summary>
        /// <param name="writeOffset">Offset in database file from where to start writing data.</param>
		/// <param name="data">Data to write.</param>
		/// <param name="offset">Offset in array from where to start writing data.</param>
		/// <param name="count">Number of bytes to write.</param>
		/// <returns></returns>
		internal void WriteToFile(long writeOffset,byte[] data,int offset,int count)
		{
            SetFilePosition(writeOffset);

			m_pDbFile.Write(data,offset,count);
			m_FilePosition += count;
		}

		#endregion

        #region method AppendToFile

        /// <summary>
        /// Appends specified data at the end of file.
        /// </summary>
        /// <param name="data">Data to write.</param>
        /// <param name="offset">Offset in array from where to start writing data.</param>
        /// <param name="count">Number of bytes to write.</param>
        internal void AppendToFile(byte[] data,int offset,int count)
        {
            m_pDbFile.Position = m_pDbFile.Length;

            m_pDbFile.Write(data,offset,count);

			m_FileLength = m_pDbFile.Length;
			m_FilePosition = m_pDbFile.Position;
        }

        #endregion

        #region method GetFilePosition

        /// <summary>
		/// Gets current position in file.
		/// </summary>
		/// <returns></returns>
		internal long GetFilePosition()
		{
			return m_FilePosition;
		}

		#endregion

		#region method SetFilePosition

		/// <summary>
		/// Sets file position.
		/// </summary>
		/// <param name="position">Position in file.</param>
		private void SetFilePosition(long position)
		{
			if(m_FilePosition != position){
				m_pDbFile.Position = position;
				m_FilePosition = position;
			}
		}

		#endregion
// REMOVE ME:
		#region method GoToFileEnd
/*
		/// <summary>
		/// Moves position to the end of file.
		/// </summary>
		private void GoToFileEnd()
		{
			m_pDbFile.Position = m_pDbFile.Length;
			m_FileLength = m_pDbFile.Length;
			m_FilePosition = m_FileLength;
		}
*/
		#endregion


        #region Properties Implementation

		/// <summary>
		/// Gets if there is active database file.
		/// </summary>
		public bool IsDatabaseOpen
		{
			get{ return m_pDbFile != null; }
		}

		/// <summary>
		/// Gets open database file name. Throws exception if database isn't open.
		/// </summary>
		public string FileName
		{
			get{
				if(!this.IsDatabaseOpen){
					throw new Exception("Database isn't open, please open database first !");
				}

				return m_DbFileName; 
			}
		}

		/// <summary>
		/// Gets table columns. Throws exception if database isn't open.
		/// </summary>
		public LDB_DataColumnCollection Columns
		{
			get{ 
				if(!this.IsDatabaseOpen){
					throw new Exception("Database isn't open, please open database first !");
				}

				return m_pColumns; 
			}
		}

		/// <summary>
		/// Gets current record. Returns null if there isn't current record.
		/// </summary>
		public lsDB_FixedLengthRecord CurrentRecord
		{
			get{ return m_pCurrentRecord; }
		}

		/// <summary>
		/// Gets table is locked.
		/// </summary>
		public bool TableLocked
		{
			get{ return m_TableLocked; }
		}

		#endregion
        
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Ivar Lumi

Estonia Estonia
No Biography provided

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.141223.1 | Last Updated 11 Jun 2007
Article Copyright 2007 by Ivar Lumi
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid