Allow things like multiple distinct users
A new set of credentials would break existing sessions. Support concurrent use of multiple users/passwords, since there are valid use cases. Change-Id: Ic63364f05ec9270e06656d13bbb02d7c88fd21d4
This commit is contained in:
parent
b423b68233
commit
45a8facadd
@ -78,7 +78,10 @@ class ServerSession(ipmisession.Session):
|
|||||||
self.sockaddr = clientaddr
|
self.sockaddr = clientaddr
|
||||||
self.pendingpayloads = collections.deque([])
|
self.pendingpayloads = collections.deque([])
|
||||||
self.pktqueue = collections.deque([])
|
self.pktqueue = collections.deque([])
|
||||||
ipmisession.Session.bmc_handlers[clientaddr] = self
|
if clientaddr not in ipmisession.Session.bmc_handlers:
|
||||||
|
ipmisession.Session.bmc_handlers[clientaddr] = {bmc.port: self}
|
||||||
|
else:
|
||||||
|
ipmisession.Session.bmc_handlers[clientaddr][bmc.port] = self
|
||||||
response = self.create_open_session_response(bytearray(request))
|
response = self.create_open_session_response(bytearray(request))
|
||||||
self.send_payload(response,
|
self.send_payload(response,
|
||||||
constants.payload_types['rmcpplusopenresponse'],
|
constants.payload_types['rmcpplusopenresponse'],
|
||||||
@ -267,10 +270,11 @@ class IpmiServer(object):
|
|||||||
authstatus, chancap, *oemdata)
|
authstatus, chancap, *oemdata)
|
||||||
self.kg = None
|
self.kg = None
|
||||||
self.timeout = 60
|
self.timeout = 60
|
||||||
|
self.port = port
|
||||||
addrinfo = socket.getaddrinfo(address, port, 0,
|
addrinfo = socket.getaddrinfo(address, port, 0,
|
||||||
socket.SOCK_DGRAM)[0]
|
socket.SOCK_DGRAM)[0]
|
||||||
self.serversocket = ipmisession.Session._assignsocket(addrinfo)
|
self.serversocket = ipmisession.Session._assignsocket(addrinfo)
|
||||||
ipmisession.Session.bmc_handlers[self.serversocket] = self
|
ipmisession.Session.bmc_handlers[self.serversocket] = {0: self}
|
||||||
|
|
||||||
def send_auth_cap(self, myaddr, mylun, clientaddr, clientlun, clientseq,
|
def send_auth_cap(self, myaddr, mylun, clientaddr, clientlun, clientseq,
|
||||||
sockaddr):
|
sockaddr):
|
||||||
|
@ -196,16 +196,18 @@ def _io_graball(mysockets, iowaiters):
|
|||||||
# into the select
|
# into the select
|
||||||
if len(rdata[0]) < 4:
|
if len(rdata[0]) < 4:
|
||||||
continue
|
continue
|
||||||
|
myport = mysocket.getsockname()[1]
|
||||||
rdata = rdata + (mysocket,)
|
rdata = rdata + (mysocket,)
|
||||||
relsession = None
|
relsession = None
|
||||||
if rdata[1] in Session.bmc_handlers:
|
if (rdata[1] in Session.bmc_handlers and
|
||||||
|
myport in Session.bmc_handlers[rdata[1]]):
|
||||||
# session data
|
# session data
|
||||||
rdata = rdata + (True,)
|
rdata = rdata + (True,)
|
||||||
relsession = Session.bmc_handlers[rdata[1]]
|
relsession = Session.bmc_handlers[rdata[1]][myport]
|
||||||
elif rdata[2] in Session.bmc_handlers:
|
elif rdata[2] in Session.bmc_handlers:
|
||||||
# pyghmi is the bmc, and we have sessionless data
|
# pyghmi is the bmc, and we have sessionless data
|
||||||
rdata = rdata + (False,)
|
rdata = rdata + (False,)
|
||||||
relsession = Session.bmc_handlers[rdata[2]]
|
relsession = Session.bmc_handlers[rdata[2]][0]
|
||||||
if relsession is not None:
|
if relsession is not None:
|
||||||
relsession.pktqueue.append(rdata)
|
relsession.pktqueue.append(rdata)
|
||||||
sessionqueue.append(relsession)
|
sessionqueue.append(relsession)
|
||||||
@ -302,12 +304,13 @@ class Session(object):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def _cleanup(cls):
|
def _cleanup(cls):
|
||||||
for sesskey in list(cls.bmc_handlers):
|
for sesskey in list(cls.bmc_handlers):
|
||||||
session = cls.bmc_handlers[sesskey]
|
for portent in list(cls.bmc_handlers[sesskey]):
|
||||||
session.cleaningup = True
|
session = cls.bmc_handlers[sesskey][portent]
|
||||||
session.logout()
|
session.cleaningup = True
|
||||||
|
session.logout()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _assignsocket(cls, server=None):
|
def _assignsocket(cls, server=None, forbiddensockets=()):
|
||||||
global iothread
|
global iothread
|
||||||
global iothreadready
|
global iothreadready
|
||||||
global iosockets
|
global iosockets
|
||||||
@ -321,9 +324,15 @@ class Session(object):
|
|||||||
if server is None:
|
if server is None:
|
||||||
sorted_candidates = sorted(dictitems(cls.socketpool),
|
sorted_candidates = sorted(dictitems(cls.socketpool),
|
||||||
key=operator.itemgetter(1))
|
key=operator.itemgetter(1))
|
||||||
if sorted_candidates and sorted_candidates[0][1] < MAX_BMCS_PER_SOCKET:
|
if sorted_candidates is None:
|
||||||
cls.socketpool[sorted_candidates[0][0]] += 1
|
sorted_candidates = []
|
||||||
return sorted_candidates[0][0]
|
for candidate in sorted_candidates:
|
||||||
|
if candidate[1] >= MAX_BMCS_PER_SOCKET:
|
||||||
|
break
|
||||||
|
if candidate[0] in forbiddensockets:
|
||||||
|
continue
|
||||||
|
cls.socketpool[candidate[0]] += 1
|
||||||
|
return candidate[0]
|
||||||
# we need a new socket
|
# we need a new socket
|
||||||
if server:
|
if server:
|
||||||
# Regardless of whether ipv6 is supported or not, we
|
# Regardless of whether ipv6 is supported or not, we
|
||||||
@ -403,6 +412,7 @@ class Session(object):
|
|||||||
kg=None,
|
kg=None,
|
||||||
onlogon=None):
|
onlogon=None):
|
||||||
trueself = None
|
trueself = None
|
||||||
|
forbidsock = []
|
||||||
for res in socket.getaddrinfo(bmc, port, 0, socket.SOCK_DGRAM):
|
for res in socket.getaddrinfo(bmc, port, 0, socket.SOCK_DGRAM):
|
||||||
sockaddr = res[4]
|
sockaddr = res[4]
|
||||||
if ipv6support and res[0] == socket.AF_INET:
|
if ipv6support and res[0] == socket.AF_INET:
|
||||||
@ -410,17 +420,29 @@ class Session(object):
|
|||||||
newhost = '::ffff:' + sockaddr[0]
|
newhost = '::ffff:' + sockaddr[0]
|
||||||
sockaddr = (newhost, sockaddr[1], 0, 0)
|
sockaddr = (newhost, sockaddr[1], 0, 0)
|
||||||
if sockaddr in cls.bmc_handlers:
|
if sockaddr in cls.bmc_handlers:
|
||||||
self = cls.bmc_handlers[sockaddr]
|
for portself in list(dictitems(cls.bmc_handlers[sockaddr])):
|
||||||
if (self.bmc == bmc and self.userid == userid and
|
self = portself[1]
|
||||||
self.password == password and self.kgo == kg and
|
if not ((self.logged or self.logging) and
|
||||||
(self.logged or self.logging) and
|
cls._is_session_valid(self)):
|
||||||
cls._is_session_valid(self)):
|
# we have encountered a leftover broken session
|
||||||
trueself = self
|
del cls.bmc_handlers[sockaddr][portself[0]]
|
||||||
else:
|
continue
|
||||||
del cls.bmc_handlers[sockaddr]
|
if (self.bmc == bmc and self.userid == userid and
|
||||||
|
self.password == password and self.kgo == kg):
|
||||||
|
trueself = self
|
||||||
|
break
|
||||||
|
# ok, the candidate seems to be working, but does not match
|
||||||
|
# will need to allow creation of a new session, but
|
||||||
|
# must forbid use of this socket so that the socket
|
||||||
|
# share routing code does not get confused.
|
||||||
|
# in principle, should be able to distinguish by session
|
||||||
|
# id, however it's easier this way
|
||||||
|
forbidsock.append(self.socket)
|
||||||
if trueself:
|
if trueself:
|
||||||
return trueself
|
return trueself
|
||||||
return object.__new__(cls)
|
self = object.__new__(cls)
|
||||||
|
self.forbidsock = forbidsock
|
||||||
|
return self
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
bmc,
|
bmc,
|
||||||
@ -486,7 +508,7 @@ class Session(object):
|
|||||||
if self.__class__.socketchecking is None:
|
if self.__class__.socketchecking is None:
|
||||||
self.__class__.socketchecking = threading.Lock()
|
self.__class__.socketchecking = threading.Lock()
|
||||||
with self.socketchecking:
|
with self.socketchecking:
|
||||||
self.socket = self._assignsocket()
|
self.socket = self._assignsocket(forbiddensockets=self.forbidsock)
|
||||||
self.login()
|
self.login()
|
||||||
if not self.async:
|
if not self.async:
|
||||||
while self.logging:
|
while self.logging:
|
||||||
@ -522,9 +544,13 @@ class Session(object):
|
|||||||
# since this session is broken, remove it from the handler list
|
# since this session is broken, remove it from the handler list
|
||||||
# This allows constructor to create a new, functional object to
|
# This allows constructor to create a new, functional object to
|
||||||
# replace this one
|
# replace this one
|
||||||
|
myport = self.socket.getsockname()[1]
|
||||||
for sockaddr in self.allsockaddrs:
|
for sockaddr in self.allsockaddrs:
|
||||||
if sockaddr in Session.bmc_handlers:
|
if (sockaddr in Session.bmc_handlers and
|
||||||
del Session.bmc_handlers[sockaddr]
|
myport in Session.bmc_hansdlers[sockaddr]):
|
||||||
|
del Session.bmc_handlers[sockaddr][myport]
|
||||||
|
if Session.bmc_handlers[sockaddr] == {}:
|
||||||
|
del Session.bmc_handlers[sockaddr]
|
||||||
elif not self.broken:
|
elif not self.broken:
|
||||||
self.broken = True
|
self.broken = True
|
||||||
self.socketpool[self.socket] -= 1
|
self.socketpool[self.socket] -= 1
|
||||||
@ -1200,23 +1226,14 @@ class Session(object):
|
|||||||
pkt[0] = bytearray(pkt[0])
|
pkt[0] = bytearray(pkt[0])
|
||||||
if not (pkt[0][0] == 6 and pkt[0][2:4] == b'\xff\x07'):
|
if not (pkt[0][0] == 6 and pkt[0][2:4] == b'\xff\x07'):
|
||||||
continue
|
continue
|
||||||
|
# this should be in specific context, no need to check port
|
||||||
|
# since recvfrom result was already routed to this object
|
||||||
|
# specifically
|
||||||
if pkt[1] in self.bmc_handlers:
|
if pkt[1] in self.bmc_handlers:
|
||||||
self._handle_ipmi_packet(pkt[0], sockaddr=pkt[1], qent=pkt)
|
self._handle_ipmi_packet(pkt[0], sockaddr=pkt[1], qent=pkt)
|
||||||
elif pkt[2] in self.bmc_handlers:
|
elif pkt[2] in self.bmc_handlers:
|
||||||
self.sessionless_data(pkt[0], pkt[1])
|
self.sessionless_data(pkt[0], pkt[1])
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def _route_ipmiresponse(cls, sockaddr, data, mysocket):
|
|
||||||
if not (data[0] == '\x06' and data[2:4] == '\xff\x07'): # not ipmi
|
|
||||||
return
|
|
||||||
try:
|
|
||||||
cls.bmc_handlers[sockaddr]._handle_ipmi_packet(data,
|
|
||||||
sockaddr=sockaddr)
|
|
||||||
except KeyError:
|
|
||||||
# check if we have a server attached to the target socket
|
|
||||||
if mysocket in cls.bmc_handlers:
|
|
||||||
cls.bmc_handlers[mysocket].sessionless_data(data, sockaddr)
|
|
||||||
|
|
||||||
def _handle_ipmi_packet(self, data, sockaddr=None, qent=None):
|
def _handle_ipmi_packet(self, data, sockaddr=None, qent=None):
|
||||||
if self.sockaddr is None and sockaddr is not None:
|
if self.sockaddr is None and sockaddr is not None:
|
||||||
self.sockaddr = sockaddr
|
self.sockaddr = sockaddr
|
||||||
@ -1235,7 +1252,7 @@ class Session(object):
|
|||||||
# still active UDP source port. Clear ourselves out and punt
|
# still active UDP source port. Clear ourselves out and punt
|
||||||
# to IpmiServer
|
# to IpmiServer
|
||||||
del Session.bmc_handlers[sockaddr]
|
del Session.bmc_handlers[sockaddr]
|
||||||
iserver = Session.bmc_handlers[qent[2]]
|
iserver = Session.bmc_handlers[qent[2]][0]
|
||||||
iserver.pktqueue.append(qent)
|
iserver.pktqueue.append(qent)
|
||||||
iserver.process_pktqueue()
|
iserver.process_pktqueue()
|
||||||
return
|
return
|
||||||
@ -1657,6 +1674,7 @@ class Session(object):
|
|||||||
# he have not yet picked a working sockaddr for this connection,
|
# he have not yet picked a working sockaddr for this connection,
|
||||||
# try all the candidates that getaddrinfo provides
|
# try all the candidates that getaddrinfo provides
|
||||||
self.allsockaddrs = []
|
self.allsockaddrs = []
|
||||||
|
myport = self.socket.getsockname()[1]
|
||||||
try:
|
try:
|
||||||
for res in socket.getaddrinfo(self.bmc,
|
for res in socket.getaddrinfo(self.bmc,
|
||||||
self.port,
|
self.port,
|
||||||
@ -1668,7 +1686,9 @@ class Session(object):
|
|||||||
newhost = '::ffff:' + sockaddr[0]
|
newhost = '::ffff:' + sockaddr[0]
|
||||||
sockaddr = (newhost, sockaddr[1], 0, 0)
|
sockaddr = (newhost, sockaddr[1], 0, 0)
|
||||||
self.allsockaddrs.append(sockaddr)
|
self.allsockaddrs.append(sockaddr)
|
||||||
Session.bmc_handlers[sockaddr] = self
|
if sockaddr not in Session.bmc_handlers:
|
||||||
|
Session.bmc_handlers[sockaddr] = {}
|
||||||
|
Session.bmc_handlers[sockaddr][myport] = self
|
||||||
_io_sendto(self.socket, self.netpacket, sockaddr)
|
_io_sendto(self.socket, self.netpacket, sockaddr)
|
||||||
except socket.gaierror:
|
except socket.gaierror:
|
||||||
raise exc.IpmiException(
|
raise exc.IpmiException(
|
||||||
|
Loading…
Reference in New Issue
Block a user