1 /*****************************************************************************\
3 ** Linux Call Router **
5 **---------------------------------------------------------------------------**
6 ** Copyright: Andreas Eversberg **
8 ** Asterisk socket client **
10 \*****************************************************************************/
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.
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.
23 Make a MESSAGE_SETUP or receive a MESSAGE_SETUP with the reference.
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
36 #include <sys/types.h>
40 #include <sys/ioctl.h>
41 #include <sys/socket.h>
44 #include "extension.h"
48 #include "asterisk_client.h"
53 struct admin_list *next;
55 } *admin_first = NULL;
58 * channel and call instances
60 struct chan_bchannel *bchannel_first;
61 struct chan_call *call_first;
63 struct chan_bchannel *find_bchannel_addr(unsigned long addr)
65 struct chan_bchannel *bchannel = bchannel_first;
69 if (bchannel->addr == addr)
71 bchannel = bchannel->next;
76 struct chan_bchannel *find_bchannel_ref(unsigned long ref)
78 struct chan_bchannel *bchannel = bchannel_first;
82 if (bchannel->ref == ref)
84 bchannel = bchannel->next;
89 struct chan_call *find_call_ref(unsigned long ref)
91 struct chan_call *call = call_first;
102 struct chan_call *find_call_addr(unsigned long addr)
104 struct chan_call *call = call_first;
108 if (call->addr == addr)
115 struct chan_bchannel *alloc_bchannel(void)
117 struct chan_bchannel **bchannelp = &bchannel_first;
120 bchannelp = &((*bchannelp)->next);
122 *bchannelp = (struct chan_bchannel *)MALLOC(sizeof(struct chan_bchannel));
126 void free_bchannel(struct chan_bchannel *bchannel)
128 struct chan_bchannel **temp = &bchannel_first;
132 if (*temp == bchannel)
134 *temp = (*temp)->next;
138 temp = &((*temp)->next);
142 struct chan_call *alloc_call(void)
144 struct chan_call **callp = &call_first;
147 callp = &((*callp)->next);
149 *callp = (struct chan_call *)MALLOC(sizeof(struct chan_call));
153 void free_call(struct chan_call *call)
155 struct chan_call **temp = &call_first;
161 *temp = (*temp)->next;
165 temp = &((*temp)->next);
171 * enque message to LCR
173 int send_message(int message_type, unsigned long ref, union parameter *param)
175 struct admin_list *admin, **adminp;
177 adminp = &admin_first;
179 adminp = &((*adminp)->next);
180 admin = (struct admin_list *)MALLOC(sizeof(struct admin_list));
183 admin->msg.type = message_type;
184 admin->msg.ref = ref;
185 memcpy(&admin->msg.param, param, sizeof(union parameter));
191 * message received from LCR
193 int receive_message(int message_type, unsigned long ref, union parameter *param)
195 union parameter newparam;
196 struct chan_bchannel *bchannel;
197 struct chan_call *call;
199 memset(&newparam, 0, sizeof(union parameter));
201 /* handle bchannel message*/
202 if (message_type == MESSAGE_BCHANNEL)
204 switch(param->bchannel.type)
206 case BCHANNEL_ASSIGN:
207 if ((bchannel = find_bchannel_addr(param->bchannel.addr)))
209 fprintf(stderr, "error: bchannel addr %x already assigned.\n", param->bchannel.addr);
212 /* create bchannel */
213 bchannel = alloc_bchannel();
214 bchannel->addr = param->bchannel.addr;
215 /* in case, ref is not set, this bchannel instance must
216 * be created until it is removed again by LCR */
218 if ((call = find_call_ref(ref)))
221 call->addr = param->bchannel.addr;
226 newparam.bchannel.type = BCHANNEL_ASSIGN_ACK;
227 newparam.bchannel.addr = param->bchannel.addr;
228 send_message(MESSAGE_BCHANNEL, 0, &newparam);
231 case BCHANNEL_REMOVE:
232 if (!(bchannel = find_bchannel_addr(param->bchannel.addr)))
234 fprintf(stderr, "error: bchannel addr %x not assigned.\n", param->bchannel.addr);
237 /* unlink from call */
238 if ((call = find_call_ref(bchannel->ref)))
242 /* remove bchannel */
243 free_bchannel(bchannel);
246 newparam.bchannel.type = BCHANNEL_REMOVE_ACK;
247 newparam.bchannel.addr = param->bchannel.addr;
248 send_message(MESSAGE_BCHANNEL, 0, &newparam);
253 fprintf(stderr, "received unknown bchannel message %d\n", param->bchannel.type);
259 if (message_type == MESSAGE_NEWREF)
261 if (param->direction)
263 /* new ref from lcr */
264 if (!ref || find_call_ref(ref))
266 fprintf(stderr, "illegal new ref %d received\n", ref);
273 /* new ref, as requested from this remote application */
274 call = find_call_ref(0);
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);
284 #warning process call (send setup, if pending)
292 fprintf(stderr, "received message %d without ref\n", message_type);
295 call = find_call_ref(ref);
298 /* ignore ref that is not used (anymore) */
302 /* handle messages */
305 #warning we must see if ref is a reply or a request, do we??
306 case MESSAGE_RELEASE:
307 #warning release call
312 #warning handle incoming setup, send to asterisk
320 * warning! not thread safe
321 * returns -1 for socket error, 0 for no work, 1 for work
323 int handle_socket(void)
327 struct admin_message msg;
328 struct admin_list *admin;
330 /* read from socket */
331 len = read(sock, &msg, sizeof(msg));
334 printf("Socket closed\n");
335 return(-1); // socket closed
339 if (len != sizeof(msg))
341 fprintf(stderr, "Socket short read (%d)\n", len);
342 return(-1); // socket error
344 if (msg.message != ADMIN_MESSAGE)
346 fprintf(stderr, "Socket received illegal message %d\n", msg.message);
347 return(-1); // socket error
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);
354 if (errno != EWOULDBLOCK)
356 fprintf(stderr, "Socket error %d\n", errno);
361 /* write to socket */
365 len = write(sock, &admin->msg, sizeof(msg));
368 printf("Socket closed\n");
369 return(-1); // socket closed
373 if (len != sizeof(msg))
375 fprintf(stderr, "Socket short write (%d)\n", len);
376 return(-1); // socket error
379 admin_first = admin->next;
385 if (errno != EWOULDBLOCK)
387 fprintf(stderr, "Socket error %d\n", errno);
398 int main(int argc, char *argv[])
400 char *socket_name = SOCKET_NAME;
402 struct sockaddr_un sock_address;
404 unsigned long on = 1;
405 union parameter param;
408 if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
410 fprintf(stderr, "Failed to create socket.\n");
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);
420 if ((conn = connect(sock, (struct sockaddr *)&sock_address, SUN_LEN(&sock_address))) < 0)
423 fprintf(stderr, "Failed to connect to socket \"%s\".\nIs LCR running?\n", sock_address.sun_path);
427 /* set non-blocking io */
428 if (ioctl(sock, FIONBIO, (unsigned char *)(&on)) < 0)
431 fprintf(stderr, "Failed to set socket into non-blocking IO.\n");
435 /* enque hello message */
436 memset(¶m, 0, sizeof(param));
437 SCPY(param.hello.application, "asterisk");
438 send_message(MESSAGE_HELLO, 0, ¶m);
442 ret = handle_socket();
451 /* now we say good bye */