source: mediastreamer2/src/mtu.c @ 856:3d8054c9c0b4

Last change on this file since 856:3d8054c9c0b4 was 856:3d8054c9c0b4, checked in by Simon Morlat <simon.morlat@…>, 3 years ago

expurge everything but mediastreamer2

File size: 6.3 KB
Line 
1/*
2mediastreamer2 library - modular sound and video processing and streaming
3Copyright (C) 2006  Simon MORLAT (simon.morlat@linphone.org)
4
5This program is free software; you can redistribute it and/or
6modify it under the terms of the GNU General Public License
7as published by the Free Software Foundation; either version 2
8of the License, or (at your option) any later version.
9
10This program is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18*/
19
20
21/* mtu.c : discover the mtu automatically */
22
23#include "mediastreamer2/mscommon.h"
24
25
26#if defined(WIN32) && !defined(_WIN32_WCE)
27
28HINSTANCE m_IcmpInst = NULL;
29
30typedef struct ip_option_information {
31    UCHAR   Ttl;
32    UCHAR   Tos;
33    UCHAR   Flags;
34    UCHAR   OptionsSize;
35    PUCHAR  OptionsData;
36} IP_OPTION_INFORMATION, * PIP_OPTION_INFORMATION;
37
38typedef BOOL (WINAPI *ICMPCLOSEHANDLE)(HANDLE IcmpHandle);
39typedef HANDLE (WINAPI *ICMPCREATEFILE)(VOID);
40typedef DWORD (WINAPI *ICMPSENDECHO)(HANDLE IcmpHandle,ULONG DestinationAddress, LPVOID RequestData, WORD RequestSize, PIP_OPTION_INFORMATION RequestOptions, LPVOID ReplyBuffer, DWORD ReplySize, DWORD Timeout);
41
42ICMPCLOSEHANDLE pIcmpCloseHandle = NULL;
43ICMPCREATEFILE pIcmpCreateFile = NULL;
44ICMPSENDECHO pIcmpSendEcho = NULL;
45
46#define IP_FLAG_DF      0x2         // Don't fragment this packet.
47#define IP_OPT_ROUTER_ALERT 0x94  // Router Alert Option
48
49#define IP_STATUS_BASE              11000
50#define IP_PACKET_TOO_BIG           (IP_STATUS_BASE + 9)
51#define IP_REQ_TIMED_OUT            (IP_STATUS_BASE + 10)
52
53static int mtus[] = {
54  1500,   // Ethernet, Point-to-Point (default)
55  1492,   // IEEE 802.3
56  1006,   // SLIP, ARPANET
57  576,    // X.25 Networks
58  544,    // DEC IP Portal
59  512,    // NETBIOS
60  508,    // IEEE 802/Source-Rt Bridge, ARCNET
61  296,    // Point-to-Point (low delay)
62  68,     // Official minimum
63  0
64};
65
66int ms_discover_mtu(const char *host)
67{
68  int i;
69
70        struct addrinfo hints,*ai=NULL;
71        char port[10];
72  char ipaddr[INET6_ADDRSTRLEN];
73  int err;
74
75  HANDLE hIcmp;
76  unsigned long target_addr;
77
78  struct ip_option_information ip_opts;
79  unsigned char reply_buffer[10000];
80
81  if (!m_IcmpInst)
82        {
83                m_IcmpInst = LoadLibrary("icmp.dll");
84                if (m_IcmpInst)
85                {
86                        pIcmpCloseHandle = (ICMPCLOSEHANDLE)GetProcAddress(m_IcmpInst, "IcmpCloseHandle");
87                        pIcmpCreateFile  = (ICMPCREATEFILE) GetProcAddress(m_IcmpInst, "IcmpCreateFile");
88                        pIcmpSendEcho =    (ICMPSENDECHO)   GetProcAddress(m_IcmpInst, "IcmpSendEcho");
89                }
90        }
91
92  hIcmp = pIcmpCreateFile();
93
94        memset(&hints,0,sizeof(hints));
95        hints.ai_family = PF_INET;
96        hints.ai_socktype = SOCK_DGRAM;
97       
98        snprintf(port,sizeof(port),"0");
99        err=getaddrinfo(host,port,&hints,&ai);
100        if (err!=0){
101    pIcmpCloseHandle( hIcmp );
102                ms_error("getaddrinfo(): error\n");
103                return -1;
104        }
105  getnameinfo (ai->ai_addr, ai->ai_addrlen, ipaddr, sizeof (ipaddr), port,
106               sizeof (port), NI_NUMERICHOST | NI_NUMERICSERV);
107        freeaddrinfo(ai);
108
109  target_addr=inet_addr(ipaddr);
110
111
112  /* Prepare the IP options */
113  memset(&ip_opts,0,sizeof(ip_opts));
114  ip_opts.Ttl=30;
115  ip_opts.Flags = IP_FLAG_DF | IP_OPT_ROUTER_ALERT;
116
117
118  // ignore icmpbuff data contents
119  for (i=0;mtus[i]!=0;i++)
120  {
121    char icmpbuff[2048];
122    char *icmp_data = icmpbuff;
123
124    int status = -1;
125    if (pIcmpSendEcho)
126      status=pIcmpSendEcho(hIcmp,
127                          target_addr,
128                          (LPVOID)icmp_data,
129                          mtus[i]-60, /* icmp_data_size */
130                          &ip_opts,
131                          reply_buffer,
132                          sizeof(reply_buffer),
133                          3000L); // 3 seconds
134    if (status || GetLastError() == IP_REQ_TIMED_OUT)
135    {
136      pIcmpCloseHandle( hIcmp );
137      return mtus[i];
138    }
139  }
140
141  pIcmpCloseHandle( hIcmp );
142
143  return -1;
144}
145
146#elif defined(__linux)
147
148#include <sys/types.h>
149#include <sys/socket.h>
150#include <string.h>
151#include <errno.h>
152#include <netinet/in.h>
153#include <netinet/ip.h>
154#include <netdb.h>
155
156#ifndef IP_MTU
157#define IP_MTU 14
158#endif
159
160int ms_discover_mtu(const char *host){
161        int sock;
162        int err,mtu=0,new_mtu;
163        socklen_t optlen;
164        char buf[1500-28]={0};
165        char port[10];
166        struct addrinfo hints,*ai=NULL;
167        int rand_port;
168        int retry=0;
169        struct timeval tv;
170
171        memset(&hints,0,sizeof(hints));
172        hints.ai_family = PF_INET;
173        hints.ai_socktype = SOCK_DGRAM;
174       
175        gettimeofday(&tv,NULL); 
176        srandom(tv.tv_usec);
177        rand_port=random() & 0xFFFF;
178        if (rand_port<1000) rand_port+=1000;
179        snprintf(port,sizeof(port),"%i",rand_port);
180        err=getaddrinfo(host,port,&hints,&ai);
181        if (err!=0){
182                ms_error("getaddrinfo(): %s\n",gai_strerror(err));
183                return -1;
184        }
185        sock=socket(PF_INET,SOCK_DGRAM,0);
186
187        mtu=IP_PMTUDISC_DO;
188        optlen=sizeof(mtu);
189        err=setsockopt(sock,IPPROTO_IP,IP_MTU_DISCOVER,&mtu,optlen);
190        if (err!=0){
191                ms_error("setsockopt(): %s",strerror(errno));
192                err = close(sock);
193                if (err!=0)
194                        ms_error("close(): %s", strerror(errno));
195                return -1;
196        }
197        err=connect(sock,ai->ai_addr,ai->ai_addrlen);
198        freeaddrinfo(ai);
199        if (err!=0){
200                ms_error("connect(): %s",strerror(errno));
201                err = close(sock);
202                if (err !=0)
203                        ms_error("close(): %s", strerror(errno));
204                return -1;
205        }
206        mtu=sizeof(buf);
207        do{
208                send(sock,buf,mtu,0);
209                usleep(500000);/*wait for an icmp message come back */
210                err=getsockopt(sock,IPPROTO_IP,IP_MTU,&new_mtu,&optlen);
211                if (err!=0){
212                        ms_error("getsockopt(): %s",strerror(errno));
213                        err = close(sock);
214                        if (err!=0)
215                                ms_error("close(): %s", strerror(errno));
216                        return -1;
217                }else{
218                        ms_message("Partial MTU discovered : %i",new_mtu);
219                        if (new_mtu==mtu) break;
220                        else mtu=new_mtu;
221                }
222                retry++;
223        }while(retry<10);
224       
225        ms_message("mtu to %s is %i",host,mtu);
226
227        err = close(sock);
228        if (err!=0)
229                ms_error("close() %s", strerror(errno));
230        return mtu;
231}
232
233#else
234
235int ms_discover_mtu(const char*host){
236        ms_warning("mtu discovery not implemented.");
237        return -1;
238}
239
240#endif
241
242
243void ms_set_mtu(int mtu){
244        /*60= IPv6+UDP+RTP overhead */
245        if (mtu>60){
246                if (mtu>1500) mtu=1500;/*limit to 1500, the mediastreamer2 buffer are not large enough anyway*/
247                ms_set_payload_max_size(mtu-60);
248        }else ms_set_payload_max_size(0);
249}
Note: See TracBrowser for help on using the repository browser.