@@ -20,6 +20,7 @@ cdef class _UDPSendContext:
2020 self .closed = 1
2121 PyBuffer_Release(& self .py_buf) # void
2222 self .req.data = NULL
23+ self .uv_buf.base = NULL
2324 Py_DECREF(self )
2425 self .udp = None
2526
@@ -34,7 +35,8 @@ cdef class _UDPSendContext:
3435 Py_INCREF(ctx)
3536
3637 PyObject_GetBuffer(data, & ctx.py_buf, PyBUF_SIMPLE)
37- ctx.uv_buf = uv.uv_buf_init(< char * > ctx.py_buf.buf, ctx.py_buf.len)
38+ ctx.uv_buf.base = < char * > ctx.py_buf.buf
39+ ctx.uv_buf.len = ctx.py_buf.len
3840 ctx.udp = udp
3941
4042 ctx.closed = 0
@@ -193,37 +195,63 @@ cdef class UDPTransport(UVBaseTransport):
193195 _UDPSendContext ctx
194196 system.sockaddr_storage saddr_st
195197 system.sockaddr * saddr
198+ Py_buffer try_pybuf
199+ uv.uv_buf_t try_uvbuf
200+
201+ self ._ensure_alive()
196202
197203 if self ._family not in (uv.AF_INET, uv.AF_INET6, uv.AF_UNIX):
198204 raise RuntimeError (' UDPTransport.family is undefined; cannot send' )
199205
200- if addr is not None and self ._family != uv.AF_UNIX:
201- validate_address(addr, self ._family, uv.SOCK_DGRAM, 0 )
202-
203- ctx = _UDPSendContext.new(self , data)
204- try :
205- if addr is None :
206- saddr = NULL
207- else :
206+ if addr is None :
207+ saddr = NULL
208+ else :
209+ try :
208210 __convert_pyaddr_to_sockaddr(self ._family, addr,
209211 < system.sockaddr* > & saddr_st)
210- saddr = < system.sockaddr* > (& saddr_st)
211- except Exception :
212- ctx.close()
213- raise
214-
215- err = uv.uv_udp_send(& ctx.req,
216- < uv.uv_udp_t* > self ._handle,
217- & ctx.uv_buf,
218- 1 ,
219- saddr,
220- __uv_udp_on_send)
221-
222- if err < 0 :
223- ctx.close()
212+ except (ValueError , TypeError ):
213+ raise
214+ except Exception :
215+ raise ValueError (
216+ f' {addr!r}: socket family mismatch or '
217+ f' a DNS lookup is required' )
218+ saddr = < system.sockaddr* > (& saddr_st)
219+
220+ if self ._get_write_buffer_size() == 0 :
221+ PyObject_GetBuffer(data, & try_pybuf, PyBUF_SIMPLE)
222+ try_uvbuf.base = < char * > try_pybuf.buf
223+ try_uvbuf.len = try_pybuf.len
224+ err = uv.uv_udp_try_send(< uv.uv_udp_t* > self ._handle,
225+ & try_uvbuf,
226+ 1 ,
227+ saddr)
228+ PyBuffer_Release(& try_pybuf)
229+ else :
230+ err = uv.UV_EAGAIN
231+
232+ if err == uv.UV_EAGAIN:
233+ ctx = _UDPSendContext.new(self , data)
234+ err = uv.uv_udp_send(& ctx.req,
235+ < uv.uv_udp_t* > self ._handle,
236+ & ctx.uv_buf,
237+ 1 ,
238+ saddr,
239+ __uv_udp_on_send)
240+
241+ if err < 0 :
242+ ctx.close()
243+
244+ exc = convert_error(err)
245+ self ._fatal_error(exc, True )
246+ else :
247+ self ._maybe_pause_protocol()
224248
225- exc = convert_error(err)
226- self ._fatal_error(exc, True )
249+ else :
250+ if err < 0 :
251+ exc = convert_error(err)
252+ self ._fatal_error(exc, True )
253+ else :
254+ self ._on_sent(None )
227255
228256 cdef _on_receive(self , bytes data, object exc, object addr):
229257 if exc is None :
@@ -248,15 +276,17 @@ cdef class UDPTransport(UVBaseTransport):
248276
249277 def sendto (self , data , addr = None ):
250278 if not data:
279+ # Replicating asyncio logic here.
251280 return
252281
253282 if self ._conn_lost:
254- # TODO add warning
283+ # Replicating asyncio logic here.
284+ if self ._conn_lost >= LOG_THRESHOLD_FOR_CONNLOST_WRITES:
285+ aio_logger.warning(' socket.send() raised exception.' )
255286 self ._conn_lost += 1
256287 return
257288
258289 self ._send(data, addr)
259- self ._maybe_pause_protocol()
260290
261291
262292cdef void __uv_udp_on_receive(uv.uv_udp_t* handle,
@@ -357,17 +387,3 @@ cdef void __uv_udp_on_send(uv.uv_udp_send_t* req, int status) with gil:
357387 udp._on_sent(exc)
358388 except BaseException as exc:
359389 udp._error(exc, False )
360-
361-
362- @ ft_lru_cache ()
363- def validate_address (object addr , int sock_family , int sock_type ,
364- int sock_proto ):
365- addrinfo = __static_getaddrinfo_pyaddr(
366- addr[0 ], addr[1 ],
367- uv.AF_UNSPEC, sock_type, sock_proto, 0 )
368- if addrinfo is None :
369- raise ValueError (
370- ' UDP.sendto(): address {!r} requires a DNS lookup' .format(addr))
371- if addrinfo[0 ] != sock_family:
372- raise ValueError (
373- ' UDP.sendto(): {!r} socket family mismatch' .format(addr))
0 commit comments