void test_LocalClock(void) { #ifdef REFCLOCK /* clockname() is useless otherwise */ /* We test with a refclock address of type LOCALCLOCK. * with id 8 */ u_int32 addr = REFCLOCK_ADDR; addr |= REFCLK_LOCALCLOCK << 8; addr |= 0x8; sockaddr_u address; address.sa4.sin_family = AF_INET; address.sa4.sin_addr.s_addr = htonl(addr); char stringStart[100]= ""; strcat(stringStart, clockname(REFCLK_LOCALCLOCK)); strcat(stringStart, "(8)"); char * expected = stringStart; TEST_ASSERT_EQUAL_STRING(expected, refnumtoa(&address)); #else TEST_IGNORE_MESSAGE("REFCLOCK NOT DEFINED, SKIPPING TEST"); #endif /* REFCLOCK */ }
/* * nntohost - convert network number to host name. This routine enforces * the showhostnames setting. */ const char * nntohost( sockaddr_u *netnum ) { if (!showhostnames || SOCK_UNSPEC(netnum)) return stoa(netnum); else if (ISREFCLOCKADR(netnum)) return refnumtoa(netnum); else return socktohost(netnum); }
/* * nntohost - convert network number to host name. This routine enforces * the showhostnames setting. */ char * nntohost( sockaddr_u *netnum ) { if (!showhostnames) return stoa(netnum); if (ISREFCLOCKADR(netnum)) return refnumtoa(netnum); return socktohost(netnum); }
/* * refclock_report - note the occurance of an event * * This routine presently just remembers the report and logs it, but * does nothing heroic for the trap handler. It tries to be a good * citizen and bothers the system log only if things change. */ void refclock_report( struct peer *peer, int code ) { struct refclockproc *pp; if (!(pp = peer->procptr)) return; if (code == CEVNT_BADREPLY) pp->badformat++; if (code == CEVNT_BADTIME) pp->baddata++; if (code == CEVNT_TIMEOUT) pp->noreply++; if (pp->currentstatus != code) { pp->currentstatus = code; pp->lastevent = code; if (code == CEVNT_FAULT) msyslog(LOG_ERR, "clock %s event '%s' (0x%02x)", refnumtoa(peer->srcadr.sin_addr.s_addr), ceventstr(code), code); else { NLOG(NLOG_CLOCKEVENT) msyslog(LOG_INFO, "clock %s event '%s' (0x%02x)", refnumtoa(peer->srcadr.sin_addr.s_addr), ceventstr(code), code); } } #ifdef DEBUG if (debug) printf("clock %s event '%s' (0x%02x)\n", refnumtoa(peer->srcadr.sin_addr.s_addr), ceventstr(code), code); #endif }
/* We test with a refclock address of type LOCALCLOCK. * with id 8 */ u_int32 addr = REFCLOCK_ADDR; addr |= REFCLK_LOCALCLOCK << 8; addr |= 0x8; sockaddr_u address; address.sa4.sin_family = AF_INET; address.sa4.sin_addr.s_addr = htonl(addr); std::ostringstream expected; expected << clockname(REFCLK_LOCALCLOCK) << "(8)"; EXPECT_STREQ(expected.str().c_str(), refnumtoa(&address)); } #endif /* REFCLOCK */ #ifdef REFCLOCK /* refnumtoa() is useless otherwise */ TEST_F(refnumtoaTest, UnknownId) { /* We test with a currently unused refclock ID */ u_int32 addr = REFCLOCK_ADDR; addr |= UNUSED_REFCLOCK_ID << 8; addr |= 0x4; sockaddr_u address; address.sa4.sin_family = AF_INET; address.sa4.sin_addr.s_addr = htonl(addr); std::ostringstream expected; expected << "REFCLK(" << UNUSED_REFCLOCK_ID << ",4)"; EXPECT_STREQ(expected.str().c_str(), refnumtoa(&address)); }
/* Might need to be updated if a new refclock gets this id. */ static const int UNUSED_REFCLOCK_ID = 250; }; #ifdef REFCLOCK /* clockname() is useless otherwise */ TEST_F(refnumtoaTest, LocalClock) { /* We test with a refclock address of type LOCALCLOCK. * with id 8 */ u_int32 addr = REFCLOCK_ADDR; addr |= REFCLK_LOCALCLOCK << 8; addr |= 0x8; sockaddr_u address; address.sa4.sin_family = AF_INET; address.sa4.sin_addr.s_addr = htonl(addr); std::ostringstream expected; expected << clockname(REFCLK_LOCALCLOCK) << "(8)"; EXPECT_STREQ(expected.str().c_str(), refnumtoa(&address)); }
static void wwvb_control( int unit, struct refclockstat *in_st, struct refclockstat *out_st, struct peer *peer ) { register struct wwvbunit *up; struct refclockproc *pp; pp = peer->procptr; up = pp->unitptr; if (!(pp->sloppyclockflag & CLK_FLAG1)) { if (!up->ppsapi_tried) return; up->ppsapi_tried = 0; if (!up->ppsapi_lit) return; peer->flags &= ~FLAG_PPS; peer->precision = PRECISION; time_pps_destroy(up->atom.handle); up->atom.handle = 0; up->ppsapi_lit = 0; return; } if (up->ppsapi_tried) return; /* * Light up the PPSAPI interface. */ up->ppsapi_tried = 1; if (refclock_ppsapi(pp->io.fd, &up->atom)) { up->ppsapi_lit = 1; return; } NLOG(NLOG_CLOCKINFO) msyslog(LOG_WARNING, "%s flag1 1 but PPSAPI fails", refnumtoa(&peer->srcadr)); }
static void gpsd_shutdown( int unit, peerT * peer) { clockprocT * const pp = peer->procptr; gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr; UNUSED_ARG(unit); if (up) { free(up->device); free(up); } pp->unitptr = (caddr_t)NULL; if (-1 != pp->io.fd) io_closeclock(&pp->io); pp->io.fd = -1; LOGIF(CLOCKINFO, (LOG_NOTICE, "%s: shutdown", refnumtoa(&peer->srcadr))); }
static void gpsd_stop_socket( peerT * const peer) { clockprocT * const pp = peer->procptr; gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr; if (-1 != pp->io.fd) io_closeclock(&pp->io); pp->io.fd = -1; if (syslogok(pp, up)) msyslog(LOG_INFO, "%s: closing socket to GPSD", refnumtoa(&peer->srcadr)); up->tickover = up->tickpres; up->tickpres = min(up->tickpres + 5, TICKOVER_HIGH); up->fl_vers = 0; up->fl_tpv = 0; up->fl_pps = 0; up->fl_watch = 0; }
void test_UnknownId() { #ifdef REFCLOCK /* refnumtoa() is useless otherwise */ /* We test with a currently unused refclock ID */ u_int32 addr = REFCLOCK_ADDR; addr |= UNUSED_REFCLOCK_ID << 8; addr |= 0x4; sockaddr_u address; address.sa4.sin_family = AF_INET; address.sa4.sin_addr.s_addr = htonl(addr); char stringStart [100]= "REFCLK("; char value [100] ; snprintf(value, sizeof(value), "%d", UNUSED_REFCLOCK_ID); strcat(stringStart,value); strcat(stringStart,",4)"); char * expected = stringStart; TEST_ASSERT_EQUAL_STRING(expected, refnumtoa(&address)); #else TEST_IGNORE_MESSAGE("REFCLOCK NOT DEFINED, SKIPPING TEST"); #endif /* REFCLOCK */ }
/* * refclock_report - note the occurance of an event * * This routine presently just remembers the report and logs it, but * does nothing heroic for the trap handler. It tries to be a good * citizen and bothers the system log only if things change. */ void refclock_report( struct peer *peer, int code ) { struct refclockproc *pp; pp = peer->procptr; if (pp == NULL) return; switch (code) { case CEVNT_NOMINAL: break; case CEVNT_TIMEOUT: pp->noreply++; break; case CEVNT_BADREPLY: pp->badformat++; break; case CEVNT_FAULT: break; case CEVNT_PROP: break; case CEVNT_BADDATE: case CEVNT_BADTIME: pp->baddata++; break; default: /* shouldn't happen */ break; } if (pp->currentstatus != code) { pp->currentstatus = (u_char)code; /* RFC1305: copy only iff not CEVNT_NOMINAL */ if (code != CEVNT_NOMINAL) pp->lastevent = (u_char)code; if (code == CEVNT_FAULT) msyslog(LOG_ERR, "clock %s event '%s' (0x%02x)", refnumtoa(&peer->srcadr), ceventstr(code), code); else { NLOG(NLOG_CLOCKEVENT) msyslog(LOG_INFO, "clock %s event '%s' (0x%02x)", refnumtoa(&peer->srcadr), ceventstr(code), code); } /* RFC1305: post peer clock event */ report_event(EVNT_PEERCLOCK, peer); } }
/* * Decode an incoming data buffer and print a line in the peer list */ static int doprintpeers( struct varlist *pvl, int associd, int rstatus, int datalen, const char *data, FILE *fp, int af ) { char *name; char *value = NULL; int i; int c; sockaddr_u srcadr; sockaddr_u dstadr; sockaddr_u refidadr; u_long srcport = 0; char *dstadr_refid = "0.0.0.0"; char *serverlocal; size_t drlen; u_long stratum = 0; long ppoll = 0; long hpoll = 0; u_long reach = 0; l_fp estoffset; l_fp estdelay; l_fp estjitter; l_fp estdisp; l_fp reftime; l_fp rec; l_fp ts; u_char havevar[MAXHAVE]; u_long poll_sec; char type = '?'; char refid_string[10]; char whenbuf[8], pollbuf[8]; char clock_name[LENHOSTNAME]; memset((char *)havevar, 0, sizeof(havevar)); get_systime(&ts); ZERO_SOCK(&srcadr); ZERO_SOCK(&dstadr); /* Initialize by zeroing out estimate variables */ memset((char *)&estoffset, 0, sizeof(l_fp)); memset((char *)&estdelay, 0, sizeof(l_fp)); memset((char *)&estjitter, 0, sizeof(l_fp)); memset((char *)&estdisp, 0, sizeof(l_fp)); while (nextvar(&datalen, &data, &name, &value)) { sockaddr_u dum_store; i = findvar(name, peer_var, 1); if (i == 0) continue; /* don't know this one */ switch (i) { case CP_SRCADR: if (decodenetnum(value, &srcadr)) { havevar[HAVE_SRCADR] = 1; } break; case CP_DSTADR: if (decodenetnum(value, &dum_store)) { type = decodeaddrtype(&dum_store); havevar[HAVE_DSTADR] = 1; dstadr = dum_store; if (pvl == opeervarlist) { dstadr_refid = trunc_left(stoa(&dstadr), 15); } } break; case CP_REFID: if (pvl == peervarlist) { havevar[HAVE_REFID] = 1; if (*value == '\0') { dstadr_refid = ""; } else if (strlen(value) <= 4) { refid_string[0] = '.'; (void) strcpy(&refid_string[1], value); i = strlen(refid_string); refid_string[i] = '.'; refid_string[i+1] = '\0'; dstadr_refid = refid_string; } else if (decodenetnum(value, &refidadr)) { if (SOCK_UNSPEC(&refidadr)) dstadr_refid = "0.0.0.0"; else if (ISREFCLOCKADR(&refidadr)) dstadr_refid = refnumtoa(&refidadr); else dstadr_refid = stoa(&refidadr); } else { havevar[HAVE_REFID] = 0; } } break; case CP_STRATUM: if (decodeuint(value, &stratum)) havevar[HAVE_STRATUM] = 1; break; case CP_HPOLL: if (decodeint(value, &hpoll)) { havevar[HAVE_HPOLL] = 1; if (hpoll < 0) hpoll = NTP_MINPOLL; } break; case CP_PPOLL: if (decodeint(value, &ppoll)) { havevar[HAVE_PPOLL] = 1; if (ppoll < 0) ppoll = NTP_MINPOLL; } break; case CP_REACH: if (decodeuint(value, &reach)) havevar[HAVE_REACH] = 1; break; case CP_DELAY: if (decodetime(value, &estdelay)) havevar[HAVE_DELAY] = 1; break; case CP_OFFSET: if (decodetime(value, &estoffset)) havevar[HAVE_OFFSET] = 1; break; case CP_JITTER: if (pvl == peervarlist) if (decodetime(value, &estjitter)) havevar[HAVE_JITTER] = 1; break; case CP_DISPERSION: if (decodetime(value, &estdisp)) havevar[HAVE_DISPERSION] = 1; break; case CP_REC: if (decodets(value, &rec)) havevar[HAVE_REC] = 1; break; case CP_SRCPORT: if (decodeuint(value, &srcport)) havevar[HAVE_SRCPORT] = 1; break; case CP_REFTIME: havevar[HAVE_REFTIME] = 1; if (!decodets(value, &reftime)) L_CLR(&reftime); break; default: break; } } /* * Check to see if the srcport is NTP's port. If not this probably * isn't a valid peer association. */ if (havevar[HAVE_SRCPORT] && srcport != NTP_PORT) return (1); /* * Got everything, format the line */ poll_sec = 1<<max(min3(ppoll, hpoll, NTP_MAXPOLL), NTP_MINPOLL); if (pktversion > NTP_OLDVERSION) c = flash3[CTL_PEER_STATVAL(rstatus) & 0x7]; else c = flash2[CTL_PEER_STATVAL(rstatus) & 0x3]; if (numhosts > 1) { if (peervarlist == pvl && havevar[HAVE_DSTADR]) { serverlocal = nntohost_col(&dstadr, (size_t)min(LIB_BUFLENGTH - 1, maxhostlen), TRUE); } else { if (currenthostisnum) serverlocal = trunc_left(currenthost, maxhostlen); else serverlocal = currenthost; } fprintf(fp, "%-*s ", maxhostlen, serverlocal); } if (AF_UNSPEC == af || AF(&srcadr) == af) { strncpy(clock_name, nntohost(&srcadr), sizeof(clock_name)); fprintf(fp, "%c%-15.15s ", c, clock_name); drlen = strlen(dstadr_refid); makeascii(drlen, dstadr_refid, fp); while (drlen++ < 15) fputc(' ', fp); fprintf(fp, " %2ld %c %4.4s %4.4s %3lo %7.7s %8.7s %7.7s\n", stratum, type, prettyinterval(whenbuf, sizeof(whenbuf), when(&ts, &rec, &reftime)), prettyinterval(pollbuf, sizeof(pollbuf), (int)poll_sec), reach, lfptoms(&estdelay, 3), lfptoms(&estoffset, 3), (havevar[HAVE_JITTER]) ? lfptoms(&estjitter, 3) : lfptoms(&estdisp, 3)); return (1); } else return(1); }
static void gpsd_test_socket( peerT * const peer) { clockprocT * const pp = peer->procptr; gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr; int ec, rc; socklen_t lc; /* Check if the non-blocking connect was finished by testing the * socket for writeability. Use the 'poll()' API if available * and 'select()' otherwise. */ DPRINTF(2, ("GPSD_JSON(%d): check connect, fd=%d\n", up->unit, up->fdt)); #if defined(HAVE_SYS_POLL_H) { struct pollfd pfd; pfd.events = POLLOUT; pfd.fd = up->fdt; rc = poll(&pfd, 1, 0); if (1 != rc || !(pfd.revents & POLLOUT)) return; } #elif defined(HAVE_SYS_SELECT_H) { struct timeval tout; fd_set wset; memset(&tout, 0, sizeof(tout)); FD_ZERO(&wset); FD_SET(up->fdt, &wset); rc = select(up->fdt+1, NULL, &wset, NULL, &tout); if (0 == rc || !(FD_ISSET(up->fdt, &wset))) return; } #else # error Blooper! That should have been found earlier! #endif /* next timeout is a full one... */ up->tickover = TICKOVER_LOW; /* check for socket error */ ec = 0; lc = sizeof(ec); rc = getsockopt(up->fdt, SOL_SOCKET, SO_ERROR, &ec, &lc); DPRINTF(1, ("GPSD_JSON(%d): connect finshed, fd=%d, ec=%d(%s)\n", up->unit, up->fdt, ec, strerror(ec))); if (-1 == rc || 0 != ec) { errno = ec; if (syslogok(pp, up)) msyslog(LOG_ERR, "%s: (async)cannot connect GPSD socket: %m", refnumtoa(&peer->srcadr)); goto no_socket; } /* swap socket FDs, and make sure the clock was added */ pp->io.fd = up->fdt; up->fdt = -1; if (0 == io_addclock(&pp->io)) { if (syslogok(pp, up)) msyslog(LOG_ERR, "%s: failed to register with I/O engine", refnumtoa(&peer->srcadr)); goto no_socket; } return; no_socket: if (-1 != up->fdt) close(up->fdt); up->fdt = -1; up->tickover = up->tickpres; up->tickpres = min(up->tickpres + 5, TICKOVER_HIGH); }
static int gpsd_start( int unit, peerT * peer) { clockprocT * const pp = peer->procptr; gpsd_unitT * const up = emalloc_zero(sizeof(*up)); struct stat sb; /* initialize the unit structure */ up->fdt = -1; up->addr = s_gpsd_addr; up->tickpres = TICKOVER_LOW; /* setup refclock processing */ up->unit = unit; pp->unitptr = (caddr_t)up; pp->io.fd = -1; pp->io.clock_recv = gpsd_receive; pp->io.srcclock = peer; pp->io.datalen = 0; pp->a_lastcode[0] = '\0'; pp->lencode = 0; pp->clockdesc = DESCRIPTION; memcpy(&pp->refid, REFID, 4); /* Initialize miscellaneous variables */ peer->precision = PRECISION; /* Create the device name and check for a Character Device. It's * assumed that GPSD was started with the same link, so the * names match. (If this is not practicable, we will have to * read the symlink, if any, so we can get the true device * file.) */ if (-1 == myasprintf(&up->device, "%s%u", s_dev_stem, unit)) { msyslog(LOG_ERR, "%s clock device name too long", refnumtoa(&peer->srcadr)); goto dev_fail; } if (-1 == stat(up->device, &sb) || !S_ISCHR(sb.st_mode)) { msyslog(LOG_ERR, "%s: '%s' is not a character device", refnumtoa(&peer->srcadr), up->device); goto dev_fail; } LOGIF(CLOCKINFO, (LOG_NOTICE, "%s: startup, device is '%s'", refnumtoa(&peer->srcadr), up->device)); return TRUE; dev_fail: /* On failure, remove all UNIT ressources and declare defeat. */ INSIST (up); free(up->device); free(up); pp->unitptr = (caddr_t)NULL; return FALSE; }
static void process_version( peerT * const peer , json_ctx * const jctx , const l_fp * const rtime) { clockprocT * const pp = peer->procptr; gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr; int len; char * buf; const char *revision; const char *release; /* get protocol version number */ revision = json_object_lookup_string_default( jctx, 0, "rev", "(unknown)"); release = json_object_lookup_string_default( jctx, 0, "release", "(unknown)"); errno = 0; up->proto_major = (uint16_t)json_object_lookup_int( jctx, 0, "proto_major"); up->proto_minor = (uint16_t)json_object_lookup_int( jctx, 0, "proto_minor"); if (0 == errno) { up->fl_vers = -1; if (syslogok(pp, up)) msyslog(LOG_INFO, "%s: GPSD revision=%s release=%s protocol=%u.%u", refnumtoa(&peer->srcadr), revision, release, up->proto_major, up->proto_minor); } /* With the 3.9 GPSD protocol, '*_musec' vanished and was * replace by '*_nsec'. Dispatch properly. */ if ( up->proto_major > 3 || (up->proto_major == 3 && up->proto_minor >= 9)) up->fl_nsec = -1; else up->fl_nsec = 0; /*TODO: validate protocol version! */ /* request watch for our GPS device * Reuse the input buffer, which is no longer needed in the * current cycle. Also assume that we can write the watch * request in one sweep into the socket; since we do not do * output otherwise, this should always work. (Unless the * TCP/IP window size gets lower than the length of the * request. We handle that when it happens.) */ snprintf(up->buffer, sizeof(up->buffer), s_logon, up->device); buf = up->buffer; len = strlen(buf); if (len != write(pp->io.fd, buf, len)) { /*Note: if the server fails to read our request, the * resulting data timeout will take care of the * connection! */ if (syslogok(pp, up)) msyslog(LOG_ERR, "%s: failed to write watch request (%m)", refnumtoa(&peer->srcadr)); } }
/* * shm_timer - called once every second. * * This tries to grab a sample from the SHM segment, filtering bad ones */ static void shm_timer( int unit, struct peer *peer ) { struct refclockproc * const pp = peer->procptr; struct shmunit * const up = pp->unitptr; volatile struct shmTime *shm; l_fp tsrcv; l_fp tsref; int c; /* for formatting 'a_lastcode': */ struct calendar cd; time_t tt; vint64 ts; enum segstat_t status; struct shm_stat_t shm_stat; up->ticks++; if ((shm = up->shm) == NULL) { /* try to map again - this may succeed if meanwhile some- body has ipcrm'ed the old (unaccessible) shared mem segment */ shm = up->shm = getShmTime(unit, up->forall); if (shm == NULL) { DPRINTF(1, ("%s: no SHM segment\n", refnumtoa(&peer->srcadr))); return; } } /* query the segment, atomically */ status = shm_query(shm, &shm_stat); switch (status) { case OK: DPRINTF(2, ("%s: SHM type %d sample\n", refnumtoa(&peer->srcadr), shm_stat.mode)); break; case NO_SEGMENT: /* should never happen, but is harmless */ return; case NOT_READY: DPRINTF(1, ("%s: SHM not ready\n",refnumtoa(&peer->srcadr))); up->notready++; return; case BAD_MODE: DPRINTF(1, ("%s: SHM type blooper, mode=%d\n", refnumtoa(&peer->srcadr), shm->mode)); up->bad++; msyslog (LOG_ERR, "SHM: bad mode found in shared memory: %d", shm->mode); return; case CLASH: DPRINTF(1, ("%s: type 1 access clash\n", refnumtoa(&peer->srcadr))); msyslog (LOG_NOTICE, "SHM: access clash in shared memory"); up->clash++; return; default: DPRINTF(1, ("%s: internal error, unknown SHM fetch status\n", refnumtoa(&peer->srcadr))); msyslog (LOG_NOTICE, "internal error, unknown SHM fetch status"); up->bad++; return; } /* format the last time code in human-readable form into * 'pp->a_lastcode'. Someone claimed: "NetBSD has incompatible * tv_sec". I can't find a base for this claim, but we can work * around that potential problem. BTW, simply casting a pointer * is a receipe for disaster on some architectures. */ tt = (time_t)shm_stat.tvt.tv_sec; ts = time_to_vint64(&tt); ntpcal_time_to_date(&cd, &ts); /* add ntpq -c cv timecode in ISO 8601 format */ c = snprintf(pp->a_lastcode, sizeof(pp->a_lastcode), "%04u-%02u-%02uT%02u:%02u:%02u.%09ldZ", cd.year, cd.month, cd.monthday, cd.hour, cd.minute, cd.second, (long)shm_stat.tvt.tv_nsec); pp->lencode = ((size_t)c < sizeof(pp->a_lastcode)) ? c : 0; /* check 1: age control of local time stamp */ tt = shm_stat.tvc.tv_sec - shm_stat.tvr.tv_sec; if (tt < 0 || tt > up->max_delay) { DPRINTF(1, ("%s:SHM stale/bad receive time, delay=%llds\n", refnumtoa(&peer->srcadr), (long long)tt)); up->bad++; msyslog (LOG_ERR, "SHM: stale/bad receive time, delay=%llds", (long long)tt); return; } /* check 2: delta check */ tt = shm_stat.tvr.tv_sec - shm_stat.tvt.tv_sec - (shm_stat.tvr.tv_nsec < shm_stat.tvt.tv_nsec); if (tt < 0) tt = -tt; if (up->max_delta > 0 && tt > up->max_delta) { DPRINTF(1, ("%s: SHM diff limit exceeded, delta=%llds\n", refnumtoa(&peer->srcadr), (long long)tt)); up->bad++; msyslog (LOG_ERR, "SHM: difference limit exceeded, delta=%llds\n", (long long)tt); return; } /* if we really made it to this point... we're winners! */ DPRINTF(2, ("%s: SHM feeding data\n", refnumtoa(&peer->srcadr))); tsrcv = tspec_stamp_to_lfp(shm_stat.tvr); tsref = tspec_stamp_to_lfp(shm_stat.tvt); pp->leap = shm_stat.leap; peer->precision = shm_stat.precision; refclock_process_offset(pp, tsref, tsrcv, pp->fudgetime1); up->good++; }
static void gpsd_init_socket( peerT * const peer) { clockprocT * const pp = peer->procptr; gpsd_unitT * const up = (gpsd_unitT *)pp->unitptr; addrinfoT * ai; int rc; int ov; /* draw next address to try */ if (NULL == up->addr) up->addr = s_gpsd_addr; ai = up->addr; up->addr = ai->ai_next; /* try to create a matching socket */ up->fdt = socket( ai->ai_family, ai->ai_socktype, ai->ai_protocol); if (-1 == up->fdt) { if (syslogok(pp, up)) msyslog(LOG_ERR, "%s: cannot create GPSD socket: %m", refnumtoa(&peer->srcadr)); goto no_socket; } /* make sure the socket is non-blocking */ rc = fcntl(up->fdt, F_SETFL, O_NONBLOCK, 1); if (-1 == rc) { if (syslogok(pp, up)) msyslog(LOG_ERR, "%s: cannot set GPSD socket to non-blocking: %m", refnumtoa(&peer->srcadr)); goto no_socket; } /* disable nagling */ ov = 1; rc = setsockopt(up->fdt, IPPROTO_TCP, TCP_NODELAY, (char*)&ov, sizeof(ov)); if (-1 == rc) { if (syslogok(pp, up)) msyslog(LOG_INFO, "%s: cannot disable TCP nagle: %m", refnumtoa(&peer->srcadr)); } /* start a non-blocking connect */ rc = connect(up->fdt, ai->ai_addr, ai->ai_addrlen); if (-1 == rc && errno != EINPROGRESS) { if (syslogok(pp, up)) msyslog(LOG_ERR, "%s: cannot connect GPSD socket: %m", refnumtoa(&peer->srcadr)); goto no_socket; } return; no_socket: if (-1 != up->fdt) close(up->fdt); up->fdt = -1; up->tickover = up->tickpres; up->tickpres = min(up->tickpres + 5, TICKOVER_HIGH); }