~ubuntu-branches/ubuntu/quantal/linphone/quantal

« back to all changes in this revision

Viewing changes to osipua/src/udp.c

  • Committer: Bazaar Package Importer
  • Author(s): Samuel Mimram
  • Date: 2004-06-30 13:58:16 UTC
  • Revision ID: james.westby@ubuntu.com-20040630135816-wwx75gdlodkqbabb
Tags: upstream-0.12.2
ImportĀ upstreamĀ versionĀ 0.12.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
  The osipua library is a library based on oSIP that implements CallLeg and User Agent
 
3
  level.
 
4
  Copyright (C) 2001  Simon MORLAT simon.morlat@free.fr
 
5
                                                                                        Aymeric MOIZARD jack@atosc.org
 
6
  This library is free software; you can redistribute it and/or
 
7
  modify it under the terms of the GNU Lesser General Public
 
8
  License as published by the Free Software Foundation; either
 
9
  version 2.1 of the License, or (at your option) any later version.
 
10
 
 
11
  This library is distributed in the hope that it will be useful,
 
12
  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
14
  Lesser General Public License for more details.
 
15
 
 
16
  You should have received a copy of the GNU Lesser General Public
 
17
  License along with this library; if not, write to the Free Software
 
18
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
19
*/
 
20
 
 
21
#include <sys/types.h>
 
22
#include <sys/socket.h>
 
23
 
 
24
#include <netinet/in.h>
 
25
#include <arpa/inet.h>
 
26
#include <unistd.h>
 
27
#include "udp.h"
 
28
#include "osipmanager.h"
 
29
#include "osipua.h"
 
30
 
 
31
#ifdef INET6  
 
32
#include <sys/types.h>  
 
33
#include <sys/socket.h>  
 
34
#include <netdb.h>  
 
35
#define STRN_EQ(x,y,l) (strncasecmp((x),(y),(l)) == 0)  
 
36
#endif
 
37
 
 
38
extern OsipManager *def_manager;
 
39
 
 
40
int udp_receive (OsipManager * manager);
 
41
 
 
42
void osipua_execute(OsipManager *manager)
 
43
{
 
44
        long int time_elapsed;
 
45
        transaction_t *trn;
 
46
        
 
47
        osip_ict_execute (manager->config);
 
48
        osip_nict_execute (manager->config);
 
49
        osip_ist_execute (manager->config);
 
50
        osip_nist_execute (manager->config);
 
51
        
 
52
        
 
53
        osip_timers_ict_execute (manager->config);
 
54
        osip_timers_ist_execute (manager->config);
 
55
        osip_timers_nict_execute (manager->config);
 
56
        osip_timers_nist_execute (manager->config);
 
57
#ifdef OSIP_RETRANSMISSIONS
 
58
        osip_retransmissions_execute(manager->config);
 
59
#endif
 
60
        /* free killed transaction */
 
61
        while ( (trn=fifo_tryget(&manager->garbage_trn))!=NULL){
 
62
                transaction_free(trn);
 
63
                sfree(trn);
 
64
        }
 
65
}
 
66
 
 
67
void osipua_distribute_event(OsipManager *m, sipevent_t *ev)
 
68
{
 
69
        osip_t *config=m->config;
 
70
        transaction_t *trn;
 
71
        int err;
 
72
        
 
73
        smutex_lock(m->mutex);
 
74
        err=osip_find_transaction_and_add_event(config,ev);
 
75
        if (err<0){
 
76
                /* check if it is not an ack for invite (not handled by osip)*/
 
77
                if (ev->type==RCV_REQACK){
 
78
                        /* stop the retransmissions of the 200 Ok the ACK matches */
 
79
#ifdef OSIP_RETRANSMISSIONS     
 
80
                        osip_stop_200ok_retransmissions(config,ev->sip);
 
81
#endif
 
82
                        msg_free(ev->sip);
 
83
                        sfree(ev->sip);
 
84
                        sfree(ev);
 
85
                }
 
86
                else if (ev->type==RCV_STATUS_2XX){
 
87
                        /* this a retransmission of 200 Ok */
 
88
                        msg_free(ev->sip);
 
89
                        sfree(ev->sip);
 
90
                        sfree(ev);
 
91
                }
 
92
                else if (EVT_IS_INCOMINGREQ(ev)){
 
93
                        /* not an ack, of course */
 
94
                        trn=osip_create_transaction(config,ev);
 
95
                        transaction_execute(trn,ev);
 
96
                }
 
97
        }else{
 
98
                /* an existing transaction was found */
 
99
                osipua_execute(m);
 
100
        }
 
101
        
 
102
        smutex_unlock(m->mutex);
 
103
}
 
104
 
 
105
 
 
106
void *
 
107
sipd_thread (void *managerp)
 
108
{
 
109
        OsipManager *manager = (OsipManager *) managerp;        
 
110
        int err;
 
111
        
 
112
        osip_trace (OSIP_INFO1, ("Entering osipua thread.\n"));
 
113
        manager->thread_pid=getpid();
 
114
        
 
115
        while (manager->udp_run_cond)
 
116
        {
 
117
                int i, j, k, nb;
 
118
                fd_set osipfdset;
 
119
                struct timeval timeout;
 
120
#ifdef __linux
 
121
                socklen_t slen;
 
122
#else
 
123
                int slen;
 
124
#endif
 
125
#ifdef INET6  
 
126
                struct sockaddr_storage sa;  
 
127
#else
 
128
                struct sockaddr_in sa;
 
129
#endif
 
130
 
 
131
                memcpy (&osipfdset, &manager->udpfdset, sizeof (fd_set));
 
132
                timeout.tv_sec = manager->recv_tout.tv_sec;     /* timeout can be modified by linux !! */
 
133
                timeout.tv_usec = manager->recv_tout.tv_usec;
 
134
                nb = select (manager->max_udpfd + 1, &osipfdset, NULL, NULL,&timeout);
 
135
                /* if something to read on the control file descriptor, then exit thread */
 
136
                if (nb > 0)
 
137
                {
 
138
                        if (FD_ISSET (manager->udp_unblock_fd, &osipfdset))
 
139
                        {
 
140
                                //printf("Receiving something on unblock_fd\n");
 
141
                                read (manager->udp_unblock_fd, manager->udp_buf,
 
142
                              SIP_MESSAGE_MAX_LENGTH);
 
143
                                nb--;
 
144
                        }
 
145
                        //printf("Something to read !!!!!!!!!!!!!!!!!\n");
 
146
                        for (j = 0, k = 0; (j < OSIP_MAX_UDP_PORTS) && (k < nb); j++)
 
147
                        {
 
148
                                if (FD_ISSET (manager->udpfds[j], &osipfdset))
 
149
                                {
 
150
                                        k++;
 
151
                                        slen = sizeof (sa);
 
152
                                        i = recvfrom (manager->udpfds[j],
 
153
                                          manager->udp_buf,
 
154
                                          SIP_MESSAGE_MAX_LENGTH, 0,
 
155
                                          (struct sockaddr *) &sa, &slen);
 
156
                                        if (i > 0)
 
157
                                        {
 
158
                                                /* Message might not end with a "\0" but we know the number of */
 
159
                                                /* char received! */
 
160
                                                sipevent_t *sipevent;
 
161
                                                unsigned short int port = 0;  
 
162
                                                char *name;
 
163
#ifdef INET6
 
164
                                                int error;  
 
165
                                                char namebuf[BUFSIZ];  
 
166
                                                char sbuf[NI_MAXSERV];
 
167
#endif
 
168
                                                manager->udp_buf[i] = '\0';
 
169
#ifdef INET6
 
170
                                                error = getnameinfo((struct sockaddr *)&sa, slen,
 
171
                                                                    namebuf, sizeof(namebuf), NULL, 0, NI_NUMERICHOST);
 
172
                                                if (error) {
 
173
                                                  osip_trace (OSIP_INFO1, ("getnameinfo error\n"));
 
174
                                                }
 
175
                                                else
 
176
                                                {
 
177
                                                  name = namebuf;
 
178
                                                  if (STRN_EQ(name, "::ffff:", 7))
 
179
                                                      name += 7;
 
180
                                                  switch(((struct sockaddr *)&sa)->sa_family){
 
181
                                                  case AF_INET:
 
182
                                                    port = ntohs(((struct sockaddr_in*)&sa)->sin_port);
 
183
                                                    osip_trace (OSIP_INFO1,
 
184
                                                                ("info: Message from %s:%i\n",
 
185
                                                                 name,
 
186
                                                                 port));
 
187
                                                    break;
 
188
                                                  case AF_INET6:
 
189
                                                    port = ntohs(((struct sockaddr_in6*)&sa)->sin6_port);
 
190
                                                    osip_trace (OSIP_INFO1,
 
191
                                                                ("info: Message from [%s]:%i\n",
 
192
                                                                 name,
 
193
                                                                 port));
 
194
                                                    break;
 
195
                                                  default:
 
196
                                                    osip_trace(OSIP_WARNING,
 
197
                                                               ("Cant find port number"));
 
198
                                                  }
 
199
                                                }
 
200
#else
 
201
                                                name = inet_ntoa (sa.sin_addr);
 
202
                                                port = sa.sin_port;
 
203
#endif
 
204
                                                osip_trace (OSIP_INFO1,
 
205
                                                    ("info: RECEIVING UDP MESSAGE:\n%s\n",
 
206
                                                     manager->udp_buf));
 
207
                                        
 
208
                                                sipevent = osip_parse (manager->udp_buf);
 
209
                                                if (sipevent != NULL){
 
210
                                                  if (MSG_IS_REQUEST(sipevent->sip))
 
211
                                                    {
 
212
                                                      osipua_fix_via_header(sipevent,
 
213
                                                                            name,
 
214
                                                                            port);
 
215
                                                    }
 
216
                                                  osipua_distribute_event(manager,sipevent);
 
217
                                                }       
 
218
                                        }
 
219
                                        else    /* if i>0 */
 
220
                                        {
 
221
                                          osip_trace(OSIP_ERROR,
 
222
                                             ("UDP listener failed while receiving data!\n"));
 
223
                                        }
 
224
                                }
 
225
                        }
 
226
                        /* messages have been received */
 
227
                }
 
228
                smutex_lock(manager->mutex);
 
229
                osipua_execute(manager);
 
230
                smutex_unlock(manager->mutex);
 
231
                
 
232
        }
 
233
        osip_trace (OSIP_INFO1, ("Exiting osipua thread.\n"));
 
234
        return NULL;
 
235
}
 
236
 
 
237
int
 
238
osipua_fix_via_header(sipevent_t *evt, char *ip_addr, int port)
 
239
{
 
240
  generic_param_t *rport;
 
241
  via_t *via;
 
242
  /* get Top most Via header: */
 
243
  if (evt==NULL||evt->sip==NULL)
 
244
    return -1;
 
245
  via = list_get(evt->sip->vias, 0);
 
246
  if (via==NULL||via->host==NULL)
 
247
    /* Hey, we could build it? */
 
248
    return -1;
 
249
 
 
250
  via_param_getbyname(via, "rport", &rport);
 
251
 
 
252
  /* detect rport */
 
253
  if (rport!=NULL)
 
254
    {
 
255
      if (rport->gvalue==NULL)
 
256
        {
 
257
          rport->gvalue = (char *) smalloc(8);
 
258
          snprintf(rport->gvalue, 8, "%i", port);
 
259
        } /* else bug? */
 
260
    }
 
261
 
 
262
  /* only add the received parameter if the 'sent-by' value does not contains
 
263
     this ip address */
 
264
  if (0==strcmp(via->host, ip_addr)) /* don't need the received parameter */
 
265
    return 0;
 
266
  via_set_received(via, sgetcopy(ip_addr));
 
267
  return 0;
 
268
}
 
269
 
 
270
 
 
271
int
 
272
udp_send (transaction_t * trn, sip_t * sipmsg, char *host, int port, int sock)
 
273
{
 
274
#ifdef INET6  
 
275
         struct sockaddr_storage addr;  
 
276
         struct addrinfo hints, *res;  
 
277
         char num[8];  
 
278
         int error;  
 
279
#else
 
280
        struct sockaddr_in addr;
 
281
        unsigned long int one_inet_addr;
 
282
#endif
 
283
        char *message;
 
284
        
 
285
        if (sipmsg==NULL){
 
286
                osip_trace(OSIP_ERROR,("Null message !!"));
 
287
                return 0;
 
288
        }
 
289
        
 
290
        msg_2char(sipmsg,&message);
 
291
        if (message==NULL) {
 
292
                osip_trace(OSIP_ERROR,("msg_2char failed !!"));
 
293
                return 0;
 
294
        }
 
295
        osip_trace(OSIP_INFO1,("Sending message:\n%s",message));
 
296
        
 
297
 
 
298
       /* I add that code for compatibility with older version:
 
299
          This code is not needed anymore with libosip-0.9.2 and >.
 
300
          The "received" parameter IS ALWAYS THERE because linphone
 
301
          add it itself to evry incoming requests.
 
302
       */
 
303
        if (MSG_IS_RESPONSE(sipmsg))
 
304
          {
 
305
            via_t *via;
 
306
            char *host;
 
307
            int port;
 
308
            generic_param_t *maddr;
 
309
            generic_param_t *received;
 
310
            generic_param_t *rport;
 
311
            via = list_get(sipmsg->vias, 0);
 
312
            via_param_getbyname(via, "maddr", &maddr);
 
313
            via_param_getbyname(via, "received", &received);
 
314
            via_param_getbyname(via, "rport", &rport);
 
315
            /* 1: for reliable protocol (not supported)
 
316
               2: check maddr and multicast usage (not supported) */
 
317
            if (maddr!=NULL)
 
318
              host = maddr->gvalue;
 
319
            /* we should check if this is a multicast address and use
 
320
               set the "ttl" in this case. */
 
321
            else if (received!=NULL)
 
322
              host = received->gvalue;
 
323
            else host = via->host;
 
324
            
 
325
            if (rport==NULL||rport->gvalue==NULL)
 
326
              {
 
327
                if (via->port!=NULL) port = satoi(via->port);
 
328
                else port = 5060;
 
329
              }
 
330
            else
 
331
              port = satoi(rport->gvalue);
 
332
          }
 
333
 
 
334
#ifdef INET6  
 
335
        memset(&hints, 0, sizeof(hints));  
 
336
        hints.ai_family = PF_UNSPEC;  
 
337
        hints.ai_socktype = SOCK_DGRAM;  
 
338
        hints.ai_flags = AI_NUMERICHOST;  
 
339
        snprintf(num, sizeof(num), "%d", port);  
 
340
        error = getaddrinfo(host, num,  &hints, &res);  
 
341
        if (error) {  
 
342
          osip_trace (OSIP_INFO1,  
 
343
                      ("error: %s: %s\n", host, gai_strerror(error)));  
 
344
          return -1;  
 
345
        }  
 
346
        if (res->ai_addrlen > sizeof(addr)) {  
 
347
          osip_trace (OSIP_INFO1,  
 
348
                      ("error: sockaddr too large\n"));  
 
349
          freeaddrinfo(res);
 
350
          return -1;  
 
351
        }  
 
352
        memcpy(&addr, res->ai_addr, res->ai_addrlen);  
 
353
        freeaddrinfo(res);  
 
354
#else
 
355
        if ((int) (one_inet_addr = inet_addr (host)) == -1)
 
356
        {
 
357
                osip_trace (OSIP_INFO1,
 
358
                            ("error: destination is not an ip address:%s\n",
 
359
                             host));
 
360
                return -1;
 
361
        }
 
362
        else
 
363
        {
 
364
                addr.sin_addr.s_addr = one_inet_addr;
 
365
        }
 
366
 
 
367
        addr.sin_port = htons ((short) port);
 
368
        addr.sin_family = AF_INET;
 
369
#endif
 
370
        if (sock<=0){
 
371
                osip_trace(OSIP_INFO1,("warning: using default manager socket to send a message.\n"));
 
372
                sock=def_manager->send_sock;
 
373
        }
 
374
 
 
375
        if (0 > sendto (sock, (const void *) message, strlen (message), 0,
 
376
                        (struct sockaddr *) &addr, sizeof (addr)))
 
377
        {
 
378
                osip_trace(OSIP_ERROR,("udp_send: could not send message using socket %i: %s\n",sock,strerror(errno)));
 
379
        }
 
380
 
 
381
        
 
382
        return 0;
 
383
}