mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-11-03 09:01:54 -05:00 
			
		
		
		
	bluez5: protect against NULL transport
The transport can be destroyed at any time, make sure we don't crash when it does.
This commit is contained in:
		
							parent
							
								
									4c80656a7b
								
							
						
					
					
						commit
						c4cf5e6629
					
				
					 4 changed files with 49 additions and 30 deletions
				
			
		| 
						 | 
					@ -361,6 +361,8 @@ static int send_buffer(struct impl *this)
 | 
				
			||||||
	struct rtp_header *header;
 | 
						struct rtp_header *header;
 | 
				
			||||||
	struct rtp_payload *payload;
 | 
						struct rtp_payload *payload;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spa_return_val_if_fail(this->transport, -EIO);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	header = (struct rtp_header *)this->buffer;
 | 
						header = (struct rtp_header *)this->buffer;
 | 
				
			||||||
	payload = (struct rtp_payload *)(this->buffer + sizeof(struct rtp_header));
 | 
						payload = (struct rtp_payload *)(this->buffer + sizeof(struct rtp_header));
 | 
				
			||||||
	memset(this->buffer, 0, sizeof(struct rtp_header)+sizeof(struct rtp_payload));
 | 
						memset(this->buffer, 0, sizeof(struct rtp_header)+sizeof(struct rtp_payload));
 | 
				
			||||||
| 
						 | 
					@ -487,6 +489,8 @@ static int set_bitpool(struct impl *this, int bitpool)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct port *port = &this->port;
 | 
						struct port *port = &this->port;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spa_return_val_if_fail(this->transport, -EIO);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (bitpool < this->min_bitpool)
 | 
						if (bitpool < this->min_bitpool)
 | 
				
			||||||
		bitpool = this->min_bitpool;
 | 
							bitpool = this->min_bitpool;
 | 
				
			||||||
	if (bitpool > this->max_bitpool)
 | 
						if (bitpool > this->max_bitpool)
 | 
				
			||||||
| 
						 | 
					@ -715,7 +719,11 @@ static void a2dp_on_timeout(struct spa_source *source)
 | 
				
			||||||
static int init_sbc(struct impl *this)
 | 
					static int init_sbc(struct impl *this)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
        struct spa_bt_transport *transport = this->transport;
 | 
					        struct spa_bt_transport *transport = this->transport;
 | 
				
			||||||
	a2dp_sbc_t *conf = transport->configuration;
 | 
						a2dp_sbc_t *conf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spa_return_val_if_fail(transport, -EIO);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						conf = transport->configuration;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sbc_init(&this->sbc, 0);
 | 
						sbc_init(&this->sbc, 0);
 | 
				
			||||||
	this->sbc.endian = SBC_LE;
 | 
						this->sbc.endian = SBC_LE;
 | 
				
			||||||
| 
						 | 
					@ -797,6 +805,8 @@ static int do_start(struct impl *this)
 | 
				
			||||||
	if (this->started)
 | 
						if (this->started)
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spa_return_val_if_fail(this->transport, -EIO);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	this->following = is_following(this);
 | 
						this->following = is_following(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        spa_log_debug(this->log, NAME " %p: start following:%d", this, this->following);
 | 
					        spa_log_debug(this->log, NAME " %p: start following:%d", this, this->following);
 | 
				
			||||||
| 
						 | 
					@ -1039,6 +1049,8 @@ impl_node_port_enum_params(void *object, int seq,
 | 
				
			||||||
	case SPA_PARAM_EnumFormat:
 | 
						case SPA_PARAM_EnumFormat:
 | 
				
			||||||
		if (result.index > 0)
 | 
							if (result.index > 0)
 | 
				
			||||||
			return 0;
 | 
								return 0;
 | 
				
			||||||
 | 
							if (this->transport == NULL)
 | 
				
			||||||
 | 
								return -EIO;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		switch (this->transport->codec) {
 | 
							switch (this->transport->codec) {
 | 
				
			||||||
		case A2DP_CODEC_SBC:
 | 
							case A2DP_CODEC_SBC:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -408,6 +408,10 @@ static void a2dp_on_ready_read(struct spa_source *source)
 | 
				
			||||||
		spa_log_error(this->log, "source is not an input, rmask=%d", source->rmask);
 | 
							spa_log_error(this->log, "source is not an input, rmask=%d", source->rmask);
 | 
				
			||||||
		goto stop;
 | 
							goto stop;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if (this->transport == NULL) {
 | 
				
			||||||
 | 
							spa_log_debug(this->log, "no transport, stop reading");
 | 
				
			||||||
 | 
							goto stop;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* update the current pts */
 | 
						/* update the current pts */
 | 
				
			||||||
	spa_system_clock_gettime(this->data_system, CLOCK_MONOTONIC, &this->now);
 | 
						spa_system_clock_gettime(this->data_system, CLOCK_MONOTONIC, &this->now);
 | 
				
			||||||
| 
						 | 
					@ -494,11 +498,10 @@ static int do_start(struct impl *this)
 | 
				
			||||||
	if (this->started)
 | 
						if (this->started)
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (this->transport == NULL)
 | 
					 | 
				
			||||||
		return -EIO;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	spa_log_debug(this->log, NAME" %p: start", this);
 | 
						spa_log_debug(this->log, NAME" %p: start", this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spa_return_val_if_fail(this->transport != NULL, -EIO);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (this->transport->state >= SPA_BT_TRANSPORT_STATE_PENDING)
 | 
						if (this->transport->state >= SPA_BT_TRANSPORT_STATE_PENDING)
 | 
				
			||||||
		res = transport_start(this);
 | 
							res = transport_start(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -693,7 +696,6 @@ impl_node_port_enum_params(void *object, int seq,
 | 
				
			||||||
	case SPA_PARAM_EnumFormat:
 | 
						case SPA_PARAM_EnumFormat:
 | 
				
			||||||
		if (result.index > 0)
 | 
							if (result.index > 0)
 | 
				
			||||||
			return 0;
 | 
								return 0;
 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (this->transport == NULL)
 | 
							if (this->transport == NULL)
 | 
				
			||||||
			return -EIO;
 | 
								return -EIO;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -130,6 +130,7 @@ struct impl {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Counts */
 | 
						/* Counts */
 | 
				
			||||||
	uint64_t sample_count;
 | 
						uint64_t sample_count;
 | 
				
			||||||
 | 
						uint32_t write_mtu;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define NAME "sco-sink"
 | 
					#define NAME "sco-sink"
 | 
				
			||||||
| 
						 | 
					@ -347,7 +348,7 @@ static int impl_node_set_param(void *object, uint32_t id, uint32_t flags,
 | 
				
			||||||
static bool write_data(struct impl *this, const uint8_t *data, uint32_t size, uint32_t *total_written)
 | 
					static bool write_data(struct impl *this, const uint8_t *data, uint32_t size, uint32_t *total_written)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	uint32_t local_total_written = 0;
 | 
						uint32_t local_total_written = 0;
 | 
				
			||||||
	const uint32_t mtu_size = this->transport->write_mtu;
 | 
						const uint32_t mtu_size = this->write_mtu;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	while (local_total_written <= (size - mtu_size)) {
 | 
						while (local_total_written <= (size - mtu_size)) {
 | 
				
			||||||
		const int bytes_written = write(this->sock_fd, data, mtu_size);
 | 
							const int bytes_written = write(this->sock_fd, data, mtu_size);
 | 
				
			||||||
| 
						 | 
					@ -414,28 +415,29 @@ static int render_buffers(struct impl *this, uint64_t now_time)
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void fill_socket (struct impl *this)
 | 
					static void fill_socket(struct impl *this)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  struct port *port = &this->port;
 | 
						struct port *port = &this->port;
 | 
				
			||||||
  static const uint8_t zero_buffer[1024 * 4] = { 0, };
 | 
						static const uint8_t zero_buffer[1024 * 4] = { 0, };
 | 
				
			||||||
  uint32_t fill_size = this->transport->write_mtu;
 | 
						uint32_t fill_size = this->write_mtu;
 | 
				
			||||||
  uint32_t fills = 0;
 | 
						uint32_t fills = 0;
 | 
				
			||||||
  uint32_t total_written = 0;
 | 
						uint32_t total_written = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /* Fill the socked */
 | 
					 | 
				
			||||||
  while (fills < FILL_FRAMES) {
 | 
					 | 
				
			||||||
          uint32_t written = 0;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
          /* Write the data */
 | 
						/* Fill the socket */
 | 
				
			||||||
          if (!write_data(this, zero_buffer, fill_size, &written))
 | 
						while (fills < FILL_FRAMES) {
 | 
				
			||||||
                  break;
 | 
							uint32_t written = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          total_written += written;
 | 
							/* Write the data */
 | 
				
			||||||
          fills++;
 | 
							if (!write_data(this, zero_buffer, fill_size, &written))
 | 
				
			||||||
  }
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /* Update the sample count */
 | 
							total_written += written;
 | 
				
			||||||
  this->sample_count += total_written / port->frame_size;
 | 
							fills++;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Update the sample count */
 | 
				
			||||||
 | 
						this->sample_count += total_written / port->frame_size;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void sco_on_flush(struct spa_source *source)
 | 
					static void sco_on_flush(struct spa_source *source)
 | 
				
			||||||
| 
						 | 
					@ -479,7 +481,7 @@ static void sco_on_timeout(struct spa_source *source)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* If this is the first timeout, set the start time and fill the socked */
 | 
						/* If this is the first timeout, set the start time and fill the socked */
 | 
				
			||||||
	if (this->start_time == 0) {
 | 
						if (this->start_time == 0) {
 | 
				
			||||||
		fill_socket (this);
 | 
							fill_socket(this);
 | 
				
			||||||
		this->start_time = now_time;
 | 
							this->start_time = now_time;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -503,7 +505,7 @@ static int do_start(struct impl *this)
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Make sure the transport is valid */
 | 
						/* Make sure the transport is valid */
 | 
				
			||||||
	spa_return_val_if_fail (this->transport != NULL, -EIO);
 | 
						spa_return_val_if_fail(this->transport != NULL, -EIO);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Set the following flag */
 | 
						/* Set the following flag */
 | 
				
			||||||
	this->following = is_following(this);
 | 
						this->following = is_following(this);
 | 
				
			||||||
| 
						 | 
					@ -517,6 +519,7 @@ static int do_start(struct impl *this)
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Set the write MTU */
 | 
						/* Set the write MTU */
 | 
				
			||||||
 | 
						this->write_mtu = this->transport->write_mtu;
 | 
				
			||||||
	val = FILL_FRAMES * this->transport->write_mtu;
 | 
						val = FILL_FRAMES * this->transport->write_mtu;
 | 
				
			||||||
	if (setsockopt(this->sock_fd, SOL_SOCKET, SO_SNDBUF, &val, sizeof(val)) < 0)
 | 
						if (setsockopt(this->sock_fd, SOL_SOCKET, SO_SNDBUF, &val, sizeof(val)) < 0)
 | 
				
			||||||
		spa_log_warn(this->log, "sco-sink %p: SO_SNDBUF %m", this);
 | 
							spa_log_warn(this->log, "sco-sink %p: SO_SNDBUF %m", this);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -117,6 +117,7 @@ struct impl {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct timespec now;
 | 
						struct timespec now;
 | 
				
			||||||
	uint32_t sample_count;
 | 
						uint32_t sample_count;
 | 
				
			||||||
 | 
						uint32_t read_mtu;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define NAME "sco-source"
 | 
					#define NAME "sco-source"
 | 
				
			||||||
| 
						 | 
					@ -294,8 +295,9 @@ static void reset_buffers(struct port *port)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool read_data(struct impl *this, uint8_t *data, uint32_t size, uint32_t *total_read) {
 | 
					static bool read_data(struct impl *this, uint8_t *data, uint32_t size, uint32_t *total_read)
 | 
				
			||||||
	const uint32_t mtu_size = this->transport->read_mtu;
 | 
					{
 | 
				
			||||||
 | 
						const uint32_t mtu_size = this->read_mtu;
 | 
				
			||||||
	uint32_t local_total_read = 0;
 | 
						uint32_t local_total_read = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Read chunks of mtu_size */
 | 
						/* Read chunks of mtu_size */
 | 
				
			||||||
| 
						 | 
					@ -321,7 +323,7 @@ static bool read_data(struct impl *this, uint8_t *data, uint32_t size, uint32_t
 | 
				
			||||||
 | 
					
 | 
				
			||||||
done:
 | 
					done:
 | 
				
			||||||
	if (total_read)
 | 
						if (total_read)
 | 
				
			||||||
	  *total_read = local_total_read;
 | 
							*total_read = local_total_read;
 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -428,7 +430,8 @@ static int do_start(struct impl *this)
 | 
				
			||||||
		spa_log_warn(this->log, "sco-source %p: SO_SNDBUF %m", this);
 | 
							spa_log_warn(this->log, "sco-source %p: SO_SNDBUF %m", this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Set the read MTU */
 | 
						/* Set the read MTU */
 | 
				
			||||||
	val = FILL_FRAMES * this->transport->read_mtu;
 | 
						this->read_mtu = this->transport->read_mtu;
 | 
				
			||||||
 | 
						val = FILL_FRAMES * this->read_mtu;
 | 
				
			||||||
	if (setsockopt(this->sock_fd, SOL_SOCKET, SO_RCVBUF, &val, sizeof(val)) < 0)
 | 
						if (setsockopt(this->sock_fd, SOL_SOCKET, SO_RCVBUF, &val, sizeof(val)) < 0)
 | 
				
			||||||
		spa_log_warn(this->log, "sco-source %p: SO_RCVBUF %m", this);
 | 
							spa_log_warn(this->log, "sco-source %p: SO_RCVBUF %m", this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -644,7 +647,6 @@ impl_node_port_enum_params(void *object, int seq,
 | 
				
			||||||
	case SPA_PARAM_EnumFormat:
 | 
						case SPA_PARAM_EnumFormat:
 | 
				
			||||||
		if (result.index > 0)
 | 
							if (result.index > 0)
 | 
				
			||||||
			return 0;
 | 
								return 0;
 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (this->transport == NULL)
 | 
							if (this->transport == NULL)
 | 
				
			||||||
			return -EIO;
 | 
								return -EIO;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue