1# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: t -*-
2# vi: set ft=python sts=4 ts=4 sw=4 noet :
3
4# This file is part of Fail2Ban.
5#
6# Fail2Ban is free software; you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation; either version 2 of the License, or
9# (at your option) any later version.
10#
11# Fail2Ban is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with Fail2Ban; if not, write to the Free Software
18# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19
20# Author: Cyril Jaquier
21#
22
23__author__ = "Cyril Jaquier"
24__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
25__license__ = "GPL"
26
27#from cPickle import dumps, loads, HIGHEST_PROTOCOL
28from pickle import dumps, loads, HIGHEST_PROTOCOL
29from ..protocol import CSPROTO
30import socket
31import sys
32
33class CSocket:
34
35	def __init__(self, sock="/var/run/fail2ban/fail2ban.sock", timeout=-1):
36		# Create an INET, STREAMing socket
37		#self.csock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
38		self.__csock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
39		self.__deftout = self.__csock.gettimeout()
40		if timeout != -1:
41			self.settimeout(timeout)
42		#self.csock.connect(("localhost", 2222))
43		self.__csock.connect(sock)
44
45	def __del__(self):
46		self.close()
47
48	def send(self, msg, nonblocking=False, timeout=None):
49		# Convert every list member to string
50		obj = dumps(list(map(CSocket.convert, msg)), HIGHEST_PROTOCOL)
51		self.__csock.send(obj)
52		self.__csock.send(CSPROTO.END)
53		return self.receive(self.__csock, nonblocking, timeout)
54
55	def settimeout(self, timeout):
56		self.__csock.settimeout(timeout if timeout != -1 else self.__deftout)
57
58	def close(self):
59		if not self.__csock:
60			return
61		try:
62			self.__csock.sendall(CSPROTO.CLOSE + CSPROTO.END)
63			self.__csock.shutdown(socket.SHUT_RDWR)
64		except socket.error: # pragma: no cover - normally unreachable
65			pass
66		try:
67			self.__csock.close()
68		except socket.error: # pragma: no cover - normally unreachable
69			pass
70		self.__csock = None
71
72	@staticmethod
73	def convert(m):
74		"""Convert every "unexpected" member of message to string"""
75		if isinstance(m, (str, bool, int, float, list, dict, set)):
76			return m
77		else: # pragma: no cover
78			return str(m)
79
80	@staticmethod
81	def receive(sock, nonblocking=False, timeout=None):
82		msg = CSPROTO.EMPTY
83		if nonblocking: sock.setblocking(0)
84		if timeout: sock.settimeout(timeout)
85		bufsize = 1024
86		while msg.rfind(CSPROTO.END, -32) == -1:
87			chunk = sock.recv(bufsize)
88			if not len(chunk):
89				raise socket.error(104, 'Connection reset by peer')
90			if chunk == CSPROTO.END: break
91			msg = msg + chunk
92			if bufsize < 32768: bufsize <<= 1
93		return loads(msg)
94