1 /*
2 *
3 * XASTIR, Amateur Station Tracking and Information Reporting
4 * Copyright (C) 2000-2019 The Xastir Group
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 *
20 * Look at the README for more information on the program.
21 */
22
23
24
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif // HAVE_CONFIG_H
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <unistd.h>
32 #include <setjmp.h>
33 #include <sys/socket.h>
34 #include <string.h>
35
36 #include <netinet/in.h> // Moved ahead of inet.h as reports of some *BSD's not
37 // including this as they should.
38 #include <arpa/inet.h>
39 //#include <netinet/tcp.h> // Needed for TCP_NODELAY setsockopt() (disabling Nagle algorithm)
40
41 #ifdef HAVE_NETDB_H
42 #include <netdb.h>
43 #endif // HAVE_NETDB_H
44
45 #include <sys/types.h>
46 #include <sys/wait.h>
47 #include <errno.h>
48
49 #include <poll.h>
50
51 #include "xastir.h"
52
53 // Must be last include file
54 #include "leak_detection.h"
55
56 // Atttempt to send to one of the addresses, waiting for 10 seconds
57 // for (hopefully) a response. Returns 1 on success or 0 if we didn't
58 // get a response. (Any response is considered a success)
try_exchange(struct addrinfo * addr,char * buffer,int UNUSED (buflen))59 int try_exchange(struct addrinfo *addr, char *buffer, int UNUSED(buflen) )
60 {
61 int sockfd, n;
62 socklen_t length;
63 struct sockaddr_storage from;
64 struct pollfd polls;
65
66 sockfd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
67 if (sockfd < 0)
68 {
69 fprintf(stderr, "socket error: %s\n", strerror(errno));
70 return(0);
71 }
72
73 n = sendto(sockfd, buffer, (size_t)strlen(buffer), 0, addr->ai_addr,
74 addr->ai_addrlen);
75 if (n < 0)
76 {
77 fprintf(stderr, "Sendto error %s\n", strerror(errno));
78 close(sockfd);
79 return(0);
80 }
81
82 polls.fd = sockfd;
83 polls.events = POLLIN;
84
85 // wait for up to 10 seconds for a response.
86 n = poll(&polls, 1, 10 * 1000);
87 if(n == 0)
88 {
89 fprintf(stderr, "Timeout waiting for response\n");
90 close(sockfd);
91 return 0;
92 }
93 else if (n < 0 )
94 {
95 fprintf(stderr, "poll() returned an error: %s\n", strerror(errno));
96 close(sockfd);
97 return 0;
98 }
99
100 // Response should be waiting, get it.
101 length = sizeof(from);
102 n = recvfrom(sockfd, buffer, 256, 0, (struct sockaddr *)&from, &length);
103 if (n < 0)
104 {
105 fprintf(stderr, "recvfrom: %s\n", strerror(errno));
106 close(sockfd);
107 return(0);
108 }
109
110 close(sockfd);
111 return 1;
112 }
113
114 #ifndef AI_DEFAULT
115 #define AI_DEFAULT (AI_V4MAPPED|AI_ADDRCONFIG)
116 #endif
117
118 // Loop through the possible addresses for hostname (probably IPv6 and IPv4)
119 // Tries until we are successful (get a reponse) or we run out of addresses
exchange_packet(char * hostname,char * port,char * buffer,int buflen)120 int exchange_packet(char *hostname, char *port, char *buffer, int buflen)
121 {
122 struct addrinfo hints, *res, *r;
123 int error;
124 int success = 0;
125
126 memset(&hints, 0, sizeof(hints));
127 hints.ai_family = PF_UNSPEC;
128 hints.ai_socktype = SOCK_DGRAM;
129 hints.ai_flags = AI_DEFAULT;
130
131 error = getaddrinfo(hostname, port, &hints, &res);
132 if (error)
133 {
134 fprintf(stderr, "Error: Unable to lookup addresses for host %s port %s\n",
135 hostname, port);
136 return 1;
137 }
138
139 r = res;
140 while(!success && r)
141 {
142 success = try_exchange(r, buffer, buflen);
143 r = r->ai_next;
144 if(!success && r)
145 {
146 fprintf(stderr, "Trying next address to send to\n");
147 }
148 }
149
150 freeaddrinfo(res);
151 return success;
152 }
153
154 // Send a UDP packet to a UDP listening port. This allows scripts
155 // and other programs to inject packets into Xastir via UDP
156 // protocol.
157 // Inputs:
158 // hostname (argv[1])
159 // port (argv[2])
160 // callsign (argv[3])
161 // passcode (argv[4])
162 // optional flags: -identify
163 // -to_rf
164 // -to_inet
165 // APRS Packet (argv[5])
166 // Returns:
167 // 0: Message sent, ack received
168 // 1: Error condition
169 //
170 //
171 //
main(int argc,char * argv[])172 int main(int argc, char *argv[])
173 {
174 char buffer[512];
175 char callsign[10];
176 char extra[100];
177 int passcode;
178 char message[256];
179 int ii, success;
180
181
182 if (argc < 6)
183 {
184 fprintf(stderr,
185 "\nUsage: xastir_udp_client server port call passcode -identify\n");
186 fprintf(stderr,
187 " xastir_udp_client server port call passcode [-to_rf] [-to_inet] \"APRS Packet\"\n");
188
189 fprintf(stderr,
190 "\nExample: xastir_udp_client localhost 2023 ab7cd 1234 \"APRS packet goes here\"\n");
191 return(1);
192 }
193
194 // Fetch the callsign
195 snprintf(callsign, sizeof(callsign), "%s", argv[3]);
196 callsign[sizeof(callsign)-1] = '\0'; // Terminate it
197
198 // Fetch the passcode
199 passcode = atoi(argv[4]);
200
201 // Check for optional flags here:
202 // -identify
203 // -to_rf
204 // -to_inet
205 //
206 extra[0] = '\0';
207 for (ii = 5; ii < argc; ii++)
208 {
209 if (strstr(argv[ii], "-identify"))
210 {
211 //fprintf(stderr,"Found -identify\n");
212 strncat(extra, ",-identify", sizeof(extra)-strlen(extra)-1);
213 }
214 else if (strstr(argv[ii], "-to_rf"))
215 {
216 //fprintf(stderr,"Found -to_rf\n");
217 strncat(extra, ",-to_rf", sizeof(extra)-strlen(extra)-1);
218 }
219 else if (strstr(argv[ii], "-to_inet"))
220 {
221 //fprintf(stderr,"Found -to_inet\n");
222 strncat(extra, ",-to_inet", sizeof(extra)-strlen(extra)-1);
223 }
224 }
225
226
227 // fprintf(stdout, "Please enter the message: ");
228
229 // Fetch message portion from the end of the command-line
230 snprintf(message, sizeof(message), "%s", argv[argc-1]);
231 message[sizeof(message)-1] = '\0'; // Terminate it
232
233 if (message[0] == '\0') // Empty message
234 {
235 return(1);
236 }
237
238 memset(buffer, 0, 256);
239 // fgets(buffer, 255, stdin);
240
241 snprintf(buffer,
242 sizeof(buffer),
243 "%s,%d%s\n%s\n",
244 callsign,
245 passcode,
246 extra,
247 message);
248
249 //fprintf(stderr, "%s", buffer);
250
251 success = exchange_packet(argv[1], argv[2], buffer, 256);
252 if(!success)
253 {
254 fprintf(stdout, "No response received.\n");
255 return(1);
256 }
257 fprintf(stdout,"Received: %s\n", buffer);
258
259 if (strncmp(buffer, "NACK", 4) == 0)
260 {
261 //fprintf(stderr,"returning 1\n");
262 return(1); // Received a NACK
263 }
264 else if (strncmp(buffer, "ACK", 3) == 0)
265 {
266 //fprintf(stderr,"returning 0\n");
267 return(0); // Received an ACK
268 }
269 else
270 {
271 //fprintf(stderr,"returning 1\n");
272 return(1); // Received something other than ACK or NACK
273 }
274 }
275
276
277