jabberd2  2.2.16
c2s/pbx.c
Go to the documentation of this file.
00001 /* vim: set noet ts=4 sw=4: */
00002 /*
00003  * jabberd - Jabber Open Source Server
00004  * Copyright (c) 2009 Tomasz Sterna
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA
00019  */
00020 
00028 #include "c2s.h"
00029 
00030 #define COMMANDLINE_LENGTH_MAX  2048
00031 static void _pbx_close_pipe(c2s_t c2s);
00032 static void _pbx_open_pipe(c2s_t c2s, int mode);
00033 static void _pbx_read_pipe(c2s_t c2s);
00034 static void _pbx_write_pipe(c2s_t c2s);
00035 int _pbx_process_command(c2s_t c2s, char *cmd);
00036 
00037 static void _pbx_read_command(c2s_t c2s) {
00038     char buf[COMMANDLINE_LENGTH_MAX];
00039     char *bufp;
00040 
00041     bufp = (char*)&buf;
00042     while (read(c2s->pbx_pipe_fd, bufp, 1) > 0)
00043         if(bufp - ((char*)&buf) < COMMANDLINE_LENGTH_MAX-1) bufp++;
00044     *bufp = '\0';
00045 
00046     log_debug(ZONE, "command read: %s", buf);
00047 
00048     _pbx_close_pipe(c2s);
00049 
00050     if(_pbx_process_command(c2s, buf) == 0)
00051         _pbx_write_pipe(c2s);
00052 
00053     _pbx_read_pipe(c2s);
00054 }
00055 
00056 static int _pbx_mio_callback(mio_t m, mio_action_t a, mio_fd_t fd, void *data, void *arg) {
00057     c2s_t c2s = (c2s_t) arg;
00058 
00059     log_debug(ZONE, "action %s on PBX pipe", a==0?"action_ACCEPT":a==1?"action_READ":a==2?"action_WRITE":a==3?"action_CLOSE":"-unknown-");
00060 
00061     switch(a) {
00062         case action_READ:
00063             log_debug(ZONE, "read action on fd %d", fd->fd);
00064             _pbx_read_command(c2s);
00065             return 1; /* want to read again */
00066 
00067         case action_WRITE:
00068             /* write buffered lines from jqueue */
00069             _pbx_close_pipe(c2s);
00070             return 0;
00071 
00072         case action_CLOSE:
00073             c2s->pbx_pipe_mio_fd = 0;
00074             c2s->pbx_pipe_fd = -1;
00075             return 0;
00076 
00077         default:
00078             break;
00079     }
00080 
00081     return 0;
00082 }
00083 
00084 static void _pbx_close_pipe(c2s_t c2s) {
00085     log_debug(ZONE, "### close_pipe");
00086     if(c2s->pbx_pipe_mio_fd)
00087         mio_close(c2s->mio, c2s->pbx_pipe_mio_fd);
00088 }
00089 
00090 static void _pbx_open_pipe(c2s_t c2s, int mode) {
00091 #ifdef WIN32
00092     log_debug(ZONE, "PBX is not supported under Windows");
00093     log_write(c2s->log, LOG_ERR, "PBX for Windows is not supported yet");
00094     exit(EXIT_FAILURE);
00095 #else
00096     log_debug(ZONE, "### open_pipe");
00097     c2s->pbx_pipe_fd = open(c2s->pbx_pipe, mode | O_NONBLOCK);
00098     if(c2s->pbx_pipe_fd == -1) {
00099         c2s->pbx_pipe_mio_fd = 0;
00100         log_debug(ZONE, "error opening pipe: %d %s", errno, strerror(errno));
00101         log_write(c2s->log, LOG_ERR, "failed to open PBX named pipe %s for %s", c2s->pbx_pipe, mode==O_RDONLY?"reading":"writing");
00102         exit(EXIT_FAILURE);
00103     } else
00104         c2s->pbx_pipe_mio_fd = mio_register(c2s->mio, c2s->pbx_pipe_fd, _pbx_mio_callback, (void *) c2s);
00105 #endif
00106 }
00107 /* open pipe for reading */
00108 static void _pbx_read_pipe(c2s_t c2s) {
00109     log_debug(ZONE, "### read_pipe");
00110     _pbx_open_pipe(c2s, O_RDONLY);
00111     mio_read(c2s->mio, c2s->pbx_pipe_mio_fd);
00112 }
00113 /* trigger buffer write */
00114 static void _pbx_write_pipe(c2s_t c2s) {
00115     log_debug(ZONE, "### write_pipe");
00116     _pbx_open_pipe(c2s, O_RDWR);
00117     mio_write(c2s->mio, c2s->pbx_pipe_mio_fd);
00118 }
00119 
00120 void c2s_pbx_init(c2s_t c2s) {
00121 #ifdef WIN32
00122     log_debug(ZONE, "PBX is not supported under Windows");
00123     log_write(c2s->log, LOG_ERR, "PBX for Windows is not supported yet");
00124     exit(EXIT_FAILURE);
00125 #else
00126     struct stat sb;
00127 
00128     /* create the FIFO */
00129     if(stat(c2s->pbx_pipe, &sb) == -1) {
00130         if(mkfifo(c2s->pbx_pipe, S_IRUSR | S_IWUSR | S_IRGRP) == -1) {
00131             log_write(c2s->log, LOG_ERR, "failed to create PBX named pipe: %s", c2s->pbx_pipe);
00132             exit(EXIT_FAILURE);
00133         }
00134     }else{
00135         if(!S_ISFIFO(sb.st_mode)) {
00136             log_write(c2s->log, LOG_ERR, "file %s exists but is not a named pipe", c2s->pbx_pipe);
00137             exit(EXIT_FAILURE);
00138         }
00139     }
00140 
00141     _pbx_read_pipe(c2s);
00142 #endif
00143 }