jabberd2  2.3.3
pbx.c
Go to the documentation of this file.
1 /* vim: set noet ts=4 sw=4: */
2 /*
3  * jabberd - Jabber Open Source Server
4  * Copyright (c) 2009 Tomasz Sterna
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA
19  */
20 
28 #include "c2s.h"
29 
30 #define COMMANDLINE_LENGTH_MAX 2048
31 static void _pbx_close_pipe(c2s_t c2s);
32 static void _pbx_open_pipe(c2s_t c2s, int mode);
33 static void _pbx_read_pipe(c2s_t c2s);
34 static void _pbx_write_pipe(c2s_t c2s);
35 int _pbx_process_command(c2s_t c2s, const char *cmd);
36 
37 static void _pbx_read_command(c2s_t c2s) {
38  char buf[COMMANDLINE_LENGTH_MAX];
39  char *bufp;
40 
41  bufp = (char*)&buf;
42  while (read(c2s->pbx_pipe_fd, bufp, 1) > 0)
43  if(bufp - ((char*)&buf) < COMMANDLINE_LENGTH_MAX-1) bufp++;
44  *bufp = '\0';
45 
46  log_debug(ZONE, "command read: %s", buf);
47 
48  _pbx_close_pipe(c2s);
49 
50  if(_pbx_process_command(c2s, buf) == 0)
51  _pbx_write_pipe(c2s);
52 
53  _pbx_read_pipe(c2s);
54 }
55 
56 static int _pbx_mio_callback(mio_t m, mio_action_t a, mio_fd_t fd, void *data, void *arg) {
57  c2s_t c2s = (c2s_t) arg;
58 
59  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-");
60 
61  switch(a) {
62  case action_READ:
63  log_debug(ZONE, "read action on fd %d", fd->fd);
64  _pbx_read_command(c2s);
65  return 1; /* want to read again */
66 
67  case action_WRITE:
68  /* write buffered lines from jqueue */
69  _pbx_close_pipe(c2s);
70  return 0;
71 
72  case action_CLOSE:
73  c2s->pbx_pipe_mio_fd = 0;
74  c2s->pbx_pipe_fd = -1;
75  return 0;
76 
77  default:
78  break;
79  }
80 
81  return 0;
82 }
83 
84 static void _pbx_close_pipe(c2s_t c2s) {
85  log_debug(ZONE, "### close_pipe");
86  if(c2s->pbx_pipe_mio_fd)
87  mio_close(c2s->mio, c2s->pbx_pipe_mio_fd);
88 }
89 
90 static void _pbx_open_pipe(c2s_t c2s, int mode) {
91 #ifdef WIN32
92  log_debug(ZONE, "PBX is not supported under Windows");
93  log_write(c2s->log, LOG_ERR, "PBX for Windows is not supported yet");
94  exit(EXIT_FAILURE);
95 #else
96  log_debug(ZONE, "### open_pipe");
97  c2s->pbx_pipe_fd = open(c2s->pbx_pipe, mode | O_NONBLOCK);
98  if(c2s->pbx_pipe_fd == -1) {
99  c2s->pbx_pipe_mio_fd = 0;
100  log_debug(ZONE, "error opening pipe: %d %s", errno, strerror(errno));
101  log_write(c2s->log, LOG_ERR, "failed to open PBX named pipe %s for %s", c2s->pbx_pipe, mode==O_RDONLY?"reading":"writing");
102  exit(EXIT_FAILURE);
103  } else
104  c2s->pbx_pipe_mio_fd = mio_register(c2s->mio, c2s->pbx_pipe_fd, _pbx_mio_callback, (void *) c2s);
105 #endif
106 }
107 /* open pipe for reading */
108 static void _pbx_read_pipe(c2s_t c2s) {
109  log_debug(ZONE, "### read_pipe");
110  _pbx_open_pipe(c2s, O_RDONLY);
111  mio_read(c2s->mio, c2s->pbx_pipe_mio_fd);
112 }
113 /* trigger buffer write */
114 static void _pbx_write_pipe(c2s_t c2s) {
115  log_debug(ZONE, "### write_pipe");
116  _pbx_open_pipe(c2s, O_RDWR);
117  mio_write(c2s->mio, c2s->pbx_pipe_mio_fd);
118 }
119 
120 void c2s_pbx_init(c2s_t c2s) {
121 #ifdef WIN32
122  log_debug(ZONE, "PBX is not supported under Windows");
123  log_write(c2s->log, LOG_ERR, "PBX for Windows is not supported yet");
124  exit(EXIT_FAILURE);
125 #else
126  struct stat sb;
127 
128  /* create the FIFO */
129  if(stat(c2s->pbx_pipe, &sb) == -1) {
130  if(mkfifo(c2s->pbx_pipe, S_IRUSR | S_IWUSR | S_IRGRP) == -1) {
131  log_write(c2s->log, LOG_ERR, "failed to create PBX named pipe: %s", c2s->pbx_pipe);
132  exit(EXIT_FAILURE);
133  }
134  }else{
135  if(!S_ISFIFO(sb.st_mode)) {
136  log_write(c2s->log, LOG_ERR, "file %s exists but is not a named pipe", c2s->pbx_pipe);
137  exit(EXIT_FAILURE);
138  }
139  }
140 
141  _pbx_read_pipe(c2s);
142 #endif
143 }
static void _pbx_close_pipe(c2s_t c2s)
Definition: pbx.c:84
void log_write(log_t log, int level, const char *msgfmt,...)
Definition: log.c:104
static void _pbx_read_command(c2s_t c2s)
Definition: pbx.c:37
void c2s_pbx_init(c2s_t c2s)
Definition: pbx.c:120
mio_action_t
these are the actions and a handler type assigned by the applicaiton using mio
Definition: mio.h:106
Definition: mio.h:109
static void _pbx_read_pipe(c2s_t c2s)
Definition: pbx.c:108
mio_fd_t pbx_pipe_mio_fd
Definition: c2s.h:233
#define mio_read(m, fd)
process read events for this fd
Definition: mio.h:161
mio_t mio
mio context
Definition: c2s.h:165
struct c2s_st * c2s_t
Definition: c2s.h:53
int _pbx_process_command(c2s_t c2s, const char *cmd)
process commandline
Definition: pbx_commands.c:118
#define log_debug(...)
Definition: log.h:65
Definition: c2s.h:151
#define COMMANDLINE_LENGTH_MAX
Definition: pbx.c:30
static void _pbx_open_pipe(c2s_t c2s, int mode)
Definition: pbx.c:90
int pbx_pipe_fd
Definition: c2s.h:232
int fd
Definition: mio.h:102
static int _pbx_mio_callback(mio_t m, mio_action_t a, mio_fd_t fd, void *data, void *arg)
Definition: pbx.c:56
Definition: mio.h:100
#define mio_close(m, fd)
request that mio close this fd
Definition: mio.h:155
static void _pbx_write_pipe(c2s_t c2s)
Definition: pbx.c:114
#define mio_write(m, fd)
mio should try the write action on this fd now
Definition: mio.h:158
#define ZONE
Definition: mio_impl.h:76
log_t log
logging
Definition: c2s.h:189
const char * pbx_pipe
PBX integration named pipe.
Definition: c2s.h:231
#define mio_register(m, fd, app, arg)
for adding an existing socket connected to this mio
Definition: mio.h:148