Version 0.1.1 from FTP
[asterisk/asterisk.git] / channel.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Channel Management
5  * 
6  * Copyright (C) 1999, Mark Spencer
7  *
8  * Mark Spencer <markster@linux-support.net>
9  *
10  * This program is free software, distributed under the terms of
11  * the GNU General Public License
12  */
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <pthread.h>
17 #include <string.h>
18 #include <sys/time.h>
19 #include <signal.h>
20 #include <errno.h>
21 #include <asterisk/sched.h>
22 #include <asterisk/options.h>
23 #include <asterisk/channel.h>
24 #include <asterisk/channel_pvt.h>
25 #include <asterisk/logger.h>
26 #include <asterisk/file.h>
27 #include <asterisk/translate.h>
28
29 struct chanlist {
30         char type[80];
31         char description[80];
32         int capabilities;
33         struct ast_channel * (*requester)(char *type, int format, void *data);
34         struct chanlist *next;
35 } *backends = NULL;
36
37 struct ast_channel *channels = NULL;
38
39 /* Protect the channel list (highly unlikely that two things would change
40    it at the same time, but still! */
41    
42 static pthread_mutex_t chlock = PTHREAD_MUTEX_INITIALIZER;
43
44 int ast_channel_register(char *type, char *description, int capabilities,
45                 struct ast_channel *(*requester)(char *type, int format, void *data))
46 {
47         struct chanlist *chan, *last=NULL;
48         if (pthread_mutex_lock(&chlock)) {
49                 ast_log(LOG_WARNING, "Unable to lock channel list\n");
50                 return -1;
51         }
52         chan = backends;
53         while(chan) {
54                 if (!strcasecmp(type, chan->type)) {
55                         ast_log(LOG_WARNING, "Already have a handler for type '%s'\n", type);
56                         pthread_mutex_unlock(&chlock);
57                         return -1;
58                 }
59                 last = chan;
60                 chan = chan->next;
61         }
62         chan = malloc(sizeof(struct chanlist));
63         if (!chan) {
64                 ast_log(LOG_WARNING, "Out of memory\n");
65                 pthread_mutex_unlock(&chlock);
66                 return -1;
67         }
68         strncpy(chan->type, type, sizeof(chan->type));
69         strncpy(chan->description, description, sizeof(chan->description));
70         chan->capabilities = capabilities;
71         chan->requester = requester;
72         chan->next = NULL;
73         if (last)
74                 last->next = chan;
75         else
76                 backends = chan;
77         if (option_debug)
78                 ast_log(LOG_DEBUG, "Registered handler for '%s' (%s)\n", chan->type, chan->description);
79         else if (option_verbose > 1)
80                 ast_verbose( VERBOSE_PREFIX_2 "Registered channel type '%s' (%s)\n", chan->type, chan->description);
81         pthread_mutex_unlock(&chlock);
82         return 0;
83 }
84
85 struct ast_channel *ast_channel_alloc(void)
86 {
87         struct ast_channel *tmp;
88         struct ast_channel_pvt *pvt;
89         pthread_mutex_lock(&chlock);
90         tmp = malloc(sizeof(struct ast_channel));
91         memset(tmp, 0, sizeof(struct ast_channel));
92         if (tmp) {
93                 pvt = malloc(sizeof(struct ast_channel_pvt));
94                 if (pvt) {
95                         memset(pvt, 0, sizeof(struct ast_channel_pvt));
96                         tmp->sched = sched_context_create();
97                         if (tmp->sched) {
98                                 tmp->fd = -1;
99                                 strncpy(tmp->name, "**Unknown**", sizeof(tmp->name));
100                                 tmp->pvt = pvt;
101                                 tmp->state = AST_STATE_DOWN;
102                                 tmp->stack = -1;
103                                 tmp->streamid = -1;
104                                 tmp->appl = NULL;
105                                 tmp->data = NULL;
106                                 pthread_mutex_init(&tmp->lock, NULL);
107                                 strncpy(tmp->context, "default", sizeof(tmp->context));
108                                 strncpy(tmp->exten, "s", sizeof(tmp->exten));
109                                 tmp->priority=1;
110                                 tmp->next = channels;
111                                 channels= tmp;
112                         } else {
113                                 ast_log(LOG_WARNING, "Unable to create schedule context\n");
114                                 free(tmp);
115                                 tmp = NULL;
116                         }
117                 } else {
118                         ast_log(LOG_WARNING, "Out of memory\n");
119                         free(tmp);
120                         tmp = NULL;
121                 }
122         } else 
123                 ast_log(LOG_WARNING, "Out of memory\n");
124         pthread_mutex_unlock(&chlock);
125         return tmp;
126 }
127
128 struct ast_channel *ast_channel_walk(struct ast_channel *prev)
129 {
130         struct ast_channel *l, *ret=NULL;
131         pthread_mutex_lock(&chlock);
132         l = channels;
133         if (!prev) {
134                 pthread_mutex_unlock(&chlock);
135                 return l;
136         }
137         while(l) {
138                 if (l == prev)
139                         ret = l->next;
140                 l = l->next;
141         }
142         pthread_mutex_unlock(&chlock);
143         return ret;
144         
145 }
146
147 void ast_channel_free(struct ast_channel *chan)
148 {
149         struct ast_channel *last=NULL, *cur;
150         pthread_mutex_lock(&chlock);
151         cur = channels;
152         while(cur) {
153                 if (cur == chan) {
154                         if (last)
155                                 last->next = cur->next;
156                         else
157                                 channels = cur->next;
158                         break;
159                 }
160                 last = cur;
161                 cur = cur->next;
162         }
163         if (!cur)
164                 ast_log(LOG_WARNING, "Unable to find channel in list\n");
165         if (chan->pvt->pvt)
166                 ast_log(LOG_WARNING, "Channel '%s' may not have been hung up properly\n", chan->name);
167         if (chan->trans)
168                 ast_log(LOG_WARNING, "Hard hangup called on '%s' while a translator is in place!  Expect a failure.\n", chan->name);
169         if (chan->pbx) 
170                 ast_log(LOG_WARNING, "PBX may not have been terminated properly on '%s'\n", chan->name);
171         if (chan->dnid)
172                 free(chan->dnid);
173         if (chan->callerid)
174                 free(chan->callerid);   
175         pthread_mutex_destroy(&chan->lock);
176         free(chan);
177         pthread_mutex_unlock(&chlock);
178 }
179
180 int ast_softhangup(struct ast_channel *chan)
181 {
182         int res = 0;
183         if (chan->stream)
184                 ast_stopstream(chan);
185         if (option_debug)
186                 ast_log(LOG_DEBUG, "Soft-Hanging up channel '%s'\n", chan->name);
187         if (chan->trans)
188                 ast_log(LOG_WARNING, "Soft hangup called on '%s' while a translator is in place!  Expect a failure.\n", chan->name);
189         if (chan->pvt->hangup)
190                 res = chan->pvt->hangup(chan);
191         if (chan->pvt->pvt)
192                 ast_log(LOG_WARNING, "Channel '%s' may not have been hung up properly\n", chan->name);
193         if (chan->pbx) 
194                 ast_log(LOG_WARNING, "PBX may not have been terminated properly on '%s'\n", chan->name);        
195         /* Interrupt any select call or such */
196         if (chan->blocking)
197                 pthread_kill(chan->blocker, SIGURG);
198         return res;
199 }
200
201 int ast_hangup(struct ast_channel *chan)
202 {
203         int res = 0;
204         if (chan->stream)
205                 ast_stopstream(chan);
206         if (chan->sched)
207                 sched_context_destroy(chan->sched);
208         if (chan->blocking)
209                 ast_log(LOG_WARNING, "Hard hangup called, while fd is blocking!  Expect a failure\n");
210         if (option_debug)
211                 ast_log(LOG_DEBUG, "Hanging up channel '%s'\n", chan->name);
212         if (chan->pvt->hangup)
213                 res = chan->pvt->hangup(chan);
214         ast_channel_free(chan);
215         return res;
216 }
217
218 void ast_channel_unregister(char *type)
219 {
220         struct chanlist *chan, *last=NULL;
221         if (option_debug)
222                 ast_log(LOG_DEBUG, "Unregistering channel type '%s'\n", type);
223         if (pthread_mutex_lock(&chlock)) {
224                 ast_log(LOG_WARNING, "Unable to lock channel list\n");
225                 return;
226         }
227         chan = backends;
228         while(chan) {
229                 if (!strcasecmp(chan->type, type)) {
230                         if (last)
231                                 last->next = chan->next;
232                         else
233                                 backends = backends->next;
234                         free(chan);
235                         pthread_mutex_unlock(&chlock);
236                         return;
237                 }
238                 last = chan;
239                 chan = chan->next;
240         }
241         pthread_mutex_unlock(&chlock);
242 }
243
244 int ast_answer(struct ast_channel *chan)
245 {
246         /* Answer the line, if possible */
247         if (chan->state == AST_STATE_RING) {
248                 if (chan->pvt->answer)
249                         return chan->pvt->answer(chan);
250         }
251         return 0;
252 }
253
254 int ast_waitfor_n_fd(int *fds, int n, int *ms)
255 {
256         /* Wait for x amount of time on a file descriptor to have input.  */
257         struct timeval tv;
258         fd_set rfds, efds;
259         int res;
260         int x, max=-1;
261         int winner = -1;
262         
263         tv.tv_sec = *ms / 1000;
264         tv.tv_usec = (*ms % 1000) * 1000;
265         FD_ZERO(&rfds);
266         FD_ZERO(&efds);
267         for (x=0;x<n;x++) {
268                 FD_SET(fds[x], &rfds);
269                 FD_SET(fds[x], &efds);
270                 if (fds[x] > max)
271                         max = fds[x];
272         }
273         if (*ms >= 0) 
274                 res = select(max + 1, &rfds, NULL, &efds, &tv);
275         else
276                 res = select(max + 1, &rfds, NULL, &efds, NULL);
277         for (x=0;x<n;x++) {
278                 if ((FD_ISSET(fds[x], &rfds) || FD_ISSET(fds[x], &efds)) && (winner < 0))
279                         winner = fds[x];
280         }
281         *ms = tv.tv_sec * 1000 + tv.tv_usec / 1000;
282         if (res < 0)
283                 *ms = -10;
284         return winner;
285 }
286
287 struct ast_channel *ast_waitfor_n(struct ast_channel **c, int n, int *ms)
288 {
289         /* Wait for x amount of time on a file descriptor to have input.  */
290         struct timeval tv;
291         fd_set rfds, efds;
292         int res;
293         int x, max=-1;
294         struct ast_channel *winner = NULL;
295         
296         tv.tv_sec = *ms / 1000;
297         tv.tv_usec = (*ms % 1000) * 1000;
298         FD_ZERO(&rfds);
299         FD_ZERO(&efds);
300         for (x=0;x<n;x++) {
301                 FD_SET(c[x]->fd, &rfds);
302                 FD_SET(c[x]->fd, &efds);
303                 CHECK_BLOCKING(c[x]);
304                 if (c[x]->fd > max)
305                         max = c[x]->fd;
306         }
307         if (*ms >= 0) 
308                 res = select(max + 1, &rfds, NULL, &efds, &tv);
309         else
310                 res = select(max + 1, &rfds, NULL, &efds, NULL);
311         for (x=0;x<n;x++) {
312                 c[x]->blocking = 0;
313                 if ((FD_ISSET(c[x]->fd, &rfds) || FD_ISSET(c[x]->fd, &efds)) && !winner)
314                         winner = c[x];
315         }
316         *ms = tv.tv_sec * 1000 + tv.tv_usec / 1000;
317         if (res < 0)
318                 *ms = -10;
319         return winner;
320 }
321
322 int ast_waitfor(struct ast_channel *c, int ms)
323 {
324         if (ast_waitfor_n(&c, 1, &ms)) {
325                 if (ms < 0)
326                         return -ms;
327                 return ms;
328         }
329         /* Error if ms < 0 */
330         if (ms < 0) 
331                 return -1;
332         return 0;
333 }
334
335 char ast_waitfordigit(struct ast_channel *c, int ms)
336 {
337         struct ast_frame *f;
338         char result = 0;
339         /* Wait for a digit, no more than ms milliseconds total. */
340         while(ms && !result) {
341                 ms = ast_waitfor(c, ms);
342                 if (ms < 0) /* Error */
343                         result = -1; 
344                 else if (ms > 0) {
345                         /* Read something */
346                         f = ast_read(c);
347                         if (f) {
348                                 if (f->frametype == AST_FRAME_DTMF) 
349                                         result = f->subclass;
350                                 ast_frfree(f);
351                         } else
352                                 result = -1;
353                 }
354         }
355         return result;
356 }
357
358 struct ast_frame *ast_read(struct ast_channel *chan)
359 {
360         struct ast_frame *f = NULL;
361         chan->blocker = pthread_self();
362         if (chan->pvt->read)
363                 f = chan->pvt->read(chan);
364         else
365                 ast_log(LOG_WARNING, "No read routine on channel %s\n", chan);
366         return f;
367 }
368
369 int ast_write(struct ast_channel *chan, struct ast_frame *fr)
370 {
371         int res = -1;
372         CHECK_BLOCKING(chan);
373         switch(fr->frametype) {
374         case AST_FRAME_CONTROL:
375                 /* XXX Interpret control frames XXX */
376                 ast_log(LOG_WARNING, "Don't know how to handle control frames yet\n");
377                 break;
378         case AST_FRAME_DTMF:
379                 
380                 if (chan->pvt->send_digit)
381                         res = chan->pvt->send_digit(chan, fr->subclass);
382                 break;
383         default:
384                 if (chan->pvt->write)
385                         res = chan->pvt->write(chan, fr);
386         }
387         chan->blocking = 0;
388         return res;
389 }
390
391 struct ast_channel *ast_request(char *type, int format, void *data)
392 {
393         struct chanlist *chan;
394         struct ast_channel *c = NULL;
395         if (pthread_mutex_lock(&chlock)) {
396                 ast_log(LOG_WARNING, "Unable to lock channel list\n");
397                 return NULL;
398         }
399         chan = backends;
400         while(chan) {
401                 if (!strcasecmp(type, chan->type)) {
402                         if (!(chan->capabilities & format)) {
403                                 format = ast_translator_best_choice(format, chan->capabilities);
404                         }
405                         if (chan->requester)
406                                 c = chan->requester(type, format, data);
407                         pthread_mutex_unlock(&chlock);
408                         break;
409                 }
410                 chan = chan->next;
411         }
412         if (!chan)
413                 ast_log(LOG_WARNING, "No channel type registered for '%s'\n", type);
414         return c;
415 }
416
417 int ast_call(struct ast_channel *chan, char *addr, int timeout) 
418 {
419         /* Place an outgoing call, but don't wait any longer than timeout ms before returning. 
420            If the remote end does not answer within the timeout, then do NOT hang up, but 
421            return anyway.  */
422         int res = -1;
423         if (chan->pvt->call)
424                 res = chan->pvt->call(chan, addr, timeout);
425         return res;
426 }
427
428 int ast_readstring(struct ast_channel *c, char *s, int len, int timeout, int ftimeout, char *enders)
429 {
430         int pos=0;
431         int to = ftimeout;
432         char d;
433         if (!len)
434                 return -1;
435         do {
436                 if (c->streamid > -1) {
437                         d = ast_waitstream(c, AST_DIGIT_ANY);
438                         ast_stopstream(c);
439                         if (!d)
440                                 d = ast_waitfordigit(c, to);
441                 } else {
442                         d = ast_waitfordigit(c, to);
443                 }
444                 if (d < 0)
445                         return -1;
446                 if (!strchr(enders, d))
447                         s[pos++] = d;
448                 if ((d == 0) || strchr(enders, d) || (pos >= len - 1)) {
449                         s[pos]='\0';
450                         return 0;
451                 }
452                 to = timeout;
453         } while(1);
454         /* Never reached */
455         return 0;
456 }