Protocol Plug-in Programming Guide: Using the Protocol Level Plug-in API
Previous Next Contents Index


Chapter 2 Using the Protocol Level Plug-in API

This chapter describes using the Protocol Level Plug-in API to write protocol level plug-ins. The examples in this chapter come from the Anti-Relay Plug-in, a protocol level plug-in that allows you to prevent other sites from using your site to relay UBE on to other sites.

The chapter has the following sections:


Using Protocol Level Plug-in Functions
A Protocol Level SMTP plug-in is a shared object or shared library, which Messaging Server loads at start time. A plug-in must export the following Protocol Level Plug-in API functions:

Table 2.1 Protocol Level Plug-in API functions
Function
Operation
PPModule_Init
Initialize the plug-in.
PPModule_NewProtPlug
Create an instance of the plug-in.
ProtPlug_ProcessLine
Process a line received in the protocol.
ProtPlug_Delete
Free plug-in resources.
PPModule_Exit
Clean up and exit.

Each operation in the table links to a further explanation that includes the function. To see how these functions are used in a protocol level plug-in, see Chapter 4, "Sample Protocol Level Plug-ins."

Initialize the plug-in
The server calls this function once at start-up to initialize the plug-in session.

int PPModule_Init(ProtPlugSystem *pSys) 
This function provides the entry point for the protocol plug-in library represented by the *pSys parameter. This parameter points to a structure that contains function pointers for thread synchronization, memory management, and other operations. The function returns 0 on success or values other than zero if it fails.

If PPModule_Init fails, the PPModule_Exit function is not called.

Create an instance of the plug-in
The server calls this function to create a new instance of a ProtPlug, the session analogue of a plug-in module. When the server calls this function, it expects that a ProtPlug structure will be returned to it. ProtPlug is a user-defined structure that you can create with your own data. This structure should contain any session specific data required by the plug-in.

ProtPlug *PPModule_NewProtPlug(PPSession *ps);
The ps parameter is the opaque handle that the plug-in uses to call session-specific functions. It is common to store this as one of the elements in the ProtPlug structure. The function returns a pointer to a new ProtPlug structure.

Process a line received in the protocol
The server calls this function to set the action the plug-in performs when a line has been received in the protocol.

int ProtPlug_ProcessLine(ProtPlug *ppp, 
char *pszLine,
char **ppszResp)
The ppp parameter is a pointer to the session structure returned by PPModule_NewProtPlug.

The pszLine parameter represents the line to be processed, which can be an SMTP command or the body of the message. This line is null terminated and includes "\r\n".

When a new connection is established, the MTA calls the plug-in and passes a null pointer as this parameter, which is a request for a protocol banner. The plug-in may respond with PP_SKIP. The memory pointed to by pszLine is owned by the server and should not be modified or freed by the ProtPlug.

The ppszResp parameter represents the desired response, which must be null-terminated and include "\r\n". The memory pointed to by *ppszResp belongs to the ProtPlug and need only be valid until the next call to ProtPlug_ProcessLine or ProtPlug_Delete. The server will not modify or free it.

The function returns one of the values shown in Table 2.2:

Table 2.2 Return values for ProtPlug_ProcessLine
Value
Description
PP_DONE
The command was handled, and is over. No more lines remain.
PP_MORE
The command was handled, but has not finished. More lines are needed.
PP_SKIP
The command was ignored. Subsequent lines for the command should not be sent to this ProtPlug.
PP_CLOSE
The command was handled. The session (connection) should be closed after sending the response (if any).

This function is called in a multi-threaded context, and so must be thread safe.

Free plug-in resources
The server calls this function to free all resources associated with an instance of a protocol level plug-in.

void ProtPlug_Delete(ProtPlug *ppp)
The ppp parameter points to the ProtPlug structure that represents the session to be deleted.

Since this function is called in a multi-threaded context, make sure that it is thread safe.

Clean up and exit
The server calls this function to perform cleanup for the plug-in before the server exits. Any global resources used by the plug-ins, which may include configuration data, LDAP handles, and other data, should be cleaned up here. The server calls this function before it exits and after all protocol plug-in sessions (represented by ProtPlug structures) have been deleted.

void PPModule_Exit(void); 
This function takes no parameters and has no return value.


Working with Plug-in Structures
Protocol Level Plug-in functions operate on several data structures.

Table 2.3 Protocol Level Plug-in API data structures
Structure
Description
PPMutex
Represents the mutex synchronization object.
PPSession
Represents the handle to the current server session.
PPSessionActions
Represents available actions for the plug-in session.
ProtPlugSystem
Represents the protocol level plug-in library.
ProtPlug
Represents the protocol level plug-in session.

This section describes these Protocol Level Plug-in structures:

To see how these structures are used in a sample SMTP plug-in, see Chapter 4, "Sample Protocol Level Plug-ins."

The ProtPlugSystem Structure
The ProtPlugSystem structure provides the interface for plug-in services including memory management, obtaining session-specific information, and handling mutex synchronization objects. It is provided to the PPModule_Init function at server start-up.

typedef struct ProtPlugSystemStruct 
{
void *(*PPRealloc)(void *pOld, int nSize);
/* all memory comes from here */
PPMutex *(*PPMutex_New)(void);
void (*PPMutex_Lock)(PPMutex *pm);
void (*PPMutex_Unlock)(PPMutex *pm);
void (*PPMutex_Delete)(PPMutex *pm);
char *(*PPGetIni)(char *pszKey, char *pszDefault,
char *pszResult, int nResultSize);
void (*PPLogPrintf)(char *pszFormat,...);
struct in_addr (*PPGetHostByName)(char *pszName);
char *(*PPGetHostByAddr)(struct in_addr ina, char *pBuf,
int nBufSize);
}
ProtPlugSystem;
The ProtPlugSystem structure contains function pointers that provide a number of services.

The PPSessionActions Structure
The PPSessionActions structure defines the actions that can take place during the plug-in session. Basically, the plug-in can either pass control to the next plug-in the chain or retrieve session-specific properties, which can include the client IP-address, the authentication state, and other values.

#include <protplug.h>
typedef struct PPSessionActionsStruct
{
int (*DeferLine)
(
PPSession *ps, char *pszLine, char **ppszResp);
char *(*GetProperty)
(PPSession *ps, char *pszKey, char *pszDefault);
} PPSessionActions;
The PPSessionActions structure contains function pointers that define these actions.

Warning. You must always use the access macros defined in the Protocol Level Plug-in API to call the functions defined in this structure. See "Using Macros."§


Using Macros
The Protocol Level Plug-in API contains macros that call two functions, DeferLine and GetProperty, which are defined as function pointers within the PPSessionActions structure. You should always use these macros to call these two functions.

To see how this structure is used in a sample SMTP plug-in, see Chapter 4, "Sample Protocol Level Plug-ins."

Passing Control to the Next Plug-in
The plug-in usually should decide to let the calling plug-in see and act on the response and pass control on to the next plug-in in the chain. Use the PPSESSION_DEFERLINE macro to perform this operation.

This macro calls the DeferLine function, which is defined as a function pointer in the PPSessionActions structure. You must always use this macro to call this function.

#define PPSESSION_DEFERLINE(p, l, r) \
((PPSessionActions *)(p))->DeferLine((p), (l), (r))
The p parameter reprsents the plug-in session. The l parameter returns the current line. The r parameter returns a pointer to a response, either PP_DONE, PP_MORE, PP_SKIP, or PP_CLOSE. For a description of these responses, see Table 2.2.

Retrieving Session-Specific Information
This macro allows the client to retrieve information about the current session, such as client IP-address and authentication state. To do this, it calls the GetProperty function, which is defined as a function pointer in the PPSessionActions structure. You must always use this macro to call this function.

#define PPSESSION_GETPROPERTY(p, k, d) \
(((PPSessionActions *)(p))->GetProperty((p), (k), (d)))
The p parameter represents the plug-in session. The k parameter represents the key names of session-specific properties whose values you can get from the server. The keys you can use are shown in Table 2.4.

Table 2.4 Keys for the pszKey parameter of the GETPROPERTY macro
pszKey Value
Description
TLS
yes/no, in TLS
ESMTP
yes/no, got good EHLO signal
BadCert
yes/no, SSLclientcert bad
ReceivedLines
int, "Received" lines
SizeOfHeader
int
SizeOfBody
int
PeerName
peer name (if available)
PeerIP
peer ip (dot-quad)
HostName
server hostname
HeloDomain
domain given in ehlo
SenderAuthed
yes/no
AuthSender
authenticated sender
Sender
from
Recipients
recipient list, comma separated
BadCommands
int, number of bad commands so far in the current session

The pszDefault parameter should always be null. This parameter is reserved for future expansion.

 

© Copyright 1999 Netscape Communications Corp., a subsidiary of America Online, Inc. All rights reserved.