1 //
2 // Copyright (c) ZeroC, Inc. All rights reserved.
3 //
4 
5 namespace IceInternal
6 {
7     using System;
8     using System.Collections.Generic;
9     using System.ComponentModel;
10     using System.Diagnostics;
11     using System.Net;
12     using System.Net.Sockets;
13     using System.Text;
14 
15     sealed class UdpTransceiver : Transceiver
16     {
fd()17         public Socket fd()
18         {
19             return _fd;
20         }
21 
initialize(Buffer readBuffer, Buffer writeBuffer, ref bool hasMoreData)22         public int initialize(Buffer readBuffer, Buffer writeBuffer, ref bool hasMoreData)
23         {
24             if(_state == StateNeedConnect)
25             {
26                 _state = StateConnectPending;
27                 try
28                 {
29                     if(_sourceAddr != null)
30                     {
31                         _fd.Bind(_sourceAddr);
32                     }
33                     _fd.Connect(_addr);
34                 }
35                 catch(SocketException ex)
36                 {
37                     if(Network.wouldBlock(ex))
38                     {
39                         return SocketOperation.Connect;
40                     }
41                     throw new Ice.ConnectFailedException(ex);
42                 }
43                 catch(Exception ex)
44                 {
45                     throw new Ice.ConnectFailedException(ex);
46                 }
47                 _state = StateConnected;
48             }
49 
50             Debug.Assert(_state >= StateConnected);
51             return SocketOperation.None;
52         }
53 
closing(bool initiator, Ice.LocalException ex)54         public int closing(bool initiator, Ice.LocalException ex)
55         {
56             //
57             // Nothing to do.
58             //
59             return SocketOperation.None;
60         }
61 
close()62         public void close()
63         {
64             if(_fd != null)
65             {
66                 try
67                 {
68                     _fd.Close();
69                 }
70                 catch(System.IO.IOException)
71                 {
72                 }
73                 _fd = null;
74             }
75         }
76 
bind()77         public EndpointI bind()
78         {
79             if(Network.isMulticast((IPEndPoint)_addr))
80             {
81                 Network.setReuseAddress(_fd, true);
82                 _mcastAddr = (IPEndPoint)_addr;
83                 if(AssemblyUtil.isWindows)
84                 {
85                     //
86                     // Windows does not allow binding to the mcast address itself
87                     // so we bind to INADDR_ANY (0.0.0.0) instead. As a result,
88                     // bi-directional connection won't work because the source
89                     // address won't the multicast address and the client will
90                     // therefore reject the datagram.
91                     //
92                     if(_addr.AddressFamily == AddressFamily.InterNetwork)
93                     {
94                         _addr = new IPEndPoint(IPAddress.Any, _port);
95                     }
96                     else
97                     {
98                         _addr = new IPEndPoint(IPAddress.IPv6Any, _port);
99                     }
100                 }
101 
102                 _addr = Network.doBind(_fd, _addr);
103                 if(_port == 0)
104                 {
105                     _mcastAddr.Port = ((IPEndPoint)_addr).Port;
106                 }
107                 Network.setMcastGroup(_fd, _mcastAddr.Address, _mcastInterface);
108             }
109             else
110             {
111                  _addr = Network.doBind(_fd, _addr);
112             }
113             _bound = true;
114             _endpoint = _endpoint.endpoint(this);
115             return _endpoint;
116         }
117 
destroy()118         public void destroy()
119         {
120             _readEventArgs.Dispose();
121             _writeEventArgs.Dispose();
122         }
123 
write(Buffer buf)124         public int write(Buffer buf)
125         {
126             if(!buf.b.hasRemaining())
127             {
128                 return SocketOperation.None;
129             }
130 
131             Debug.Assert(buf.b.position() == 0);
132             Debug.Assert(_fd != null && _state >= StateConnected);
133 
134             // The caller is supposed to check the send size before by calling checkSendSize
135             Debug.Assert(Math.Min(_maxPacketSize, _sndSize - _udpOverhead) >= buf.size());
136 
137             int ret = 0;
138             while(true)
139             {
140                 try
141                 {
142                     if(_state == StateConnected)
143                     {
144                         ret = _fd.Send(buf.b.rawBytes(), 0, buf.size(), SocketFlags.None);
145                     }
146                     else
147                     {
148                         if(_peerAddr == null)
149                         {
150                             throw new Ice.SocketException();
151                         }
152                         ret = _fd.SendTo(buf.b.rawBytes(), 0, buf.size(), SocketFlags.None, _peerAddr);
153                     }
154                     break;
155                 }
156                 catch(SocketException ex)
157                 {
158                     if(Network.interrupted(ex))
159                     {
160                         continue;
161                     }
162 
163                     if(Network.wouldBlock(ex))
164                     {
165                         return SocketOperation.Write;
166                     }
167 
168                     if(Network.connectionLost(ex))
169                     {
170                         throw new Ice.ConnectionLostException(ex);
171                     }
172                     else
173                     {
174                         throw new Ice.SocketException(ex);
175                     }
176                 }
177                 catch(Exception e)
178                 {
179                     throw new Ice.SyscallException(e);
180                 }
181             }
182 
183             Debug.Assert(ret > 0);
184             Debug.Assert(ret == buf.b.limit());
185             buf.b.position(buf.b.limit());
186             return SocketOperation.None;
187         }
188 
read(Buffer buf, ref bool hasMoreData)189         public int read(Buffer buf, ref bool hasMoreData)
190         {
191             if(!buf.b.hasRemaining())
192             {
193                 return SocketOperation.None;
194             }
195 
196             Debug.Assert(buf.b.position() == 0);
197             Debug.Assert(_fd != null);
198 
199             int packetSize = Math.Min(_maxPacketSize, _rcvSize - _udpOverhead);
200             buf.resize(packetSize, true);
201             buf.b.position(0);
202 
203             int ret = 0;
204             while(true)
205             {
206                 try
207                 {
208                     EndPoint peerAddr = _peerAddr;
209                     if(peerAddr == null)
210                     {
211                         if(_addr.AddressFamily == AddressFamily.InterNetwork)
212                         {
213                             peerAddr = new IPEndPoint(IPAddress.Any, 0);
214                         }
215                         else
216                         {
217                             Debug.Assert(_addr.AddressFamily == AddressFamily.InterNetworkV6);
218                             peerAddr = new IPEndPoint(IPAddress.IPv6Any, 0);
219                         }
220                     }
221 
222                     // TODO: Workaround for https://github.com/dotnet/corefx/issues/31182
223                     if(_state == StateConnected ||
224                        AssemblyUtil.isMacOS && _fd.AddressFamily == AddressFamily.InterNetworkV6 && _fd.DualMode)
225                     {
226                         ret = _fd.Receive(buf.b.rawBytes(), 0, buf.b.limit(), SocketFlags.None);
227                     }
228                     else
229                     {
230                         ret = _fd.ReceiveFrom(buf.b.rawBytes(), 0, buf.b.limit(), SocketFlags.None, ref peerAddr);
231                         _peerAddr = (IPEndPoint)peerAddr;
232                     }
233                     break;
234                 }
235                 catch(SocketException e)
236                 {
237                     if(Network.recvTruncated(e))
238                     {
239                         // The message was truncated and the whole buffer is filled. We ignore
240                         // this error here, it will be detected at the connection level when
241                         // the Ice message size is checked against the buffer size.
242                         ret = buf.size();
243                         break;
244                     }
245 
246                     if(Network.interrupted(e))
247                     {
248                         continue;
249                     }
250 
251                     if(Network.wouldBlock(e))
252                     {
253                         return SocketOperation.Read;
254                     }
255 
256                     if(Network.connectionLost(e))
257                     {
258                         throw new Ice.ConnectionLostException();
259                     }
260                     else
261                     {
262                         throw new Ice.SocketException(e);
263                     }
264                 }
265                 catch(Exception e)
266                 {
267                     throw new Ice.SyscallException(e);
268                 }
269             }
270 
271             if(ret == 0)
272             {
273                 throw new Ice.ConnectionLostException();
274             }
275 
276             if(_state == StateNeedConnect)
277             {
278                 Debug.Assert(_incoming);
279 
280                 //
281                 // If we must connect, then we connect to the first peer that sends us a packet.
282                 //
283                 bool connected = Network.doConnect(_fd, _peerAddr, null);
284                 Debug.Assert(connected);
285                 _state = StateConnected; // We're connected now
286 
287                 if(_instance.traceLevel() >= 1)
288                 {
289                     string s = "connected " + protocol() + " socket\n" + ToString();
290                     _instance.logger().trace(_instance.traceCategory(), s);
291                 }
292             }
293 
294             buf.resize(ret, true);
295             buf.b.position(ret);
296 
297             return SocketOperation.None;
298         }
299 
startRead(Buffer buf, AsyncCallback callback, object state)300         public bool startRead(Buffer buf, AsyncCallback callback, object state)
301         {
302             Debug.Assert(buf.b.position() == 0);
303 
304             int packetSize = Math.Min(_maxPacketSize, _rcvSize - _udpOverhead);
305             buf.resize(packetSize, true);
306             buf.b.position(0);
307 
308             try
309             {
310                 // TODO: Workaround for https://github.com/dotnet/corefx/issues/31182
311                 if(_state == StateConnected ||
312                    AssemblyUtil.isMacOS && _fd.AddressFamily == AddressFamily.InterNetworkV6 && _fd.DualMode)
313                 {
314                     _readCallback = callback;
315                     _readEventArgs.UserToken = state;
316                     _readEventArgs.SetBuffer(buf.b.rawBytes(), buf.b.position(), packetSize);
317                     return !_fd.ReceiveAsync(_readEventArgs);
318                 }
319                 else
320                 {
321                     Debug.Assert(_incoming);
322                     _readCallback = callback;
323                     _readEventArgs.UserToken = state;
324                     _readEventArgs.SetBuffer(buf.b.rawBytes(), 0, buf.b.limit());
325                     return !_fd.ReceiveFromAsync(_readEventArgs);
326                 }
327             }
328             catch(SocketException ex)
329             {
330                 if(Network.recvTruncated(ex))
331                 {
332                     // Nothing todo
333                     return true;
334                 }
335                 else
336                 {
337                     if(Network.connectionLost(ex))
338                     {
339                         throw new Ice.ConnectionLostException(ex);
340                     }
341                     else
342                     {
343                         throw new Ice.SocketException(ex);
344                     }
345                 }
346             }
347         }
348 
finishRead(Buffer buf)349         public void finishRead(Buffer buf)
350         {
351             if(_fd == null)
352             {
353                 return;
354             }
355 
356             int ret;
357             try
358             {
359                 if(_readEventArgs.SocketError != SocketError.Success)
360                 {
361                     throw new SocketException((int)_readEventArgs.SocketError);
362                 }
363                 ret = _readEventArgs.BytesTransferred;
364                 // TODO: Workaround for https://github.com/dotnet/corefx/issues/31182
365                 if(_state != StateConnected &&
366                    !(AssemblyUtil.isMacOS && _fd.AddressFamily == AddressFamily.InterNetworkV6 && _fd.DualMode))
367                 {
368                     _peerAddr = _readEventArgs.RemoteEndPoint;
369                 }
370             }
371             catch(SocketException ex)
372             {
373                 if(Network.recvTruncated(ex))
374                 {
375                     // The message was truncated and the whole buffer is filled. We ignore
376                     // this error here, it will be detected at the connection level when
377                     // the Ice message size is checked against the buffer size.
378                     ret = buf.size();
379                 }
380                 else
381                 {
382                     if(Network.connectionLost(ex))
383                     {
384                         throw new Ice.ConnectionLostException(ex);
385                     }
386 
387                     if(Network.connectionRefused(ex))
388                     {
389                         throw new Ice.ConnectionRefusedException(ex);
390                     }
391                     else
392                     {
393                         throw new Ice.SocketException(ex);
394                     }
395                 }
396             }
397 
398             if(ret == 0)
399             {
400                 throw new Ice.ConnectionLostException();
401             }
402 
403             Debug.Assert(ret > 0);
404 
405             if(_state == StateNeedConnect)
406             {
407                 Debug.Assert(_incoming);
408 
409                 //
410                 // If we must connect, then we connect to the first peer that
411                 // sends us a packet.
412                 //
413                 bool connected = !_fd.ConnectAsync(_readEventArgs);
414                 Debug.Assert(connected);
415                 _state = StateConnected; // We're connected now
416 
417                 if(_instance.traceLevel() >= 1)
418                 {
419                     string s = "connected " + protocol() + " socket\n" + ToString();
420                     _instance.logger().trace(_instance.traceCategory(), s);
421                 }
422             }
423 
424             buf.resize(ret, true);
425             buf.b.position(ret);
426         }
427 
startWrite(Buffer buf, AsyncCallback callback, object state, out bool completed)428         public bool startWrite(Buffer buf, AsyncCallback callback, object state, out bool completed)
429         {
430             if(!_incoming && _state < StateConnected)
431             {
432                 Debug.Assert(_addr != null);
433                 completed = false;
434                 if(_sourceAddr != null)
435                 {
436                     _fd.Bind(_sourceAddr);
437                 }
438                 _writeEventArgs.UserToken = state;
439                 return !_fd.ConnectAsync(_writeEventArgs);
440             }
441 
442             Debug.Assert(_fd != null);
443 
444             // The caller is supposed to check the send size before by calling checkSendSize
445             Debug.Assert(Math.Min(_maxPacketSize, _sndSize - _udpOverhead) >= buf.size());
446 
447             Debug.Assert(buf.b.position() == 0);
448 
449             bool completedSynchronously;
450             try
451             {
452                 _writeCallback = callback;
453 
454                 if(_state == StateConnected)
455                 {
456                     _writeEventArgs.UserToken = state;
457                     _writeEventArgs.SetBuffer(buf.b.rawBytes(), 0, buf.b.limit());
458                     completedSynchronously = !_fd.SendAsync(_writeEventArgs);
459                 }
460                 else
461                 {
462                     if(_peerAddr == null)
463                     {
464                         throw new Ice.SocketException();
465                     }
466                     _writeEventArgs.RemoteEndPoint = _peerAddr;
467                     _writeEventArgs.UserToken = state;
468                     _writeEventArgs.SetBuffer(buf.b.rawBytes(), 0, buf.b.limit());
469                     completedSynchronously = !_fd.SendToAsync(_writeEventArgs);
470                 }
471             }
472             catch(SocketException ex)
473             {
474                 if(Network.connectionLost(ex))
475                 {
476                     throw new Ice.ConnectionLostException(ex);
477                 }
478                 else
479                 {
480                     throw new Ice.SocketException(ex);
481                 }
482             }
483 
484             completed = true;
485             return completedSynchronously;
486         }
487 
finishWrite(Buffer buf)488         public void finishWrite(Buffer buf)
489         {
490             if(_fd == null)
491             {
492                 buf.b.position(buf.size()); // Assume all the data was sent for at-most-once semantics.
493                 _writeEventArgs = null;
494                 return;
495             }
496 
497             if(!_incoming && _state < StateConnected)
498             {
499                 if(_writeEventArgs.SocketError != SocketError.Success)
500                 {
501                     SocketException ex = new SocketException((int)_writeEventArgs.SocketError);
502                     if(Network.connectionRefused(ex))
503                     {
504                         throw new Ice.ConnectionRefusedException(ex);
505                     }
506                     else
507                     {
508                         throw new Ice.ConnectFailedException(ex);
509                     }
510                 }
511                 return;
512             }
513 
514             int ret;
515             try
516             {
517                 if(_writeEventArgs.SocketError != SocketError.Success)
518                 {
519                     throw new SocketException((int)_writeEventArgs.SocketError);
520                 }
521                 ret = _writeEventArgs.BytesTransferred;
522             }
523             catch(SocketException ex)
524             {
525                 if(Network.connectionLost(ex))
526                 {
527                     throw new Ice.ConnectionLostException(ex);
528                 }
529                 else
530                 {
531                     throw new Ice.SocketException(ex);
532                 }
533             }
534 
535             if(ret == 0)
536             {
537                 throw new Ice.ConnectionLostException();
538             }
539 
540             Debug.Assert(ret > 0);
541             Debug.Assert(ret == buf.b.limit());
542             buf.b.position(buf.b.position() + ret);
543         }
544 
protocol()545         public string protocol()
546         {
547             return _instance.protocol();
548         }
549 
getInfo()550         public Ice.ConnectionInfo getInfo()
551         {
552             Ice.UDPConnectionInfo info = new Ice.UDPConnectionInfo();
553             if(_fd != null)
554             {
555                 EndPoint localEndpoint = Network.getLocalAddress(_fd);
556                 info.localAddress = Network.endpointAddressToString(localEndpoint);
557                 info.localPort = Network.endpointPort(localEndpoint);
558                 if(_state == StateNotConnected)
559                 {
560                     if(_peerAddr != null)
561                     {
562                         info.remoteAddress = Network.endpointAddressToString(_peerAddr);
563                         info.remotePort = Network.endpointPort(_peerAddr);
564                     }
565                 }
566                 else
567                 {
568                     EndPoint remoteEndpoint = Network.getRemoteAddress(_fd);
569                     if(remoteEndpoint != null)
570                     {
571                         info.remoteAddress = Network.endpointAddressToString(remoteEndpoint);
572                         info.remotePort = Network.endpointPort(remoteEndpoint);
573                     }
574                 }
575                 info.rcvSize = Network.getRecvBufferSize(_fd);
576                 info.sndSize = Network.getSendBufferSize(_fd);
577             }
578 
579             if(_mcastAddr != null)
580             {
581                 info.mcastAddress = Network.endpointAddressToString(_mcastAddr);
582                 info.mcastPort = Network.endpointPort(_mcastAddr);
583             }
584             return info;
585         }
586 
checkSendSize(Buffer buf)587         public void checkSendSize(Buffer buf)
588         {
589             //
590             // The maximum packetSize is either the maximum allowable UDP packet size, or
591             // the UDP send buffer size (which ever is smaller).
592             //
593             int packetSize = Math.Min(_maxPacketSize, _sndSize - _udpOverhead);
594             if(packetSize < buf.size())
595             {
596                 throw new Ice.DatagramLimitException();
597             }
598         }
599 
setBufferSize(int rcvSize, int sndSize)600         public void setBufferSize(int rcvSize, int sndSize)
601         {
602             setBufSize(rcvSize, sndSize);
603         }
604 
ToString()605         public override string ToString()
606         {
607             if(_fd == null)
608             {
609                 return "<closed>";
610             }
611 
612             string s;
613             if(_incoming && !_bound)
614             {
615                 s = "local address = " + Network.addrToString(_addr);
616             }
617             else if(_state == StateNotConnected)
618             {
619                 s = "local address = " + Network.localAddrToString(Network.getLocalAddress(_fd));
620                 if(_peerAddr != null)
621                 {
622                     s += "\nremote address = " + Network.addrToString(_peerAddr);
623                 }
624             }
625             else
626             {
627                 s = Network.fdToString(_fd);
628             }
629 
630             if(_mcastAddr != null)
631             {
632                 s += "\nmulticast address = " + Network.addrToString(_mcastAddr);
633             }
634             return s;
635         }
636 
toDetailedString()637         public string toDetailedString()
638         {
639             StringBuilder s = new StringBuilder(ToString());
640             List<string> intfs;
641             if(_mcastAddr == null)
642             {
643                 intfs = Network.getHostsForEndpointExpand(Network.endpointAddressToString(_addr),
644                                                           _instance.protocolSupport(), true);
645             }
646             else
647             {
648                 intfs = Network.getInterfacesForMulticast(_mcastInterface,
649                                                           Network.getProtocolSupport(_mcastAddr.Address));
650             }
651             if(intfs.Count != 0)
652             {
653                 s.Append("\nlocal interfaces = ");
654                 s.Append(string.Join(", ", intfs.ToArray()));
655             }
656             return s.ToString();
657         }
658 
effectivePort()659         public int effectivePort()
660         {
661             return Network.endpointPort(_addr);
662         }
663 
664         //
665         // Only for use by UdpConnector.
666         //
UdpTransceiver(ProtocolInstance instance, EndPoint addr, EndPoint sourceAddr, string mcastInterface, int mcastTtl)667         internal UdpTransceiver(ProtocolInstance instance, EndPoint addr, EndPoint sourceAddr, string mcastInterface,
668                                 int mcastTtl)
669         {
670             _instance = instance;
671             _addr = addr;
672             _sourceAddr = sourceAddr;
673 
674             _readEventArgs = new SocketAsyncEventArgs();
675             _readEventArgs.RemoteEndPoint = _addr;
676             _readEventArgs.Completed += new EventHandler<SocketAsyncEventArgs>(ioCompleted);
677 
678             _writeEventArgs = new SocketAsyncEventArgs();
679             _writeEventArgs.RemoteEndPoint = _addr;
680             _writeEventArgs.Completed += new EventHandler<SocketAsyncEventArgs>(ioCompleted);
681 
682             _mcastInterface = mcastInterface;
683             _state = StateNeedConnect;
684             _incoming = false;
685 
686             try
687             {
688                 _fd = Network.createSocket(true, _addr.AddressFamily);
689                 setBufSize(-1, -1);
690                 Network.setBlock(_fd, false);
691                 if(Network.isMulticast((IPEndPoint)_addr))
692                 {
693                     if(_mcastInterface.Length > 0)
694                     {
695                         Network.setMcastInterface(_fd, _mcastInterface, _addr.AddressFamily);
696                     }
697                     if(mcastTtl != -1)
698                     {
699                         Network.setMcastTtl(_fd, mcastTtl, _addr.AddressFamily);
700                     }
701                 }
702             }
703             catch(Ice.LocalException)
704             {
705                 _fd = null;
706                 throw;
707             }
708         }
709 
710         //
711         // Only for use by UdpEndpoint.
712         //
UdpTransceiver(UdpEndpointI endpoint, ProtocolInstance instance, string host, int port, string mcastInterface, bool connect)713         internal UdpTransceiver(UdpEndpointI endpoint, ProtocolInstance instance, string host, int port,
714                                 string mcastInterface, bool connect)
715         {
716             _endpoint = endpoint;
717             _instance = instance;
718             _state = connect ? StateNeedConnect : StateNotConnected;
719             _mcastInterface = mcastInterface;
720             _incoming = true;
721             _port = port;
722 
723             try
724             {
725                 _addr = Network.getAddressForServer(host, port, instance.protocolSupport(), instance.preferIPv6());
726 
727                 _readEventArgs = new SocketAsyncEventArgs();
728                 _readEventArgs.RemoteEndPoint = _addr;
729                 _readEventArgs.Completed += new EventHandler<SocketAsyncEventArgs>(ioCompleted);
730 
731                 _writeEventArgs = new SocketAsyncEventArgs();
732                 _writeEventArgs.RemoteEndPoint = _addr;
733                 _writeEventArgs.Completed += new EventHandler<SocketAsyncEventArgs>(ioCompleted);
734 
735                 _fd = Network.createServerSocket(true, _addr.AddressFamily, instance.protocolSupport());
736                 setBufSize(-1, -1);
737                 Network.setBlock(_fd, false);
738             }
739             catch(Ice.LocalException)
740             {
741                 if(_readEventArgs != null)
742                 {
743                     _readEventArgs.Dispose();
744                 }
745                 if(_writeEventArgs != null)
746                 {
747                     _writeEventArgs.Dispose();
748                 }
749                 _fd = null;
750                 throw;
751             }
752         }
753 
setBufSize(int rcvSize, int sndSize)754         private void setBufSize(int rcvSize, int sndSize)
755         {
756             Debug.Assert(_fd != null);
757 
758             for (int i = 0; i < 2; ++i)
759             {
760                 bool isSnd;
761                 string direction;
762                 string prop;
763                 int dfltSize;
764                 int sizeRequested;
765                 if(i == 0)
766                 {
767                     isSnd = false;
768                     direction = "receive";
769                     prop = "Ice.UDP.RcvSize";
770                     dfltSize = Network.getRecvBufferSize(_fd);
771                     sizeRequested = rcvSize;
772                     _rcvSize = dfltSize;
773                 }
774                 else
775                 {
776                     isSnd = true;
777                     direction = "send";
778                     prop = "Ice.UDP.SndSize";
779                     dfltSize = Network.getSendBufferSize(_fd);
780                     sizeRequested = sndSize;
781                     _sndSize = dfltSize;
782                 }
783 
784                 //
785                 // Get property for buffer size if size not passed in.
786                 //
787                 if(sizeRequested == -1)
788                 {
789                     sizeRequested = _instance.properties().getPropertyAsIntWithDefault(prop, dfltSize);
790                 }
791                 //
792                 // Check for sanity.
793                 //
794                 if(sizeRequested < (_udpOverhead + Protocol.headerSize))
795                 {
796                     _instance.logger().warning("Invalid " + prop + " value of " + sizeRequested + " adjusted to " +
797                                                dfltSize);
798                     sizeRequested = dfltSize;
799                 }
800 
801                 if(sizeRequested != dfltSize)
802                 {
803                     //
804                     // Try to set the buffer size. The kernel will silently adjust
805                     // the size to an acceptable value. Then read the size back to
806                     // get the size that was actually set.
807                     //
808                     int sizeSet;
809                     if(i == 0)
810                     {
811                         Network.setRecvBufferSize(_fd, sizeRequested);
812                         _rcvSize = Network.getRecvBufferSize(_fd);
813                         sizeSet = _rcvSize;
814                     }
815                     else
816                     {
817                         Network.setSendBufferSize(_fd, sizeRequested);
818                         _sndSize = Network.getSendBufferSize(_fd);
819                         sizeSet = _sndSize;
820                     }
821 
822                     //
823                     // Warn if the size that was set is less than the requested size
824                     // and we have not already warned
825                     //
826                     if(sizeSet < sizeRequested)
827                     {
828                         BufSizeWarnInfo winfo = _instance.getBufSizeWarn(Ice.UDPEndpointType.value);
829                         if((isSnd && (!winfo.sndWarn || winfo.sndSize != sizeRequested)) ||
830                            (!isSnd && (!winfo.rcvWarn || winfo.rcvSize != sizeRequested)))
831                         {
832                             _instance.logger().warning("UDP " + direction + " buffer size: requested size of " +
833                                                        sizeRequested + " adjusted to " + sizeSet);
834 
835                             if(isSnd)
836                             {
837                                 _instance.setSndBufSizeWarn(Ice.UDPEndpointType.value, sizeRequested);
838                             }
839                             else
840                             {
841                                 _instance.setRcvBufSizeWarn(Ice.UDPEndpointType.value, sizeRequested);
842                             }
843                         }
844                     }
845                 }
846             }
847         }
848 
ioCompleted(object sender, SocketAsyncEventArgs e)849         internal void ioCompleted(object sender, SocketAsyncEventArgs e)
850         {
851             switch (e.LastOperation)
852             {
853             case SocketAsyncOperation.Receive:
854             case SocketAsyncOperation.ReceiveFrom:
855                 _readCallback(e.UserToken);
856                 break;
857             case SocketAsyncOperation.Send:
858             case SocketAsyncOperation.Connect:
859                 _writeCallback(e.UserToken);
860                 break;
861             default:
862                 throw new ArgumentException("The last operation completed on the socket was not a receive or send");
863             }
864         }
865 
866         private UdpEndpointI _endpoint;
867         private ProtocolInstance _instance;
868         private int _state;
869         private bool _incoming;
870         private int _rcvSize;
871         private int _sndSize;
872         private Socket _fd;
873         private EndPoint _addr;
874         private EndPoint _sourceAddr;
875         private IPEndPoint _mcastAddr = null;
876         private EndPoint _peerAddr = null;
877         private string _mcastInterface = null;
878 
879         private int _port = 0;
880         private bool _bound = false;
881 
882         private SocketAsyncEventArgs _writeEventArgs;
883         private SocketAsyncEventArgs _readEventArgs;
884 
885         AsyncCallback _writeCallback;
886         AsyncCallback _readCallback;
887 
888         private const int StateNeedConnect = 0;
889         private const int StateConnectPending = 1;
890         private const int StateConnected = 2;
891         private const int StateNotConnected = 3;
892 
893         //
894         // The maximum IP datagram size is 65535. Subtract 20 bytes for the IP header and 8 bytes for the UDP header
895         // to get the maximum payload.
896         //
897         private const int _udpOverhead = 20 + 8;
898         private const int _maxPacketSize = 65535 - _udpOverhead;
899     }
900 }
901