Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

gh-65920: Implementsocket.sendfile withTransmitFile on Windows#112337

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Open
aisk wants to merge11 commits intopython:main
base:main
Choose a base branch
Loading
fromaisk:windows-socket-sendfile
Open
Show file tree
Hide file tree
Changes from9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletionsLib/socket.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -55,6 +55,13 @@
import os, sys, io, selectors
from enum import IntEnum, IntFlag

try:
import _overlapped
import msvcrt
except ImportError:
_overlapped = None
msvcrt = None

try:
import errno
except ImportError:
Expand DownExpand Up@@ -451,6 +458,39 @@ def _sendfile_use_send(self, file, offset=0, count=None):
if total_sent > 0 and hasattr(file, 'seek'):
file.seek(offset + total_sent)

if _overlapped:
def _sendfile_use_transmitfile(self, file, offset=0, count=None):
self._check_sendfile_params(file, offset, count)
timeout = self.gettimeout()
if timeout == 0:
raise ValueError("non-blocking sockets are not supported")
ov = _overlapped.Overlapped()
offset_low = offset & 0xffff_ffff
offset_high = (offset >> 32) & 0xffff_ffff
count = count or 0
try:
fileno = file.fileno()
except (AttributeError, io.UnsupportedOperation) as err:
raise _GiveupOnSendfile(err) # not a regular file
try:
os.fstat(fileno)
except OSError as err:
raise _GiveupOnSendfile(err) # not a regular file
ov.TransmitFile(self.fileno(), msvcrt.get_osfhandle(fileno),
offset_low, offset_high, count, 0, 0)
timeout_ms = _overlapped.INFINITE
if timeout is not None:
timeout_ms = int(timeout * 1000)
try:
sent = ov.getresultex(timeout_ms, False)
except WindowsError as e:
if e.winerror == 258:
raise TimeoutError('timed out')
raise
if sent > 0 and hasattr(file, 'seek'):
file.seek(offset + sent)
return sent

def _check_sendfile_params(self, file, offset, count):
if 'b' not in getattr(file, 'mode', 'b'):
raise ValueError("file should be opened in binary mode")
Expand DownExpand Up@@ -483,6 +523,8 @@ def sendfile(self, file, offset=0, count=None):
Non-blocking sockets are not supported.
"""
try:
if sys.platform == "win32":
return self._sendfile_use_transmitfile(file, offset, count)
return self._sendfile_use_sendfile(file, offset, count)
except _GiveupOnSendfile:
return self._sendfile_use_send(file, offset, count)
Expand Down
9 changes: 9 additions & 0 deletionsLib/test/test_socket.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -6434,6 +6434,15 @@ def meth_from_sock(self, sock):
return getattr(sock, "_sendfile_use_sendfile")


@unittest.skipUnless(sys.platform == "win32", "Windows only test.")
class SendfileUsingTransmitfileTest(SendfileUsingSendTest):
"""
Test the TransmitFile() implementation of socket.sendfile().
"""
def meth_from_sock(self, sock):
return getattr(sock, "_sendfile_use_transmitfile")


@unittest.skipUnless(HAVE_SOCKET_ALG, 'AF_ALG required')
class LinuxKernelCryptoAPI(unittest.TestCase):
# tests for AF_ALG
Expand Down
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
Use :c:func:`!TransmitFile` on Windows to implement :func:`socket.sendfile`.
37 changes: 36 additions & 1 deletionModules/clinic/overlapped.c.h
View file
Open in desktop

Some generated files are not rendered by default. Learn more abouthow customized files appear on GitHub.

116 changes: 81 additions & 35 deletionsModules/overlapped.c
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -849,44 +849,13 @@ _overlapped_Overlapped_cancel_impl(OverlappedObject *self)
Py_RETURN_NONE;
}

/*[clinic input]
_overlapped.Overlapped.getresult

wait: BOOL(c_default='FALSE') = False
/

Retrieve result of operation.

If wait is true then it blocks until the operation is finished. If wait
is false and the operation is still pending then an error is raised.
[clinic start generated code]*/

static PyObject *
_overlapped_Overlapped_getresult_impl(OverlappedObject *self, BOOL wait)
/*[clinic end generated code: output=8c9bd04d08994f6c input=aa5b03e9897ca074]*/
check_getresult_error(OverlappedObject *self, DWORD transferred)
{
DWORD transferred = 0;
BOOL ret;
DWORD err;
PyObject *addr;

if (self->type == TYPE_NONE) {
PyErr_SetString(PyExc_ValueError, "operation not yet attempted");
return NULL;
}
PyObject *addr = NULL;
DWORD err = self->error;

if (self->type == TYPE_NOT_STARTED) {
PyErr_SetString(PyExc_ValueError, "operation failed to start");
return NULL;
}

Py_BEGIN_ALLOW_THREADS
ret = GetOverlappedResult(self->handle, &self->overlapped, &transferred,
wait);
Py_END_ALLOW_THREADS

self->error = err = ret ? ERROR_SUCCESS : GetLastError();
switch (err) {
switch (self->error) {
case ERROR_SUCCESS:
case ERROR_MORE_DATA:
break;
Expand DownExpand Up@@ -978,6 +947,82 @@ _overlapped_Overlapped_getresult_impl(OverlappedObject *self, BOOL wait)
}
}

/*[clinic input]
_overlapped.Overlapped.getresult

wait: BOOL(c_default='FALSE') = False
/

Retrieve result of operation.

If wait is true then it blocks until the operation is finished. If wait
is false and the operation is still pending then an error is raised.
[clinic start generated code]*/

static PyObject *
_overlapped_Overlapped_getresult_impl(OverlappedObject *self, BOOL wait)
/*[clinic end generated code: output=8c9bd04d08994f6c input=aa5b03e9897ca074]*/
{
DWORD transferred = 0;
BOOL ret;

if (self->type == TYPE_NONE) {
PyErr_SetString(PyExc_ValueError, "operation not yet attempted");
return NULL;
}

if (self->type == TYPE_NOT_STARTED) {
PyErr_SetString(PyExc_ValueError, "operation failed to start");
return NULL;
}

Py_BEGIN_ALLOW_THREADS
ret = GetOverlappedResult(self->handle, &self->overlapped, &transferred,
wait);
Py_END_ALLOW_THREADS

self->error = ret ? ERROR_SUCCESS : GetLastError();

return check_getresult_error(self, transferred);
}

/*[clinic input]
_overlapped.Overlapped.getresultex

milliseconds: DWORD
alertable: BOOL
/

[clinic start generated code]*/

static PyObject *
_overlapped_Overlapped_getresultex_impl(OverlappedObject *self,
DWORD milliseconds, BOOL alertable)
/*[clinic end generated code: output=ce0eb6ffb9618e54 input=ef4f4cab49ac1d80]*/
{
DWORD transferred = 0;
BOOL ret;

if (self->type == TYPE_NONE) {
PyErr_SetString(PyExc_ValueError, "operation not yet attempted");
return NULL;
}

if (self->type == TYPE_NOT_STARTED) {
PyErr_SetString(PyExc_ValueError, "operation failed to start");
return NULL;
}

Py_BEGIN_ALLOW_THREADS
ret = GetOverlappedResultEx(self->handle, &self->overlapped, &transferred,
milliseconds, alertable);
Py_END_ALLOW_THREADS

self->error = ret ? ERROR_SUCCESS : GetLastError();

return check_getresult_error(self, transferred);
}

static PyObject *
do_ReadFile(OverlappedObject *self, HANDLE handle,
char *bufstart, DWORD buflen)
Expand DownExpand Up@@ -1927,6 +1972,7 @@ _overlapped_Overlapped_WSARecvFromInto_impl(OverlappedObject *self,

static PyMethodDef Overlapped_methods[] = {
_OVERLAPPED_OVERLAPPED_GETRESULT_METHODDEF
_OVERLAPPED_OVERLAPPED_GETRESULTEX_METHODDEF
_OVERLAPPED_OVERLAPPED_CANCEL_METHODDEF
_OVERLAPPED_OVERLAPPED_READFILE_METHODDEF
_OVERLAPPED_OVERLAPPED_READFILEINTO_METHODDEF
Expand Down

[8]ページ先頭

©2009-2025 Movatter.jp