This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: Remaining buffer from socket isn't available anymore after calling socket.recv the first time
Type: behavior Stage: resolved
Components: Library (Lib) Versions: Python 3.4
process
Status: closed Resolution: not a bug
Dependencies: Superseder:
Assigned To: Nosy List: Sworddragon, neologix
Priority: normal Keywords:

Created on 2014-06-21 05:04 by Sworddragon, last changed 2022-04-11 14:58 by admin. This issue is now closed.

Messages (4)
msg221155 - (view) Author: (Sworddragon) Date: 2014-06-21 05:04
If I'm receiving data from a socket (several bytes) and making the first call to socket.recv(1) all is fine but the second call won't get any further data. But doing this again with socket.recv(2) instead will successfully get the 2 bytes. Here is a testcase:


Script:

def icmp_packet(type, code, data):
	length_data = len(data)
	if length_data % 2 == 1:
		data += b'\x00'
	checksum = code | type << 8
	i = 0
	while i < length_data:
		checksum += data[i + 1] | data[i] << 8
		checksum = (checksum & 65535) + (checksum >> 16)
		i += 2
	return bytes([type]) + bytes([code]) + (checksum ^ 65535).to_bytes(2, 'big') + data

import socket

connection = socket.socket(proto = socket.IPPROTO_ICMP, type = socket.SOCK_RAW)
connection.settimeout(1)
connection.sendto(icmp_packet(8, 0, b'\x00\x00\x00\x00'), ('8.8.8.8', 0))
print(connection.recv(2))
connection.close()
connection = socket.socket(proto = socket.IPPROTO_ICMP, type = socket.SOCK_RAW)
connection.settimeout(1)
connection.sendto(icmp_packet(8, 0, b'\x00\x00\x00\x00'), ('8.8.8.8', 0))
print(connection.recv(1))
print(connection.recv(1))
connection.close()


Here is the result:

root@ubuntu:/home/sworddragon/tmp# python3 test.py
b'E\x00'
b'E'
Traceback (most recent call last):
  File "test.py", line 24, in <module>
    print(connection.recv(1))
socket.timeout: timed out
msg221164 - (view) Author: Charles-François Natali (neologix) * (Python committer) Date: 2014-06-21 10:08
> If I'm receiving data from a socket (several bytes) and making the
> first call to socket.recv(1) all is fine but the second call won't get
> any further data. But doing this again with socket.recv(2) instead will
> successfully get the 2 bytes. Here is a testcase:

First, note that Python just calles the underlying recv() syscall, so it's not at fault here.

And actually, noone's at fault here, because what you're trying to do doesn't make sense: ICMP is datagram-oriented, so you should use recvfrom(): and if you try to receive less bytes than the datagram size, the rest will be discarded, like UDP.
msg221182 - (view) Author: (Sworddragon) Date: 2014-06-21 18:27
> and if you try to receive less bytes than the datagram size, the rest will be discarded, like UDP.

I'm wondering how would it be possible then to fetch packets of an unknown size without using an extremely big buffer.
msg221223 - (view) Author: Charles-François Natali (neologix) * (Python committer) Date: 2014-06-22 06:40
> I'm wondering how would it be possible then to fetch packets of an unknown size without using an extremely big buffer.

IP packets are limited to 64K, so just pass a 64K buffer, that's not
"extremely big".
If you really wanted to avoid this, you could try the FIONREAD ioctl,
but I wouldn't advise it.
History
Date User Action Args
2022-04-11 14:58:05adminsetgithub: 66018
2014-06-22 06:40:56neologixsetmessages: + msg221223
2014-06-21 18:27:50Sworddragonsetmessages: + msg221182
2014-06-21 10:08:56neologixsetstatus: open -> closed

nosy: + neologix
messages: + msg221164

resolution: not a bug
stage: resolved
2014-06-21 05:04:51Sworddragoncreate