|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
# tio.py - I/O functions
|
|
Packit |
6bd9ab |
#
|
|
Packit |
6bd9ab |
# Copyright (C) 2010, 2011, 2012, 2013 Arthur de Jong
|
|
Packit |
6bd9ab |
#
|
|
Packit |
6bd9ab |
# This library is free software; you can redistribute it and/or
|
|
Packit |
6bd9ab |
# modify it under the terms of the GNU Lesser General Public
|
|
Packit |
6bd9ab |
# License as published by the Free Software Foundation; either
|
|
Packit |
6bd9ab |
# version 2.1 of the License, or (at your option) any later version.
|
|
Packit |
6bd9ab |
#
|
|
Packit |
6bd9ab |
# This library is distributed in the hope that it will be useful,
|
|
Packit |
6bd9ab |
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
6bd9ab |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
6bd9ab |
# Lesser General Public License for more details.
|
|
Packit |
6bd9ab |
#
|
|
Packit |
6bd9ab |
# You should have received a copy of the GNU Lesser General Public
|
|
Packit |
6bd9ab |
# License along with this library; if not, write to the Free Software
|
|
Packit |
6bd9ab |
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
Packit |
6bd9ab |
# 02110-1301 USA
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
import os
|
|
Packit |
6bd9ab |
import socket
|
|
Packit |
6bd9ab |
import struct
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
# definition for reading and writing INT32 values
|
|
Packit |
6bd9ab |
_int32 = struct.Struct('!i')
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
# FIXME: use something from constants.py to determine the correct size
|
|
Packit |
6bd9ab |
_struct_timeval = struct.Struct('ll')
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
class TIOStreamError(Exception):
|
|
Packit |
6bd9ab |
pass
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
class TIOStream(object):
|
|
Packit |
6bd9ab |
"""File-like object that allows reading and writing nslcd-protocol
|
|
Packit |
6bd9ab |
entities."""
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
def __init__(self, conn):
|
|
Packit |
6bd9ab |
conn.setblocking(1)
|
|
Packit |
6bd9ab |
conn.setsockopt(socket.SOL_SOCKET, socket.SO_RCVTIMEO, _struct_timeval.pack(0, 500000))
|
|
Packit |
6bd9ab |
conn.setsockopt(socket.SOL_SOCKET, socket.SO_SNDTIMEO, _struct_timeval.pack(60, 0))
|
|
Packit |
6bd9ab |
self.fp = os.fdopen(conn.fileno(), 'w+b', 1024 * 1024)
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
def read(self, size):
|
|
Packit |
6bd9ab |
return self.fp.read(size)
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
def read_int32(self):
|
|
Packit |
6bd9ab |
return _int32.unpack(self.read(_int32.size))[0]
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
def read_string(self, maxsize=None):
|
|
Packit |
6bd9ab |
num = self.read_int32()
|
|
Packit |
6bd9ab |
if maxsize and num >= maxsize:
|
|
Packit |
6bd9ab |
raise TIOStreamError()
|
|
Packit |
6bd9ab |
return self.read(num)
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
def read_address(self):
|
|
Packit |
6bd9ab |
"""Read an address (usually IPv4 or IPv6) from the stream and return
|
|
Packit |
6bd9ab |
the address as a string representation."""
|
|
Packit |
6bd9ab |
af = self.read_int32()
|
|
Packit |
6bd9ab |
return socket.inet_ntop(af, self.read_string(maxsize=64))
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
def write(self, value):
|
|
Packit |
6bd9ab |
self.fp.write(value)
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
def write_int32(self, value):
|
|
Packit |
6bd9ab |
self.write(_int32.pack(value))
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
def write_string(self, value):
|
|
Packit |
6bd9ab |
self.write_int32(len(value))
|
|
Packit |
6bd9ab |
self.write(value)
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
def write_stringlist(self, value):
|
|
Packit |
6bd9ab |
lst = tuple(value)
|
|
Packit |
6bd9ab |
self.write_int32(len(lst))
|
|
Packit |
6bd9ab |
for string in lst:
|
|
Packit |
6bd9ab |
self.write_string(string)
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
@staticmethod
|
|
Packit |
6bd9ab |
def _to_address(value):
|
|
Packit |
6bd9ab |
# try IPv4 first
|
|
Packit |
6bd9ab |
try:
|
|
Packit |
6bd9ab |
return socket.AF_INET, socket.inet_pton(socket.AF_INET, value)
|
|
Packit |
6bd9ab |
except socket.error:
|
|
Packit |
6bd9ab |
pass # try the next one
|
|
Packit |
6bd9ab |
# fall back to IPv6
|
|
Packit |
6bd9ab |
return socket.AF_INET6, socket.inet_pton(socket.AF_INET6, value)
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
def write_address(self, value):
|
|
Packit |
6bd9ab |
"""Write an address (usually IPv4 or IPv6) in a string representation
|
|
Packit |
6bd9ab |
to the stream."""
|
|
Packit |
6bd9ab |
# first try to make it into an IPv6 address
|
|
Packit |
6bd9ab |
af, address = TIOStream._to_address(value)
|
|
Packit |
6bd9ab |
self.write_int32(af)
|
|
Packit |
6bd9ab |
self.write_string(address)
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
def close(self):
|
|
Packit |
6bd9ab |
try:
|
|
Packit |
6bd9ab |
self.fp.close()
|
|
Packit |
6bd9ab |
except IOError:
|
|
Packit |
6bd9ab |
pass
|
|
Packit |
6bd9ab |
|
|
Packit |
6bd9ab |
def __del__(self):
|
|
Packit |
6bd9ab |
self.close()
|