Sat Apr 12 07:12:54 2008

Asterisk developer's documentation


res_smdi.c File Reference

SMDI support for Asterisk. More...

#include "asterisk.h"
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <termios.h>
#include <sys/time.h>
#include <time.h>
#include <ctype.h>
#include "asterisk/module.h"
#include "asterisk/lock.h"
#include "asterisk/utils.h"
#include "asterisk/smdi.h"
#include "asterisk/config.h"
#include "asterisk/astobj.h"
#include "asterisk/io.h"
#include "asterisk/logger.h"
#include "asterisk/options.h"

Include dependency graph for res_smdi.c:

Go to the source code of this file.

Data Structures

struct  ast_smdi_interface_container
 SMDI interface container. More...

Defines

#define SMDI_MSG_EXPIRY_TIME   30000

Functions

 AST_MODULE_INFO (ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS,"Simplified Message Desk Interface (SMDI) Resource",.load=load_module,.unload=unload_module,.reload=reload,)
void ast_smdi_interface_destroy (struct ast_smdi_interface *iface)
 ast_smdi_interface destructor.
struct ast_smdi_interfaceast_smdi_interface_find (const char *iface_name)
 Find an SMDI interface with the specified name.
void ast_smdi_md_message_destroy (struct ast_smdi_md_message *msg)
 ast_smdi_md_message destructor.
struct ast_smdi_md_messageast_smdi_md_message_pop (struct ast_smdi_interface *iface)
 Get the next SMDI message from the queue.
static void ast_smdi_md_message_push (struct ast_smdi_interface *iface, struct ast_smdi_md_message *msg)
void ast_smdi_md_message_putback (struct ast_smdi_interface *iface, struct ast_smdi_md_message *md_msg)
 Put an SMDI message back in the front of the queue.
struct ast_smdi_md_messageast_smdi_md_message_wait (struct ast_smdi_interface *iface, int timeout)
 Get the next SMDI message from the queue.
void ast_smdi_mwi_message_destroy (struct ast_smdi_mwi_message *msg)
 ast_smdi_mwi_message destructor.
struct ast_smdi_mwi_messageast_smdi_mwi_message_pop (struct ast_smdi_interface *iface)
 Get the next SMDI message from the queue.
static void ast_smdi_mwi_message_push (struct ast_smdi_interface *iface, struct ast_smdi_mwi_message *msg)
void ast_smdi_mwi_message_putback (struct ast_smdi_interface *iface, struct ast_smdi_mwi_message *mwi_msg)
 Put an SMDI message back in the front of the queue.
struct ast_smdi_mwi_messageast_smdi_mwi_message_wait (struct ast_smdi_interface *iface, int timeout)
 Get the next SMDI message from the queue.
int ast_smdi_mwi_set (struct ast_smdi_interface *iface, const char *mailbox)
 Set the MWI indicator for a mailbox.
int ast_smdi_mwi_unset (struct ast_smdi_interface *iface, const char *mailbox)
 Unset the MWI indicator for a mailbox.
static int load_module (void)
static int reload (void)
static int smdi_load (int reload)
static void * smdi_read (void *iface_p)
 Read an SMDI message.
static int unload_module (void)

Variables

static const char config_file [] = "smdi.conf"
struct module_symbols * me
struct ast_smdi_interface_container smdi_ifaces


Detailed Description

SMDI support for Asterisk.

Author:
Matthew A. Nicholson <mnicholson@digium.com>

Definition in file res_smdi.c.


Define Documentation

#define SMDI_MSG_EXPIRY_TIME   30000

Definition at line 49 of file res_smdi.c.

Referenced by smdi_load().


Function Documentation

AST_MODULE_INFO ( ASTERISK_GPL_KEY  ,
AST_MODFLAG_GLOBAL_SYMBOLS  ,
"Simplified Message Desk Interface (SMDI) Resource"  ,
load = load_module,
unload = unload_module,
reload = reload 
)

void ast_smdi_interface_destroy ( struct ast_smdi_interface iface  ) 

struct ast_smdi_interface* ast_smdi_interface_find ( const char *  iface_name  )  [read]

Find an SMDI interface with the specified name.

Parameters:
iface_name the name/port of the interface to search for.
Returns:
a pointer to the interface located or NULL if none was found. This actually returns an ASTOBJ reference and should be released using ASTOBJ_UNREF(iface, ast_smdi_interface_destroy).

Definition at line 322 of file res_smdi.c.

References ASTOBJ_CONTAINER_FIND, and smdi_ifaces.

Referenced by load_config(), and mkintf().

00323 {
00324    return (ASTOBJ_CONTAINER_FIND(&smdi_ifaces, iface_name));
00325 }

void ast_smdi_md_message_destroy ( struct ast_smdi_md_message msg  ) 

ast_smdi_md_message destructor.

Definition at line 474 of file res_smdi.c.

References free.

Referenced by ast_smdi_interface_destroy(), ast_smdi_md_message_pop(), smdi_read(), and ss_thread().

00475 {
00476    free(msg);
00477 }

struct ast_smdi_md_message* ast_smdi_md_message_pop ( struct ast_smdi_interface iface  )  [read]

Get the next SMDI message from the queue.

Parameters:
iface a pointer to the interface to use.
This function pulls the first unexpired message from the SMDI message queue on the specified interface. It will purge all expired SMDI messages before returning.

Returns:
the next SMDI message, or NULL if there were no pending messages.

Definition at line 188 of file res_smdi.c.

References ast_log(), ast_smdi_md_message_destroy(), ASTOBJ_CONTAINER_UNLINK_START, ASTOBJ_UNREF, LOG_NOTICE, ast_smdi_interface::md_q, ast_smdi_interface::msg_expiry, and ast_smdi_md_message::timestamp.

Referenced by ast_smdi_md_message_wait().

00189 {
00190    struct ast_smdi_md_message *md_msg = ASTOBJ_CONTAINER_UNLINK_START(&iface->md_q);
00191    struct timeval now;
00192    long elapsed = 0;
00193 
00194    /* purge old messages */
00195    now = ast_tvnow();
00196    while (md_msg) {
00197       elapsed = ast_tvdiff_ms(now, md_msg->timestamp);
00198 
00199       if (elapsed > iface->msg_expiry) {
00200          /* found an expired message */
00201          ASTOBJ_UNREF(md_msg, ast_smdi_md_message_destroy);
00202          ast_log(LOG_NOTICE, "Purged expired message from %s SMDI MD message queue.  Message was %ld milliseconds too old.\n",
00203             iface->name, elapsed - iface->msg_expiry);
00204          md_msg = ASTOBJ_CONTAINER_UNLINK_START(&iface->md_q);
00205       }
00206       else {
00207          /* good message, return it */
00208          break;
00209       }
00210    }
00211 
00212    return md_msg;
00213 }

static void ast_smdi_md_message_push ( struct ast_smdi_interface iface,
struct ast_smdi_md_message msg 
) [static]

Definition at line 72 of file res_smdi.c.

References ASTOBJ_CONTAINER_LINK_END, and ast_smdi_interface::md_q.

Referenced by smdi_read().

00073 {
00074    ASTOBJ_CONTAINER_LINK_END(&iface->md_q, md_msg);
00075 }

void ast_smdi_md_message_putback ( struct ast_smdi_interface iface,
struct ast_smdi_md_message md_msg 
)

Put an SMDI message back in the front of the queue.

Parameters:
iface a pointer to the interface to use.
md_msg a pointer to the message to use.
This function puts a message back in the front of the specified queue. It should be used if a message was popped but is not going to be processed for some reason, and the message needs to be returned to the queue.

Definition at line 159 of file res_smdi.c.

References ASTOBJ_CONTAINER_LINK_START, and ast_smdi_interface::md_q.

00160 {
00161    ASTOBJ_CONTAINER_LINK_START(&iface->md_q, md_msg);
00162 }

struct ast_smdi_md_message* ast_smdi_md_message_wait ( struct ast_smdi_interface iface,
int  timeout 
) [read]

Get the next SMDI message from the queue.

Parameters:
iface a pointer to the interface to use.
timeout the time to wait before returning in milliseconds.
This function pulls a message from the SMDI message queue on the specified interface. If no message is available this function will wait the specified amount of time before returning.

Returns:
the next SMDI message, or NULL if there were no pending messages and the timeout has expired.

Definition at line 227 of file res_smdi.c.

References ast_smdi_md_message_pop().

Referenced by ss_thread().

00228 {
00229    struct timeval start;
00230    long diff = 0;
00231    struct ast_smdi_md_message *msg;
00232 
00233    start = ast_tvnow();
00234    while (diff < timeout) {
00235 
00236       if ((msg = ast_smdi_md_message_pop(iface)))
00237          return msg;
00238 
00239       /* check timeout */
00240       diff = ast_tvdiff_ms(ast_tvnow(), start);
00241    }
00242 
00243    return (ast_smdi_md_message_pop(iface));
00244 }

void ast_smdi_mwi_message_destroy ( struct ast_smdi_mwi_message msg  ) 

ast_smdi_mwi_message destructor.

Definition at line 480 of file res_smdi.c.

References free.

Referenced by ast_smdi_interface_destroy(), ast_smdi_mwi_message_pop(), run_externnotify(), and smdi_read().

00481 {
00482    free(msg);
00483 }

struct ast_smdi_mwi_message* ast_smdi_mwi_message_pop ( struct ast_smdi_interface iface  )  [read]

Get the next SMDI message from the queue.

Parameters:
iface a pointer to the interface to use.
This function pulls the first unexpired message from the SMDI message queue on the specified interface. It will purge all expired SMDI messages before returning.

Returns:
the next SMDI message, or NULL if there were no pending messages.

Definition at line 256 of file res_smdi.c.

References ast_log(), ast_smdi_mwi_message_destroy(), ASTOBJ_CONTAINER_UNLINK_START, ASTOBJ_UNREF, LOG_NOTICE, ast_smdi_interface::msg_expiry, ast_smdi_interface::mwi_q, and ast_smdi_mwi_message::timestamp.

Referenced by ast_smdi_mwi_message_wait().

00257 {
00258    struct ast_smdi_mwi_message *mwi_msg = ASTOBJ_CONTAINER_UNLINK_START(&iface->mwi_q);
00259    struct timeval now;
00260    long elapsed = 0;
00261 
00262    /* purge old messages */
00263    now = ast_tvnow();
00264    while (mwi_msg)   {
00265       elapsed = ast_tvdiff_ms(now, mwi_msg->timestamp);
00266 
00267       if (elapsed > iface->msg_expiry) {
00268          /* found an expired message */
00269          ASTOBJ_UNREF(mwi_msg, ast_smdi_mwi_message_destroy);
00270          ast_log(LOG_NOTICE, "Purged expired message from %s SMDI MWI message queue.  Message was %ld milliseconds too old.\n",
00271             iface->name, elapsed - iface->msg_expiry);
00272          mwi_msg = ASTOBJ_CONTAINER_UNLINK_START(&iface->mwi_q);
00273       }
00274       else {
00275          /* good message, return it */
00276          break;
00277       }
00278    }
00279 
00280    return mwi_msg;
00281 }

static void ast_smdi_mwi_message_push ( struct ast_smdi_interface iface,
struct ast_smdi_mwi_message msg 
) [static]

Definition at line 83 of file res_smdi.c.

References ASTOBJ_CONTAINER_LINK_END, and ast_smdi_interface::mwi_q.

Referenced by smdi_read().

00084 {
00085    ASTOBJ_CONTAINER_LINK_END(&iface->mwi_q, mwi_msg);
00086 }

void ast_smdi_mwi_message_putback ( struct ast_smdi_interface iface,
struct ast_smdi_mwi_message mwi_msg 
)

Put an SMDI message back in the front of the queue.

Parameters:
iface a pointer to the interface to use.
mwi_msg a pointer to the message to use.
This function puts a message back in the front of the specified queue. It should be used if a message was popped but is not going to be processed for some reason, and the message needs to be returned to the queue.

Definition at line 173 of file res_smdi.c.

References ASTOBJ_CONTAINER_LINK_START, and ast_smdi_interface::mwi_q.

00174 {
00175    ASTOBJ_CONTAINER_LINK_START(&iface->mwi_q, mwi_msg);
00176 }

struct ast_smdi_mwi_message* ast_smdi_mwi_message_wait ( struct ast_smdi_interface iface,
int  timeout 
) [read]

Get the next SMDI message from the queue.

Parameters:
iface a pointer to the interface to use.
timeout the time to wait before returning in milliseconds.
This function pulls a message from the SMDI message queue on the specified interface. If no message is available this function will wait the specified amount of time before returning.

Returns:
the next SMDI message, or NULL if there were no pending messages and the timeout has expired.

Definition at line 295 of file res_smdi.c.

References ast_smdi_mwi_message_pop().

Referenced by run_externnotify().

00296 {
00297    struct timeval start;
00298    long diff = 0;
00299    struct ast_smdi_mwi_message *msg;
00300 
00301    start = ast_tvnow();
00302    while (diff < timeout) {
00303 
00304       if ((msg = ast_smdi_mwi_message_pop(iface)))
00305          return msg;
00306 
00307       /* check timeout */
00308       diff = ast_tvdiff_ms(ast_tvnow(), start);
00309    }
00310 
00311    return (ast_smdi_mwi_message_pop(iface));
00312 }

int ast_smdi_mwi_set ( struct ast_smdi_interface iface,
const char *  mailbox 
)

Set the MWI indicator for a mailbox.

Parameters:
iface the interface to use.
mailbox the mailbox to use.

Definition at line 93 of file res_smdi.c.

References ast_log(), ASTOBJ_UNLOCK, ASTOBJ_WRLOCK, errno, file, LOG_DEBUG, LOG_ERROR, and ast_smdi_interface::msdstrip.

Referenced by run_externnotify().

00094 {
00095    FILE *file;
00096    int i;
00097    
00098    file = fopen(iface->name, "w");
00099    if(!file) {
00100       ast_log(LOG_ERROR, "Error opening SMDI interface %s (%s) for writing\n", iface->name, strerror(errno));
00101       return 1;
00102    }  
00103 
00104    ASTOBJ_WRLOCK(iface);
00105 
00106    fprintf(file, "OP:MWI ");
00107 
00108    for(i = 0; i < iface->msdstrip; i++)
00109       fprintf(file, "0");
00110 
00111    fprintf(file, "%s!\x04", mailbox);
00112    fclose(file);
00113 
00114    ASTOBJ_UNLOCK(iface);
00115    ast_log(LOG_DEBUG, "Sent MWI set message for %s on %s\n", mailbox, iface->name);
00116    return 0;
00117 }

int ast_smdi_mwi_unset ( struct ast_smdi_interface iface,
const char *  mailbox 
)

Unset the MWI indicator for a mailbox.

Parameters:
iface the interface to use.
mailbox the mailbox to use.

Definition at line 124 of file res_smdi.c.

References ast_log(), ASTOBJ_UNLOCK, ASTOBJ_WRLOCK, errno, file, LOG_DEBUG, LOG_ERROR, and ast_smdi_interface::msdstrip.

Referenced by run_externnotify().

00125 {
00126    FILE *file;
00127    int i;
00128    
00129    file = fopen(iface->name, "w");
00130    if(!file) {
00131       ast_log(LOG_ERROR, "Error opening SMDI interface %s (%s) for writing\n", iface->name, strerror(errno));
00132       return 1;
00133    }  
00134 
00135    ASTOBJ_WRLOCK(iface);
00136 
00137    fprintf(file, "RMV:MWI ");
00138 
00139    for(i = 0; i < iface->msdstrip; i++)
00140       fprintf(file, "0");
00141 
00142    fprintf(file, "%s!\x04", mailbox);
00143    fclose(file);
00144 
00145    ASTOBJ_UNLOCK(iface);
00146    ast_log(LOG_DEBUG, "Sent MWI unset message for %s on %s\n", mailbox, iface->name);
00147    return 0;
00148 }

static int load_module ( void   )  [static]

Definition at line 709 of file res_smdi.c.

References ast_log(), AST_MODULE_LOAD_DECLINE, ASTOBJ_CONTAINER_INIT, LOG_WARNING, smdi_ifaces, and smdi_load().

00710 {
00711    int res;
00712 
00713    /* initialize our containers */
00714    memset(&smdi_ifaces, 0, sizeof(smdi_ifaces));
00715    ASTOBJ_CONTAINER_INIT(&smdi_ifaces);
00716 
00717    /* load the config and start the listener threads*/
00718    res = smdi_load(0);
00719    if (res < 0) {
00720       return res;
00721    } else if (res == 1) {
00722       ast_log(LOG_WARNING, "No SMDI interfaces are available to listen on, not starting SMDI listener.\n");
00723       return AST_MODULE_LOAD_DECLINE;
00724    } else
00725       return 0;
00726 }

static int reload ( void   )  [static]

Definition at line 737 of file res_smdi.c.

References ast_log(), LOG_WARNING, and smdi_load().

00738 {
00739    int res;
00740 
00741    res = smdi_load(1);
00742 
00743    if (res < 0) {
00744       return res;
00745    } else if (res == 1) {
00746       ast_log(LOG_WARNING, "No SMDI interfaces were specified to listen on, not starting SDMI listener.\n");
00747       return 0;
00748    } else
00749       return 0;
00750 }

static int smdi_load ( int  reload  )  [static]

Definition at line 517 of file res_smdi.c.

References ast_calloc, ast_config_destroy(), ast_config_load(), ast_log(), ast_module_ref(), ast_pthread_create_background, ast_smdi_interface_destroy(), ast_true(), ast_variable_browse(), ast_verbose(), ASTOBJ_CONTAINER_FIND, ASTOBJ_CONTAINER_INIT, ASTOBJ_CONTAINER_LINK, ASTOBJ_CONTAINER_MARKALL, ASTOBJ_CONTAINER_PRUNE_MARKED, ASTOBJ_CONTAINER_RDLOCK, ASTOBJ_CONTAINER_UNLOCK, ASTOBJ_INIT, ASTOBJ_UNMARK, ASTOBJ_UNREF, errno, ast_smdi_interface::fd, ast_smdi_interface::file, ast_variable::lineno, LOG_ERROR, LOG_NOTICE, ast_smdi_interface::md_q, ast_smdi_interface::mode, ast_smdi_interface::msdstrip, ast_smdi_interface::msg_expiry, ast_smdi_interface::mwi_q, ast_variable::name, ast_variable::next, option_verbose, smdi_ifaces, SMDI_MSG_EXPIRY_TIME, smdi_read(), ast_smdi_interface::thread, ast_variable::value, and VERBOSE_PREFIX_3.

Referenced by load_module(), and reload().

00518 {
00519    struct ast_config *conf;
00520    struct ast_variable *v;
00521    struct ast_smdi_interface *iface = NULL;
00522    int res = 0;
00523 
00524    /* Config options */
00525    speed_t baud_rate = B9600;     /* 9600 baud rate */
00526    tcflag_t paritybit = PARENB;   /* even parity checking */
00527    tcflag_t charsize = CS7;       /* seven bit characters */
00528    int stopbits = 0;              /* One stop bit */
00529    
00530    int msdstrip = 0;              /* strip zero digits */
00531    long msg_expiry = SMDI_MSG_EXPIRY_TIME;
00532    
00533    conf = ast_config_load(config_file);
00534 
00535    if (!conf) {
00536       if (reload)
00537          ast_log(LOG_NOTICE, "Unable to reload config %s: SMDI untouched\n", config_file);
00538       else
00539          ast_log(LOG_NOTICE, "Unable to load config %s: SMDI disabled\n", config_file);
00540       return 1;
00541    }
00542 
00543    /* Mark all interfaces that we are listening on.  We will unmark them
00544     * as we find them in the config file, this way we know any interfaces
00545     * still marked after we have finished parsing the config file should
00546     * be stopped.
00547     */
00548    if (reload)
00549       ASTOBJ_CONTAINER_MARKALL(&smdi_ifaces);
00550 
00551    for (v = ast_variable_browse(conf, "interfaces"); v; v = v->next) {
00552       if (!strcasecmp(v->name, "baudrate")) {
00553          if (!strcasecmp(v->value, "9600"))
00554             baud_rate = B9600;
00555          else if(!strcasecmp(v->value, "4800"))
00556             baud_rate = B4800;
00557          else if(!strcasecmp(v->value, "2400"))
00558             baud_rate = B2400;
00559          else if(!strcasecmp(v->value, "1200"))
00560             baud_rate = B1200;
00561          else {
00562             ast_log(LOG_NOTICE, "Invalid baud rate '%s' specified in %s (line %d), using default\n", v->value, config_file, v->lineno);
00563             baud_rate = B9600;
00564          }
00565       } else if (!strcasecmp(v->name, "msdstrip")) {
00566          if (!sscanf(v->value, "%d", &msdstrip)) {
00567             ast_log(LOG_NOTICE, "Invalid msdstrip value in %s (line %d), using default\n", config_file, v->lineno);
00568             msdstrip = 0;
00569          } else if (0 > msdstrip || msdstrip > 9) {
00570             ast_log(LOG_NOTICE, "Invalid msdstrip value in %s (line %d), using default\n", config_file, v->lineno);
00571             msdstrip = 0;
00572          }
00573       } else if (!strcasecmp(v->name, "msgexpirytime")) {
00574          if (!sscanf(v->value, "%ld", &msg_expiry)) {
00575             ast_log(LOG_NOTICE, "Invalid msgexpirytime value in %s (line %d), using default\n", config_file, v->lineno);
00576             msg_expiry = SMDI_MSG_EXPIRY_TIME;
00577          }
00578       } else if (!strcasecmp(v->name, "paritybit")) {
00579          if (!strcasecmp(v->value, "even"))
00580             paritybit = PARENB;
00581          else if (!strcasecmp(v->value, "odd"))
00582             paritybit = PARENB | PARODD;
00583          else if (!strcasecmp(v->value, "none"))
00584             paritybit = ~PARENB;
00585          else {
00586             ast_log(LOG_NOTICE, "Invalid parity bit setting in %s (line %d), using default\n", config_file, v->lineno);
00587             paritybit = PARENB;
00588          }
00589       } else if (!strcasecmp(v->name, "charsize")) {
00590          if (!strcasecmp(v->value, "7"))
00591             charsize = CS7;
00592          else if (!strcasecmp(v->value, "8"))
00593             charsize = CS8;
00594          else {
00595             ast_log(LOG_NOTICE, "Invalid character size setting in %s (line %d), using default\n", config_file, v->lineno);
00596             charsize = CS7;
00597          }
00598       } else if (!strcasecmp(v->name, "twostopbits")) {
00599          stopbits = ast_true(v->name);
00600       } else if (!strcasecmp(v->name, "smdiport")) {
00601          if (reload) {
00602             /* we are reloading, check if we are already
00603              * monitoring this interface, if we are we do
00604              * not want to start it again.  This also has
00605              * the side effect of not updating different
00606              * setting for the serial port, but it should
00607              * be trivial to rewrite this section so that
00608              * options on the port are changed without
00609              * restarting the interface.  Or the interface
00610              * could be restarted with out emptying the
00611              * queue. */
00612             if ((iface = ASTOBJ_CONTAINER_FIND(&smdi_ifaces, v->value))) {
00613                ast_log(LOG_NOTICE, "SMDI interface %s already running, not restarting\n", iface->name);
00614                ASTOBJ_UNMARK(iface);
00615                ASTOBJ_UNREF(iface, ast_smdi_interface_destroy);
00616                continue;
00617             }
00618          }
00619                      
00620          if (!(iface = ast_calloc(1, sizeof(*iface))))
00621             continue;
00622 
00623          ASTOBJ_INIT(iface);
00624          ASTOBJ_CONTAINER_INIT(&iface->md_q);
00625          ASTOBJ_CONTAINER_INIT(&iface->mwi_q);
00626 
00627          ast_copy_string(iface->name, v->value, sizeof(iface->name));
00628 
00629          if (!(iface->file = fopen(iface->name, "r"))) {
00630             ast_log(LOG_ERROR, "Error opening SMDI interface %s (%s)\n", iface->name, strerror(errno));
00631             ASTOBJ_UNREF(iface, ast_smdi_interface_destroy);
00632             continue;
00633          }
00634 
00635          iface->fd = fileno(iface->file);
00636 
00637          /* Set the proper attributes for our serial port. */
00638 
00639          /* get the current attributes from the port */
00640          if (tcgetattr(iface->fd, &iface->mode)) {
00641             ast_log(LOG_ERROR, "Error getting atributes of %s (%s)\n", iface->name, strerror(errno));
00642             ASTOBJ_UNREF(iface, ast_smdi_interface_destroy);
00643             continue;
00644          }
00645 
00646          /* set the desired speed */
00647          if (cfsetispeed(&iface->mode, baud_rate) || cfsetospeed(&iface->mode, baud_rate)) {
00648             ast_log(LOG_ERROR, "Error setting baud rate on %s (%s)\n", iface->name, strerror(errno));
00649             ASTOBJ_UNREF(iface, ast_smdi_interface_destroy);
00650             continue;
00651          }
00652          
00653          /* set the stop bits */
00654          if (stopbits)
00655             iface->mode.c_cflag = iface->mode.c_cflag | CSTOPB;   /* set two stop bits */
00656          else
00657             iface->mode.c_cflag = iface->mode.c_cflag & ~CSTOPB;  /* set one stop bit */
00658 
00659          /* set the parity */
00660          iface->mode.c_cflag = (iface->mode.c_cflag & ~PARENB & ~PARODD) | paritybit;
00661 
00662          /* set the character size */
00663          iface->mode.c_cflag = (iface->mode.c_cflag & ~CSIZE) | charsize;
00664          
00665          /* commit the desired attributes */
00666          if (tcsetattr(iface->fd, TCSAFLUSH, &iface->mode)) {
00667             ast_log(LOG_ERROR, "Error setting attributes on %s (%s)\n", iface->name, strerror(errno));
00668             ASTOBJ_UNREF(iface, ast_smdi_interface_destroy);
00669             continue;
00670          }
00671 
00672          /* set the msdstrip */
00673          iface->msdstrip = msdstrip;
00674 
00675          /* set the message expiry time */
00676          iface->msg_expiry = msg_expiry;
00677 
00678                         /* start the listner thread */
00679          if (option_verbose > 2)
00680             ast_verbose(VERBOSE_PREFIX_3 "Starting SMDI monitor thread for %s\n", iface->name);
00681          if (ast_pthread_create_background(&iface->thread, NULL, smdi_read, iface)) {
00682             ast_log(LOG_ERROR, "Error starting SMDI monitor thread for %s\n", iface->name);
00683             ASTOBJ_UNREF(iface, ast_smdi_interface_destroy);
00684             continue;
00685          }
00686 
00687          ASTOBJ_CONTAINER_LINK(&smdi_ifaces, iface);
00688          ASTOBJ_UNREF(iface, ast_smdi_interface_destroy);
00689          ast_module_ref(ast_module_info->self);
00690       } else {
00691          ast_log(LOG_NOTICE, "Ignoring unknown option %s in %s\n", v->name, config_file);
00692       }
00693    }
00694    ast_config_destroy(conf);
00695 
00696    /* Prune any interfaces we should no longer monitor. */
00697    if (reload)
00698       ASTOBJ_CONTAINER_PRUNE_MARKED(&smdi_ifaces, ast_smdi_interface_destroy);
00699    
00700    ASTOBJ_CONTAINER_RDLOCK(&smdi_ifaces);
00701    /* TODO: this is bad, we need an ASTOBJ method for this! */
00702    if (!smdi_ifaces.head)
00703       res = 1;
00704    ASTOBJ_CONTAINER_UNLOCK(&smdi_ifaces);
00705          
00706    return res;
00707 }

static void * smdi_read ( void *  iface_p  )  [static]

Read an SMDI message.

Parameters:
iface_p the SMDI interface to read from.
This function loops and reads from and SMDI interface. It must be stopped using pthread_cancel().

Definition at line 334 of file res_smdi.c.

References ast_calloc, ast_log(), ast_smdi_interface_destroy(), ast_smdi_md_message_destroy(), ast_smdi_md_message_push(), ast_smdi_mwi_message_destroy(), ast_smdi_mwi_message_push(), ASTOBJ_INIT, ASTOBJ_UNREF, ast_smdi_md_message::calling_st, ast_smdi_mwi_message::cause, ast_smdi_interface::file, ast_smdi_mwi_message::fwd_st, ast_smdi_md_message::fwd_st, LOG_DEBUG, LOG_ERROR, ast_smdi_md_message::mesg_desk_num, ast_smdi_md_message::mesg_desk_term, ast_smdi_interface::msdstrip, SMDI_MAX_STATION_NUM_LEN, SMDI_MESG_DESK_NUM_LEN, SMDI_MESG_DESK_TERM_LEN, SMDI_MWI_FAIL_CAUSE_LEN, ast_smdi_mwi_message::timestamp, ast_smdi_md_message::timestamp, and ast_smdi_md_message::type.

Referenced by smdi_load().

00335 {
00336    struct ast_smdi_interface *iface = iface_p;
00337    struct ast_smdi_md_message *md_msg;
00338    struct ast_smdi_mwi_message *mwi_msg;
00339    char c = '\0';
00340    char *cp = NULL;
00341    int i;
00342    int start = 0;
00343       
00344    /* read an smdi message */
00345    while ((c = fgetc(iface->file))) {
00346 
00347       /* check if this is the start of a message */
00348       if (!start) {
00349          if (c == 'M')
00350             start = 1;
00351       }
00352       else { /* Determine if this is a MD or MWI message */
00353          if(c == 'D') { /* MD message */
00354             start = 0;
00355 
00356             if (!(md_msg = ast_calloc(1, sizeof(*md_msg)))) {
00357                ASTOBJ_UNREF(iface,ast_smdi_interface_destroy);
00358                return NULL;
00359             }
00360             
00361             ASTOBJ_INIT(md_msg);
00362 
00363             /* read the message desk number */
00364             for(i = 0; i < SMDI_MESG_DESK_NUM_LEN; i++)
00365                md_msg->mesg_desk_num[i] = fgetc(iface->file);
00366 
00367             md_msg->mesg_desk_num[SMDI_MESG_DESK_NUM_LEN] = '\0';
00368 
00369             /* read the message desk terminal number */
00370             for(i = 0; i < SMDI_MESG_DESK_TERM_LEN; i++)
00371                md_msg->mesg_desk_term[i] = fgetc(iface->file);
00372 
00373             md_msg->mesg_desk_term[SMDI_MESG_DESK_TERM_LEN] = '\0';
00374 
00375             /* read the message type */
00376             md_msg->type = fgetc(iface->file);
00377             
00378             /* read the forwarding station number (may be blank) */
00379             cp = &md_msg->fwd_st[0];
00380             for (i = 0; i < SMDI_MAX_STATION_NUM_LEN + 1; i++) {
00381                if((c = fgetc(iface->file)) == ' ') {
00382                   *cp = '\0';
00383                   break;
00384                }
00385 
00386                /* store c in md_msg->fwd_st */
00387                if( i >= iface->msdstrip)
00388                   *cp++ = c;
00389             }
00390 
00391             /* make sure the value is null terminated, even if this truncates it */
00392             md_msg->fwd_st[SMDI_MAX_STATION_NUM_LEN] = '\0';
00393             cp = NULL;
00394             
00395             /* read the calling station number (may be blank) */
00396             cp = &md_msg->calling_st[0];
00397             for (i = 0; i < SMDI_MAX_STATION_NUM_LEN + 1; i++) {
00398                if (!isdigit((c = fgetc(iface->file)))) {
00399                   *cp = '\0';
00400                   break;
00401                }
00402 
00403                /* store c in md_msg->calling_st */
00404                if (i >= iface->msdstrip)
00405                   *cp++ = c;
00406             }
00407 
00408             /* make sure the value is null terminated, even if this truncates it */
00409             md_msg->calling_st[SMDI_MAX_STATION_NUM_LEN] = '\0';
00410             cp = NULL;
00411 
00412             /* add the message to the message queue */
00413             md_msg->timestamp = ast_tvnow();
00414             ast_smdi_md_message_push(iface, md_msg);
00415             ast_log(LOG_DEBUG, "Recieved SMDI MD message on %s\n", iface->name);
00416             
00417             ASTOBJ_UNREF(md_msg, ast_smdi_md_message_destroy);
00418 
00419          } else if(c == 'W') { /* MWI message */
00420             start = 0;
00421 
00422             if (!(mwi_msg = ast_calloc(1, sizeof(*mwi_msg)))) {
00423                ASTOBJ_UNREF(iface,ast_smdi_interface_destroy);
00424                return NULL;
00425             }
00426 
00427             ASTOBJ_INIT(mwi_msg);
00428 
00429             /* discard the 'I' (from 'MWI') */
00430             fgetc(iface->file);
00431             
00432             /* read the forwarding station number (may be blank) */
00433             cp = &mwi_msg->fwd_st[0];
00434             for (i = 0; i < SMDI_MAX_STATION_NUM_LEN + 1; i++) {
00435                if ((c = fgetc(iface->file)) == ' ') {
00436                   *cp = '\0';
00437                   break;
00438                }
00439 
00440                /* store c in md_msg->fwd_st */
00441                if (i >= iface->msdstrip)
00442                   *cp++ = c;
00443             }
00444 
00445             /* make sure the station number is null terminated, even if this will truncate it */
00446             mwi_msg->fwd_st[SMDI_MAX_STATION_NUM_LEN] = '\0';
00447             cp = NULL;
00448             
00449             /* read the mwi failure cause */
00450             for (i = 0; i < SMDI_MWI_FAIL_CAUSE_LEN; i++)
00451                mwi_msg->cause[i] = fgetc(iface->file);
00452 
00453             mwi_msg->cause[SMDI_MWI_FAIL_CAUSE_LEN] = '\0';
00454 
00455             /* add the message to the message queue */
00456             mwi_msg->timestamp = ast_tvnow();
00457             ast_smdi_mwi_message_push(iface, mwi_msg);
00458             ast_log(LOG_DEBUG, "Recieved SMDI MWI message on %s\n", iface->name);
00459             
00460             ASTOBJ_UNREF(mwi_msg, ast_smdi_mwi_message_destroy);
00461          } else {
00462             ast_log(LOG_ERROR, "Unknown SMDI message type recieved on %s (M%c).\n", iface->name, c);
00463             start = 0;
00464          }
00465       }
00466    }
00467 
00468    ast_log(LOG_ERROR, "Error reading from SMDI interface %s, stopping listener thread\n", iface->name);
00469    ASTOBJ_UNREF(iface,ast_smdi_interface_destroy);
00470    return NULL;
00471 }

static int unload_module ( void   )  [static]

Definition at line 728 of file res_smdi.c.

References ast_smdi_interface_destroy(), ASTOBJ_CONTAINER_DESTROY, ASTOBJ_CONTAINER_DESTROYALL, and smdi_ifaces.

00729 {
00730    /* this destructor stops any running smdi_read threads */
00731    ASTOBJ_CONTAINER_DESTROYALL(&smdi_ifaces, ast_smdi_interface_destroy);
00732    ASTOBJ_CONTAINER_DESTROY(&smdi_ifaces);
00733 
00734    return 0;
00735 }


Variable Documentation

const char config_file[] = "smdi.conf" [static]

Definition at line 51 of file res_smdi.c.

struct module_symbols* me

Definition at line 59 of file res_smdi.c.


Generated on Sat Apr 12 07:12:54 2008 for Asterisk - the Open Source PBX by  doxygen 1.5.5