1 /*
2  * This code is free software; you can redistribute it and/or modify
3  * it under the terms of the GNU General Public License as published by
4  * the Free Software Foundation; either version 2 of the License, or
5  * (at your option) any later version.
6  *
7  * This code is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  */
12 
13 #include <sys/types.h>
14 #include <sys/uio.h>
15 
16 #include "config.h"
17 #include "spectool_net_client.h"
18 
spectool_netcli_init(spectool_server * sr,char * url,char * errstr)19 int spectool_netcli_init(spectool_server *sr, char *url, char *errstr) {
20 	int ret;
21 
22 	sr->sock = -1;
23 	sr->hostname[0] = '\0';
24 	sr->port = 0;
25 	sr->url = NULL;
26 
27 	sr->host = NULL;
28 
29 	sr->bufferwrite = 1;
30 
31 	memset(sr->wbuf, 0, CLI_BUF_SZ);
32 	memset(sr->rbuf, 0, CLI_BUF_SZ);
33 
34 	sr->write_pos = 0;
35 	sr->read_pos = 0;
36 	sr->write_fill = 0;
37 	sr->read_fill = 0;
38 
39 	sr->devlist = NULL;
40 
41 	sr->state = SPECTOOL_NET_STATE_NONE;
42 
43 	if ((ret = sscanf(url, "tcp://%256[^:]:%hd", sr->hostname,
44 					  &(sr->port))) == 1) {
45 		sr->port = SPECTOOL_NET_DEFAULT_PORT;
46 	} else if (ret != 2) {
47 		snprintf(errstr, SPECTOOL_ERROR_MAX, "Could not parse server URL, expected "
48 				 "tcp://host:port");
49 		sr->state = SPECTOOL_NET_STATE_ERROR;
50 		return -1;
51 	}
52 
53 	sr->host = gethostbyname(sr->hostname);
54 
55 	if (sr->host == NULL) {
56 		snprintf(errstr, SPECTOOL_ERROR_MAX, "Could not resolve host '%s'",
57 				 sr->hostname);
58 		sr->state = SPECTOOL_NET_STATE_ERROR;
59 		return -1;
60 	}
61 
62 	memcpy((char *) &(sr->conaddr), sr->host->h_addr_list[0],
63 		   sizeof(unsigned int) < sr->host->h_length ?
64 		   		sizeof(unsigned int) : sr->host->h_length);
65 
66 	sr->url = strdup(url);
67 
68 	return 1;
69 }
70 
spectool_netcli_connect(spectool_server * sr,char * errstr)71 int spectool_netcli_connect(spectool_server *sr, char *errstr) {
72 	int save_mode;
73 
74 	struct sockaddr_in servaddr, localaddr;
75 
76 	memset(&servaddr, 0, sizeof(struct sockaddr_in));
77 	servaddr.sin_family = sr->host->h_addrtype;
78 	memcpy((char *) &servaddr.sin_addr.s_addr,
79 		   sr->host->h_addr_list[0], sr->host->h_length);
80 	servaddr.sin_port = htons(sr->port);
81 
82 	if ((sr->sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
83 		snprintf(errstr, SPECTOOL_ERROR_MAX, "Failed to create socket to server: %s",
84 				 strerror(errno));
85 		sr->state = SPECTOOL_NET_STATE_ERROR;
86 		return -1;
87 	}
88 
89 	memset(&localaddr, 0, sizeof(struct sockaddr_in));
90 	localaddr.sin_family = AF_INET;
91 	localaddr.sin_addr.s_addr = htonl(INADDR_ANY);
92 	localaddr.sin_port = htons(0);
93 
94 	if (bind(sr->sock, (struct sockaddr *) &localaddr, sizeof(localaddr)) < 0) {
95 		close(sr->sock);
96 		snprintf(errstr, SPECTOOL_ERROR_MAX, "Failed to bind socket to server: %s",
97 				 strerror(errno));
98 		sr->state = SPECTOOL_NET_STATE_ERROR;
99 		return -1;
100 	}
101 
102 	if (connect(sr->sock, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0) {
103 		close(sr->sock);
104 		snprintf(errstr, SPECTOOL_ERROR_MAX, "Failed to connect socket to server: %s",
105 				 strerror(errno));
106 		sr->state = SPECTOOL_NET_STATE_ERROR;
107 		return -1;
108 	}
109 
110 	save_mode = fcntl(sr->sock, F_GETFL, 0);
111 	fcntl(sr->sock, F_SETFL, save_mode | O_NONBLOCK);
112 
113 	sr->state = SPECTOOL_NET_STATE_CONNECTED;
114 
115 	return 1;
116 }
117 
spectool_netcli_close(spectool_server * sr)118 int spectool_netcli_close(spectool_server *sr) {
119 	spectool_net_dev *di;
120 
121 	while (sr->devlist != NULL) {
122 		di = sr->devlist->next;
123 		free(sr->devlist);
124 		sr->devlist = di;
125 	}
126 
127 	if (sr->sock >= 0)
128 		close(sr->sock);
129 
130 	if (sr->url != NULL)
131 		free(sr->url);
132 
133 	return 1;
134 }
135 
spectool_netcli_getstate(spectool_server * sr)136 int spectool_netcli_getstate(spectool_server *sr) {
137 	return sr->state;
138 }
139 
spectool_netcli_geturl(spectool_server * sr)140 char *spectool_netcli_geturl(spectool_server *sr) {
141 	return sr->url;
142 }
143 
spectool_netcli_getpollfd(spectool_server * sr)144 int spectool_netcli_getpollfd(spectool_server *sr) {
145 	return sr->sock;
146 }
147 
spectool_netcli_getwritefd(spectool_server * sr)148 int spectool_netcli_getwritefd(spectool_server *sr) {
149 	return sr->sock;
150 }
151 
spectool_netcli_getaddr(spectool_server * sr)152 unsigned int spectool_netcli_getaddr(spectool_server *sr) {
153 	return sr->conaddr;
154 }
155 
spectool_netcli_getport(spectool_server * sr)156 unsigned short int spectool_netcli_getport(spectool_server *sr) {
157 	return sr->port;
158 }
159 
spectool_netcli_setbufferwrite(spectool_server * sr,int buf)160 void spectool_netcli_setbufferwrite(spectool_server *sr, int buf) {
161 	sr->bufferwrite = buf;
162 }
163 
spectool_netcli_getwritepend(spectool_server * sr)164 int spectool_netcli_getwritepend(spectool_server *sr) {
165 	return (sr->write_pos < sr->write_fill);
166 }
167 
spectool_netcli_poll(spectool_server * sr,char * errstr)168 int spectool_netcli_poll(spectool_server *sr, char *errstr) {
169 	spectool_fr_header *header;
170 	int res;
171 	int ret = 0;
172 
173 	if (sr->sock < 0)
174 		return -1;
175 
176 	while (sr->read_fill - sr->read_pos >= spectool_fr_header_size()) {
177 		header = (spectool_fr_header *) &(sr->rbuf[sr->read_pos]);
178 
179 		/* Nuke the buffer entirely and start over if we can't find a
180 		 * sentinel */
181 		if (ntohl(header->sentinel) != SPECTOOL_NET_SENTINEL) {
182 			sr->read_fill = 0;
183 			sr->read_pos = 0;
184 			return 0;
185 		}
186 
187 		if (ntohs(header->frame_len) > (sr->read_fill - sr->read_pos)) {
188 			return 0;
189 		}
190 
191 		sr->read_pos += ntohs(header->frame_len);
192 
193 		/* If we've finished the packet reset the buffer to the beginning */
194 		if (sr->read_pos >= sr->read_fill) {
195 			sr->read_pos = 0;
196 			sr->read_fill = 0;
197 		}
198 
199 		/* We only care about device and sweeps, the rest get ignored (for now) */
200 		if (header->block_type == SPECTOOL_NET_FRAME_DEVICE) {
201 			if ((res = spectool_netcli_block_netdev(sr, header, errstr)) < 0) {
202 				return -1;
203 			}
204 
205 			if (res > 0) {
206 				ret |= SPECTOOL_NETCLI_POLL_NEWDEVS;
207 			}
208 
209 		} else if (header->block_type == SPECTOOL_NET_FRAME_SWEEP) {
210 			if ((res = spectool_netcli_block_sweep(sr, header, errstr)) < 0) {
211 				return -1;
212 			}
213 
214 			if (res > 0) {
215 				ret |= SPECTOOL_NETCLI_POLL_NEWSWEEPS;
216 			}
217 		}
218 	}
219 
220 	/* Read as much as we can */
221 	if ((res = read(sr->sock, &(sr->rbuf[sr->read_fill]),
222 					CLI_BUF_SZ - sr->read_fill)) <= 0) {
223 		if (errno == EAGAIN)
224 			return ret;
225 
226 		snprintf(errstr, SPECTOOL_ERROR_MAX, "Failed to read from socket: %s",
227 				 strerror(errno));
228 		sr->state == SPECTOOL_NET_STATE_ERROR;
229 		return -1;
230 	}
231 
232 	sr->read_fill += res;
233 
234 	if (res > 0) {
235 		ret |= SPECTOOL_NETCLI_POLL_ADDITIONAL;
236 	}
237 
238 	return ret;
239 }
240 
spectool_netcli_writepoll(spectool_server * sr,char * errstr)241 int spectool_netcli_writepoll(spectool_server *sr, char *errstr) {
242 	int res;
243 
244 	if ((res = write(sr->sock, &(sr->wbuf[sr->write_pos]),
245 					 sr->write_fill - sr->write_pos)) < 0) {
246 		snprintf(errstr, SPECTOOL_ERROR_MAX, "write() failed on %s",
247 				 strerror(errno));
248 		return -1;
249 	}
250 
251 	sr->write_pos += res;
252 
253 	if (sr->write_pos >= sr->write_fill) {
254 		sr->write_fill = 0;
255 		sr->write_pos = 0;
256 	}
257 
258 	return 1;
259 }
260 
spectool_netcli_block_netdev(spectool_server * sr,spectool_fr_header * header,char * errstr)261 int spectool_netcli_block_netdev(spectool_server *sr, spectool_fr_header *header,
262 								 char *errstr) {
263 	spectool_fr_device *dev;
264 	spectool_net_dev *sni;
265 	int bsize = ntohs(header->frame_len) - spectool_fr_header_size();
266 
267 	int num_devices;
268 	int x;
269 
270 	num_devices = header->num_blocks;
271 
272 	for (x = 0; x < header->num_blocks; x++) {
273 		/* If we can't fit, bail.  In the future this will have to be
274 		 * rewritten to handle variable sized devices, maybe */
275 		if (bsize < spectool_fr_device_size() * (x + 1)) {
276 			return -1;
277 		}
278 
279 		dev = (spectool_fr_device *) &(header->data[spectool_fr_device_size() * x]);
280 
281 		/* Is this the last device? */
282 		if (dev->device_version == SPECTOOL_NET_DEVTYPE_LASTDEV) {
283 			sr->state == SPECTOOL_NET_STATE_CONFIGURED;
284 			return 1;
285 		}
286 
287 		/* Does this device exist in the list?  If it does, just update it,
288 		 * otherwise we need to make a new one */
289 		sni = sr->devlist;
290 		while (sni != NULL) {
291 			if (ntohl(dev->device_id) == sni->device_id)
292 				break;
293 
294 			sni = sni->next;
295 		}
296 
297 		if (sni == NULL) {
298 			sni = (spectool_net_dev *) malloc(sizeof(spectool_net_dev));
299 			sni->phydev = NULL;
300 			sni->next = sr->devlist;
301 			sr->devlist = sni;
302 		}
303 
304 		sni->device_version = dev->device_version;
305 		sni->device_flags = ntohs(dev->device_flags);
306 		sni->device_id = ntohl(dev->device_id);
307 
308 		snprintf(sni->device_name, 256, "%s", dev->device_name);
309 		sni->device_name[dev->device_name_len] = '\0';
310 
311 		sni->amp_offset_mdbm = ntohl(dev->amp_offset_mdbm) * -1;
312 		sni->amp_res_mdbm = ntohl(dev->amp_res_mdbm);
313 		sni->rssi_max = ntohs(dev->rssi_max);
314 
315 		sni->def_start_khz = ntohl(dev->def_start_khz);
316 		sni->def_res_hz = ntohl(dev->def_res_hz);
317 		sni->def_num_samples = ntohs(dev->def_num_samples);
318 
319 		sni->start_khz = ntohl(dev->start_khz);
320 		sni->res_hz = ntohl(dev->res_hz);
321 		sni->num_samples = ntohs(dev->num_samples);
322 	}
323 
324 	return 0;
325 }
326 
spectool_netcli_block_sweep(spectool_server * sr,spectool_fr_header * header,char * errstr)327 int spectool_netcli_block_sweep(spectool_server *sr, spectool_fr_header *header,
328 								char *errstr) {
329 	spectool_fr_sweep *sweep;
330 	int x, y;
331 	int bsize = ntohs(header->frame_len) - spectool_fr_header_size();
332 	int pos = 0;
333 	spectool_net_dev *sni;
334 	spectool_sample_sweep *auxsweep;
335 
336 	for (x = 0; x < header->num_blocks; x++) {
337 		sweep = (spectool_fr_sweep *) &(header->data[pos]);
338 
339 		if (bsize - pos < 2) {
340 			/* way too short, bail with error */
341 			snprintf(errstr, SPECTOOL_ERROR_MAX, "Got runt sweep frame, bailing");
342 			return -1;
343 		}
344 
345 		if (ntohs(sweep->frame_len) < spectool_fr_sweep_size(0)) {
346 			/* Again, too short */
347 			snprintf(errstr, SPECTOOL_ERROR_MAX, "Got runt sweep frame, bailing");
348 			return -1;
349 		}
350 
351 		sni = sr->devlist;
352 		while (sni != NULL) {
353 			if (ntohl(sweep->device_id) == sni->device_id)
354 				break;
355 
356 			sni = sni->next;
357 		}
358 
359 		if (sni == NULL) {
360 			snprintf(errstr, SPECTOOL_ERROR_MAX, "Got sweep frame for device which "
361 					 "was not advertised, discarding");
362 			return -1;
363 		}
364 
365 		if (ntohs(sweep->frame_len) <
366 			spectool_fr_sweep_size(sni->num_samples)) {
367 			snprintf(errstr, SPECTOOL_ERROR_MAX, "Got sweep frame too small to hold "
368 					 "indicated number of samples, bailing - %u samples %u < %u",
369 					 sni->num_samples,
370 					 ntohs(sweep->frame_len),
371 					 spectool_fr_sweep_size(sni->num_samples));
372 			return -1;
373 		}
374 
375 
376 		pos += htons(sweep->frame_len);
377 
378 		/* For now we don't bother tracking data for devices which don't have a
379 		 * phydev linked to them -- we shouldn't get it, anyhow */
380 		if (sni->phydev == NULL)
381 			continue;
382 
383 		if ((auxsweep = ((spectool_net_dev_aux *) (sni->phydev->auxptr))->sweep) != NULL) {
384 			free(auxsweep);
385 		}
386 
387 		auxsweep =
388 			(spectool_sample_sweep *) malloc(SPECTOOL_SWEEP_SIZE(sni->num_samples));
389 
390 		/* Copy data out of our device record (this will change later when the
391 		 * spectool internals change) */
392 		auxsweep->start_khz = sni->start_khz;
393 		auxsweep->res_hz = sni->res_hz;
394 		auxsweep->num_samples = sni->num_samples;
395 		auxsweep->end_khz =
396 			((auxsweep->res_hz / 1000) * auxsweep->num_samples) +
397 			auxsweep->start_khz;
398 
399 		auxsweep->amp_offset_mdbm = sni->amp_offset_mdbm;
400 		auxsweep->amp_res_mdbm = sni->amp_res_mdbm;
401 		auxsweep->rssi_max = sni->rssi_max;
402 
403 		/* Lock start and end to the same */
404 		auxsweep->tm_start.tv_sec =
405 			auxsweep->tm_end.tv_sec =
406 			ntohl(sweep->start_sec);
407 		auxsweep->tm_start.tv_usec =
408 			auxsweep->tm_end.tv_usec =
409 			ntohl(sweep->start_usec);
410 
411 		/* Copy the RSSI data */
412 		for (y = 0; y < sni->num_samples; y++) {
413 			auxsweep->sample_data[y] = sweep->sample_data[y];
414 
415 			if (sni->phydev->min_rssi_seen > sweep->sample_data[y])
416 				sni->phydev->min_rssi_seen = sweep->sample_data[y];
417 		}
418 
419 		auxsweep->min_rssi_seen = sni->phydev->min_rssi_seen;
420 
421 		auxsweep->phydev = sni->phydev;
422 
423 		/* Flag that we got a new frame */
424 		((spectool_net_dev_aux *) (sni->phydev->auxptr))->new_sweep = 1;
425 		((spectool_net_dev_aux *) (sni->phydev->auxptr))->sweep = auxsweep;
426 		write(((spectool_net_dev_aux *) (sni->phydev->auxptr))->spipe[1], "0", 1);
427 	}
428 
429 	return 1;
430 }
431 
spectool_netcli_append(spectool_server * sr,uint8_t * data,int len,char * errstr)432 int spectool_netcli_append(spectool_server *sr, uint8_t *data, int len, char *errstr) {
433 	if (sr->bufferwrite == 0) {
434 		if (write(sr->sock, data, len) < 0) {
435 			snprintf(errstr, SPECTOOL_ERROR_MAX, "write() failed on %s",
436 					 strerror(errno));
437 			return -1;
438 		}
439 
440 		return 1;
441 	}
442 
443 	if (sr->write_fill + len >= CLI_BUF_SZ) {
444 		snprintf(errstr, SPECTOOL_ERROR_MAX, "Network client write buffer can't "
445 				 "fit %d bytes, %d of %d full", len, sr->write_fill, CLI_BUF_SZ);
446 		return -1;
447 	}
448 
449 	memcpy(&(sr->wbuf[sr->write_fill]), data, len);
450 	sr->write_fill += len;
451 
452 	return 1;
453 }
454 
spectool_netcli_enabledev(spectool_server * sr,unsigned int dev_id,char * errstr)455 spectool_phy *spectool_netcli_enabledev(spectool_server *sr, unsigned int dev_id,
456 									 char *errstr) {
457 	spectool_phy *phyret;
458 	spectool_net_dev_aux *aux;
459 	spectool_net_dev *sni;
460 	spectool_fr_header *header;
461 	spectool_fr_command *cmd;
462 	spectool_fr_command_enabledev *cmde;
463 	int sz;
464 
465 	sni = sr->devlist;
466 	while (sni != NULL) {
467 		if (dev_id == sni->device_id)
468 			break;
469 
470 		sni = sni->next;
471 	}
472 
473 	if (sni == NULL) {
474 		snprintf(errstr, SPECTOOL_ERROR_MAX, "Could not find device %u in list "
475 				 "from server.", dev_id);
476 		return NULL;
477 	}
478 
479 	if (sni->phydev != NULL)
480 		return sni->phydev;
481 
482 	sz = spectool_fr_header_size() +
483 		spectool_fr_command_size(spectool_fr_command_enabledev_size(0));
484 
485 	header = (spectool_fr_header *) malloc(sz);
486 
487 	cmd = (spectool_fr_command *) header->data;
488 	cmde = (spectool_fr_command_enabledev *) cmd->command_data;
489 
490 	header->sentinel = htonl(SPECTOOL_NET_SENTINEL);
491 	header->frame_len = htons(sz);
492 	header->proto_version = SPECTOOL_NET_PROTO_VERSION;
493 	header->block_type = SPECTOOL_NET_FRAME_COMMAND;
494 	header->num_blocks = 1;
495 
496 	cmd->frame_len =
497 		htons(spectool_fr_command_size(spectool_fr_command_enabledev_size(0)));
498 	cmd->command_id = SPECTOOL_NET_COMMAND_ENABLEDEV;
499 	cmd->command_len = htons(spectool_fr_command_enabledev_size(0));
500 
501 	cmde->device_id = htonl(dev_id);
502 
503 	if (spectool_netcli_append(sr, (uint8_t *) header, sz, errstr) < 0) {
504 		free(header);
505 		return NULL;
506 	}
507 
508 	free(header);
509 
510 	phyret = (spectool_phy *) malloc(SPECTOOL_PHY_SIZE);
511 	aux = (spectool_net_dev_aux *) malloc(sizeof(spectool_net_dev_aux));
512 	phyret->auxptr = aux;
513 
514 	aux->sweep = NULL;
515 	aux->new_sweep = 0;
516 
517 	pipe(aux->spipe);
518 	fcntl(aux->spipe[0], F_SETFL, fcntl(aux->spipe[0], F_GETFL, 0) | O_NONBLOCK);
519 
520 	phyret->device_spec = (spectool_dev_spec *) malloc(sizeof(spectool_dev_spec));
521 
522 	phyret->state = SPECTOOL_STATE_CONFIGURING;
523 	phyret->min_rssi_seen = -1;
524 
525 	phyret->device_spec->device_id = sni->device_id;
526 	phyret->device_spec->device_version = sni->device_version;
527 	phyret->device_spec->device_flags = sni->device_flags;
528 
529 	phyret->device_spec->num_sweep_ranges = 1;
530 
531 	phyret->device_spec->supported_ranges =
532 		(spectool_sample_sweep *) malloc(SPECTOOL_SWEEP_SIZE(0));
533 
534 	phyret->device_spec->supported_ranges[0].num_samples = sni->def_num_samples;
535 	phyret->device_spec->supported_ranges[0].amp_offset_mdbm = sni->amp_offset_mdbm;
536 	phyret->device_spec->supported_ranges[0].amp_res_mdbm = sni->amp_res_mdbm;
537 	phyret->device_spec->supported_ranges[0].rssi_max = sni->rssi_max;
538 
539 	phyret->device_spec->supported_ranges[0].start_khz = sni->start_khz;
540 	phyret->device_spec->supported_ranges[0].end_khz =
541 			((sni->res_hz / 1000) * sni->num_samples) +
542 			sni->start_khz;
543 	phyret->device_spec->supported_ranges[0].res_hz = sni->res_hz;
544 
545 	phyret->device_spec->default_range = phyret->device_spec->supported_ranges;
546 
547 	phyret->device_spec->cur_profile = 0;
548 
549 	phyret->open_func = &spectool_net_open;
550 	phyret->close_func = &spectool_net_close;
551 	phyret->poll_func = &spectool_net_poll;
552 	phyret->pollfd_func = &spectool_net_getpollfd;
553 	phyret->setcalib_func = &spectool_net_setcalibration;
554 	phyret->getsweep_func = &spectool_net_getsweep;
555 	phyret->setposition_func = &spectool_net_setposition;
556 
557 	snprintf(phyret->device_spec->device_name, SPECTOOL_PHY_NAME_MAX,
558 			 "%s", sni->device_name);
559 
560 	sni->phydev = phyret;
561 
562 	return phyret;
563 }
564 
spectool_netcli_disabledev(spectool_server * sr,spectool_phy * dev)565 int spectool_netcli_disabledev(spectool_server *sr, spectool_phy *dev) {
566 	spectool_net_dev_aux *aux;
567 	spectool_net_dev *sni;
568 	spectool_fr_header *header;
569 	spectool_fr_command *cmd;
570 	spectool_fr_command_disabledev *cmdd;
571 	char errstr[SPECTOOL_ERROR_MAX];
572 	int sz;
573 
574 	sni = sr->devlist;
575 	while (sni != NULL) {
576 		if (dev == sni->phydev)
577 			break;
578 
579 		sni = sni->next;
580 	}
581 
582 	if (sni == NULL) {
583 		return -1;
584 	}
585 
586 	if (sni->phydev == NULL)
587 		return -1;
588 
589 	sz = spectool_fr_header_size() +
590 		spectool_fr_command_size(spectool_fr_command_disabledev_size(0));
591 
592 	header = (spectool_fr_header *) malloc(sz);
593 
594 	cmd = (spectool_fr_command *) header->data;
595 	cmdd = (spectool_fr_command_disabledev *) cmd->command_data;
596 
597 	header->sentinel = htonl(SPECTOOL_NET_SENTINEL);
598 	header->frame_len = htons(sz);
599 	header->proto_version = SPECTOOL_NET_PROTO_VERSION;
600 	header->block_type = SPECTOOL_NET_FRAME_COMMAND;
601 	header->num_blocks = 1;
602 
603 	cmd->frame_len =
604 		htons(spectool_fr_command_size(spectool_fr_command_disabledev_size(0)));
605 	cmd->command_id = SPECTOOL_NET_COMMAND_DISABLEDEV;
606 	cmd->command_len = htons(spectool_fr_command_disabledev_size(0));
607 
608 	cmdd->device_id = htonl(sni->device_id);
609 
610 	free(dev->auxptr);
611 	free(dev);
612 	sni->phydev = NULL;
613 
614 	if (spectool_netcli_append(sr, (uint8_t *) header, sz, errstr) < 0) {
615 		free(header);
616 		return -1;
617 	}
618 
619 	free(header);
620 
621 	return 1;
622 }
623 
spectool_net_setcalibration(spectool_phy * phydev,int in_calib)624 void spectool_net_setcalibration(spectool_phy *phydev, int in_calib) {
625 	return;
626 }
627 
spectool_net_poll(spectool_phy * phydev)628 int spectool_net_poll(spectool_phy *phydev) {
629 	int ret = SPECTOOL_POLL_NONE;
630 	char junk[8];
631 
632 	read(((spectool_net_dev_aux *) phydev->auxptr)->spipe[0], junk, 8);
633 
634 	if (phydev->state == SPECTOOL_STATE_CONFIGURING) {
635 		ret |= SPECTOOL_POLL_CONFIGURED;
636 		ret |= SPECTOOL_POLL_ADDITIONAL;
637 		phydev->state = SPECTOOL_STATE_RUNNING;
638 		return ret;
639 	}
640 
641 	if (((spectool_net_dev_aux *) phydev->auxptr)->new_sweep) {
642 		((spectool_net_dev_aux *) phydev->auxptr)->new_sweep = 0;
643 		ret |= SPECTOOL_POLL_SWEEPCOMPLETE;
644 	}
645 
646 	return ret;
647 }
648 
spectool_net_getpollfd(spectool_phy * phydev)649 int spectool_net_getpollfd(spectool_phy *phydev) {
650 	 return ((spectool_net_dev_aux *) phydev->auxptr)->spipe[0];
651 }
652 
spectool_net_open(spectool_phy * phydev)653 int spectool_net_open(spectool_phy *phydev) {
654 	return 1;
655 }
656 
spectool_net_close(spectool_phy * phydev)657 int spectool_net_close(spectool_phy *phydev) {
658 	/* TODO - fill this in w/a close */
659 	close(((spectool_net_dev_aux *) phydev->auxptr)->spipe[0]);
660 	close(((spectool_net_dev_aux *) phydev->auxptr)->spipe[1]);
661 	return 1;
662 }
663 
spectool_net_getsweep(spectool_phy * phydev)664 spectool_sample_sweep *spectool_net_getsweep(spectool_phy *phydev) {
665 	return ((spectool_net_dev_aux *) phydev->auxptr)->sweep;
666 }
667 
spectool_net_setposition(spectool_phy * phydev,int in_profile,int start_khz,int res_hz)668 int spectool_net_setposition(spectool_phy *phydev, int in_profile,
669 							 int start_khz, int res_hz) {
670 	/* todo - fill this in */
671 	return 1;
672 }
673 
spectool_netcli_initbroadcast(short int port,char * errstr)674 int spectool_netcli_initbroadcast(short int port, char *errstr) {
675 	struct sockaddr_in lsin;
676 	int sock;
677 	int x;
678 
679 	memset(&lsin, 0, sizeof(struct sockaddr_in));
680 	lsin.sin_family = AF_INET;
681 	lsin.sin_port = htons(port);
682 	lsin.sin_addr.s_addr = INADDR_ANY;
683 
684 	if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
685 		snprintf(errstr, SPECTOOL_ERROR_MAX,
686 				 "netcli broadcast listen socket failed: %s", strerror(errno));
687 		return -1;
688 	}
689 
690 	/* we don't seem to need this in listen mode?
691 	x = 1;
692 	if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &x, sizeof(x)) < 0) {
693 		snprintf(errstr, SPECTOOL_ERROR_MAX,
694 				 "netcli broadcast listen socket bcast sockopt failed: %s",
695 				 strerror(errno));
696 		close(sock);
697 		return -1;
698 	}
699 	*/
700 
701 	fcntl(sock, F_SETFL, fcntl(sock, F_GETFL, 0) | O_NONBLOCK);
702 
703 	if (bind(sock, (struct sockaddr *) &lsin, sizeof(lsin)) < 0) {
704 		snprintf(errstr, SPECTOOL_ERROR_MAX,
705 				 "netcli broadcast listen socket bind failed: %s",
706 				 strerror(errno));
707 		close(sock);
708 		return -1;
709 	}
710 
711 	return sock;
712 }
713 
spectool_netcli_pollbroadcast(int sock,char * ret_url,char * errstr)714 int spectool_netcli_pollbroadcast(int sock, char *ret_url, char *errstr) {
715 	struct msghdr rcv_msg;
716 	struct iovec iov;
717 	spectool_fr_broadcast buf;
718 	struct sockaddr_in recv_addr;
719 
720 	iov.iov_base = &buf;
721 	iov.iov_len = sizeof(spectool_fr_broadcast);
722 
723 	rcv_msg.msg_name = &recv_addr;
724 	rcv_msg.msg_namelen = sizeof(recv_addr);
725 	rcv_msg.msg_iov = &iov;
726 	rcv_msg.msg_iovlen = 1;
727 	rcv_msg.msg_control = NULL;
728 	rcv_msg.msg_controllen = 0;
729 
730 	if (recvmsg(sock, &rcv_msg, 0) < 0) {
731 		snprintf(errstr, SPECTOOL_ERROR_MAX,
732 				 "netcli broadcast recv failed: %s", strerror(errno));
733 		return -1;
734 	}
735 
736 	if (ntohl(buf.sentinel) == SPECTOOL_NET_SENTINEL) {
737 		snprintf(ret_url, SPECTOOL_NETCLI_URL_MAX, "tcp://%s:%hu",
738 				 inet_ntoa(recv_addr.sin_addr), ntohs(buf.server_port));
739 		return 1;
740 	}
741 
742 	return 0;
743 }
744 
745