def connect_to_service(self, username, password): # get logger tmp_logger = logging.getLogger(__name__) if not self._sock or not self._rem_addr: # log the case tmp_logger.error("Control socket or remote address is None.") raise sing_errs.InternalError(sing_errs.INT_ERR_MEMORY) # try to connect to the service res = self._sock.connect_ex(self._rem_addr) if res != 0: # try a few more times tmp_logger.warn( "Control Socket did not connect at the first attempt. res_code: {0}" .format(res)) # the only error which is handled, ECONNREFUSED count = 3 # try a few times if ECONNREFUSED while count > 0 and res == errno.ECONNREFUSED: time.sleep(1.0) # give some time to the service count -= 1 # update counter res = self._sock.connect_ex(self._rem_addr) if res != 0: # not a success tmp_logger.error( "Cannot connect to the service after a few attempts.") raise sing_errs.InternalError(sing_errs.INT_ERR_IPC) # socket has successfully connected self._connected = True # authenticate the user tmp_logger.info("Socket has connected to the storage service.") self.send_request(sing_msgs.MSG_AUTH, 0, username=username, passwd=password) # wait for a confirmation from the service return self.recv_request(sing_msgs.MSG_CON_REPLY)
def _init_shared_memory(self, write_addr, write_size, write_name, read_addr, read_size, read_name): """ After a successful connection establishment with the sing local service, initialize the internal data structures. """ self._write_mem = self._create_write_buf(write_addr, write_size) self._read_mem = self._create_read_buf(read_addr, read_size) # check if the objects have been created properly if not self._write_mem or not self._read_mem: raise sing_errs.InternalError(sing_errs.INT_ERR_MEMORY) # try to connect to the memory regions # the system may throw some exceptions self._write_mem.init_mem(write_name) self._read_mem.init_mem(read_name)
def read_data(self, read_addr, read_len): # if the read address is out of the range # throw an exception tmp_logger = logging.getLogger() tmp_logger.info("read_shared_memory") if read_addr >= self._end_addr or\ read_addr < self._beg_addr: tmp_logger.error("Reading address ranges are wrong") raise sing_errs.InternalError(sing_errs.INT_ERR_PROT) # read the given number of bytes and # return a tuple: (read_bytes, data_string) # move to the correct place of the file self._mmap.seek((read_addr - self._beg_addr), os.SEEK_SET) can_read = min(read_len, self._end_addr - read_addr) d_read = self._mmap.read(can_read) return (len(d_read), d_read)
def delete_data(self, rados_obj): """ Delete a storage object at the given path. """ tmp_logger = logging.getLogger(__name__) tmp_logger.info("delete_data: {0}".format(rados_obj.get_data_path())) mark_id = self._get_unique_id() # message id self._ctrl.send_request(sing_msgs.MSG_DELETE, mark_id, data_path=rados_obj.get_data_path()) # wait for permission from the service res = self._ctrl.recv_request(sing_msgs.MSG_STATUS) # STATUS message must be received assert res.msg_type == sing_msgs > MSG_STATUS, "Delete receives some different message" assert res.msg_id == mark_id, "STATUS id != message id" # if status is success, return if res.op_status == sing_msg.STAT_SUCCESS: return # other possible cases if res.op_status == sing_msgs.ERR_PATH: raise sing_errs.PathError(rados_obj.get_data_path(), False) elif res.op_status == sing_msgs.ERR_DENY: raise sing_errs.PathError(rados_obj.get_data_path(), True) elif res.op_status == sing_msgs.ERR_QUOTA: raise sing_errs.QuotaError(obj_len, 0) elif res.op_status == sing_msgs.ERR_PROT: protocol = rados_obj.get_data_path().split(":") raise sing_errs.ProtError(protocol[0]) else: # some internal error raise sing_errs.InternalError(sing_errs.INT_ERR_UNKNOWN)
def send_request(self, req_type, req_id, **kwargs): """ Send a request to the service. """ tmp_logger = logging.getLogger(__name__) tmp_logger.info("send_request: {0}".format(req_type)) # create a message msg = InterMessage.create_message(req_type, req_id, **kwargs) if not msg: tmp_logger.error("Cannot create an IPC message in send_request") raise sing_errs.InternalError(sing_errs.INT_ERR_IPC) # send the message bin_data = msg.encode_msg() # encode the message into # a binary string # try to write the message tmp_logger.info("Encoded message is being sent to the service") self._sock.sendall(bin_data, 0)
def recv_request(self, req_type, **kwargs): """ Receive a request from the service. """ tmp_logger = logging.getLogger(__name__) tmp_logger.info("recv_request: ".format(req_type)) msg = InterMessage.create_message(req_type, 0, **kwargs) if not msg: tmp_logger.error("recv_request: msg is None") raise sing_errs.InternalError(sing_errs.INT_ERR_IPC) # read the header of the received message tmp_header = [] header_size = msg.get_header_size() while header_size > 0: tm_hr = self._sock.recv(header_size, 0) if not tm_hr: # internal error tmp_logger.error("Cannot read header") raise sing_errs.InternalError(sing_errs.INT_ERR_READ) # append the data and update the byte counter tmp_header.append(tm_hr) header_size -= len(tm_hr) # combine the header into one binary string header = b"".join(tmp_header) # decode the header msg.decode_header(header) # need to check if the reuired message type # match the received one if req_type != msg.msg_type: # special case -- status message received if msg.msg_type != sing_msgs.MSG_STATUS: # error tmp_logger.error( "wrong message received: requested = {0}, received = {1}". format(req_type, msg.msg_type)) raise sing_errs.InternalError(sing_errs.INT_ERR_PROT) # a status message received instead of the requested tmp_msg = InterMessage.create_message(sing_msgs.MSG_STATUS, 0) if not tmp_msg: # memory problem tmp_logger.errror("Out of memory") raise sing_errs.InternalError(sing_errs.INT_ERR_MEMORY) tmp_msg.msg_type = sing_msgs.MSG_STATUS tmp_msg.msg_id = msg.msg_id tmp_msg.msg_length = msg.msg_length # reassign the message msg = tmp_msg left_to_read = msg.msg_length - msg.get_header_size() raw_data = [] # store a list of binary strings while left_to_read > 0: # read until data is read or # an error occurs read_data = self._sock.recv(left_to_read, 0) if not read_data: # Error occured tmp_logger.error("socket.recv returns None") raise sing_errs.InternalError(sing_errs.INT_ERR_UNKNOWN) raw_data.append(read_data) left_to_read -= len(read_data) # message has successfully been read tmp_logger.info("read_request: decoding the received message") msg.decode_msg(b"".join(raw_data)) # decode the raw data # to a message return msg # return the read message
def read_raw_data(self, rados_obj): """ Read a rados object from the shared memory. """ tmp_logger = logging.getLogger(__name__) tmp_logger.info("read_raw_data") ref_data = rados_obj.get_raw_data() # reference to # raw data of the object # ask for request from the service mark_id = self._get_unique_id() self._ctrl.send_request(sing_msgs.MSG_READ, mark_id, data_path=rados_obj.get_data_path(), properties=1) # wait for response res = self._ctrl.recv_request(sing_msgs.MSG_WRITE) # check the status of the previous message if res.msg_type == sing_msgs.MSG_STATUS: tmp_logger.error("read_raw_data: == MSG_STATUS") if res.op_status == ERR_PATH: raise sing_errs.PathError(rado_obj.get_data_path(), False) elif res.op_status == ERR_DENY: raise sing_errs.PathError(rados_obj.get_data_path(), True) else: tmp_logger.warn("MSG_STATUS: non path related read") raise sing_errs.InternalError(sing_errs.INT_ERR_UNKNOWN) if res.data_path != rados_obj.get_data_path(): # some internal # error tmp_logger.error("read_raw_data: data_path != rados.data_path") self.close() raise sing_errs.InternalError(sing_errs.INT_ERR_PROT) assert res.msg_id == mark_id, "Not the same ID" #assert res.prop_bitmap == 1, "Write flag is unset" # read data from the shared memory read_bytes, read_data = self._read_mem.read_data( res.mem_addr, res.data_length) if read_bytes != res.data_length: # an error, notify the service self._ctrl.send_request(sing_msgs.MSG_STATUS, mark_id, status_type=sing_msgs.ERR_INTER) tmp_logger.error("read_raw_data: read_bytes != res.data_length") self.close() raise sing_errs.InternalError(sing_errs.INT_ERR_READ) else: # notify that the data has been read self._ctrl.send_request(sing_msgs.MSG_READ, mark_id, data_path=rados_obj.get_data_path(), properties=0) # append data rados_obj.extend_data(read_data) # wait for the next message from the service while True: # next chunk of data res = self._ctrl.recv_request(sing_msgs.MSG_WRITE) assert res.msg_type == sing_msgs.MSG_WRITE, "Not a WRITE msg" # check if writing is complete if res.mem_addr == 0 and res.data_length == 0: # notify a success self._ctrl.send_request(sing_msgs.MSG_READ, mark_id, data_path=rados_obj.get_data_path()) return # done reading the rados object assert res.msg_id == mark_id, "Not the same ID as read's one" # read data from the shared memory read_bytes, read_data = self._read_mem.read_data( res.mem_addr, res.data_length) if read_bytes != res.data_length: # an error, notify the service self._ctrl.send_request(sing_msgs.MSG_STATUS, mark_id, status_type=sing_msgs.ERR_INTER) tmp_logger.error( "read_raw_data: read_bytes != res.data_length") self.close() raise sing_errs.InternalError(sing_errs.INT_ERR_PROT) else: # notify a success self._ctrl.send_request(sing_msgs.MSG_READ, mark_id, data_path=rados_obj.get_data_path()) # append data and loop back rados_obj.extend_data(read_data)
def write_raw_data(self, rados_obj): """ Write rados object to the shared memory """ tmp_logger = logging.getLogger(__name__) tmp_logger.info("write_raw_data") # rados object has a length so that it could # keep writing until fully written ref_data = rados_obj.get_raw_data() # reference to data obj_len = rados_obj.get_len() # length in bytes # request for a permission from the service # to write the new data mark_id = self._get_unique_id() # message id self._ctrl.send_request(sing_msgs.MSG_WRITE, mark_id, data_path=rados_obj.get_data_path(), properties=1, start_addr=0, data_length=obj_len) # wait for permission from the service res = self._ctrl.recv_request(sing_msgs.MSG_READ) # check if the message is either a READ or a STATUS # message # some error occured if res.msg_type == sing_msgs.MSG_STATUS: # throw an exception if res.op_status == sing_msgs.ERR_PATH: raise sing_errs.PathError(rados_obj.get_data_path(), False) elif res.op_status == sing_msgs.ERR_DENY: raise sing_errs.PathError(rados_obj.get_data_path(), True) elif res.op_status == sing_msgs.ERR_QUOTA: raise sing_errs.QuotaError(obj_len, 0) elif res.op_status == sing_msgs.ERR_PROT: protocol = rados_obj.get_data_path().split(":") raise sing_errs.ProtError(protocol[0]) else: # some internal error raise sing_errs.InternalError(sing_errs.INT_ERR_UNKNOWN) # make sure a READ response assert res.msg_type == sing_msgs.MSG_READ, "Not READ msg" # since it is the first write message, expect to # receive a read with the bitmap flag set assert res.prop_bitmap == 1, "READ bitmap unset" # keep writing until an exception occurs or # the entire object has been written mem_addr = self._write_mem.get_write_addr() # where data # will be written written_bytes = self._write_mem.write_data(ref_data) if written_bytes <= 0: # something wrong tmp_logger.error("'written_bytes' <= 0") self.close() raise sing_errs.InternalError(sing_errs.INT_ERR_WRITE) obj_len -= written_bytes # update the number of written bytes # send a notification to the service about the data mark_id = self._get_unique_id() self._ctrl.send_request(sing_msgs.MSG_WRITE, mark_id, data_path=rados_obj.get_data_path(), properties=0, start_addr=mem_addr, data_length=written_bytes) # wait for response res = self._ctrl.recv_request(sing_msgs.MSG_READ) # check if the message is either a READ or a STATUS # message # some error occured if res.msg_type == sing_msgs.MSG_STATUS: # throw an exception # some internal error raise sing_errs.InternalError(sing_errs.INT_ERR_UNKNOWN) # make sure a READ response assert res.msg_type == sing_msgs.MSG_READ, "Not READ msg" # the flag must be unset assert res.prop_bitmap == 0, "READ bitmap set" # write the rest of the data std_index = written_bytes while obj_len > 0: # write all the data mem_addr = self._write_mem.get_write_addr() send_buf = self._avail_buffer() written_bytes = self._write_mem.write_data( ref_data[std_index:std_index + send_buf:1]) # check the number of bytes if written_bytes <= 0: self.close() raise sing_errs.InternalError(sing_errs.INT_ERR_WRITE) # send a requst to the service mark_id = self._get_unique_id() self._ctrl.send_request(sing_msgs.MSG_WRITE, mark_id, data_path=rados_obj.get_data_path(), properties=0, start_addr=mem_addr, data_length=written_bytes) # update the values obj_len -= written_bytes std_index += written_bytes # wait for a response from the service res = self._ctrl.recv_request(sing_msgs.MSG_READ) # check the status of the previous write if res.msg_type == sing_msgs.MSG_STATUS: # some internal error raise sing_errs.InternalError(sing_errs.INT_ERR_UNKNOWN) assert res.msg_type == sing_msgs.MSG_READ, "Not READ msg" # ensure that the bit flag is reset assert res.prop_bitmap == 0, "READ bitmap is set" # done with the rados object mark_id = self._get_unique_id() self._ctrl.send_request(sing_msgs.MSG_WRITE, mark_id, data_path=rados_obj.get_data_path(), properties=0, start_addr=0, data_length=0) res = self._ctrl.recv_request(sing_msgs.MSG_READ) # check the status of the previous write assert res.msg_type == sing_msgs.MSG_READ, "Not READ msg" # ensure that the bit flag is reset assert res.prop_bitmap == 0, "READ bitmap is set"