Codename Pineapple

Home page | Mailing list | Docs

Last updated: Sat Feb 3 05:01:46 2007

Asterisk developer's documentation :: Codename Pineapple


res_smdi.c File Reference


Detailed Description

SMDI support for Asterisk.

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

Definition in file res_smdi.c.

#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.
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.
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.
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.
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.
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"
module_symbols * me
ast_smdi_interface_container smdi_ifaces
 SMDI interface container.


Define Documentation

#define SMDI_MSG_EXPIRY_TIME   30000
 

Definition at line 48 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  ) 
 

ast_smdi_interface destructor.

Definition at line 489 of file res_smdi.c.

References ast_module_unref(), AST_PTHREADT_NULL, AST_PTHREADT_STOP, ast_smdi_md_message_destroy(), ast_smdi_mwi_message_destroy(), ASTOBJ_CONTAINER_DESTROY, ASTOBJ_CONTAINER_DESTROYALL, ast_smdi_interface::file, free, ast_smdi_interface::md_q, ast_smdi_interface::mwi_q, and ast_smdi_interface::thread.

Referenced by destroy_zt_pvt(), smdi_read(), and unload_module().

00490 {
00491    if (iface->thread != AST_PTHREADT_NULL && iface->thread != AST_PTHREADT_STOP) {
00492       pthread_cancel(iface->thread);
00493       pthread_join(iface->thread, NULL);
00494    }
00495    
00496    iface->thread = AST_PTHREADT_STOP;
00497    
00498    if(iface->file) 
00499       fclose(iface->file);
00500    
00501    ASTOBJ_CONTAINER_DESTROYALL(&iface->md_q, ast_smdi_md_message_destroy);
00502    ASTOBJ_CONTAINER_DESTROYALL(&iface->mwi_q, ast_smdi_mwi_message_destroy);
00503    ASTOBJ_CONTAINER_DESTROY(&iface->md_q);
00504    ASTOBJ_CONTAINER_DESTROY(&iface->mwi_q);
00505    free(iface);
00506 
00507    ast_module_unref(ast_module_info->self);
00508 }

struct ast_smdi_interface* ast_smdi_interface_find const char *  iface_name  ) 
 

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 323 of file res_smdi.c.

References ASTOBJ_CONTAINER_FIND, and smdi_ifaces.

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

void ast_smdi_md_message_destroy struct ast_smdi_md_message msg  ) 
 

ast_smdi_md_message destructor.

Definition at line 477 of file res_smdi.c.

References free.

Referenced by ast_smdi_interface_destroy(), and ast_smdi_md_message_pop().

00478 {
00479    free(msg);
00480 }

struct ast_smdi_md_message* ast_smdi_md_message_pop struct ast_smdi_interface iface  ) 
 

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 189 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().

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

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

Definition at line 71 of file res_smdi.c.

References ASTOBJ_CONTAINER_LINK_END, and ast_smdi_interface::md_q.

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

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 160 of file res_smdi.c.

References ASTOBJ_CONTAINER_LINK_START, and ast_smdi_interface::md_q.

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

struct ast_smdi_md_message* ast_smdi_md_message_wait struct ast_smdi_interface iface,
int  timeout
 

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 228 of file res_smdi.c.

References ast_smdi_md_message_pop().

Referenced by ss_thread().

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

void ast_smdi_mwi_message_destroy struct ast_smdi_mwi_message msg  ) 
 

ast_smdi_mwi_message destructor.

Definition at line 483 of file res_smdi.c.

References free.

Referenced by ast_smdi_interface_destroy(), and ast_smdi_mwi_message_pop().

00484 {
00485    free(msg);
00486 }

struct ast_smdi_mwi_message* ast_smdi_mwi_message_pop struct ast_smdi_interface iface  ) 
 

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 257 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().

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

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

Definition at line 82 of file res_smdi.c.

References ASTOBJ_CONTAINER_LINK_END, and ast_smdi_interface::mwi_q.

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

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 174 of file res_smdi.c.

References ASTOBJ_CONTAINER_LINK_START, and ast_smdi_interface::mwi_q.

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

struct ast_smdi_mwi_message* ast_smdi_mwi_message_wait struct ast_smdi_interface iface,
int  timeout
 

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 296 of file res_smdi.c.

References ast_smdi_mwi_message_pop().

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

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 92 of file res_smdi.c.

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

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

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    if (option_debug)
00147       ast_log(LOG_DEBUG, "Sent MWI unset message for %s on %s\n", mailbox, iface->name);
00148    return 0;
00149 }

static int load_module void   )  [static]
 

Definition at line 712 of file res_smdi.c.

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

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

static int reload void   )  [static]
 

Definition at line 740 of file res_smdi.c.

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

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

static int smdi_load int  reload  )  [static]
 

Definition at line 520 of file res_smdi.c.

References ast_config_load(), ast_log(), ast_variable_browse(), ASTOBJ_CONTAINER_MARKALL, ast_variable::lineno, LOG_NOTICE, ast_smdi_interface::msdstrip, ast_smdi_interface::msg_expiry, ast_variable::name, ast_variable::next, smdi_ifaces, SMDI_MSG_EXPIRY_TIME, and ast_variable::value.

Referenced by load_module(), and reload().

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

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 335 of file res_smdi.c.

References ast_calloc, ast_smdi_interface_destroy(), ASTOBJ_INIT, ASTOBJ_UNREF, ast_smdi_md_message::calling_st, ast_smdi_interface::file, ast_smdi_md_message::fwd_st, ast_smdi_interface::msdstrip, SMDI_MAX_STATION_NUM_LEN, SMDI_MESG_DESK_NUM_LEN, and SMDI_MESG_DESK_TERM_LEN.

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

static int unload_module void   )  [static]
 

Definition at line 731 of file res_smdi.c.

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

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


Variable Documentation

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

Definition at line 50 of file res_smdi.c.

struct module_symbols* me
 

Definition at line 58 of file res_smdi.c.

struct ast_smdi_interface_container smdi_ifaces
 

SMDI interface container.

Referenced by ast_smdi_interface_find(), load_module(), smdi_load(), and unload_module().


Asterisk is a trademark for Digium, inc.. | Edvina.net | Asterisk.org | This documentation was generated with Doxygen