gpsd.c
来自「gpsd, a popular GPS daemon.」· C语言 代码 · 共 1,824 行 · 第 1/4 页
C
1,824 行
/*@ -observertrans @*/ if (!rtcm_service) rtcm_service = getservbyname("rtcm", "tcp") ? "rtcm" : DEFAULT_RTCM_PORT; /*@ +observertrans @*/ if ((nsock = passivesock(rtcm_service, "tcp", QLEN)) < 0) { gpsd_report(LOG_ERROR,"RTCM104 socket create failed, netlib error %d\n",nsock); exit(2); } gpsd_report(LOG_INF, "listening on port %s\n", rtcm_service);#endif /* RTCM104_SERVICE */#ifdef NTPSHM_ENABLE if (getuid() == 0) { (void)nice(-10); /* for precise timekeeping increase priority */ (void)ntpshm_init(&context, nowait); } else { gpsd_report (2, "Unable to start ntpshm. gpsd must run as root.\n"); }#endif /* NTPSHM_ENABLE */#ifdef DBUS_ENABLE /* we need to connect to dbus as root */ if (initialize_dbus_connection()) { /* the connection could not be started */ gpsd_report (2, "unable to connect to the DBUS system bus\n"); } else gpsd_report (2, "successfully connected to the DBUS system bus\n");#endif /* DBUS_ENABLE */ if (getuid() == 0 && go_background) { struct passwd *pw; struct stat stb; /* make default devices accessible even after we drop privileges */ for (i = optind; i < argc; i++) if (stat(argv[i], &stb) == 0) (void)chmod(argv[i], stb.st_mode|S_IRGRP|S_IWGRP); /* * Drop privileges. Up to now we've been running as root. Instead, * set the user ID to 'nobody' (or whatever the --enable-gpsd-user * is) and the group ID to the owning group of a prototypical TTY * device. This limits the scope of any compromises in the code. * It requires that all GPS devices have their group read/write * permissions set. */ if ((optind<argc&&stat(argv[optind], &stb)==0)||stat(PROTO_TTY,&stb)==0) { gpsd_report(LOG_PROG, "changing to group %d\n", stb.st_gid); if (setgid(stb.st_gid) != 0) gpsd_report(LOG_ERROR, "setgid() failed, errno %s\n", strerror(errno)); } pw = getpwnam( GPSD_USER ); if (pw) (void)seteuid(pw->pw_uid); } gpsd_report(LOG_INF, "running with effective group ID %d\n", getegid()); gpsd_report(LOG_INF, "running with effective user ID %d\n", geteuid()); for (sub = subscribers; sub < subscribers + MAXSUBSCRIBERS; sub++) { gps_clear_fix(&sub->fixbuffer); gps_clear_fix(&sub->oldfix); } /* daemon got termination or interrupt signal */ if ((st = setjmp(restartbuf)) > 0) { /* try to undo all device configurations */ for (dfd = 0; dfd < MAXDEVICES; dfd++) { if (allocated_channel(&channels[dfd])) (void)gpsd_wrap(&channels[dfd]); } gpsd_report(LOG_WARN, "gpsd restarted by SIGHUP\n"); } /* Handle some signals */ signalled = 0; (void)signal(SIGHUP, onsig); (void)signal(SIGINT, onsig); (void)signal(SIGTERM, onsig); (void)signal(SIGQUIT, onsig); (void)signal(SIGPIPE, SIG_IGN); FD_SET(msock, &all_fds); adjust_max_fd(msock, true);#ifdef RTCM104_SERVICE FD_SET(nsock, &all_fds); adjust_max_fd(nsock, true);#endif /* RTCM104_SERVICE */ FD_ZERO(&control_fds); /* optimization hack to defer having to read subframe data */ if (time(NULL) < START_SUBFRAME) context.valid |= LEAP_SECOND_VALID; for (i = optind; i < argc; i++) { struct gps_device_t *device = open_device(argv[i]); if (!device) { gpsd_report(LOG_ERROR, "GPS device %s nonexistent or can't be read\n", argv[i]); } } while (0 == signalled) { (void)memcpy((char *)&rfds, (char *)&all_fds, sizeof(rfds)); gpsd_report(LOG_RAW+2, "select waits\n"); /* * Poll for user commands or GPS data. The timeout doesn't * actually matter here since select returns whenever one of * the file descriptors in the set goes ready. The point * of tracking maxfd is to keep the set of descriptors that * select(2) has to poll here as small as possible (for * low-clock-rate SBCs and the like). */ /*@ -usedef @*/ tv.tv_sec = 1; tv.tv_usec = 0; if (select(maxfd+1, &rfds, NULL, NULL, &tv) < 0) { if (errno == EINTR) continue; gpsd_report(LOG_ERROR, "select: %s\n", strerror(errno)); exit(2); } /*@ +usedef @*/#ifdef __UNUSED__ { char dbuf[BUFSIZ]; dbuf[0] = '\0'; for (sub = subscribers; sub < subscribers + MAXSUBSCRIBERS; sub++) if (FD_ISSET(sub->fd, &all_fds)) (void)snprintf(dbuf + strlen(dbuf), sizeof(dbuf)-strlen(dbuf), " %d", sub->fd); strlcat(dbuf, "} -> {", BUFSIZ); for (sub = subscribers; sub < subscribers + MAXSUBSCRIBERS; sub++) if (FD_ISSET(sub->fd, &rfds)) (void)snprintf(dbuf + strlen(dbuf), sizeof(dbuf)-strlen(dbuf), " %d", sub->fd); gpsd_report(LOG_RAW, "Polling descriptor set: {%s}\n", dbuf); }#endif /* UNUSED */ /* always be open to new client connections */ if (FD_ISSET(msock, &rfds)) { socklen_t alen = (socklen_t)sizeof(fsin); char *c_ip; /*@i1@*/int ssock = accept(msock, (struct sockaddr *) &fsin, &alen); if (ssock < 0) gpsd_report(LOG_ERROR, "accept: %s\n", strerror(errno)); else { struct subscriber_t *client = NULL; int opts = fcntl(ssock, F_GETFL); if (opts >= 0) (void)fcntl(ssock, F_SETFL, opts | O_NONBLOCK); c_ip = sock2ip(ssock); client = allocate_client(); if (client == NULL) { gpsd_report(LOG_ERROR, "Client %s connect on fd %d -" "no subscriber slots available\n", c_ip, ssock); (void)close(ssock); } else { FD_SET(ssock, &all_fds); adjust_max_fd(ssock, true); client->fd = ssock; client->active = timestamp(); client->tied = false; client->requires = ANY; gpsd_report(LOG_INF, "client %s (%d) connect on fd %d\n", c_ip, sub_index(client), ssock); } } FD_CLR(msock, &rfds); }#ifdef RTCM104_SERVICE /* also to RTCM client connections */ if (FD_ISSET(nsock, &rfds)) { char *c_ip; socklen_t alen = (socklen_t)sizeof(fsin); /*@i1@*/int ssock = accept(nsock, (struct sockaddr *)&fsin, &alen); if (ssock < 0) gpsd_report(LOG_ERROR, "accept: %s\n", strerror(errno)); else { struct subscriber_t *client = NULL; int opts = fcntl(ssock, F_GETFL); if (opts >= 0) (void)fcntl(ssock, F_SETFL, opts | O_NONBLOCK); c_ip = sock2ip(ssock); client = allocate_client(); if (client == NULL) { gpsd_report(LOG_ERROR, "Client %s connect on fd %d -" "no subscriber slots available\n", c_ip, ssock); close(ssock); } else { FD_SET(ssock, &all_fds); adjust_max_fd(ssock, true); client->active = true; client->tied = false; client->requires = RTCM104; client->fd = ssock; gpsd_report(LOG_INF, "client %s (%d) connect on fd %d\n", c_ip, sub_index(client), ssock); } } FD_CLR(nsock, &rfds); }#endif /* RTCM104_SERVICE */ /* also be open to new control-socket connections */ if (csock > -1 && FD_ISSET(csock, &rfds)) { socklen_t alen = (socklen_t)sizeof(fsin); /*@i1@*/int ssock = accept(csock, (struct sockaddr *) &fsin, &alen); if (ssock < 0) gpsd_report(LOG_ERROR, "accept: %s\n", strerror(errno)); else { gpsd_report(LOG_INF, "control socket connect on %d\n", ssock); FD_SET(ssock, &all_fds); FD_SET(ssock, &control_fds); adjust_max_fd(ssock, true); } FD_CLR(csock, &rfds); } if (context.dsock >= 0 && FD_ISSET(context.dsock, &rfds)) { /* be ready for DGPS reports */ if (dgnss_poll(&context) == -1){ FD_CLR(context.dsock, &all_fds); FD_CLR(context.dsock, &rfds); context.dsock = -1; } } /* read any commands that came in over control sockets */ for (cfd = 0; cfd < FD_SETSIZE; cfd++) if (FD_ISSET(cfd, &control_fds)) { char buf[BUFSIZ]; while (read(cfd, buf, sizeof(buf)-1) > 0) { gpsd_report(LOG_IO, "<= control(%d): %s\n", cfd, buf); handle_control(cfd, buf); } (void)close(cfd); FD_CLR(cfd, &all_fds); FD_CLR(cfd, &control_fds); adjust_max_fd(cfd, false); } /* poll all active devices */ for (channel = channels; channel < channels + MAXDEVICES; channel++) { if (!allocated_channel(channel)) continue; /* pass the current RTCM correction to the GPS if new */ if (channel->device_type) rtcm_relay(channel); /* get data from the device */ changed = 0; if (channel->gpsdata.gps_fd >= 0 && FD_ISSET(channel->gpsdata.gps_fd, &rfds)) { gpsd_report(LOG_RAW+1, "polling %d\n", channel->gpsdata.gps_fd); changed = gpsd_poll(channel); if (changed == ERROR_SET) { gpsd_report(LOG_WARN, "packet sniffer failed to sync up\n"); FD_CLR(channel->gpsdata.gps_fd, &all_fds); adjust_max_fd(channel->gpsdata.gps_fd, false); gpsd_deactivate(channel); } else if ((changed & ONLINE_SET) == 0) { gpsd_report(LOG_INF, "GPS is offline (%lf sec since data)\n", timestamp() - channel->gpsdata.online); FD_CLR(channel->gpsdata.gps_fd, &all_fds); adjust_max_fd(channel->gpsdata.gps_fd, false); gpsd_deactivate(channel); notify_watchers(channel, "GPSD,X=0\r\n"); } else { /* handle laggy response to a firmware version query*/ if ((changed & DEVICEID_SET) != 0) { char id[NMEA_MAX]; assert(channel->device_type != NULL); (void)snprintf(id, sizeof(id), "GPSD,I=%s", channel->device_type->type_name); if (channel->subtype[0] != '\0') { (void)strlcat(id, " ", sizeof(id)); (void)strlcat(id,channel->subtype,sizeof(id)); } (void)strlcat(id, "\r\n", sizeof(id)); notify_watchers(channel, id); } /* copy/merge channel data into subscriber fix buffers */ for (sub = subscribers; sub < subscribers + MAXSUBSCRIBERS; sub++) { if (sub->device == channel) { if (sub->buffer_policy == casoc && (changed & CYCLE_START_SET)!=0) gps_clear_fix(&sub->fixbuffer); /* don't downgrade mode if holding previous fix */ if (sub->fixbuffer.mode > sub->device->gpsdata.fix.mode) changed &=~ MODE_SET; gpsd_report(LOG_PROG, "transfer mask on %s: %02x\n", sub->device->gpsdata.tag, changed); gps_merge_fix(&sub->fixbuffer, changed, &sub->device->gpsdata.fix); gpsd_error_model(sub->device, &sub->fixbuffer, &sub->oldfix); } } }#ifdef RTCM104_SERVICE /* copy each RTCM-104 correction to all GPSes */ if ((changed & RTCM_SET) != 0) { for (gps = channels; gps < channels + MAXDEVICES; gps++) if (gps->device_type != NULL && gps->device_type->rtcm_writer != NULL) (void)gps->device_type->rtcm_writer(gps, (char *)channel->outbuffer, channel->outbuflen); }#endif /* RTCM104_SERVICE */ } for (sub = subscribers; sub < subscribers + MAXSUBSCRIBERS; sub++) { /* some listeners may be in watcher mode */ if (sub->watcher) { char cmds[4] = ""; channel->poll_times[sub - subscribers] = timestamp(); if (changed &~ ONLINE_SET) { if (changed & (LATLON_SET | MODE_SET)) (void)strlcat(cmds, "o", 4); if (changed & SATELLITE_SET) (void)strlcat(cmds, "y", 4); if (channel->gpsdata.profiling!=0) (void)strlcat(cmds, "$", 4); } if (cmds[0] != '\0') (void)handle_gpsd_request(sub, cmds, (int)strlen(cmds)); } }#ifdef DBUS_ENABLE if (changed &~ ONLINE_SET) { if (changed & (LATLON_SET | MODE_SET)) send_dbus_fix (channel); }#endif }#ifdef NOT_FIXED if (context.fixcnt > 0 && context.dsock == -1) { for (channel=channels; channel < channels+MAXDEVICES; channel++) { if (channel->gpsdata.fix.mode > MODE_NO_FIX) { dgnss_autoconnect(&context, channel->gpsdata.fix.latitude, channel->gpsdata.fix.longitude); break; } } }#endif /* accept and execute commands for all clients */ for (sub = subscribers; sub < subscribers + MAXSUBSCRIBERS; sub++) { if (sub->active == 0) continue; if (FD_ISSET(sub->fd, &rfds)) { char buf[BUFSIZ]; int buflen; gpsd_report(LOG_PROG, "checking client(%d)\n", sub_index(sub)); if ((buflen = (int)read(sub->fd, buf, sizeof(buf) - 1)) <= 0) { detach_client(sub); } else { if (buf[buflen-1] != '\n') buf[buflen++] = '\n'; buf[buflen] = '\0'; gpsd_report(LOG_IO, "<= client(%d): %s", sub_index(sub), buf);#ifdef RTCM104_SERVICE if (sub->requires==RTCM104 || sub->requires==ANY) { if (handle_rtcm_request(sub, buf, buflen) < 0) detach_client(sub); } else#endif /* RTCM104_SERVICE */ { if (sub->device){ /* * when a command comes in, to update .active to * timestamp() so we don't close the connection * after POLLER_TIMEOUT seconds. This makes * POLLER_TIMEOUT useful. */ sub->active = sub->device->poll_times[sub_index(sub)] = timestamp(); } if (handle_gpsd_request(sub, buf, buflen) < 0) detach_client(sub); } } } else if (sub->device == NULL && timestamp() - sub->active > ASSIGNMENT_TIMEOUT) { gpsd_report(LOG_WARN, "client(%d) timed out before assignment request.\n", sub_index(sub)); detach_client(sub); } else if (sub->device != NULL && !(sub->watcher || sub->raw>0) && timestamp() - sub->active > POLLER_TIMEOUT) { gpsd_report(LOG_WARN, "client(%d) timed out on command wait.\n", cfd); detach_client(sub); } } /* * Close devices with an identified packet type but no remaining * subscribers. The reason the test has this particular form is * so that, immediately after device open, we'll keep reading * packets until a type is identified even though there are no * subscribers yet. We need this to happen so that subscribers * can later choose a device by packet type. */ if (!nowait) for (channel=channels; channel < channels+MAXDEVICES; channel++) { if (allocated_channel(channel)) { if (channel->packet.type != BAD_PACKET) { bool need_gps = false; for (cfd = 0; cfd < MAXSUBSCRIBERS; cfd++) if (subscribers[cfd].device == channel) need_gps = true; if (!need_gps && channel->gpsdata.gps_fd > -1) { gpsd_report(LOG_RAW, "unflagging descriptor %d\n", channel->gpsdata.gps_fd); FD_CLR(channel->gpsdata.gps_fd, &all_fds); adjust_max_fd(channel->gpsdata.gps_fd, false); gpsd_deactivate(channel); } } } } } /* if we make it here, we got a signal... deal with it */ /* restart on SIGHUP, clean up and exit otherwise */ if (SIGHUP == (int)signalled) longjmp(restartbuf, 1); gpsd_report(LOG_WARN, "Received terminating signal %d. Exiting...\n",signalled); /* try to undo all device configurations */ for (dfd = 0; dfd < MAXDEVICES; dfd++) { if (allocated_channel(&channels[dfd])) (void)gpsd_wrap(&channels[dfd]); } if (control_socket) (void)unlink(control_socket); if (pid_file) (void)unlink(pid_file); return 0;}/*@ +mustfreefresh @*/
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?