Sun Java System Messaging Server 6 2005Q4 MTA Developer's Reference

Chapter 2 MTA SDK Programming Considerations

This chapter describes procedures and run time instructions useful for programmers using the Sun Java System Messaging Server MTA SDK. It includes the following topics:

Running Your Enqueue and Dequeue Programs

At run time, when your program enqueues a message to, or dequeues a message from the MTA, the SDK must be able to determine the name of the MTA channel under which to perform the enqueue or dequeue. If this name cannot be determined, then the enqueue or dequeue operation will fail. Consequently, when calling mtaEnqueueStart() or mtaDequeueStart(), a channel name can be specified. Whether or not you need to specify this channel name depends upon the conditions under which your program runs. While developing your program and manually running it, you may either code the channel name into your program or specify it through your run time environment with the PMDF_CHANNEL environment variable. For example, to do the latter on UNIX® platforms use a command of the following form:

# PMDF_CHANNEL=channel-name program-name

where channel-name is the name of the channel and program-name is the name of the executable program to run.

In production, if your program will run as a master or slave channel program under the MTA Job Controller, then you do not need to specify the channel name; it will automatically be set by the Job Controller using the PMDF_CHANNEL environment variable. If, however, your program will be run manually or as a server, then either the program can specify its channel name through code or using the PMDF_CHANNEL environment variable. For the latter, setting the environment variable is typically achieved by wrapping your executable program with a shell script. The shell script would set the environment and then invoke your program, as illustrated in the following code example:


#!/bin/sh

PMDF_CHANNEL=channel-name

PMDF_CHANNEL_OPTION=option-file-path

export PMDF_CHANNEL PMDF_CHANNEL_OPTION

program-name

exit

The option-file-path shown in the previous example is the full, absolute path to the channel’s option file, if any.

A program can query the SDK to determine what channel name is being used with either the mtaChannelGetName(), mtaEnqueueInfo(), or mtaDequeueInfo() routines. The former returns the channel name the SDK will use when no other name is explicitly specified through code. The latter two return the name specifically being used with a given enqueue or dequeue context.


Note –

The SDK only reads the PMDF_CHANNEL environment variable once per program invocation. As such, running code cannot expect to change its channel name by changing the value of the environment variable.


Debugging Programs and Logging Diagnostics

The SDK has diagnostic facilities that may help in tracking down unusual behavior. Enable SDK diagnostics in one of two ways: either when the SDK is initialized with mtaInit() or afterwards with mtaDebug(). The following table lists the diagnostics types that may be enabled through either routine:

Diagnostic Type  

Description  

MTA_DEBUG_SDK

Provide diagnostics whenever the SDK returns an error status 

MTA_DEBUG_DEQUEUE

Provide diagnostics from the MTA low-level dequeue library 

MTA_DEBUG_ENQUEUE

Provide diagnostics from the MTA low-level enqueue library 

MTA_DEBUG_OS

Provide diagnostics from the MTA low-level, operating-system dependent library 

All diagnostic output is written to stdout. In the case of a channel program, this is typically the channel’s debug file. Message enqueue and dequeue activities performed through the MTA SDK (and Callable Send facility) will be logged when the channels involved are marked with the logging channel keyword.

Required Privileges

Use of the MTA SDK often requires access rights to the MTA message queues and configuration data. Indeed, were such rights not required, then any user capable of logging in to the operating system of the machine running Messaging Server could read messages out of the MTA message queues and send fraudulent mail messages. Consequently, any programs using the MTA SDK need read access to the MTA configuration, possibly including files with credentials required to bind to either the Job Controller or an LDAP server or both. Additionally, programs that will enqueue messages to the MTA need write access to the MTA message queues. Programs that will dequeue messages from the MTA need read, write, and delete access to the MTA message queues.

To facilitate this access, site-developed programs that will enqueue or dequeue messages should be owned and run by the account used for Messaging Server. The programs do not need to run as a superuser with root access in order to enqueue or dequeue mail to the MTA. However, it is safe to allow them to do so, if needed for concerns outside the scope of Messaging Server. For instance, if the program will be performing other functions requiring system access rights, it needs to run as a superuser with root access.

Compiling and Linking Programs

This section contains information useful for compiling and linking your C programs.

Compiling

To declare the SDK routines, data structures, constant, and error codes, C programs should use the msg_server_base/include/mtasdk.h header file.

Linking Instructions for Solaris

The linking instructions that follow are for the Solaris platform:

The table that follows shows the link command used to link a C program to the SDK:


% SERVER_ROOT=msg_svr_base
% cc -o program program.c \
     -I$SERVER_ROOT/include \
     -L$SERVER_ROOT/lib \
     -lmtasdk

In the example, msg_server_base is the directory path to the top-level Messaging Server directory, and program is the name of your program.

If running the program in a standalone mode, that is, not under the Job Controller, then the CONFIGROOT, INSTANCEDIR, IMTA_TAILOR, and the LD_LIBRARY_PATH environment variables must be defined. See the imsimta shell script used to launch MTA programs and utilities for details.

Running Your Test Programs

This section describes the tasks that are typically required for running your test programs that enqueue or dequeue messages. The tasks are divided into two groups, those used to run your test programs in a fully functional messaging environment, and those needed if you want to run them manually:

ProcedureTo Run Test Programs in a Messaging Environment

Steps
  1. Add a test channel to the bottom of the imta.cnf file.

    For example:


    (required blank line)
    x_test
    x-test-daemon
  2. Add rewrite rules to the top of the imta.cnf file.

    The following code fragment illustrates this:


    x_test $U%x-test@x-test-daemon
  3. To enable your test channel so that mail can be addressed to user@x_test, recompile your configuration and restart the SMTP server.

    Use the instructions found in the following code example:


    # imsimta cnbuild
    # imsimta restart dispatcher
  4. Create the job_controller.site text file.

    The file should be owned by the Messaging Server and reside in the same directory as the job_controller.cnf file. The following code example shows the lines you must add to the file:


    [CHANNEL=x_test]
    master_command=file-path
    

    In the above example, file-path is the full path to your executable program.

  5. Make sure your executable has permissions and ownership such that the Messaging Server can run it.

  6. Restart the Job Controller.

    Use the command found in the following code example:


    # imsimta restart job_controller
    

    If the program performing enqueues is also a channel that will be dequeuing messages, and more specifically, is doing intermediate processing that leaves the envelope recipient addresses unchanged, then special rewrite rules must be used to prevent a message loop in that the channel just enqueues the mail back to itself. For directions on how to prevent a message loop and other specific examples of rewrite rules, see Preventing Mail Loops when Re-enqueuing Mail.

ProcedureTo Manually Run Your Test Programs

Steps
  1. If the program does not explicitly set the channel name, then you must define the PMDF_CHANNEL environment variable.

    The value of that variable must be the name of your channel. The following example shows how to set the PMDF_CHANNEL environment variable:


    # PMDF_CHANNEL=x_test
    # export PMDF_CHANNEL

    For further information, see Running Your Enqueue and Dequeue Programs.

  2. Ensure that any environment variables required to run a program linked against the MTA SDK are defined.

    See Compiling and Linking Programs for additional information.

  3. Under some circumstances, it might be useful to comment out the master_command= line in the job_controller.site file.

    If you do this, you can enqueue mail to your test channel but not have the Job Controller actually run your channel program.

  4. When repeatedly testing your channel program, it is often necessary to restart the Job Controller before each manual test run.

    Otherwise, the Job Controller will hand off messages to your program on the first manual run but not the second manual run. The Job Controller will think that retries of the messages need to be delayed by several hours. By restarting the Job Controller, you cause it to “forget” which queued messages are to be deferred. Thus, when you run your channel again, it will be presented with all of the queued messages.

Preventing Mail Loops when Re-enqueuing Mail

This section shows how to add a new rewrite rule to prevent a message loop from happening if the program is doing intermediate processing that leaves the envelope recipient addresses unchanged. Otherwise, the channel would just enqueue the mail back to itself.

For discussion purposes, suppose that the channel is to provide intermediate processing for mail addressed to user@siroe.com. Further, the imta.cnf file has the following rewrite rule for siroe.com:

siroe.com $U@siroe.com

For example, as shown in the code example that follows, assume that the intermediate processing channel’s name is “xloop_test.” Near the bottom of the imta.cnf file with other channel definitions, you would see the following definition:


xloop_test
x-looptest-daemon

Then, as shown in the following example, a new rewrite rule for siroe.com needs to be added to the top of the imta.cnf file:


siroe.com $U%siroe.com@x-looptest-daemon$Nxloop_test
siroe.com $U@siroe.com

The new rewrite rule causes the following to happen:

Miscellaneous Programming Considerations

This section covers miscellaneous topics of interest to programmer’s using the SDK:

Retrieving Error Codes

With few exceptions, all routines in the SDK return an integer-valued result with a value of zero (0) indicating success. When a non-zero value is returned, it is also saved in a per-thread data section, which may be retrieved with either the mtaErrno() function or the mta_errno C pre-processor macro.

The exceptional routines either return nothing (that is, always succeed), or return a string pointer, and signify an error with a return value of NULL.

Writing Output From a Channel Program

The C runtime library stdout input-output destination may be usurped by the SDK, depending upon the context under which a channel program has been invoked. As such, programs that will operate as channels should use the mtaLog() routine to write information to their log file. Such programs should never write output directly to stdout or stderr or other generic I/O destinations, such as Pascal’s output, or FORTRAN’s default output logical unit. There’s no telling where such output might go: it might go to the Job Controller’s log file, it might even go down a network pipe to a remote client or server.


Note –

The channel log file is a different file from the MTA log file. The mtaLog() and mtaAccountingLogClose() are unrelated routines.


Considerations for Persistent Programs

There are two main problems to consider when creating programs that persist over long periods of time (for weeks or months):

Refreshing Stale Configuration Information

Some programs, once started, run indefinitely (for weeks or months). An example of this kind of program is a server that listens continually for incoming mail connections, enqueuing received messages. Site-specific configuration information is loaded at initialization. In the case of these long running programs, the information can become stale due to changes to configuration information, such as rewrite rules or channel definitions. Subsequent calls to mtaInit() do not accomplish this task. A program must exit and restart in order to ensure that all configuration information is reloaded.

Keeping the Log File Available For Update

A program that enqueues and dequeues messages may open the MTA log file, mail.log_current. For persistent programs, care should be taken that this log file is not left open during periods of inactivity. Otherwise, activities that require exclusive access to this file will be blocked. Before going idle, persistent programs should call mtaAccountingLogClose(). The log file will automatically reopened when needed.


Note –

The MTA log file, mail.log_current, is not the log written to by mtaLog().