Use BITS for files transfer job

Overview of Background Intelligent Transfer Service (BITS)

Background Intelligent Transfer Service (BITS) transfers files (downloads or uploads) between a client and server and provides progress information related to the transfers. The ‘Automatic update’ feature in Windows operating system (versions XP, 2003 server, 2000 SP3) works under this BITS concept and infrastructure.

Use BITS for applications that need to:

Asynchronously transfer files in the foreground or background.

Preserve the responsiveness of other network applications.

Automatically resume file transfers after network disconnects and computer restarts.

 

As a part of Maintainability & Supportability features in my product, I need to ship client’s log files to the server over internet. I used BITS to perform this task.

Using BITS for uploading log files

Step 1: Collect all log files and Prepare single upload file

Use Cabinet APIs – FCI APIs for creating single compressed file for upload. Cabinet.dll contains these APIs which are available on the windows OS since NT/98.

Step 2: Get BITS Server information

Get the BITS server path for uploading log files. This server url can be saved in a config file of the application.

Step 3: Upload the file using BITS

Perform following to send the file to server using BITS

Connect to the BITS service.

Create a transfer upload job.

Add file to the job.

Start the job.

Determine if BITS successfully transferred the files.

Complete the job.

Point to note when using BITS

The user whose currently logged on to the system and created the BITS job is the owner of the job. User login context is very dependent factor. If user logs off / switches user (fast user switching feature in Vista), BITS will not proceed transferring the file and only resume when the same user (who is owner of the job) re-logins again the system.

If your transfer job is not depended on user context at all, then create a new windows service and run it on Local System / Local Service / Network Service account. As these are system accounts and are always logged on, this approach should be best suited when end-user dependency is not required for transfer job.

 

Setting up a BITS server - Following are the server requirements to enable BITS upload:

Requires IIS 6.0 on Windows Server 2003 - On Windows Server 2003, use the Windows Components Wizard to install the BITS server extension. From Control Panel, select Add or Remove Programs. Then, select Add/Remove Windows Components to display the Windows Components Wizard. The BITS server extension is a subcomponent of Internet Information Services (IIS) which is a sub-component of Application Server.

Creating virtual directory and mapping physical directory

Open IIS console by typing ‘inetmgr’ in Run command. Right click Default website and select New >> virtual directory. Give a virtual directory name and map it to a physical path. Once virtual directory is created under default website, right click the newly created virtual directory and select properties. Under BITS extension tab, check the Allow clients to transfer data to this virtual directory check box. To alter default settings (like control maximum size of file being transferred etc.) select Customize settings radio button.

The above process of creating and configuring virtual directory can be automated by simple script.

// upload virtual directory name

var UPLOAD_VIRTUAL_DIRECTORY = "UploadLogs"

// name of the server that we will be uploading to

var UPLOAD_SERVER = "localhost"

// physical path of the virtual directory - argument to the script

var LocalDirectoryName = null

var FSO = new ActiveXObject("Scripting.FileSystemObject")

var WSH = new ActiveXObject("WScript.Shell")

//----------------------------------------------------------------------------

// MAIN EXECUTION

//----------------------------------------------------------------------------

if (WScript.Arguments.length < 1)

{

    Usage()

    WScript.Quit(1)

}

LocalDirectoryName = WScript.Arguments(0)

/*

 * Perform input parameter validation and check for dependent components

 */

 

Msg("\n---------- Verifying parameter and dependent components")

ValidateUserInput()

VerifyIISInstalled()

VerifyBITSExtensionsInstalled()

/*

 * Create IIS Virtual directory

 */

 

Msg("\n---------- Creating IIS virtual directory")

CreateLocalDirs(LocalDirectoryName)

var uploadVdir = CreateVirtualDirectory(UPLOAD_VIRTUAL_DIRECTORY, LocalDirectoryName)

/*

 * Configure Virtual directory to enable BITS upload

 */

 

Msg("\n---------- Configuring virtual directories for upload")

ConfigureUploadVdir(uploadVdir)

Msg("\n---------- DONE!")

WScript.Quit(0)

//----------------------------------------------------------------------------

// Auxiliary functions

//----------------------------------------------------------------------------

function Usage()

{

          WScript.Echo(

          "\n==========================================================\n" +

          " BITS UPLOAD CONFIGURATION SCRIPT \n" +

          "==========================================================\n\n" +

          "This script will assist you in configuring your IIS server for the BITS upload. \n\n" +

          "Usage:\n " + WScript.ScriptName + " <local_path>\n" +

          "where:\n <local_path> is the directory of the local machine where your upload files will be transferred. \n" +

          " The directory will be created by the script and cannot exist already.\n" )

         

}

function FatalError(msg, err)

{

          WScript.Echo("ERROR: " + msg)

          if (err)

          {

                   WScript.Echo("The error message returned by the system is: " + err.description + " (" + err.number + ")")

          }

          WScript.Quit(1)

}

function Msg(msg)

{

          WScript.Echo(msg)

}

//----------------------------------------------------------------------------

// Scripts methods to create virtual dir, local path, configure virtual dir

//----------------------------------------------------------------------------

function ValidateUserInput()

{

          if (FSO.FolderExists(LocalDirectoryName))

          {

                   FatalError("The directory " + LocalDirectoryName + " already exists. Please provide a new path as a parameter to the script.")

          }

}

function VerifyIISInstalled()

{

          Msg("Verifying that IIS is installed on this machine...")

          // if this call fails an exception is going to be thrown

          try

          {

                   var oIIS = GetObject("IIS://" + UPLOAD_SERVER + "/W3SVC/1/ROOT")

          }

          catch (err)

          {

                   FatalError("This script could not verify that IIS is installed. Please verify your installation and try again.", err)

          }

}

function VerifyBITSExtensionsInstalled()

{

          Msg("Verifying that BITS Extensions is installed on this machine...")

          try

          {

                   var oWWWRoot = GetObject("IIS://" + UPLOAD_SERVER + "/W3SVC/1/ROOT")

                   var test = oWWWRoot.BITSUploadEnabled

          }

          catch (err)

          {

                   FatalError("This script could not verify that BITS Extensions are installed. BITS Extensions can be installed\n" +

                                      "on Windows Server 2003 by using Control Panel's Add/Remove Windows Components.", err)

          }

}

function CreateDirectory(path)

{

          try

          {

                   Msg("Creating the local directory " + path + ".")

                   FSO.CreateFolder(path)

          }

          catch (err)

          {

                   FatalError("The directory " + path + " cannot be created.", err)

          }

}

function CreateLocalDirs(rootpath)

{

          CreateDirectory(rootpath)

          CreateDirectory(rootpath + "\\" + UPLOAD_VIRTUAL_DIRECTORY)

}

function CreateVirtualDirectory(name, physicalpath)

{

    Msg("Creating the virtual directory '" + name + "'.")

          var oWWWRoot = GetObject("IIS://" + UPLOAD_SERVER + "/W3SVC/1/ROOT")

          // test if the vdir already exists

          try

          {

                   var test = GetObject("IIS://" + UPLOAD_SERVER + "/W3SVC/1/ROOT/" + name)

                   FatalError("The virtual directory named " + name + " already exists. \n" +

                                      "Please delete it before using this script.")

          }

          catch (err)

          {

                   // Will reach catch block if the virtual directory donot already exist in IIS

                   // this is a valid case

                   // just continue creating vdir in case of error

          }

          oVdir = oWWWRoot.Create("IIsWebVirtualDir", name)

          oVdir.Path = physicalpath + "\\" + name

          oVdir.AppIsolated = 0

          oVdir.EnableDirBrowsing = false

          oVdir.SetInfo()

          return oVdir

}

function ConfigureUploadVdir(oVdir)

{

          Msg("Enabling BITS uploads on the virtual directory " + oVdir.Name)

          oVdir.AccessScript = false

          oVdir.AccessRead = false

          oVdir.SetInfo()

          oVdir.EnableBITSUploads()

          oVdir.BITSMaximumUploadSize = 104857600

          oVdir.SetInfo()

}

This script will Create, configure virtual directory called ‘UploadLogs’ on the IIS and enable BITS upload. This script will accept the local machine’s folder path as parameter which will be mapped as physical directory of the to-be created virtual directory. The BITS uploaded log files will be copied to this physical path.

Reference:

The zip attachment contains a word document having extensive details on BITS.

Using BITS.zip

Comments