Merged revisions 331147,331200 via svnmerge from
[asterisk/asterisk.git] / addons / ooh323c / src / ooLogChan.c
1 /*
2  * Copyright (C) 2004-2005 by Objective Systems, Inc.
3  *
4  * This software is furnished under an open source license and may be 
5  * used and copied only in accordance with the terms of this license. 
6  * The text of the license may generally be found in the root 
7  * directory of this installation in the COPYING file.  It 
8  * can also be viewed online at the following URL:
9  *
10  *   http://www.obj-sys.com/open/license.html
11  *
12  * Any redistributions of this file including modified versions must 
13  * maintain this copyright notice.
14  *
15  *****************************************************************************/
16
17 #include "asterisk.h"
18 #include "asterisk/lock.h"
19
20 #include "ooCalls.h"
21 #include "ooh323ep.h"
22
23 /** Global endpoint structure */
24 extern OOH323EndPoint gH323ep;
25
26 OOLogicalChannel* ooAddNewLogicalChannel(OOH323CallData *call, int channelNo, 
27                                          int sessionID, char *dir, 
28                                          ooH323EpCapability *epCap)
29 {
30    OOLogicalChannel *pNewChannel=NULL, *pChannel=NULL;
31    OOMediaInfo *pMediaInfo = NULL;
32    OOTRACEDBGC5("Adding new media channel for cap %d dir %s (%s, %s)\n",
33                epCap->cap, dir, call->callType, call->callToken);
34    /* Create a new logical channel entry */
35    pNewChannel = (OOLogicalChannel*)memAlloc(call->pctxt, 
36                                                      sizeof(OOLogicalChannel));
37    if(!pNewChannel)
38    {
39       OOTRACEERR3("ERROR:Memory - ooAddNewLogicalChannel - pNewChannel "
40                   "(%s, %s)\n", call->callType, call->callToken);
41       return NULL;
42    }
43    
44    memset(pNewChannel, 0, sizeof(OOLogicalChannel));
45    pNewChannel->channelNo = channelNo;
46    pNewChannel->sessionID = sessionID;
47    pNewChannel->state = OO_LOGICALCHAN_IDLE;
48    pNewChannel->type = epCap->capType;
49    /*   strcpy(pNewChannel->type, type);*/
50    strcpy(pNewChannel->dir, dir);
51
52    pNewChannel->chanCap = epCap;
53    OOTRACEDBGC4("Adding new channel with cap %d (%s, %s)\n", epCap->cap,
54                 call->callType, call->callToken); 
55    /* As per standards, media control port should be same for all 
56       proposed channels with same session ID. However, most applications
57       use same media port for transmit and receive of audio streams. Infact,
58       testing of OpenH323 based asterisk assumed that same ports are used. 
59       Hence we first search for existing media ports for same session and use 
60       them. This should take care of all cases.
61    */
62    if(call->mediaInfo)
63    {
64       pMediaInfo = call->mediaInfo;
65       while(pMediaInfo)
66       {
67          if(!strcmp(pMediaInfo->dir, dir) &&
68             (pMediaInfo->cap == epCap->cap))
69          {
70             break;
71          }
72          pMediaInfo = pMediaInfo->next;
73       }
74    }
75     
76    if(pMediaInfo)
77    {
78       OOTRACEDBGC3("Using configured media info (%s, %s)\n", call->callType,
79                    call->callToken);
80       pNewChannel->localRtpPort = pMediaInfo->lMediaPort;
81       pNewChannel->localRtcpPort = pMediaInfo->lMediaCntrlPort;
82       /* If user application has not specified a specific ip and is using 
83          multihomed mode, substitute appropriate ip.
84       */
85       if(!strcmp(pMediaInfo->lMediaIP, "0.0.0.0") || !strcmp(pMediaInfo->lMediaIP, "::"))
86          strcpy(pNewChannel->localIP, call->localIP);
87       else
88          strcpy(pNewChannel->localIP, pMediaInfo->lMediaIP);
89    }
90    else{
91       OOTRACEDBGC3("Using default media info (%s, %s)\n", call->callType,
92                    call->callToken);
93       pNewChannel->localRtpPort = ooGetNextPort (OORTP);
94
95       /* Ensures that RTP port is an even one */
96       if((pNewChannel->localRtpPort & 1) == 1)
97         pNewChannel->localRtpPort = ooGetNextPort (OORTP);
98
99       pNewChannel->localRtcpPort = ooGetNextPort (OORTP);
100       strcpy(pNewChannel->localIP, call->localIP);
101    }
102    
103    /* Add new channel to the list */
104    pNewChannel->next = NULL;
105    if(!call->logicalChans) {
106       call->logicalChans = pNewChannel;
107    }
108    else{
109       pChannel = call->logicalChans;
110       while(pChannel->next)  pChannel = pChannel->next;
111       pChannel->next = pNewChannel;
112    }
113    
114    /* increment logical channels */
115    call->noOfLogicalChannels++;
116    OOTRACEINFO3("Created new logical channel entry (%s, %s)\n", call->callType,
117                 call->callToken);
118    return pNewChannel;
119 }
120
121 OOLogicalChannel* ooFindLogicalChannelByLogicalChannelNo(OOH323CallData *call,
122                                                          int ChannelNo)
123 {
124    OOLogicalChannel *pLogicalChannel=NULL;
125    if(!call->logicalChans)
126    {
127       OOTRACEWARN3("ERROR: No Open LogicalChannels - Failed "
128                   "FindLogicalChannelByChannelNo (%s, %s\n", call->callType,
129                    call->callToken);
130       return NULL;
131    }
132    pLogicalChannel = call->logicalChans;
133    while(pLogicalChannel)
134    {
135       if(pLogicalChannel->channelNo == ChannelNo)
136          break;
137       else
138          pLogicalChannel = pLogicalChannel->next;
139    }
140
141    return pLogicalChannel;
142 }
143
144 OOLogicalChannel * ooFindLogicalChannelByOLC(OOH323CallData *call, 
145                                H245OpenLogicalChannel *olc)
146 {
147    H245DataType * psDataType=NULL;
148    H245H2250LogicalChannelParameters * pslcp=NULL;
149    OOTRACEDBGC4("ooFindLogicalChannel by olc %d (%s, %s)\n", 
150             olc->forwardLogicalChannelNumber, call->callType, call->callToken);
151    if(olc->m.reverseLogicalChannelParametersPresent)
152    {
153       OOTRACEDBGC3("Finding receive channel (%s,%s)\n", call->callType, 
154                                                        call->callToken);
155       psDataType = &olc->reverseLogicalChannelParameters.dataType;
156       /* Only H2250LogicalChannelParameters are supported */
157       if(olc->reverseLogicalChannelParameters.multiplexParameters.t !=
158          T_H245OpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters_h2250LogicalChannelParameters){
159          OOTRACEERR4("Error:Invalid olc %d received (%s, %s)\n", 
160            olc->forwardLogicalChannelNumber, call->callType, call->callToken);
161          return NULL;
162       }
163       pslcp = olc->reverseLogicalChannelParameters.multiplexParameters.u.h2250LogicalChannelParameters;
164
165       return ooFindLogicalChannel(call, pslcp->sessionID, "receive", psDataType);
166    }
167    else{
168       OOTRACEDBGC3("Finding transmit channel (%s, %s)\n", call->callType, 
169                                                            call->callToken);
170       psDataType = &olc->forwardLogicalChannelParameters.dataType;
171       /* Only H2250LogicalChannelParameters are supported */
172       if(olc->forwardLogicalChannelParameters.multiplexParameters.t != 
173          T_H245OpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters_h2250LogicalChannelParameters)
174       {
175          OOTRACEERR4("Error:Invalid olc %d received (%s, %s)\n", 
176            olc->forwardLogicalChannelNumber, call->callType, call->callToken);
177          return NULL;
178       }
179       pslcp = olc->forwardLogicalChannelParameters.multiplexParameters.u.h2250LogicalChannelParameters;
180       return ooFindLogicalChannel(call, pslcp->sessionID, "transmit", psDataType);
181    }
182 }
183
184 OOLogicalChannel * ooFindLogicalChannel(OOH323CallData *call, int sessionID, 
185                                         char *dir, H245DataType * dataType)
186 {
187    OOLogicalChannel * pChannel = NULL;
188    pChannel = call->logicalChans;
189    while(pChannel)
190    {
191       OOTRACEDBGC3("ooFindLogicalChannel, checking channel: %d:%s\n",
192                     pChannel->sessionID, pChannel->dir);
193       if(pChannel->sessionID == sessionID || pChannel->sessionID == 0)
194       {
195          if(!strcmp(pChannel->dir, dir))
196          {
197             OOTRACEDBGC3("ooFindLogicalChannel, comparing channel: %d:%s\n",
198                           pChannel->channelNo, pChannel->dir);
199             if(!strcmp(dir, "receive"))
200             {
201                if(ooCapabilityCheckCompatibility(call, pChannel->chanCap,
202                                                  dataType, OORX)) {
203                   return pChannel;
204                }
205             }
206             else if(!strcmp(dir, "transmit"))
207             {
208                if(ooCapabilityCheckCompatibility(call, pChannel->chanCap,
209                                                  dataType, OOTX)) {
210                   return pChannel;
211                }
212             }
213          }
214       }
215       pChannel = pChannel->next;
216    }
217    return NULL;
218 }
219
220 /* This function is used to get a logical channel with a particular session ID */
221 OOLogicalChannel* ooGetLogicalChannel
222    (OOH323CallData *call, int sessionID, char *dir)
223 {
224    OOLogicalChannel * pChannel = NULL;
225    pChannel = call->logicalChans;
226    while(pChannel)
227    {
228       if(pChannel->sessionID == sessionID && !strcmp(pChannel->dir, dir))
229          return pChannel;
230       else
231          pChannel = pChannel->next;
232    }
233    return NULL;
234 }
235
236 /* function is to get channel with particular direction */
237
238 OOLogicalChannel* ooGetTransmitLogicalChannel
239    (OOH323CallData *call)
240 {
241    OOLogicalChannel * pChannel = NULL;
242    pChannel = call->logicalChans;
243    while(pChannel)
244    {
245       OOTRACEINFO6("Listing logical channel %d cap %d state %d for (%s, %s)\n",
246                 pChannel->channelNo, pChannel->chanCap->cap, pChannel->state, 
247                 call->callType, call->callToken);
248       if(!strcmp(pChannel->dir, "transmit") && pChannel->state != OO_LOGICALCHAN_IDLE &&
249                                                pChannel->state != OO_LOGICALCHAN_PROPOSEDFS)
250          return pChannel;
251       else
252          pChannel = pChannel->next;
253    }
254    return NULL;
255 }
256
257 int ooClearAllLogicalChannels(OOH323CallData *call)
258 {
259    OOLogicalChannel * temp = NULL, *prev = NULL;
260
261    OOTRACEINFO3("Clearing all logical channels (%s, %s)\n", call->callType,
262                  call->callToken);
263    
264    temp = call->logicalChans;
265    while(temp)
266    {
267       prev = temp;
268       temp = temp->next;
269       ooClearLogicalChannel(call, prev->channelNo);/* TODO: efficiency - This causes re-search 
270                                                       of of logical channel in the list. Can be
271                                                       easily improved.*/
272    }
273    call->logicalChans = NULL;
274    return OO_OK;
275 }
276
277 int ooClearLogicalChannel(OOH323CallData *call, int channelNo)
278 {
279
280    OOLogicalChannel *pLogicalChannel = NULL;
281    ooH323EpCapability *epCap=NULL;
282
283    OOTRACEDBGC4("Clearing logical channel number %d. (%s, %s)\n", channelNo,
284                  call->callType, call->callToken);
285
286    pLogicalChannel = ooFindLogicalChannelByLogicalChannelNo(call,channelNo);
287    do { if(!pLogicalChannel)
288    {
289       OOTRACEWARN4("Logical Channel %d doesn't exist, in clearLogicalChannel."
290                    " (%s, %s)\n",
291                   channelNo, call->callType, call->callToken);
292       return OO_OK;
293    }
294
295    epCap = (ooH323EpCapability*) pLogicalChannel->chanCap;
296    if(!strcmp(pLogicalChannel->dir, "receive"))
297    {
298       if(epCap->stopReceiveChannel)
299       {
300          epCap->stopReceiveChannel(call, pLogicalChannel);
301          OOTRACEINFO4("Stopped Receive channel %d (%s, %s)\n", 
302                                  channelNo, call->callType, call->callToken);
303       }
304       else{
305          OOTRACEERR4("ERROR:No callback registered for stopReceiveChannel %d "
306                      "(%s, %s)\n", channelNo, call->callType, call->callToken);
307       }
308    }
309    else
310    {
311       if(pLogicalChannel->state == OO_LOGICALCHAN_ESTABLISHED)
312       {
313          if(epCap->stopTransmitChannel)
314          {
315             epCap->stopTransmitChannel(call, pLogicalChannel);
316             OOTRACEINFO4("Stopped Transmit channel %d (%s, %s)\n", 
317                           channelNo, call->callType, call->callToken);
318          }
319          else{
320             OOTRACEERR4("ERROR:No callback registered for stopTransmitChannel"
321                         " %d (%s, %s)\n", channelNo, call->callType, 
322                         call->callToken);
323          }
324       }
325    }
326    ooRemoveLogicalChannel(call, channelNo);/* TODO: efficiency - This causes re-search of
327                                                     of logical channel in the list. Can be
328                                                     easily improved.*/
329    }  while ((pLogicalChannel = ooFindLogicalChannelByLogicalChannelNo(call,channelNo)));
330    return OO_OK;
331 }
332
333 int ooRemoveLogicalChannel(OOH323CallData *call, int ChannelNo)
334 {
335    OOLogicalChannel * temp = NULL, *prev=NULL; 
336    if(!call->logicalChans)
337    {
338       OOTRACEERR4("ERROR:Remove Logical Channel - Channel %d not found "
339                   "Empty channel List(%s, %s)\n", ChannelNo, call->callType, 
340                   call->callToken);
341       return OO_FAILED;
342    }
343
344    temp = call->logicalChans;
345    while(temp)
346    {
347       if(temp->channelNo == ChannelNo)
348       {
349          if(!prev)   call->logicalChans = temp->next;
350          else   prev->next = temp->next;
351          memFreePtr(call->pctxt, temp->chanCap);
352          memFreePtr(call->pctxt, temp);
353          OOTRACEDBGC4("Removed logical channel %d (%s, %s)\n", ChannelNo,
354                        call->callType, call->callToken);
355          call->noOfLogicalChannels--;
356          return OO_OK;
357       }
358       prev = temp;
359       temp = temp->next;
360    }
361    
362    OOTRACEERR4("ERROR:Remove Logical Channel - Channel %d not found "
363                   "(%s, %s)\n", ChannelNo, call->callType, call->callToken);
364    return OO_FAILED;
365 }
366
367 /* 
368 Change the state of the channel as established and close all other 
369 channels with same session IDs. This is useful for handling fastStart, 
370 as the endpoint can open multiple logical channels for same sessionID.
371 Once the remote endpoint confirms it's selection, all other channels for 
372 the same sessionID must be closed.
373 */
374 int ooOnLogicalChannelEstablished
375    (OOH323CallData *call, OOLogicalChannel * pChannel)
376 {
377    OOLogicalChannel * temp = NULL, *prev=NULL; 
378    OOTRACEDBGC3("In ooOnLogicalChannelEstablished (%s, %s)\n",
379                 call->callType, call->callToken);
380    pChannel->state = OO_LOGICALCHAN_ESTABLISHED;
381    temp = call->logicalChans;
382    while(temp)
383    {
384       if(temp->channelNo != pChannel->channelNo &&
385          temp->sessionID == pChannel->sessionID &&
386          !strcmp(temp->dir, pChannel->dir)        )
387       {
388          prev = temp;
389          temp = temp->next;
390          ooClearLogicalChannel(call, prev->channelNo);
391       }
392       else
393          temp = temp->next;
394    }
395    return OO_OK;
396 }
397