[raop] If ipv6 fails, fall back to ipv4 and disable ipv6 permanently for the device

This commit is contained in:
ejurgensen 2018-09-19 23:03:33 +02:00
parent f686756dd8
commit aa3aa383ef
2 changed files with 35 additions and 19 deletions

View File

@ -103,6 +103,7 @@ struct output_device
unsigned has_password:1; unsigned has_password:1;
unsigned has_video:1; unsigned has_video:1;
unsigned requires_auth:1; unsigned requires_auth:1;
unsigned v6_disabled:1;
// Credentials if relevant // Credentials if relevant
const char *password; const char *password;

View File

@ -2005,7 +2005,7 @@ raop_session_make(struct output_device *rd, int family, output_status_cb cb, boo
break; break;
case AF_INET6: case AF_INET6:
if (!rd->v6_address || (timing_6svc.fd < 0) || (control_6svc.fd < 0)) if (!rd->v6_address || rd->v6_disabled || (timing_6svc.fd < 0) || (control_6svc.fd < 0))
return NULL; return NULL;
address = rd->v6_address; address = rd->v6_address;
@ -2731,6 +2731,9 @@ raop_cb_pin_start(struct evrtsp_request *req, void *arg)
// Forward // Forward
static int
raop_device_start(struct output_device *rd, output_status_cb cb, uint64_t rtptime);
static void static void
raop_device_stop(struct output_session *session); raop_device_stop(struct output_session *session);
@ -3701,11 +3704,31 @@ raop_v2_stream_open(struct raop_session *rs)
static void static void
raop_startup_cancel(struct raop_session *rs) raop_startup_cancel(struct raop_session *rs)
{ {
/* Try being nice to our peer */ if (!rs->session)
if (rs->session) {
raop_send_req_teardown(rs, raop_session_failure_cb, "startup_cancel"); raop_session_failure(rs);
else return;
raop_session_failure(rs); }
// Some devices don't seem to work with ipv6, so if the error wasn't a hard
// failure (bad password) we fall back to ipv4 and flag device as bad for ipv6
if (rs->family == AF_INET6 && !(rs->state & RAOP_STATE_F_FAILED))
{
// This flag is permanent and will not be overwritten by mdns advertisements
rs->device->v6_disabled = 1;
// Be nice to our peer + raop_session_failure_cb() cleans up old session
raop_send_req_teardown(rs, raop_session_failure_cb, "startup_cancel");
// Try to start a new session
raop_device_start(rs->device, rs->status_cb, rs->start_rtptime);
// Don't let the failed session make a negative status callback
rs->status_cb = NULL;
return;
}
raop_send_req_teardown(rs, raop_session_failure_cb, "startup_cancel");
} }
static void static void
@ -4014,20 +4037,12 @@ raop_cb_startup_options(struct evrtsp_request *req, void *arg)
{ {
DPRINTF(E_LOG, L_RAOP, "No response from '%s' (%s) to OPTIONS request\n", rs->devname, rs->address); DPRINTF(E_LOG, L_RAOP, "No response from '%s' (%s) to OPTIONS request\n", rs->devname, rs->address);
if (rs->device->v4_address && (rs->sa.ss.ss_family == AF_INET6))
{
DPRINTF(E_LOG, L_RAOP, "Falling back to ipv4, the ipv6 address is not responding\n");
free(rs->device->v6_address);
rs->device->v6_address = NULL;
}
goto cleanup; goto cleanup;
} }
if ((req->response_code != RTSP_OK) && (req->response_code != RTSP_UNAUTHORIZED) && (req->response_code != RTSP_FORBIDDEN)) if ((req->response_code != RTSP_OK) && (req->response_code != RTSP_UNAUTHORIZED) && (req->response_code != RTSP_FORBIDDEN))
{ {
DPRINTF(E_LOG, L_RAOP, "OPTIONS request failed '%s': %d %s\n", rs->devname, req->response_code, req->response_code_line); DPRINTF(E_LOG, L_RAOP, "OPTIONS request failed '%s' (%s): %d %s\n", rs->devname, rs->address, req->response_code, req->response_code_line);
goto cleanup; goto cleanup;
} }
@ -4040,7 +4055,7 @@ raop_cb_startup_options(struct evrtsp_request *req, void *arg)
{ {
if (rs->req_has_auth) if (rs->req_has_auth)
{ {
DPRINTF(E_LOG, L_RAOP, "Bad password for device '%s'\n", rs->devname); DPRINTF(E_LOG, L_RAOP, "Bad password for device '%s' (%s)\n", rs->devname, rs->address);
rs->state = RAOP_STATE_PASSWORD; rs->state = RAOP_STATE_PASSWORD;
goto cleanup; goto cleanup;
@ -4053,7 +4068,7 @@ raop_cb_startup_options(struct evrtsp_request *req, void *arg)
ret = raop_send_req_options(rs, raop_cb_startup_options, "startup_options"); ret = raop_send_req_options(rs, raop_cb_startup_options, "startup_options");
if (ret < 0) if (ret < 0)
{ {
DPRINTF(E_LOG, L_RAOP, "Could not re-run OPTIONS request with authentication\n"); DPRINTF(E_LOG, L_RAOP, "Could not re-run OPTIONS request with authentication for '%s' (%s)\n", rs->devname, rs->address);
goto cleanup; goto cleanup;
} }
@ -4067,7 +4082,7 @@ raop_cb_startup_options(struct evrtsp_request *req, void *arg)
ret = raop_send_req_pin_start(rs, raop_cb_pin_start, "startup_options"); ret = raop_send_req_pin_start(rs, raop_cb_pin_start, "startup_options");
if (ret < 0) if (ret < 0)
{ {
DPRINTF(E_LOG, L_RAOP, "Could not request PIN for device verification\n"); DPRINTF(E_LOG, L_RAOP, "Could not request PIN from '%s' (%s) for device verification\n", rs->devname, rs->address);
goto cleanup; goto cleanup;
} }
@ -4080,7 +4095,7 @@ raop_cb_startup_options(struct evrtsp_request *req, void *arg)
if (param) if (param)
rs->supports_post = (strstr(param, "POST") != NULL); rs->supports_post = (strstr(param, "POST") != NULL);
else else
DPRINTF(E_DBG, L_RAOP, "Could not find 'Public' header in OPTIONS reply from '%s'\n", rs->devname); DPRINTF(E_DBG, L_RAOP, "Could not find 'Public' header in OPTIONS reply from '%s' (%s)\n", rs->devname, rs->address);
if (rs->only_probe) if (rs->only_probe)
{ {