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