Exemple #1
0
    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)
Exemple #5
0
    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)
Exemple #6
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"