added exporting/importing bchannel stacks to the remote application
[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
48 int sock;
49
50 struct admin_list {
51         struct admin_list *next;
52         struct admin_msg msg;
53 } *admin_first = NULL;
54
55 /*
56  * enque message from asterisk
57  */
58 int admin_asterisk(int message_type, union parameter *param)
59 {
60         struct admin_list *admin, **adminp;
61
62         adminp = &admin_first;
63         while(*adminp)
64                 adminp = &((*adminp)->next);
65         admin = (struct admin_list *)MALLOC(sizeof(struct admin_list));
66         *adminp = admin;
67
68         admin->msg.type = message_type;
69         memcpy(&admin->msg.param, param, sizeof(union parameter));
70
71         return(0);
72 }
73
74
75 /* asterisk handler
76  * warning! not thread safe
77  * returns -1 for socket error, 0 for no work, 1 for work
78  */
79 int handle_socket(void)
80 {
81         int work = 0;
82         int len;
83         struct admin_message msg;
84         struct admin_list *admin;
85
86         /* read from socket */
87         len = read(sock, &msg, sizeof(msg));
88         if (len == 0)
89         {
90                 printf("Socket closed\n");
91                 return(-1); // socket closed
92         }
93         if (len > 0)
94         {
95                 if (len != sizeof(msg))
96                 {
97                         fprintf(stderr, "Socket short read (%d)\n", len);
98                         return(-1); // socket error
99                 }
100                 if (msg.message != ADMIN_MESSAGE)
101                 {
102                         fprintf(stderr, "Socket received illegal message %d\n", msg.message);
103                         return(-1); // socket error
104                 }
105                 printf("message received %d\n", msg.u.msg.type);
106                 work = 1;
107         } else
108         {
109                 if (errno != EWOULDBLOCK)
110                 {
111                         fprintf(stderr, "Socket error %d\n", errno);
112                         return(-1);
113                 }
114         }
115
116         /* write to socket */
117         if (!admin_first)
118                 return(work);
119         admin = admin_first;
120         len = write(sock, &admin->msg, sizeof(msg));
121         if (len == 0)
122         {
123                 printf("Socket closed\n");
124                 return(-1); // socket closed
125         }
126         if (len > 0)
127         {
128                 if (len != sizeof(msg))
129                 {
130                         fprintf(stderr, "Socket short write (%d)\n", len);
131                         return(-1); // socket error
132                 }
133                 /* free head */
134                 admin_first = admin->next;
135                 FREE(admin, 0);
136
137                 work = 1;
138         } else
139         {
140                 if (errno != EWOULDBLOCK)
141                 {
142                         fprintf(stderr, "Socket error %d\n", errno);
143                         return(-1);
144                 }
145         }
146
147         return(work);
148 }
149
150 /*
151  * main function
152  */
153 int main(int argc, char *argv[])
154 {
155         char *socket_name = SOCKET_NAME;
156         int conn;
157         struct sockaddr_un sock_address;
158         int ret;
159         unsigned long on = 1;
160         union parameter param;
161
162         /* open socket */
163         if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
164         {
165                 fprintf(stderr, "Failed to create socket.\n");
166                 exit(EXIT_FAILURE);
167         }
168
169         /* set socket address and name */
170         memset(&sock_address, 0, sizeof(sock_address));
171         sock_address.sun_family = PF_UNIX;
172         UCPY(sock_address.sun_path, socket_name);
173
174         /* connect socket */
175         if ((conn = connect(sock, (struct sockaddr *)&sock_address, SUN_LEN(&sock_address))) < 0)
176         {
177                 close(sock);
178                 fprintf(stderr, "Failed to connect to socket \"%s\".\nIs LCR running?\n", sock_address.sun_path);
179                 exit(EXIT_FAILURE);
180         }
181
182         /* set non-blocking io */
183         if (ioctl(sock, FIONBIO, (unsigned char *)(&on)) < 0)
184         {
185                 close(sock);
186                 fprintf(stderr, "Failed to set socket into non-blocking IO.\n");
187                 exit(EXIT_FAILURE);
188         }
189
190         /* enque hello message */
191         memset(&param, 0, sizeof(param));
192         SCPY(param.hello.application, "asterisk");
193         admin_asterisk(MESSAGE_HELLO, &param);
194
195         while(42)
196         {
197                 ret = handle_socket();
198                 if (ret < 0)
199                         break;
200                 if (!ret)
201                         usleep(30000);
202         }
203         
204         /* close socket */      
205         close(sock);
206         /* now we say good bye */
207         if (ret)
208         {
209                 printf("%s\n", ret);
210                 exit(EXIT_FAILURE);
211         }
212 }
213
214
215
216
217