Coverage for pyilper/piltcpip.py: 81%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

108 statements  

1#!/usr/bin/python3 

2# -*- coding: utf-8 -*- 

3# pyILPER 1.2.1 for Linux 

4# 

5# An emulator for virtual HP-IL devices for the PIL-Box 

6# derived from ILPER 1.4.5 for Windows 

7# Copyright (c) 2008-2013 Jean-Francois Garnier 

8# C++ version (c) 2013 Christoph Gießelink 

9# Python Version (c) 2015 Joachim Siebold 

10# 

11# This program is free software; you can redistribute it and/or 

12# modify it under the terms of the GNU General Public License 

13# as published by the Free Software Foundation; either version 2 

14# of the License, or (at your option) any later version. 

15# 

16# This program is distributed in the hope that it will be useful, 

17# but WITHOUT ANY WARRANTY; without even the implied warranty of 

18# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

19# GNU General Public License for more details. 

20# 

21# You should have received a copy of the GNU General Public License 

22# along with this program; if not, write to the Free Software 

23# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 

24# 

25# tcpip object class --------------------------------------------- 

26# 

27# Initial version derived from ILPER 1.43 

28# 

29# Changelog 

30# 

31# 24.09.2015 cg 

32# - added real IPv4/IPv6 dual stack mode 

33# - reconnecting server and client work now 

34# - broken loop don't crash connection any more 

35# - removed some unused class variables 

36# 05.10.2015 jsi 

37# - class statement syntax update 

38# 26.10.2015 cg 

39# - stop endless loop in sendFrame() when client connection fail 

40# 22.11.2015 cg 

41# - removed remainder call of setsrqbit() 

42# 23.11.2015 jsi 

43# - removed all of the SSRQ/CSRQ approach 

44# 29.11.2015 jsi 

45# - removed activity timer 

46# 07.02.2016 jsi 

47# - setpilbox call removed 

48# 13.10.2016 jsi 

49# - remove unregister function 

50# - store tab name if device is registered 

51# 30.10.2016 jsi 

52# - getDevices added (removed by mistake) 

53# 22.12.2016 jsi 

54# - raise TcpIpError missing second param added 

55# 06.01.2017 jsi: 

56# - check for ConnectionError exception when sendig frame to catch all exceptions 

57# 16.01.2017 jsi: 

58# - check for incoming connections to indicate isConnected 

59# - close_outsocket method added 

60# 07.01.2017 jsi: 

61# - timeout parameter added 

62# - refactoring: move code of process() and sendFrame() and device list handling 

63# to thread object 

64# 03.02.2020 jsi: 

65# - fixed Python 3.8 syntax warning 

66 

67import select 

68import socket 

69 

70class TcpIpError(Exception): 

71 def __init__(self,msg,add_msg=None): 

72 self.msg = msg 

73 if add_msg is None: 

74 self.add_msg="" 

75 else: 

76 self.add_msg = add_msg 

77 

78class cls_piltcpip: 

79 

80 def __init__(self,port,remotehost,remoteport): 

81 self.__port__=port # port for input connection 

82 self.__remotehost__=remotehost # host for output connection 

83 self.__remoteport__=remoteport # port for output connection 

84 

85 self.__devices__ = [] # list of virtual devices 

86 

87 self.__serverlist__ = [] 

88 self.__clientlist__= [] 

89 self.__outsocket__= None 

90 self.__outconnected__= False 

91 self.__inconnected__= False 

92 

93 def isConnected(self): 

94 return self.__outconnected__ and self.__inconnected__ 

95 

96# 

97# Connect to Network 

98# 

99 def open(self): 

100# 

101# open network connections 

102# 

103 host= None 

104 self.__serverlist__.clear() 

105 self.__clientlist__.clear() 

106 for res in socket.getaddrinfo(host, self.__port__, socket.AF_UNSPEC, 

107 socket.SOCK_STREAM, 0, socket.AI_PASSIVE): 

108 af, socktype, proto, canonname, sa = res 

109 try: 

110 s = socket.socket(af, socktype, proto) 

111 except OSError as msg: 

112 s = None 

113 continue 

114 try: 

115 s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 

116 s.bind(sa) 

117 s.listen(1) 

118 self.__serverlist__.append(s) 

119 except OSError as msg: 

120 s.close() 

121 continue 

122 if len(self.__serverlist__) == 0: 

123 raise TcpIpError("cannot bind to port","") 

124 

125 def openclient(self): 

126# 

127# connect to remote host 

128# 

129 self.__outsocket__ = None 

130 self.__outconnected__= False 

131 for res in socket.getaddrinfo(self.__remotehost__, self.__remoteport__, socket.AF_UNSPEC, socket.SOCK_STREAM): 

132 af, socktype, proto, canonname, sa = res 

133 try: 

134 self.__outsocket__ = socket.socket(af, socktype, proto) 

135 except OSError as msg: 

136 self.__outsocket__ = None 

137 continue 

138 try: 

139 self.__outsocket__.connect(sa) 

140 self.__outconnected__= True 

141 except OSError as msg: 

142 self.__outsocket__.close() 

143 self.__outsocket__ = None 

144 continue 

145 break 

146 return self.__outconnected__ 

147 

148# 

149# Disconnect from Network 

150# 

151 def close(self): 

152 for s in self.__clientlist__: 

153 s.close() 

154 for s in self.__serverlist__: 

155 s.close() 

156 if self.__outconnected__: 

157 self.__outsocket__.shutdown(socket.SHUT_WR) 

158 self.__outsocket__.close() 

159 self.__outsocket__= None 

160 self.__outconnected__= False 

161 

162# 

163# Close output socket 

164# 

165 def close_outsocket(self): 

166 if self.__outconnected__: 

167 self.__outsocket__.shutdown(socket.SHUT_WR) 

168 self.__outsocket__.close() 

169 self.__outsocket__= None 

170 self.__outconnected__= False 

171# 

172# Read HP-IL frame from PIL-Box (2 byte), handle connect to server socket 

173# 

174 def read(self,timeout): 

175 readable,writable,errored=select.select(self.__serverlist__ + self.__clientlist__,[],[],timeout) 

176 for s in readable: 

177 if self.__serverlist__.count(s) > 0: 

178 cs,addr = s.accept() 

179 self.__clientlist__.append(cs) 

180 self.__inconnected__= True 

181 else: 

182 bytrx = s.recv(2) 

183 if bytrx: 

184 return (socket.ntohs((bytrx[1] << 8) | bytrx[0])) 

185 else: 

186 self.__clientlist__.remove(s) 

187 s.close() 

188 self.__inconnected__= False 

189 return None 

190# 

191# send a IL frame to the virtual loop 

192# 

193 def write(self,frame): 

194 bRetry = True 

195 b=bytearray(2) 

196 f=socket.htons(frame) 

197 b[0]= f & 0xFF 

198 b[1]= f >> 8 

199 while bRetry: 

200 if self.isConnected(): 

201 try: 

202 self.__outsocket__.send(b) 

203 break 

204 except ConnectionError: 

205 self.__outsocket__.shutdown(socket.SHUT_WR) 

206 self.__outsocket__.close() 

207 self.__outsocket__= None 

208 self.__outconnected__ = False 

209 else: 

210 bRetry = self.openclient()