Asterisk - The Open Source Telephony Project GIT-master-3dae2cf
eagi_proxy.c
Go to the documentation of this file.
1/*
2 * Asterisk EAGI -> TCP/IP proxy
3 * by Danijel Korzinek (devil_slayer _at_ hotmail.com)
4 *
5 * This simple C application allows you to control asterisk thru one TCP/IP
6 * socket and listen to the conversation thru another socket.
7 *
8 * Great for ASR or wizzard-of-oz telephony systems!
9 *
10 * HOWTO:
11 * The program is compiled using the following command:
12 * gcc eagi_proxy.c -o eagi_proxy -lpthread
13 *
14 * In the dialplan, you can add something like this to the main context:
15 * exten => s,1,Answer
16 * exten => s,n,EAGI(/path/to/eagi_proxy)
17 * exten => s,n,Hangup
18 *
19 * To test the program you can use the netcat utility:
20 * (http://netcat.sourceforge.net/)
21 *
22 * -in one console run:
23 * nc -vv -l -p 8418 > /path/to/file.raw
24 * -in another run:
25 * nc -vv -l -p 8417
26 * -you can use any file for the signal or even /dev/null
27 * -you can change the port numbers in the sourcecode below
28 *
29 * Once you make the call, both programs will accept the incoming
30 * connection. The program on port 8417 will print out the enviornemnt
31 * (unless the appropriate define below is commented) and you can write
32 * any AGI command there (http://www.voip-info.org/wiki-Asterisk+AGI),
33 * e.g.:
34 * GET DATA /path/to/gsm/file 10000 4
35 *
36 * Finally, you can open the RAW file in any sound editor. The format is:
37 * RAW little-endian 8kHz 16bit
38 */
39
40#include <stdlib.h>
41#include <unistd.h>
42#include <stdio.h>
43#include <netinet/in.h>
44#include <netinet/tcp.h>
45#include <string.h>
46#include <time.h>
47#include <sys/types.h>
48#include <sys/stat.h>
49#include <sys/socket.h>
50#include <sys/time.h>
51#include <arpa/inet.h>
52#include <netdb.h>
53#include <fcntl.h>
54#include <errno.h>
55#include <ctype.h>
56#include <pthread.h>
57
58/* DEFINES */
59#define SIGNAL_PORT 8418
60#define COMMAND_PORT 8417
61#define SEND_ENVIORNMENT /*send the enviornment thru the socket*/
62/************************/
63
64
65#define BUFSIZE 1024
67
68#define WINSIZE 400 /* 25 ms @ 8 kHz and 16bit */
70
71#define WINBUF_NUM 2400 /* number of WINSIZE windows = 1 minute */
72char* winbuf;
73char *end, *bs, *be;
74/* winbuf - start of buffer
75 * end - end of buffer
76 * bs - start of data
77 * be - end of data
78 */
79
80int command_desc; /* command transfer descriptor */
81int speech_desc; /* speech signal descrriptor */
82char connected=1; /* connection state */
83
84int connect_to_host(char* host, int port); /* connect to a given host (name or IP) and given port number in nonblocking mode returning socket descriptor*/
85
86void read_full(int file, char* buffer, int num); /* read EXACTLY "num" ammount of bytes from "file" descriptor to "buffer"*/
87int read_some(int file, char* buffer, int size); /* read AT MOST "size" ammount of bytes */
88
89void write_buf(int file, char* buffer, int num); /* write "num" ammount of bytes to "file" descriptor and buffer the surplus if the write would block */
90int write_amap(int file, char* buffer, int num); /*write AT MOST "num" ammount of bytes and return ammount that was written*/
91
92void setnonblocking(int desc); /*sets the socket non-blocking; for polling */
93
94void finalize(); /* this function is run at exit */
95
96pthread_mutex_t command_mutex;/* command socket mutex */
98void* readStdin(void* ptr);
99void* readSignal(void* ptr);
100
101/* The program creates 3 threads:
102 * 1) Main thread - reads commands from the socket and sends them to asterisk
103 * 2) stdin_thread - reads asterisk output and sends it to the command socket
104 * 3) signal_thread - reads the sound from asterisk and sends it to the signal socket
105 */
106
107int main()
108{
109 int ret;
110
111 atexit(finalize);
112
113 setlinebuf(stdin);
114 setlinebuf(stdout);
115
118 bs=be=winbuf;
119
121 if(speech_desc<0)
122 {
123 perror("signal socket");
124 return -1;
125 }
126
127
129 if(command_desc<0)
130 {
131 perror("command socket");
132 return -1;
133 }
134
138
139 while(connected)
140 {
144 if(ret>0)
145 {
146 buf[ret]=0;
147 printf("%s",buf);
148 }
149 }
150
151 return 0;
152}
153
155{
156 close(command_desc);
157 close(speech_desc);
158 free(winbuf);
159}
160
161void* readStdin(void* ptr)
162{
163 while(1)/*read enviornment*/
164 {
165 fgets(buf,BUFSIZE,stdin);
166 #ifdef SEND_ENVIORNMENT
168 write_buf(command_desc,buf,strlen(buf));
170 #endif
171 if(feof(stdin) || buf[0]=='\n')
172 {
173 break;
174 }
175 }
176
177 while(connected)
178 {
179 fgets(buf,BUFSIZE,stdin);
181 write_buf(command_desc,buf,strlen(buf));
183 }
184
185 pthread_exit(NULL);
186}
187
188void* readSignal(void* ptr)
189{
190 while(connected)
191 {
194 }
195
196 pthread_exit(NULL);
197}
198
199
200void read_full(int file, char* buffer, int num)
201{
202 int count,pos=0;
203
204 while(num)
205 {
206 count=read(file,buffer+pos,num);
207 if(count==0 || (count<0 && errno!=EAGAIN))
208 {
209 connected=0;
210 return;
211 }
212 num-=count;
213 pos+=count;
214 }
215}
216
217int connect_to_host(char* name, int port)
218{
219 int address;
220 struct hostent* host_entity;
221 int res,desc;
222 int opts;
223 struct sockaddr_in host;
224
225
226 /* get address */
227 if(!strcmp(name,"localhost"))
228 address=htonl(2130706433); /*127.0.0.1*/
229 else
230 {
231 address=inet_addr(name); /* check if it's an IP that's written in the string */
232 if(address==(in_addr_t)-1)
233 {
234 host_entity = gethostbyname(name); /* search for the host under this name */
235
236 if(!host_entity)
237 {
238 fprintf(stderr,"EAGI proxy: Wrong address!\n"); /* can't find anything*/
239 return -1;
240 }
241 address=*((int*)host_entity->h_addr);
242 }
243 }
244
245 desc=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
246 if(desc<0)
247 {
248 fprintf(stderr,"EAGI proxy: Cannot create socket!\n");
249 return -1;
250 }
251
252 memset((void*)&host,0,sizeof(struct sockaddr_in));
253
254 host.sin_family=AF_INET;
255 host.sin_port=htons(port);
256 host.sin_addr.s_addr=address;
257
258 res=connect(desc,(struct sockaddr*)&host,sizeof(host));
259 if(res<0)
260 {
261 fprintf(stderr,"EAGI proxy: Cannot connect!\n");
262 return -1;
263 }
264
265 /* set to non-blocking mode */
266 opts = fcntl(desc,F_GETFL);
267 if (opts < 0) {
268 perror("fcntl(F_GETFL)");
269 exit(EXIT_FAILURE);
270 }
271 opts = (opts | O_NONBLOCK);
272 if (fcntl(desc,F_SETFL,opts) < 0) {
273 perror("fcntl(F_SETFL)");
274 exit(EXIT_FAILURE);
275 }
276
277
278 return desc;
279}
280
281int read_some(int desc, char* buffer, int size)
282{
283 unsigned char c;
284 int res,i=0;
285
286 for(;;)
287 {
288 res=read(desc,&c,1);
289 if(res<1)
290 {
291 if(errno!=EAGAIN)
292 {
293 perror("Error reading");
294 connected=0;
295 }
296 break;
297 }
298 if(res==0)
299 {
300 connected=0;
301 break;
302 }
303
304 buffer[i]=c;
305 i++;
306 }
307
308 return i;
309}
310
311/* This is a tricky function! */
312void write_buf(int desc, char* buf, int size)
313{
314 int ret;
315
316 /*NOTE: AMAP -> as much as possible */
317
318 if(be!=bs)/* if data left in buffer */
319 {
320 if(be>bs)/* if buffer not split */
321 {
322 ret=write_amap(desc,bs,be-bs);/* write AMAP */
323 bs+=ret;/* shift the start of the buffer */
324 }
325 else/* if buffer is split */
326 {
327 ret=write_amap(desc,bs,end-bs);/* write higher part first */
328 if(ret==end-bs)/* if wrote whole of the higher part */
329 {
330 ret=write_amap(desc,winbuf,be-winbuf);/* write lower part */
331 bs=winbuf+ret;/* shift start to new position */
332 }
333 else bs+=ret;/* if not wrote whole of higher part, only shift start */
334 }
335 }
336
337 if(be==bs)/* if buffer is empty now */
338 {
339 ret=write_amap(desc,buf,size);/* write AMAP of the new data */
340 buf+=ret;/* shift start of new data */
341 size-=ret;/* lower size of new data */
342 }
343
344 if(size)/* if new data still remains unsent */
345 {
346 if(be>=bs)/* if data not split */
347 {
348 if(size>end-be)/* if new data size doesn't fit higher end */
349 {
350 size-=end-be;/* reduce new data size by the higher end size */
351 memcpy(be,buf,end-be);/* copy to higher end */
352 be=winbuf;/* shift end to begining of buffer */
353 buf+=end-be;/* shift start of new data */
354 }
355 else/* if new data fits the higher end */
356 {
357 memcpy(be,buf,size);/* copy to higher end */
358 be+=size;/* shift end by size */
359 if(be>=end)/* if end goes beyond the buffer */
360 be=winbuf;/* restart */
361 size=0;/* everything copied */
362 }
363 }
364
365 if(size)/* if new data still remains */
366 {
367 if(size>=bs-be)/* if new data doesn't fit between end and start */
368 {
369 fprintf(stderr,"Buffer overflow!\n");
370 size=bs-be-1;/* reduce the size that we can copy */
371 }
372
373 if(size)/* if we can copy anything */
374 {
375 memcpy(be,buf,size);/* copy the new data between end and start */
376 be+=size;/* shift end by size */
377 }
378 }
379 }
380}
381
382int write_amap(int desc, char* buf, int size)
383{
384 int ret;
385 ret=write(desc,buf,size);
386 if(ret<0)
387 {
388 if(errno!=EAGAIN)
389 {
390 perror("Error writing");
391 connected=0;
392 }
393 return 0;
394 }
395 if(ret==0)
396 connected=0;
397
398 return ret;
399}
400
401
403{
404 int opts;
405
406 opts = fcntl(desc,F_GETFL);
407 if(opts < 0)
408 {
409 perror("fcntl(F_GETFL)");
410 exit(-1);
411 }
412
413 opts = (opts | O_NONBLOCK );
414 if(fcntl(desc,F_SETFL,opts) < 0)
415 {
416 perror("fcntl(F_SETFL)");
417 exit(-1);
418 }
419}
static const char desc[]
Definition: cdr_radius.c:84
int connect_to_host(char *host, int port)
Definition: eagi_proxy.c:217
void * readSignal(void *ptr)
Definition: eagi_proxy.c:188
#define COMMAND_PORT
Definition: eagi_proxy.c:60
char * winbuf
Definition: eagi_proxy.c:72
void finalize()
Definition: eagi_proxy.c:154
char * be
Definition: eagi_proxy.c:73
char connected
Definition: eagi_proxy.c:82
void read_full(int file, char *buffer, int num)
Definition: eagi_proxy.c:200
pthread_t signal_thread
Definition: eagi_proxy.c:97
void setnonblocking(int desc)
Definition: eagi_proxy.c:402
char * bs
Definition: eagi_proxy.c:73
#define WINBUF_NUM
Definition: eagi_proxy.c:71
char * end
Definition: eagi_proxy.c:73
void write_buf(int file, char *buffer, int num)
Definition: eagi_proxy.c:312
pthread_mutex_t command_mutex
Definition: eagi_proxy.c:96
pthread_t stdin_thread
Definition: eagi_proxy.c:97
int speech_desc
Definition: eagi_proxy.c:81
int command_desc
Definition: eagi_proxy.c:80
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
int read_some(int file, char *buffer, int size)
Definition: eagi_proxy.c:281
#define WINSIZE
Definition: eagi_proxy.c:68
int main()
Definition: eagi_proxy.c:107
int write_amap(int file, char *buffer, int num)
Definition: eagi_proxy.c:382
#define BUFSIZE
Definition: eagi_proxy.c:65
void * readStdin(void *ptr)
Definition: eagi_proxy.c:161
#define SIGNAL_PORT
Definition: eagi_proxy.c:59
char window[WINSIZE]
Definition: eagi_proxy.c:69
char * address
Definition: f2c.h:59
static const char name[]
Definition: format_mp3.c:68
char * malloc()
void free()
#define gethostbyname
Definition: lock.h:639
#define pthread_create
Definition: lock.h:642
#define pthread_mutex_lock
Definition: lock.h:625
#define pthread_mutex_t
Definition: lock.h:622
#define pthread_mutex_unlock
Definition: lock.h:626
#define pthread_mutex_init
Definition: lock.h:628
#define EXIT_FAILURE
int errno
#define NULL
Definition: resample.c:96
static struct test_val c
Time-related functions and macros.