5757# Typing imports
5858from typing import (
5959 Any ,
60- Callable ,
6160 Dict ,
61+ List ,
6262 NoReturn ,
6363 Optional ,
6464 Tuple ,
@@ -322,6 +322,26 @@ def send(self, x):
322322class L3PacketSocket (L2Socket ):
323323 desc = "read/write packets at layer 3 using Linux PF_PACKET sockets"
324324
325+ def __init__ (self ,
326+ iface = None , # type: Optional[Union[str, NetworkInterface]]
327+ type = ETH_P_ALL , # type: int
328+ promisc = None , # type: Optional[Any]
329+ filter = None , # type: Optional[Any]
330+ nofilter = 0 , # type: int
331+ monitor = None , # type: Optional[Any]
332+ ):
333+ self .send_socks = {}
334+ super (L3PacketSocket , self ).__init__ (
335+ iface = iface ,
336+ type = type ,
337+ promisc = promisc ,
338+ filter = filter ,
339+ nofilter = nofilter ,
340+ monitor = monitor ,
341+ )
342+ self .filter = filter
343+ self .send_socks = {network_name (self .iface ): self }
344+
325345 def recv (self , x = MTU , ** kwargs ):
326346 # type: (int, **Any) -> Optional[Packet]
327347 pkt = SuperSocket .recv (self , x , ** kwargs )
@@ -332,39 +352,68 @@ def recv(self, x=MTU, **kwargs):
332352
333353 def send (self , x ):
334354 # type: (Packet) -> int
355+ # Select the file descriptor to send the packet on.
335356 iff = x .route ()[0 ]
336357 if iff is None :
337358 iff = network_name (conf .iface )
338- sdto = (iff , self .type )
339- self .outs .bind (sdto )
340- sn = self .outs .getsockname ()
341- ll = lambda x : x # type: Callable[[Packet], Packet]
342359 type_x = type (x )
343- if type_x in conf .l3types :
344- sdto = (iff , conf .l3types .layer2num [type_x ])
345- if sn [3 ] in conf .l2types :
346- ll = lambda x : conf .l2types .num2layer [sn [3 ]]() / x
347- if self .lvl == 3 and not issubclass (self .LL , type_x ):
348- warning ("Incompatible L3 types detected using %s instead of %s !" ,
349- type_x , self .LL )
350- self .LL = type_x
351- sx = raw (ll (x ))
352- x .sent_time = time .time ()
360+ if iff not in self .send_socks :
361+ self .send_socks [iff ] = L3PacketSocket (
362+ iface = iff ,
363+ type = conf .l3types .layer2num .get (type_x , self .type ),
364+ filter = self .filter ,
365+ promisc = self .promisc ,
366+ )
367+ fd = self .send_socks [iff ].outs
368+ if self .lvl == 3 :
369+ if not issubclass (self .LL , type_x ):
370+ warning ("Incompatible L3 types detected using %s instead of %s !" ,
371+ type_x , self .LL )
372+ self .LL = type_x
373+ if self .lvl == 2 :
374+ sx = bytes (self .LL () / x )
375+ else :
376+ sx = bytes (x )
377+ # Now send.
378+ try :
379+ x .sent_time = time .time ()
380+ except AttributeError :
381+ pass
353382 try :
354- return self . outs . sendto (sx , sdto )
383+ return fd . send (sx )
355384 except socket .error as msg :
356385 if msg .errno == 22 and len (sx ) < conf .min_pkt_size :
357- return self . outs .send (
386+ return fd .send (
358387 sx + b"\x00 " * (conf .min_pkt_size - len (sx ))
359388 )
360389 elif conf .auto_fragment and msg .errno == 90 :
361390 i = 0
362391 for p in x .fragment ():
363- i += self . outs . sendto ( raw ( ll ( p )), sdto )
392+ i += fd . send ( bytes ( self . LL () / p ) )
364393 return i
365394 else :
366395 raise
367396
397+ @staticmethod
398+ def select (sockets , remain = None ):
399+ # type: (List[SuperSocket], Optional[float]) -> List[SuperSocket]
400+ socks = [] # type: List[SuperSocket]
401+ for sock in sockets :
402+ if isinstance (sock , L3PacketSocket ):
403+ socks += sock .send_socks .values ()
404+ else :
405+ socks .append (sock )
406+ return L2Socket .select (socks , remain = remain )
407+
408+ def close (self ):
409+ # type: () -> None
410+ if self .closed :
411+ return
412+ super (L3PacketSocket , self ).close ()
413+ for fd in self .send_socks .values ():
414+ if fd is not self :
415+ fd .close ()
416+
368417
369418class VEthPair (object ):
370419 """
0 commit comments