fixes
[lcr.git] / asterisk_client.c
1 /*****************************************************************************\
2 **                                                                           **
3 ** Linux Call Router                                                         **
4 **                                                                           **
5 **---------------------------------------------------------------------------**
6 ** Copyright: Andreas Eversberg                                              **
7 **                                                                           **
8 ** Asterisk socket client                                                    **
9 **                                                                           **
10 \*****************************************************************************/
11
12 /*
13
14 How does it work:
15
16 To connect, open a socket and send a MESSAGE_HELLO to admin socket with
17 the application name. This name is unique an can be used for routing calls.
18
19 To make a call, send a MESSAGE_NEWREF and a new reference is received.
20 When receiving a call, a new reference is received.
21 The reference is received with MESSAGE_NEWREF.
22
23 Make a MESSAGE_SETUP or receive a MESSAGE_SETUP with the reference.
24
25 To release call and reference, send or receive MESSAGE_RELEASE.
26 From that point on, the ref is not valid, so no other message may be sent
27 with that reference.
28
29 */
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <stdarg.h>
35 #include <errno.h>
36 #include <sys/types.h>
37 #include <time.h>
38 #include <unistd.h>
39 #include <fcntl.h>
40 #include <sys/ioctl.h>
41 #include <sys/socket.h>
42 #include <sys/un.h>
43 #include "macro.h"
44 #include "extension.h"
45 #include "message.h"
46 #include "admin.h"
47 #include "cause.h"
48 #include "asterisk_client.h"
49
50 int sock;
51
52 struct admin_list {
53         struct admin_list *next;
54         struct admin_msg msg;
55 } *admin_first = NULL;
56
57 /*
58  * channel and call instances
59  */
60 struct chan_bchannel *bchannel_first;
61 struct chan_call *call_first;
62
63 struct chan_bchannel *find_bchannel_handle(unsigned long addr)
64 {
65         struct chan_bchannel *bchannel = bchannel_first;
66
67         while(bchannel)
68         {
69                 if (bchannel->addr == addr)
70                         break;
71                 bchannel = bchannel->next;
72         }
73         return(bchannel);
74 }
75
76 struct chan_bchannel *find_bchannel_ref(unsigned long ref)
77 {
78         struct chan_bchannel *bchannel = bchannel_first;
79
80         while(bchannel)
81         {
82                 if (bchannel->ref == ref)
83                         break;
84                 bchannel = bchannel->next;
85         }
86         return(bchannel);
87 }
88
89 struct chan_call *find_call_ref(unsigned long ref)
90 {
91         struct chan_call *call = call_first;
92
93         while(call)
94         {
95                 if (call->ref == ref)
96                         break;
97                 call = call->next;
98         }
99         return(call);
100 }
101
102 struct chan_call *find_call_addr(unsigned long addr)
103 {
104         struct chan_call *call = call_first;
105
106         while(call)
107         {
108                 if (call->addr == addr)
109                         break;
110                 call = call->next;
111         }
112         return(call);
113 }
114
115 struct chan_bchannel *alloc_bchannel(void)
116 {
117         struct chan_bchannel **bchannelp = &bchannel_first;
118
119         while(*bchannelp)
120                 bchannelp = &((*bchannelp)->next);
121
122         *bchannelp = (struct chan_bchannel *)MALLOC(sizeof(struct chan_bchannel));
123         return(*bchannelp);
124 }
125
126 void free_bchannel(struct chan_bchannel *bchannel)
127 {
128         struct chan_bchannel **temp = &bchannel_first;
129
130         while(*temp)
131         {
132                 if (*temp == bchannel)
133                 {
134                         *temp = (*temp)->next;
135                         free(bchannel);
136                         return;
137                 }
138                 temp = &((*temp)->next);
139         }
140 }
141
142 struct chan_call *alloc_call(void)
143 {
144         struct chan_call **callp = &call_first;
145
146         while(*callp)
147                 callp = &((*callp)->next);
148
149         *callp = (struct chan_call *)MALLOC(sizeof(struct chan_call));
150         return(*callp);
151 }
152
153 void free_call(struct chan_call *call)
154 {
155         struct chan_call **temp = &call_first;
156
157         while(*temp)
158         {
159                 if (*temp == call)
160                 {
161                         *temp = (*temp)->next;
162                         free(call);
163                         return;
164                 }
165                 temp = &((*temp)->next);
166         }
167 }
168
169
170 /*
171  * enque message to LCR
172  */
173 int send_message(int message_type, unsigned long ref, union parameter *param)
174 {
175         struct admin_list *admin, **adminp;
176
177         adminp = &admin_first;
178         while(*adminp)
179                 adminp = &((*adminp)->next);
180         admin = (struct admin_list *)MALLOC(sizeof(struct admin_list));
181         *adminp = admin;
182
183         admin->msg.type = message_type;
184         admin->msg.ref = ref;
185         memcpy(&admin->msg.param, param, sizeof(union parameter));
186
187         return(0);
188 }
189
190 /*
191  * message received from LCR
192  */
193 int receive_message(int message_type, unsigned long ref, union parameter *param)
194 {
195         union parameter newparam;
196         struct chan_bchannel *bchannel;
197         struct chan_call *call;
198
199         memset(&newparam, 0, sizeof(union parameter));
200
201         /* handle bchannel message*/
202         if (message_type == MESSAGE_BCHANNEL)
203         {
204                 switch(param->bchannel.type)
205                 {
206                         case BCHANNEL_ASSIGN:
207                         if ((bchannel = find_bchannel_handle(param->bchannel.handle)))
208                         {
209                                 fprintf(stderr, "error: bchannel handle %x already assigned.\n", param->bchannel.handle);
210                                 return(-1);
211                         }
212                         /* create bchannel */
213                         bchannel = alloc_bchannel();
214                         bchannel->addr = param->bchannel.handle;
215                         /* in case, ref is not set, this bchannel instance must
216                          * be created until it is removed again by LCR */
217                         /* link to call */
218                         if ((call = find_call_ref(ref)))
219                         {
220                                 bchannel->ref = ref;
221                                 call->addr = param->bchannel.handle;
222                         }
223
224 #warning open stack
225                         /* acknowledge */
226                         newparam.bchannel.type = BCHANNEL_ASSIGN_ACK;
227                         newparam.bchannel.handle = param->bchannel.handle;
228                         send_message(MESSAGE_BCHANNEL, 0, &newparam);
229                         break;
230
231                         case BCHANNEL_REMOVE:
232                         if (!(bchannel = find_bchannel_handle(param->bchannel.handle)))
233                         {
234                                 fprintf(stderr, "error: bchannel handle %x not assigned.\n", param->bchannel.handle);
235                                 return(-1);
236                         }
237                         /* unlink from call */
238                         if ((call = find_call_ref(bchannel->ref)))
239                         {
240                                 call->addr = 0;
241                         }
242                         /* remove bchannel */
243                         free_bchannel(bchannel);
244 #warning close stack
245                         /* acknowledge */
246                         newparam.bchannel.type = BCHANNEL_REMOVE_ACK;
247                         newparam.bchannel.handle = param->bchannel.handle;
248                         send_message(MESSAGE_BCHANNEL, 0, &newparam);
249                         
250                         break;
251
252                         default:
253                         fprintf(stderr, "received unknown bchannel message %d\n", param->bchannel.type);
254                 }
255                 return(0);
256         }
257
258         /* handle new ref */
259         if (message_type == MESSAGE_NEWREF)
260         {
261                 if (param->direction)
262                 {
263                         /* new ref from lcr */
264                         if (!ref || find_call_ref(ref))
265                         {
266                                 fprintf(stderr, "illegal new ref %d received\n", ref);
267                                 return(-1);
268                         }
269                         call = alloc_call();
270                         call->ref = ref;
271                 } else
272                 {
273                         /* new ref, as requested from this remote application */
274                         call = find_call_ref(0);
275                         if (!call)
276                         {
277                                 /* send release, if ref does not exist */
278                                 newparam.disconnectinfo.cause = CAUSE_NORMAL;
279                                 newparam.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
280                                 send_message(MESSAGE_RELEASE, ref, &newparam);
281                                 return(0);
282                         }
283                         call->ref = ref;
284 #warning process call (send setup, if pending)
285                 }
286                 return(0);
287         }
288
289         /* check ref */
290         if (!ref)
291         {
292                 fprintf(stderr, "received message %d without ref\n", message_type);
293                 return(-1);
294         }
295         call = find_call_ref(ref);
296         if (!call)
297         {
298                 /* ignore ref that is not used (anymore) */
299                 return(0);
300         }
301
302         /* handle messages */
303         switch(message_type)
304         {
305 #warning we must see if ref is a reply or a request, do we??
306                 case MESSAGE_RELEASE:
307 #warning release call
308                 free_call(call);
309                 return(0);
310
311                 case MESSAGE_SETUP:
312 #warning handle incoming setup, send to asterisk
313                 break;
314         }
315         return(0);
316 }
317
318
319 /* asterisk handler
320  * warning! not thread safe
321  * returns -1 for socket error, 0 for no work, 1 for work
322  */
323 int handle_socket(void)
324 {
325         int work = 0;
326         int len;
327         struct admin_message msg;
328         struct admin_list *admin;
329
330         /* read from socket */
331         len = read(sock, &msg, sizeof(msg));
332         if (len == 0)
333         {
334                 printf("Socket closed\n");
335                 return(-1); // socket closed
336         }
337         if (len > 0)
338         {
339                 if (len != sizeof(msg))
340                 {
341                         fprintf(stderr, "Socket short read (%d)\n", len);
342                         return(-1); // socket error
343                 }
344                 if (msg.message != ADMIN_MESSAGE)
345                 {
346                         fprintf(stderr, "Socket received illegal message %d\n", msg.message);
347                         return(-1); // socket error
348                 }
349                 receive_message(msg.u.msg.type, msg.u.msg.ref, &msg.u.msg.param);
350                 printf("message received %d\n", msg.u.msg.type);
351                 work = 1;
352         } else
353         {
354                 if (errno != EWOULDBLOCK)
355                 {
356                         fprintf(stderr, "Socket error %d\n", errno);
357                         return(-1);
358                 }
359         }
360
361         /* write to socket */
362         if (!admin_first)
363                 return(work);
364         admin = admin_first;
365         len = write(sock, &admin->msg, sizeof(msg));
366         if (len == 0)
367         {
368                 printf("Socket closed\n");
369                 return(-1); // socket closed
370         }
371         if (len > 0)
372         {
373                 if (len != sizeof(msg))
374                 {
375                         fprintf(stderr, "Socket short write (%d)\n", len);
376                         return(-1); // socket error
377                 }
378                 /* free head */
379                 admin_first = admin->next;
380                 FREE(admin, 0);
381
382                 work = 1;
383         } else
384         {
385                 if (errno != EWOULDBLOCK)
386                 {
387                         fprintf(stderr, "Socket error %d\n", errno);
388                         return(-1);
389                 }
390         }
391
392         return(work);
393 }
394
395 /*
396  * main function
397  */
398 int main(int argc, char *argv[])
399 {
400         char *socket_name = SOCKET_NAME;
401         int conn;
402         struct sockaddr_un sock_address;
403         int ret;
404         unsigned long on = 1;
405         union parameter param;
406
407         /* open socket */
408         if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
409         {
410                 fprintf(stderr, "Failed to create socket.\n");
411                 exit(EXIT_FAILURE);
412         }
413
414         /* set socket address and name */
415         memset(&sock_address, 0, sizeof(sock_address));
416         sock_address.sun_family = PF_UNIX;
417         UCPY(sock_address.sun_path, socket_name);
418
419         /* connect socket */
420         if ((conn = connect(sock, (struct sockaddr *)&sock_address, SUN_LEN(&sock_address))) < 0)
421         {
422                 close(sock);
423                 fprintf(stderr, "Failed to connect to socket \"%s\".\nIs LCR running?\n", sock_address.sun_path);
424                 exit(EXIT_FAILURE);
425         }
426
427         /* set non-blocking io */
428         if (ioctl(sock, FIONBIO, (unsigned char *)(&on)) < 0)
429         {
430                 close(sock);
431                 fprintf(stderr, "Failed to set socket into non-blocking IO.\n");
432                 exit(EXIT_FAILURE);
433         }
434
435         /* enque hello message */
436         memset(&param, 0, sizeof(param));
437         SCPY(param.hello.application, "asterisk");
438         send_message(MESSAGE_HELLO, 0, &param);
439
440         while(42)
441         {
442                 ret = handle_socket();
443                 if (ret < 0)
444                         break;
445                 if (!ret)
446                         usleep(30000);
447         }
448         
449         /* close socket */      
450         close(sock);
451         /* now we say good bye */
452         if (ret)
453         {
454                 printf("%s\n", ret);
455                 exit(EXIT_FAILURE);
456         }
457 }
458
459
460
461
462