int ntrip_open(struct gps_device_t *device, char *caster) /* open a connection to a Ntrip broadcaster */ { char *amp, *colon, *slash; char *auth = NULL; char *port = NULL; char *stream = NULL; char *url = NULL; int ret = -1; char t[strlen(caster) + 1]; char *tmp = t; switch (device->ntrip.conn_state) { case ntrip_conn_init: /* this has to be done here, because it is needed for multi-stage connection */ device->servicetype = service_ntrip; device->ntrip.works = false; device->ntrip.sourcetable_parse = false; device->ntrip.stream.set = false; (void)strlcpy(tmp, caster, sizeof(t)); if ((amp = strchr(tmp, '@')) != NULL) { if (((colon = strchr(tmp, ':')) != NULL) && colon < amp) { auth = tmp; *amp = '\0'; tmp = amp + 1; url = tmp; } else { gpsd_log(&device->context->errout, LOG_ERROR, "can't extract user-ID and password from %s\n", caster); device->ntrip.conn_state = ntrip_conn_err; return -1; } } if ((slash = strchr(tmp, '/')) != NULL) { *slash = '\0'; stream = slash + 1; } else { /* todo: add autoconnect like in dgpsip.c */ gpsd_log(&device->context->errout, LOG_ERROR, "can't extract Ntrip stream from %s\n", caster); device->ntrip.conn_state = ntrip_conn_err; return -1; } if ((colon = strchr(tmp, ':')) != NULL) { port = colon + 1; *colon = '\0'; } if (!port) { port = "rtcm-sc104"; if (!getservbyname(port, "tcp")) port = DEFAULT_RTCM_PORT; } (void)strlcpy(device->ntrip.stream.mountpoint, stream, sizeof(device->ntrip.stream.mountpoint)); if (auth != NULL) (void)strlcpy(device->ntrip.stream.credentials, auth, sizeof(device->ntrip.stream.credentials)); /* * Semantically url and port ought to be non-NULL by now, * but just in case...this code appeases Coverity. */ if (url != NULL) (void)strlcpy(device->ntrip.stream.url, url, sizeof(device->ntrip.stream.url)); if (port != NULL) (void)strlcpy(device->ntrip.stream.port, port, sizeof(device->ntrip.stream.port)); ret = ntrip_stream_req_probe(&device->ntrip.stream, &device->context->errout); if (ret == -1) { device->ntrip.conn_state = ntrip_conn_err; return -1; } device->gpsdata.gps_fd = ret; device->ntrip.conn_state = ntrip_conn_sent_probe; return ret; case ntrip_conn_sent_probe: ret = ntrip_sourcetable_parse(device); if (ret == -1) { device->ntrip.conn_state = ntrip_conn_err; return -1; } if (ret == 0 && device->ntrip.stream.set == false) { return ret; } (void)close(device->gpsdata.gps_fd); if (ntrip_auth_encode(&device->ntrip.stream, device->ntrip.stream.credentials, device->ntrip.stream.authStr, sizeof(device->ntrip.stream.authStr)) != 0) { device->ntrip.conn_state = ntrip_conn_err; return -1; } ret = ntrip_stream_get_req(&device->ntrip.stream, &device->context->errout); if (ret == -1) { device->ntrip.conn_state = ntrip_conn_err; return -1; } device->gpsdata.gps_fd = ret; device->ntrip.conn_state = ntrip_conn_sent_get; break; case ntrip_conn_sent_get: ret = ntrip_stream_get_parse(&device->ntrip.stream, device->gpsdata.gps_fd, &device->context->errout); if (ret == -1) { device->ntrip.conn_state = ntrip_conn_err; return -1; } device->ntrip.conn_state = ntrip_conn_established; device->ntrip.works = true; // we know, this worked. break; case ntrip_conn_established: case ntrip_conn_err: return -1; } return ret; }
/*@ -nullpass @*//* work around a splint bug */ static int ntrip_stream_open(const char *caster, const char *port, /*@null@*/ const char *auth, struct gps_context_t *context, struct ntrip_stream_t *stream) { char buf[BUFSIZ]; char authstr[128]; int opts; if (ntrip_auth_encode(stream, auth, authstr, sizeof(authstr)) < 0) { gpsd_report(LOG_ERROR, "User-ID and password needed for %s:%s/%s\n", caster, port, stream->mountpoint); return -1; } if ((context->dsock = netlib_connectsock(AF_UNSPEC, caster, port, "tcp")) < 0) return -1; (void)snprintf(buf, sizeof(buf), "GET /%s HTTP/1.1\r\n" "User-Agent: NTRIP gpsd/%s\r\n" "Accept: rtk/rtcm, dgps/rtcm\r\n" "%s" "Connection: close\r\n" "\r\n", stream->mountpoint, VERSION, authstr); if (write(context->dsock, buf, strlen(buf)) != (ssize_t) strlen(buf)) { printf("ntrip stream write error on %d\n", context->dsock); return -1; } memset(buf, 0, sizeof(buf)); if (read(context->dsock, buf, sizeof(buf) - 1) == -1) goto close; /* parse 401 Unauthorized */ if (strstr(buf, NTRIP_UNAUTH)) { gpsd_report(LOG_ERROR, "%s not authorized for Ntrip stream %s:%s/%s\n", auth, caster, port, stream->mountpoint); goto close; } /* parse SOURCETABLE */ if (strstr(buf, NTRIP_SOURCETABLE)) { gpsd_report(LOG_ERROR, "Broadcaster doesn't recognize Ntrip stream %s:%s/%s\n", caster, port, stream->mountpoint); goto close; } /* parse ICY 200 OK */ if (!strstr(buf, NTRIP_ICY)) { gpsd_report(LOG_ERROR, "Unknown reply %s from Ntrip service %s:%s/%s\n", buf, caster, port, stream->mountpoint); goto close; } opts = fcntl(context->dsock, F_GETFL); if (opts >= 0) (void)fcntl(context->dsock, F_SETFL, opts | O_NONBLOCK); context->netgnss_service = netgnss_ntrip; #ifndef S_SPLINT_S context->netgnss_privdata = stream; #endif return context->dsock; close: (void)close(context->dsock); return -1; }