Esempio n. 1
0
/* Open a DS9490  -- low level code (to allow for repeats)  */
static GOOD_OR_BAD DS9490_redetect_low(struct connection_in * in)
{
	// discover devices
	libusb_device **device_list;
	int n_devices = libusb_get_device_list( Globals.luc, &device_list) ;
	int i_device ;
	
	if ( n_devices < 1 ) {
		LEVEL_CONNECT("Could not find a list of USB devices");
		if ( n_devices<0 ) {
			LEVEL_DEBUG("<%s>",libusb_error_name(n_devices));
		}
		return gbBAD;
	}

	for ( i_device = 0 ; i_device < n_devices ; ++i_device ) {
		libusb_device * current = device_list[i_device] ;
		if ( GOOD( USB_match( current ) ) ) {
			// try to open the DS9490
			if ( BAD(DS9490_open_and_name( current, in )) ) {
				LEVEL_CONNECT("Cannot open USB bus master, Find next...");
				continue;
			}
			if ( GOOD( DS9490_redetect_match( in ) ) ) {
				break ;
			}
			DS9490_close(in);
		}
	}
	
	libusb_free_device_list(device_list, 1);
	return (in->master.usb.lusb_handle!=NULL) ? gbGOOD : gbBAD ;
}
Esempio n. 2
0
/* All general stored data will be assigned to this "head" channel */
static GOOD_OR_BAD HeadChannel(struct connection_in *head)
{
    /* Intentionally put the wrong index */
    head->master.i2c.index = 1;

    if ( BAD(DS2482_channel_select(head)) ) {	/* Couldn't switch */
        head->master.i2c.index = 0;	/* restore correct value */
        LEVEL_CONNECT("DS2482-100 (Single channel)");
        if ( GOOD(DS2483_test(head->pown->file_descriptor)) ) {
            head->master.i2c.type = ds2483 ;
        } else {
            head->master.i2c.type = ds2482_100 ;
        }

        return gbGOOD;				/* happy as DS2482-100 */
    }

    // It's a DS2482-800 (8 channels) to set up other 7 with this one as "head"
    LEVEL_CONNECT("DS2482-800 (Eight channels)");
    /* Must be a DS2482-800 */
    head->master.i2c.channels = 8;
    head->master.i2c.type = ds2482_800 ;
    head->Adapter = adapter_DS2482_800;

    return CreateChannels(head);
}
Esempio n. 3
0
/* Open a DS9490  -- low level code (to allow for repeats)  */
static GOOD_OR_BAD DS9490_detect_all_adapters(struct port_in * pin_first)
{
	// discover devices
	struct port_in * pin = pin_first ;
	libusb_device **device_list;
	int n_devices = libusb_get_device_list( Globals.luc, &device_list) ;
	int i_device ;
	
	if ( n_devices < 1 ) {
		LEVEL_CONNECT("Could not find a list of USB devices");
		if ( n_devices<0 ) {
			LEVEL_DEBUG("<%s>",libusb_error_name(n_devices));
		}
		return gbBAD ;
	}

	for ( i_device = 0 ; i_device < n_devices ; ++i_device ) {
		libusb_device * current = device_list[i_device] ;
		if ( GOOD( USB_match( current ) ) ) {
			struct connection_in * in = pin->first ;
			if ( BAD(DS9490_open_and_name( current, in)) ) {
				LEVEL_DEBUG("Cannot open USB device %.d:%.d", libusb_get_device_address(current), libusb_get_bus_number(current) );
				continue ;
			} else if ( BAD(DS9490_ID_this_master(in)) ) {
				DS9490_close(in) ;
				LEVEL_DEBUG("Cannot access USB device %.d:%.d", libusb_get_device_address(current), libusb_get_bus_number(current) );
				continue;
			} else{
				pin = NewPort(NULL) ; // no reason to copy anything
				if ( pin == NULL ) {
					return gbGOOD ;
				}
				// set up the new connection for the next adapter
				DS9490_setroutines(in);
			}
		}
	}
	
	libusb_free_device_list(device_list, 1);

	if ( pin == pin_first ) {
		LEVEL_CONNECT("No USB DS9490 bus masters used");
		return gbBAD;
	}
	// Remove the extra connection
	RemovePort(pin);
	return gbGOOD ;
}
Esempio n. 4
0
/* Open a DS9490  -- low level code (to allow for repeats)  */
static GOOD_OR_BAD DS9490_detect_specific_adapter(int bus_nr, int dev_nr, struct connection_in * in)
{
	// discover devices
	libusb_device **device_list;
	int n_devices = libusb_get_device_list( Globals.luc, &device_list) ;
	int i_device ;
	
	if ( n_devices < 1 ) {
		LEVEL_CONNECT("Could not find a list of USB devices");
		if ( n_devices<0 ) {
			LEVEL_DEBUG("<%s>",libusb_error_name(n_devices));
		}
		return gbBAD ;
	}

	// Mark this connection as taking only this address pair. Important for reconnections.
	in->master.usb.specific_usb_address = 1 ;

	for ( i_device = 0 ; i_device < n_devices ; ++i_device ) {
		libusb_device * current = device_list[i_device] ;
		if ( GOOD( USB_match( current ) ) ) {
			if ( libusb_get_bus_number(current) != bus_nr ) {
				continue ;
			}
			
			if ( libusb_get_device_address(current) != dev_nr ) {
				continue ;
			}
			
			if ( BAD(DS9490_open_and_name( current, in)) ) {
				LEVEL_DEBUG("Cannot open USB device %.d:%.d", libusb_get_device_address(current), libusb_get_bus_number(current) );
				break ;
			} else if ( BAD(DS9490_ID_this_master(in)) ) {
				DS9490_close(in) ;
				LEVEL_DEBUG("Cannot access USB device %.d:%.d", libusb_get_device_address(current), libusb_get_bus_number(current) );
				break ;
			} else{
				libusb_free_device_list(device_list, 1);
				return gbGOOD ;
			}
		}
	}
	
	libusb_free_device_list(device_list, 1);

	LEVEL_CONNECT("No USB DS9490 bus master found matching %d:%d", bus_nr,dev_nr);
	return gbBAD;
}
Esempio n. 5
0
// Called in a thread
static void * OW_Browse_Bonjour(void * v)
{
	struct connection_in * in = v ;
	DNSServiceErrorType dnserr;

	DETACH_THREAD;
	MONITOR_RLOCK ;
	dnserr = DNSServiceBrowse(&in->master.browse.bonjour_browse, 0, 0, "_owserver._tcp", NULL, BrowseBack, NULL);

	if (dnserr != kDNSServiceErr_NoError) {
		LEVEL_CONNECT("DNSServiceBrowse error = %d", dnserr);
		MONITOR_RUNLOCK ;
		return VOID_RETURN ;
	}

	// Blocks, which is why this is in it's own thread
	while (DNSServiceProcessResult(in->master.browse.bonjour_browse) == kDNSServiceErr_NoError) {
		//printf("DNSServiceProcessResult ref %ld\n",(long int)rs->sref) ;
		continue;
	}
	DNSServiceRefDeallocate(in->master.browse.bonjour_browse);
	in->master.browse.bonjour_browse = 0 ;
	MONITOR_RUNLOCK ;
	return VOID_RETURN;
}
Esempio n. 6
0
/* Register the out port with Bonjour -- might block so done in a separate thread */
static void *Announce(void *v)
{
	struct connection_out *out = v;
	DNSServiceRef sref = 0;
	DNSServiceErrorType err;

	struct sockaddr sa;
	//socklen_t sl = sizeof(sa);
	socklen_t sl = 128;
	uint16_t port ;
	char * service_name ;
	char name[63] ;

	DETACH_THREAD;

	if (getsockname(out->file_descriptor, &sa, &sl)) {
		LEVEL_CONNECT("Could not get port number of device.");
		pthread_exit(NULL);
		return VOID_RETURN;
	}

	port = ntohs(((struct sockaddr_in *) (&sa))->sin_port) ;

	/* Add the service */
	switch (Globals.program_type) {
		case program_type_httpd:
			service_name = (Globals.announce_name) ? Globals.announce_name : "OWFS (1-wire) Web" ;
			UCLIBCLOCK;
			snprintf(name,62,"%s <%d>",service_name,(int)port);
			UCLIBCUNLOCK;
			err = DNSServiceRegister(&sref, 0, 0, name,"_http._tcp", NULL, NULL, port, 0, NULL, RegisterBack, out) ;
			Announce_Post_Register(sref, err) ;
			err = DNSServiceRegister(&sref, 0, 0, name,"_owhttpd._tcp", NULL, NULL, port, 0, NULL, RegisterBack, out) ;
			break ;
		case program_type_server:
		case program_type_external:
			service_name = (Globals.announce_name) ? Globals.announce_name : "OWFS (1-wire) Server" ;
			UCLIBCLOCK;
			snprintf(name,62,"%s <%d>",service_name,(int)port);
			UCLIBCUNLOCK;
			err = DNSServiceRegister(&sref, 0, 0, name,"_owserver._tcp", NULL, NULL, port, 0, NULL, RegisterBack, out) ;
			break;
		case program_type_ftpd:
			service_name = (Globals.announce_name) ? Globals.announce_name : "OWFS (1-wire) FTP" ;
			UCLIBCLOCK;
			snprintf(name,62,"%s <%d>",service_name,(int)port);
			UCLIBCUNLOCK;
			err = DNSServiceRegister(&sref, 0, 0, name,"_owftp._tcp", NULL, NULL, port, 0, NULL, RegisterBack, out) ;
			break;
		default:
			err = kDNSServiceErr_NoError ;
			break ;
	}

	Announce_Post_Register(sref, err) ;
	LEVEL_DEBUG("Normal completion");
	pthread_exit(NULL);

	return VOID_RETURN;
}
Esempio n. 7
0
// RESET called with bus locked
RESET_TYPE BUS_reset(const struct parsedname *pn)
{
	struct connection_in * in = pn->selected_connection ;
	STAT_ADD1_BUS(e_bus_resets, in);

	switch ( (in->iroutines.reset) (pn) ) {
	case BUS_RESET_OK:
		in->reconnect_state = reconnect_ok;	// Flag as good!
		if (in->ds2404_found && ((in->iroutines.flags&ADAP_FLAG_no2404delay)==0) ) {
			// extra delay for alarming DS1994/DS2404 complience
			UT_delay(5);
		}

		return BUS_RESET_OK ;
	case BUS_RESET_SHORT:
		/* Shorted 1-wire bus or minor error shouldn't cause a reconnect */
		in->AnyDevices = anydevices_unknown;
		LEVEL_CONNECT("1-wire bus short circuit.");
		STAT_ADD1_BUS(e_bus_short_errors, in);
		return BUS_RESET_SHORT;
	case BUS_RESET_ERROR:
		if ( in->ds2404_found ) {
			// extra reset for DS1994/DS2404 might be needed
			if ( (in->iroutines.reset) (pn) == BUS_RESET_OK ) {
				return BUS_RESET_OK ;
			}
		}
	default:
		in->reconnect_state++;	// Flag for eventual reconnection
		LEVEL_DEBUG("Reset error. Reconnection %d/%d",in->reconnect_state,reconnect_error); 
		STAT_ADD1_BUS(e_bus_reset_errors, in);
		return BUS_RESET_ERROR ;
	}
}
Esempio n. 8
0
/* Includes a count of the rejected existing USB devices
 * needed for compatibility with the -u2 -u3 arguments
 */
GOOD_OR_BAD USB_next_match_until_n(struct usb_list *ul, int num)
{
	int found = 0 ;
	
	while (ul->bus) {
		// First pass, look for next device
		if (ul->dev == NULL) {
			ul->dev = ul->bus->devices;
		} else {				// New bus, find first device
			ul->dev = ul->dev->next;
			ul->usb_dev_number = -1 ;
		}
		if (ul->dev) {			// device found
			if (ul->dev->descriptor.idVendor != DS2490_USB_VENDOR || ul->dev->descriptor.idProduct != DS2490_USB_PRODUCT) {
				continue;		// not DS9490
			}
			if ( sscanf( ul->dev->filename, "%u", &(ul->usb_dev_number) ) <= 0 ) {
				ul->usb_dev_number = -1 ;
			}
			++ found ;
			if ( found < num ) {
				continue ;
			}
			LEVEL_CONNECT("Bus master found: %.d:%.d", ul->usb_bus_number, ul->usb_dev_number);
			return usbdevice_in_use( ul );
		} else {
			ul->bus = ul->bus->next;
			if ( ul->bus == NULL || sscanf( ul->bus->dirname, "%u", &(ul->usb_bus_number) ) <= 0 ) {
				ul->usb_bus_number = -1 ;
			}
			ul->dev = NULL;
		}
	}
	return gbBAD;
}
Esempio n. 9
0
/* Re-open a DS2482 */
static GOOD_OR_BAD DS2482_redetect(const struct parsedname *pn)
{
    struct connection_in *head = pn->selected_connection->master.i2c.head;
    int address = head->master.i2c.i2c_address;
    FILE_DESCRIPTOR_OR_ERROR file_descriptor;
    struct address_pair ap ; // to get device name from device:address

    /* open the i2c port */
    Parse_Address( DEVICENAME(head), &ap ) ;
    file_descriptor = open(ap.first.alpha, O_RDWR );
    Free_Address( &ap ) ;
    if ( FILE_DESCRIPTOR_NOT_VALID(file_descriptor) ) {
        ERROR_CONNECT("Could not open i2c device %s", DEVICENAME(head));
        return gbBAD;
    }

    /* address is known */
    if (ioctl(file_descriptor, I2C_SLAVE, address) < 0) {
        ERROR_CONNECT("Cound not set i2c address to %.2X", address);
    } else {
        BYTE c;
        /* write the RESET code */
        if (i2c_smbus_write_byte(file_descriptor, DS2482_CMD_RESET)	// reset
                || BAD(DS2482_readstatus(&c, file_descriptor, DS2482_Chip_reset_usec))	// pause .5 usec then read status
                || (c != (DS2482_REG_STS_LL | DS2482_REG_STS_RST))	// make sure status is properly set
           ) {
            LEVEL_CONNECT("i2c device at %s address %d cannot be reset. Not a DS2482.", DEVICENAME(head), address);
        } else {
            struct connection_in * next ;
            head->master.i2c.current = 0;
            head->pown->file_descriptor = file_descriptor;
            head->pown->state = cs_deflowered ;
            head->pown->type = ct_i2c ;
            head->master.i2c.configchip = 0x00;	// default configuration register after RESET
            LEVEL_CONNECT("i2c device at %s address %d reset successfully", DEVICENAME(head), address);
            for ( next = head->pown->first; next; next = next->next ) {
                /* loop through devices, matching those that have the same "head" */
                /* BUSLOCK also locks the sister channels for this */
                next->reconnect_state = reconnect_ok;
            }
            return gbGOOD;
        }
    }
    /* fellthough, no device found */
    close(file_descriptor);
    return gbBAD;
}
Esempio n. 10
0
void OW_Browse(struct connection_in *in)
{
	if ( Globals.zero == zero_avahi ) {
		
#if OW_AVAHI
		if ( BAD(OW_Avahi_Browse(in))) {
			LEVEL_CONNECT("Avahi Browse problem.");
		}
#endif /* OW_AVAHI */
	} else if ( Globals.zero == zero_bonjour ) {
		pthread_t thread;
		int err = pthread_create(&thread, DEFAULT_THREAD_ATTR, OW_Browse_Bonjour, (void *) in);
		if (err) {
			LEVEL_CONNECT("Bonjour Browse thread error %d.", err);
		}
	}
}
Esempio n. 11
0
static void Announce_Post_Register(DNSServiceRef sref, DNSServiceErrorType err)
{
	if (err == kDNSServiceErr_NoError) {
		DNSServiceProcessResult(sref);
	} else {
		LEVEL_CONNECT("Unsuccessful call to DNSServiceRegister err = %d", err);
	}
}
Esempio n. 12
0
/* Open a DS9490  -- low level code (to allow for repeats)  */
static GOOD_OR_BAD DS9490_detect_single_adapter(int usb_nr, struct connection_in * in)
{
	// discover devices
	libusb_device **device_list;
	int n_devices = libusb_get_device_list( Globals.luc, &device_list) ;
	int i_device ;
	
	if ( n_devices < 1 ) {
		LEVEL_CONNECT("Could not find a list of USB devices");
		if ( n_devices<0 ) {
			LEVEL_DEBUG("<%s>",libusb_error_name(n_devices));
		}
		return gbBAD ;
	}

	for ( i_device = 0 ; i_device < n_devices ; ++i_device ) {
		libusb_device * current = device_list[i_device] ;
		if ( GOOD( USB_match( current ) ) ) {
			--usb_nr ;
			if ( usb_nr > 0 ) {
				continue ;
			}
			
			if ( BAD(DS9490_open_and_name( current, in)) ) {
				LEVEL_DEBUG("Cannot open USB device %.d:%.d", libusb_get_device_address(current), libusb_get_bus_number(current) );
				break ;
			} else if ( BAD(DS9490_ID_this_master(in)) ) {
				DS9490_close(in) ;
				LEVEL_DEBUG("Cannot access USB device %.d:%.d", libusb_get_device_address(current), libusb_get_bus_number(current) );
				break ;
			} else{
				libusb_free_device_list(device_list, 1);
				return gbGOOD ;
			}
		}
	}
	
	libusb_free_device_list(device_list, 1);

	LEVEL_CONNECT("No USB DS9490 bus master found");
	return gbBAD;
}
Esempio n. 13
0
static int Test_HA7_response( struct HA7_response * ha7_response )
{
	LEVEL_DEBUG("From ha7_response: signature=%.2s, command=%X, port=%d, ssl=%d, MAC=%.12s, device=%s",
	ha7_response->signature,
	ntohs(ha7_response->command),
	ntohs(ha7_response->port),
	ntohs(ha7_response->sslport),
	ha7_response->serial_num,
	ha7_response->dev_name) ;

	if (memcmp("HA", ha7_response->signature, 2)) {
		LEVEL_CONNECT("HA7 response signature error");
		return 1;
	}
	if ( 0x8001 != ntohs(ha7_response->command) ) {
		LEVEL_CONNECT("HA7 response command error");
		return 1;
	}
	return 0 ;
}
Esempio n. 14
0
GOOD_OR_BAD FS_FindHA7(void)
{
	struct addrinfo *ai;
	struct addrinfo hint;
	struct addrinfo *now;
	int number_found = 0;
	int getaddr_error ;

	LEVEL_DEBUG("Attempting udp multicast search for the HA7Net bus master at %s:%s",HA7_DISCOVERY_ADDRESS,HA7_DISCOVERY_PORT);
	Setup_HA7_hint( &hint ) ;
	if ((getaddr_error = getaddrinfo(HA7_DISCOVERY_ADDRESS, HA7_DISCOVERY_PORT, &hint, &ai))) {
		LEVEL_CONNECT("Couldn't set up HA7 broadcast message %s", gai_strerror(getaddr_error));
		return gbBAD;
	}

	for (now = ai; now; now = now->ai_next) {
		ASCII name[INET_ADDRSTRLEN+20]; // tcp quad + port
		struct port_in * pin ;
		struct connection_in *in;

		if ( Get_HA7_response( now, name ) ) {
			continue ;
		}

		pin = NewPort(NO_CONNECTION) ;
		if (pin == NULL) {
			continue;
		}
		in = pin->first ;

		pin->type = ct_tcp ;
		pin->init_data = owstrdup(name);
		DEVICENAME(in) = owstrdup(name);
		pin->busmode = bus_ha7net;

		LEVEL_CONNECT("HA7Net bus master discovered at %s",DEVICENAME(in));
		++number_found ;
	}
	freeaddrinfo(ai);
	return number_found > 0 ? gbGOOD : gbBAD ;
}
Esempio n. 15
0
static GOOD_OR_BAD DS2482_channel_select(struct connection_in * in)
{
    struct connection_in *head = in->master.i2c.head;
    int chan = in->master.i2c.index;
    FILE_DESCRIPTOR_OR_ERROR file_descriptor = in->pown->file_descriptor;

    /*
    	Write and verify codes for the CHANNEL_SELECT command (DS2482-800 only).
    	To set the channel, write the value at the index of the channel.
    	Read and compare against the corresponding value to verify the change.
    */
    static const BYTE W_chan[8] = { 0xF0, 0xE1, 0xD2, 0xC3, 0xB4, 0xA5, 0x96, 0x87 };
    static const BYTE R_chan[8] = { 0xB8, 0xB1, 0xAA, 0xA3, 0x9C, 0x95, 0x8E, 0x87 };

    if ( FILE_DESCRIPTOR_NOT_VALID(file_descriptor) ) {
        LEVEL_CONNECT("Calling a closed i2c channel (%d) "I2Cformat" ", chan,I2Cvar(in));
        return gbBAD;
    }

    /* Already properly selected? */
    /* All `100 (1 channel) will be caught here */
    if (chan != head->master.i2c.current) {
        int read_back;

        /* Select command */
        if (i2c_smbus_write_byte_data(file_descriptor, DS2482_CMD_CHANNEL_SELECT, W_chan[chan]) < 0) {
            LEVEL_DEBUG("Channel select set error");
            return gbBAD;
        }

        /* Read back and confirm */
        read_back = i2c_smbus_read_byte(file_descriptor);
        if (read_back < 0) {
            LEVEL_DEBUG("Channel select get error");
            return gbBAD; // flag for DS2482-100 vs -800 detection
        }
        if (((BYTE) read_back) != R_chan[chan]) {
            LEVEL_DEBUG("Channel selected doesn't match");
            return gbBAD; // flag for DS2482-100 vs -800 detection
        }

        /* Set the channel in head */
        head->master.i2c.current = in->master.i2c.index;
    }

    /* Now check the configuration register */
    /* This is since configuration is per chip, not just channel */
    if (in->master.i2c.configreg != head->master.i2c.configchip) {
        return SetConfiguration(in->master.i2c.configreg, in);
    }

    return gbGOOD;
}
Esempio n. 16
0
/* Stolen from Unix Network Programming by Stevens, Fenner, Rudoff p89 */
ssize_t tcp_read(int file_descriptor, void *vptr, size_t n, const struct timeval * ptv)
{
	size_t nleft;
	ssize_t nread;
	char *ptr;
	//printf("NetRead attempt %d bytes Time:(%ld,%ld)\n",(int)n,ptv->tv_sec,ptv->tv_usec ) ;
	ptr = vptr;
	nleft = n;
	while (nleft > 0) {
		int rc;
		fd_set readset;
		struct timeval tv = { ptv->tv_sec, ptv->tv_usec, };

		/* Initialize readset */
		FD_ZERO(&readset);
		FD_SET(file_descriptor, &readset);

		/* Read if it doesn't timeout first */
		rc = select(file_descriptor + 1, &readset, NULL, NULL, &tv);
		if (rc > 0) {
			/* Is there something to read? */
			if (FD_ISSET(file_descriptor, &readset) == 0) {
				return -EIO;	/* error */
			}
			//update_max_delay(pn);
			if ((nread = read(file_descriptor, ptr, nleft)) < 0) {
				if (errno == EINTR) {
					errno = 0;	// clear errno. We never use it anyway.
					nread = 0;	/* and call read() again */
				} else {
					ERROR_DATA("Network data read error\n");
					return (-1);
				}
			} else if (nread == 0) {
				break;			/* EOF */
			}
			//Debug_Bytes( "NETREAD",ptr, nread ) ;
			nleft -= nread;
			ptr += nread;
		} else if (rc < 0) {	/* select error */
			if (errno == EINTR) {
				/* select() was interrupted, try again */
				continue;
			}
			ERROR_DATA("Selection error (network)\n");
			return -EINTR;
		} else {				/* timed out */
			LEVEL_CONNECT("TIMEOUT after %d bytes\n", n - nleft);
			return -EAGAIN;
		}
	}
	return (n - nleft);			/* return >= 0 */
}
Esempio n. 17
0
/* Open a DS9490  -- low level code (to allow for repeats)  */
static GOOD_OR_BAD DS9490_redetect_match( struct connection_in * in)
{
	struct dirblob db ;
	BYTE sn[SERIAL_NUMBER_SIZE] ;
	int device_number ;

	LEVEL_DEBUG("Attempting reconnect on %s",SAFESTRING(DEVICENAME(in)));

	// Special case -- originally untagged adapter
	if ( in->master.usb.ds1420_address[0] == '\0' ) {
		LEVEL_CONNECT("Since originally untagged bus master, we will use first available slot.");
		return gbGOOD ;
	}

	// Generate a root directory
	RETURN_BAD_IF_BAD( DS9490_root_dir( &db, in ) ) ;

	// This adapter has no tags, so not the one we want
	if ( DirblobElements( &db) == 0 ) {
		DirblobClear( &db ) ;
		LEVEL_DATA("Empty directory on [%s] (Doesn't match initial scan).", SAFESTRING(DEVICENAME(in)));
		return gbBAD ;
	}

	// Scan directory for a match to the original tag
	device_number = 0 ;
	while ( DirblobGet( device_number, sn, &db ) == 0 ) {
		if (memcmp(sn, in->master.usb.ds1420_address, SERIAL_NUMBER_SIZE) == 0) {	// same tag device?
			LEVEL_DATA("Matching device [%s].", SAFESTRING(DEVICENAME(in)));
			DirblobClear( &db ) ;
			return gbGOOD ;
		}
		++device_number ;
	}
	// Couldn't find correct ds1420 chip on this adapter
	LEVEL_CONNECT("Couldn't find correct ds1420 chip on this bus master [%s] (want: " SNformat ")", SAFESTRING(DEVICENAME(in)), SNvar(in->master.usb.ds1420_address));
	DirblobClear( &db ) ;
	return gbBAD;
}
Esempio n. 18
0
/* Note, config is stored as only the lower nibble */
static GOOD_OR_BAD SetConfiguration(BYTE c, struct connection_in *in)
{
    struct connection_in *head = in->master.i2c.head;
    FILE_DESCRIPTOR_OR_ERROR file_descriptor = in->pown->file_descriptor;
    int read_back;

    /* Write, readback, and compare configuration register */
    /* Logic error fix from Uli Raich */
    if (i2c_smbus_write_byte_data(file_descriptor, DS2482_CMD_WRITE_CONFIG, c | ((~c) << 4))
            || (read_back = i2c_smbus_read_byte(file_descriptor)) < 0 || ((BYTE) read_back != c)
       ) {
        head->master.i2c.configchip = 0xFF;	// bad value to trigger retry
        LEVEL_CONNECT("Trouble changing DS2482 configuration register "I2Cformat" ",I2Cvar(in));
        return gbBAD;
    }
    /* Clear the strong pull-up power bit(register is automatically cleared by reset) */
    in->master.i2c.configreg = head->master.i2c.configchip = c & ~DS2482_REG_CFG_SPU;
    return gbGOOD;
}
Esempio n. 19
0
void ZeroConf_Announce(struct connection_out *out)
{
	if ( Globals.announce_off) {
		return;
	} else if ( Globals.zero == zero_avahi ) {
		
#if OW_AVAHI
		GOOD_OR_BAD oaa = OW_Avahi_Announce( out ) ;
		LEVEL_DEBUG( "Avahi (zero-configuration service) broadcast was %s successful",BAD(oaa)?"NOT":"") ;
#endif /* OW_AVAHI */

	} else if ( Globals.zero == zero_bonjour ) {
		pthread_t thread;
		int err = pthread_create(&thread, DEFAULT_THREAD_ATTR, Announce, (void *) out);
		if (err) {
			LEVEL_CONNECT("Zeroconf/Bonjour registration thread error %d.", err);
		}
	}
}
Esempio n. 20
0
static int Get_HA7_response( struct addrinfo *now, char * name )
{
	struct timeval tv = { 50, 0 };
	FILE_DESCRIPTOR_OR_ERROR file_descriptor;
	struct HA7_response ha7_response ;

	struct sockaddr_in from ;
	socklen_t fromlen = sizeof(struct sockaddr_in) ;
	int on = 1;

	file_descriptor = socket(now->ai_family, now->ai_socktype, now->ai_protocol) ;
	if ( FILE_DESCRIPTOR_NOT_VALID(file_descriptor) ) {
		ERROR_DEBUG("Cannot get socket file descriptor for broadcast.");
		return 1;
	}
//	fcntl (file_descriptor, F_SETFD, FD_CLOEXEC); // for safe forking
	if (setsockopt(file_descriptor, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) == -1) {
		ERROR_DEBUG("Cannot set socket option for broadcast.");
		return 1;
	}
	if (sendto(file_descriptor, "HA\000\001", 4, 0, now->ai_addr, now->ai_addrlen)
		!= 4) {
		ERROR_CONNECT("Trouble sending broadcast message");
		return 1;
	}

	/* now read */
	if ( udp_read(file_descriptor, &ha7_response, sizeof(struct HA7_response), &tv, &from, &fromlen) != sizeof(struct HA7_response) ) {
		LEVEL_CONNECT("HA7 response bad length");
		return 1;
	}

	if ( Test_HA7_response( &ha7_response ) ) {
		return 1 ;
	}

	UCLIBCLOCK ;
	snprintf(name,INET_ADDRSTRLEN+20,"%s:%d",inet_ntoa(from.sin_addr),ntohs(ha7_response.port));
	UCLIBCUNLOCK ;

	return 0 ;
}
Esempio n. 21
0
int ClientAddr(char *sname, struct connection_in *in)
{
	struct addrinfo hint;
	char *p;
	int ret;

	if (sname == NULL || sname[0] == '\0') {
		sname = "4304";
	}
	if ((p = strrchr(sname, ':'))) {	/* : exists */
		p[0] = '\0';			/* Separate tokens in the string */
		in->tcp.host = strdup(sname);
		in->tcp.service = strdup(&p[1]);
		p[0] = ':';				/* restore name string */
	} else {
#if OW_CYGWIN
		in->tcp.host = strdup("127.0.0.1");
#else
		in->tcp.host = NULL;
#endif
		in->tcp.service = strdup(sname);
	}

	memset(&hint, 0, sizeof(struct addrinfo));
	hint.ai_socktype = SOCK_STREAM;
#if OW_CYGWIN
	hint.ai_family = AF_INET;
#else
	hint.ai_family = AF_UNSPEC;
#endif

//printf("ClientAddr: [%s] [%s]\n", in->connin.tcp.host, in->connin.tcp.service);

	if ((ret = getaddrinfo(in->tcp.host, in->tcp.service, &hint, &in->tcp.ai))) {
		LEVEL_CONNECT("GetAddrInfo error %s\n", gai_strerror(ret));
		return -1;
	}
	return 0;
}
Esempio n. 22
0
static void SetConninData( int indx, const char * type, struct port_in *pin )
{
	struct connection_in * in = pin->first ;
	char name[20] ;

	pin->file_descriptor = indx;
	pin->type = ct_none ;
	in->master.fake.index = indx;
	in->master.fake.templow = Globals.templow;
	in->master.fake.temphigh = Globals.temphigh;
	LEVEL_CONNECT("Setting up %s Bus Master (%d)", type, indx);

	UCLIBCLOCK ;
	snprintf(name, 18, "%s.%d", type, indx);
	UCLIBCUNLOCK ;

	GetAllDeviceNames( pin ) ;

	// Device name and init_data diverge now
	SAFEFREE(DEVICENAME(in)) ;
	DEVICENAME(in) = owstrdup(name);
}
Esempio n. 23
0
void ZeroConf_Announce(struct connection_out *out)
{
	(void) out;
	LEVEL_CONNECT("Zeroconf not enabled");
	return;
}
Esempio n. 24
0
/* return < 0 if failure */
ZERO_OR_ERROR tcp_read(FILE_DESCRIPTOR_OR_ERROR file_descriptor, BYTE * buffer, size_t requested_size, const struct timeval * ptv, size_t * chars_in)
{
	size_t to_be_read = requested_size ;

	if ( FILE_DESCRIPTOR_NOT_VALID( file_descriptor ) ) {
		return -EBADF ;
	}

	LEVEL_DEBUG("attempt %d bytes Time: "TVformat,(int)requested_size, TVvar(ptv) ) ;
	*chars_in = 0 ;
	while (to_be_read > 0) {
		int select_result;
		fd_set readset;
		struct timeval tv ;

		/* Initialize readset */
		FD_ZERO(&readset);
		FD_SET(file_descriptor, &readset);

		/* Read if it doesn't timeout first */
		timercpy( &tv, ptv ) ;
		select_result = select(file_descriptor + 1, &readset, NULL, NULL, &tv);
		if (select_result > 0) {
			ssize_t read_result;

			/* Is there something to read? */
			if (FD_ISSET(file_descriptor, &readset) == 0) {
				LEVEL_DEBUG("tcp_error -- nothing avialable to read");
				return -EBADF ;	/* error */
			}
			errno = 0 ;
			read_result = read(file_descriptor, &buffer[*chars_in], to_be_read) ;
			if ( read_result < 0 ) {
				if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) {
					read_result = 0;	/* and call read() again */
				} else {
					LEVEL_DATA("Network data read error errno=%d %s", errno, strerror(errno));
					STAT_ADD1(NET_read_errors);
					return -EBADF ;
				}
			} else if (read_result == 0) {
				break;			/* EOF */
			}
			TrafficInFD("NETREAD", &buffer[*chars_in], read_result, file_descriptor ) ;
			to_be_read -= read_result;
			*chars_in += read_result ;
		} else if (select_result < 0) {	/* select error */
			if (errno == EINTR) {
				/* select() was interrupted, try again */
				continue;
			}
			ERROR_DATA("Select error");
			return -EBADF;
		} else {				/* timed out */
			LEVEL_CONNECT("TIMEOUT after %d bytes", requested_size - to_be_read);
			return -EAGAIN;
		}
	}
	LEVEL_DEBUG("read: %d - %d = %d",(int)requested_size, (int) to_be_read, (int) (requested_size-to_be_read) ) ;
	return 0;
}
Esempio n. 25
0
/* Try to see if there is a DS2482 device on the specified i2c bus */
static GOOD_OR_BAD DS2482_detect_single(int lowindex, int highindex, char * i2c_device, struct port_in *pin)
{
    int test_address[8] = { 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, };	// the last 4 are -800 only
    int i2c_index;
    FILE_DESCRIPTOR_OR_ERROR file_descriptor;
    struct connection_in * in = pin->first ;

    /* Sanity check */
    if ( lowindex < 0 ) {
        LEVEL_DEBUG("Bad lower bound");
        return gbBAD ;
    }
    if ( highindex >= (int) (sizeof(test_address)/sizeof(int)) ) {
        LEVEL_DEBUG("Bad upper bound");
        return gbBAD ;
    }

    /* open the i2c port */
    file_descriptor = open(i2c_device, O_RDWR);
    if ( FILE_DESCRIPTOR_NOT_VALID(file_descriptor) ) {
        ERROR_CONNECT("Could not open i2c device %s", i2c_device);
        return gbBAD;
    }

    /* Set up low-level routines */
    DS2482_setroutines(in);

    for (i2c_index = lowindex; i2c_index <= highindex; ++i2c_index) {
        int trial_address = test_address[i2c_index] ;
        /* set the candidate address */
        if (ioctl(file_descriptor, I2C_SLAVE, trial_address) < 0) {
            ERROR_CONNECT("Cound not set trial i2c address to %.2X", trial_address);
        } else {
            BYTE c;
            LEVEL_CONNECT("Found an i2c device at %s address %.2X", i2c_device, trial_address);
            /* Provisional setup as a DS2482-100 ( 1 channel ) */
            in->pown->file_descriptor = file_descriptor;
            pin->state = cs_deflowered;
            pin->type = ct_i2c ;
            in->master.i2c.i2c_address = trial_address;
            in->master.i2c.i2c_index = i2c_index;
            in->master.i2c.index = 0;
            in->master.i2c.channels = 1;
            in->master.i2c.current = 0;
            in->master.i2c.head = in;
            in->adapter_name = "DS2482-100";
            in->master.i2c.configreg = 0x00 ;	// default configuration setting desired
            if ( Globals.i2c_APU ) {
                in->master.i2c.configreg |= DS2482_REG_CFG_APU ;
            }
            if ( Globals.i2c_PPM ) {
                in->master.i2c.configreg |= DS2482_REG_CFG_PPM ;
            }
            in->Adapter = adapter_DS2482_100;

            /* write the RESET code */
            if (i2c_smbus_write_byte(file_descriptor, DS2482_CMD_RESET)	// reset
                    || BAD(DS2482_readstatus(&c, file_descriptor, DS2482_Chip_reset_usec))	// pause .5 usec then read status
                    || (c != (DS2482_REG_STS_LL | DS2482_REG_STS_RST))	// make sure status is properly set
               ) {
                LEVEL_CONNECT("i2c device at %s address %.2X cannot be reset. Not a DS2482.", i2c_device, trial_address);
                continue;
            }
            LEVEL_CONNECT("i2c device at %s address %.2X appears to be DS2482-x00", i2c_device, trial_address);
            in->master.i2c.configchip = 0x00;	// default configuration register after RESET
            // Note, only the lower nibble of the device config stored

            // Create name
            SAFEFREE( DEVICENAME(in) ) ;
            DEVICENAME(in) = owmalloc( strlen(i2c_device) + 10 ) ;
            if ( DEVICENAME(in) ) {
                UCLIBCLOCK;
                snprintf(DEVICENAME(in), strlen(i2c_device) + 10, "%s:%.2X", i2c_device, trial_address);
                UCLIBCUNLOCK;
            }

            /* Now see if DS2482-100 or DS2482-800 */
            return HeadChannel(in);
        }
    }
    /* fell though, no device found */
    COM_close( in ) ;
    return gbBAD;
}
Esempio n. 26
0
/* ---------------------------------------------- */
int main(int argc, char *argv[])
{
	int c;
	struct Fuse_option fuse_options;

	/* Set up owlib */
	LibSetup(program_type_filesystem);

	/* grab our executable name */
	if (argc > 0) {
		Globals.progname = owstrdup(argv[0]);
	}
	//mtrace() ;
	/* process command line arguments */
	while ((c = getopt_long(argc, argv, OWLIB_OPT, owopts_long, NULL)) != -1) {
		switch (c) {
		case 'V':
			fprintf(stderr, "%s version:\n\t" VERSION "\n", argv[0]);
			break;
		case e_fuse_opt:		/* fuse_mnt_opt */
			if (fuse_mnt_opt) {
				owfree(fuse_mnt_opt);
			}
			fuse_mnt_opt = Fuse_arg(optarg, "FUSE mount options");
			if (fuse_mnt_opt == NULL) {
				ow_exit(0);
			}
			break;
		case e_fuse_open_opt:	/* fuse_open_opt */
			if (fuse_open_opt) {
				owfree(fuse_open_opt);
			}
			fuse_open_opt = Fuse_arg(optarg, "FUSE open options");
			if (fuse_open_opt == NULL) {
				ow_exit(0);
			}
			break;
		}
		if ( BAD( owopt(c, optarg) ) ) {
			ow_exit(0);			/* rest of message */
		}
	}

	/* non-option arguments */
	while (optind < argc - 1) {
		ARG_Generic(argv[optind]);
		++optind;
	}
	while (optind < argc) {
		if (Outbound_Control.active) {
			ARG_Generic(argv[optind]);
		} else {
			ARG_Server(argv[optind]);
		}
		++optind;
	}

	if (Outbound_Control.active == 0) {
		LEVEL_DEFAULT("No mount point specified.\nTry '%s -h' for help.", argv[0]);
		ow_exit(1);
	}
	// FUSE directory mounting
	LEVEL_CONNECT("fuse mount point: %s", Outbound_Control.head->name);

	// Signal handler is set in fuse library
	//set_signal_handlers(exit_handler);

	/* Set up adapters */
	if ( BAD(LibStart()) ) {
		ow_exit(1);
	}

#if FUSE_VERSION >= 14
	/* Set up "command line" for main fuse routines */
	Fuse_setup(&fuse_options);	// command line setup
	Fuse_add(Outbound_Control.head->name, &fuse_options);	// mount point
#if FUSE_VERSION >= 22
	Fuse_add("-o", &fuse_options);	// add "-o direct_io" to prevent buffering
	Fuse_add("direct_io", &fuse_options);
#endif							/* FUSE_VERSION >= 22 */
	if (!Globals.want_background) {
		Fuse_add("-f", &fuse_options);	// foreground for fuse too
		if (Globals.error_level > 2) {
			Fuse_add("-d", &fuse_options);	// debug for fuse too
		}
	}
	Fuse_parse(fuse_mnt_opt, &fuse_options);
	LEVEL_DEBUG("fuse_mnt_opt=[%s]", fuse_mnt_opt);
	Fuse_parse(fuse_open_opt, &fuse_options);
	LEVEL_DEBUG("fuse_open_opt=[%s]", fuse_open_opt);
	if (Globals.allow_other) {
		Fuse_add("-o", &fuse_options);	// add "-o allow_other" to permit other users access
		Fuse_add("allow_other", &fuse_options);
	}
#if OW_MT == 0
	Fuse_add("-s", &fuse_options);	// single threaded
#endif							/* OW_MT */
	Globals.now_background = Globals.want_background;	// tell "error" that we are background
#if 0
	{
		int i;
		for (i = 0; i < fuse_options.argc; i++) {
			LEVEL_DEBUG("fuse_options.argv[%d]=[%s]", i, fuse_options.argv[i]);
		}
	}
#endif
#if FUSE_VERSION > 25
	fuse_main(fuse_options.argc, fuse_options.argv, &owfs_oper, NULL);
#else							/* FUSE_VERSION <= 25 */
	fuse_main(fuse_options.argc, fuse_options.argv, &owfs_oper);
#endif							/* FUSE_VERSION <= 25 */
	Fuse_cleanup(&fuse_options);
#endif

	ow_exit(0);
	return 0;
}
Esempio n. 27
0
void OW_Browse(struct connection_in *in)
{
	(void) in ;
	LEVEL_CONNECT("Avahi and Bonjour not enabled");
}
Esempio n. 28
0
GOOD_OR_BAD ClientAddr(char *sname, char * default_port, struct connection_in *in)
{
	struct port_in * pin = in->pown ;
	struct addrinfo hint;
	struct address_pair ap ;
	int ret;

	Parse_Address( sname, &ap ) ;

	switch ( ap.entries ) {
	case 0: // Complete default address
		pin->dev.tcp.host = NULL;
		pin->dev.tcp.service = owstrdup(default_port);
		break ;
	case 1: // single entry -- usually port unless a dotted quad
		switch ( ap.first.type ) {
		case address_none:
			pin->dev.tcp.host = NULL;
			pin->dev.tcp.service = owstrdup(default_port);
			break ;
		case address_dottedquad:
			// looks like an IP address
			pin->dev.tcp.host = owstrdup(ap.first.alpha);
			pin->dev.tcp.service = owstrdup(default_port);
			break ;
		case address_numeric:
			pin->dev.tcp.host = NULL;
			pin->dev.tcp.service = owstrdup(ap.first.alpha);
			break ;
		default:
			// assume it's a port if it's the SERVER
			if ( strcasecmp( default_port, DEFAULT_SERVER_PORT ) == 0 ) {
				pin->dev.tcp.host = NULL;
				pin->dev.tcp.service = owstrdup(ap.first.alpha);
			} else {
				pin->dev.tcp.host = owstrdup(ap.first.alpha);
				pin->dev.tcp.service = owstrdup(default_port);
			}
			break ;
		}
		break ;
	case 2:
	default: // address:port format -- unambiguous
		pin->dev.tcp.host = ( ap.first.type == address_none ) ? NULL : owstrdup(ap.first.alpha) ;
		pin->dev.tcp.service = ( ap.second.type == address_none ) ? owstrdup(default_port) : owstrdup(ap.second.alpha) ;
		break ;
	}
	Free_Address( &ap ) ;

	memset(&hint, 0, sizeof(struct addrinfo));
//    hint.ai_socktype = SOCK_STREAM | SOCK_CLOEXEC ;
    hint.ai_socktype = SOCK_STREAM ;

#if OW_CYGWIN
	hint.ai_family = AF_INET;
	if( pin->dev.tcp.host == NULL) {
		/* getaddrinfo doesn't work with host=NULL for cygwin */
		pin->dev.tcp.host = owstrdup("127.0.0.1");
	}
#else
	hint.ai_family = AF_UNSPEC;
#endif

	LEVEL_DEBUG("IP address=[%s] port=[%s]", SAFESTRING( pin->dev.tcp.host), pin->dev.tcp.service);
	ret = getaddrinfo( pin->dev.tcp.host, pin->dev.tcp.service, &hint, &( pin->dev.tcp.ai) ) ;
	if ( ret != 0 ) {
		LEVEL_CONNECT("GETADDRINFO error %s", gai_strerror(ret));
		return gbBAD;
	}
	return gbGOOD;
}
Esempio n. 29
0
/* Device-specific functions */
GOOD_OR_BAD ENET_monitor_detect(struct port_in *pin)
{
	struct connection_in * in = pin->first ;
	struct address_pair ap ;
	pthread_t thread ;
	
	/* init_data has form "scan" or "scan:15" (15 seconds) */
	Parse_Address( pin->init_data, &ap ) ;
	in->master.enet_monitor.enet_scan_interval = DEFAULT_ENET_SCAN_INTERVAL ;
	switch ( ap.entries ) {
		case 0:
			in->master.enet_monitor.enet_scan_interval = DEFAULT_ENET_SCAN_INTERVAL ;
			break ;
		case 1:
			switch( ap.first.type ) {
				case address_numeric:
					in->master.enet_monitor.enet_scan_interval = ap.first.number ;
					break ;
				default:
					in->master.enet_monitor.enet_scan_interval = DEFAULT_ENET_SCAN_INTERVAL ;
					break ;
			}
			break ;
		case 2:
			switch( ap.second.type ) {
				case address_numeric:
					in->master.enet_monitor.enet_scan_interval = ap.second.number ;
					break ;
				default:
					in->master.enet_monitor.enet_scan_interval = DEFAULT_ENET_SCAN_INTERVAL ;
					break ;
			}
			break ;
	}
	Free_Address( &ap ) ;

	pin->type = ct_none ;

	// Device name will not be init_data copy
	SAFEFREE(DEVICENAME(in)) ;
	DEVICENAME(in) = owstrdup("ENET bus monitor") ;

	pin->file_descriptor = FILE_DESCRIPTOR_BAD;
	in->iroutines.detect = ENET_monitor_detect;
	in->Adapter = adapter_enet_monitor;
	in->iroutines.reset = NO_RESET_ROUTINE;
	in->iroutines.next_both = NO_NEXT_BOTH_ROUTINE;
	in->iroutines.PowerByte = NO_POWERBYTE_ROUTINE;
	in->iroutines.ProgramPulse = NO_PROGRAMPULSE_ROUTINE;
	in->iroutines.sendback_data = NO_SENDBACKDATA_ROUTINE;
	in->iroutines.sendback_bits = NO_SENDBACKBITS_ROUTINE;
	in->iroutines.select = NO_SELECT_ROUTINE;
	in->iroutines.select_and_sendback = NO_SELECTANDSENDBACK_ROUTINE ;
	in->iroutines.set_config = NO_SET_CONFIG_ROUTINE;
	in->iroutines.get_config = NO_GET_CONFIG_ROUTINE;
	in->iroutines.reconnect = NO_RECONNECT_ROUTINE;
	in->iroutines.close = ENET_monitor_close;
	in->iroutines.verify = NO_VERIFY_ROUTINE ;
	in->iroutines.flags = ADAP_FLAG_sham;
	in->adapter_name = "ENET scan";
	pin->busmode = bus_enet_monitor ; // repeat since can come via usb=scan
	
	Init_Pipe( in->master.enet_monitor.shutdown_pipe ) ;
	if ( pipe( in->master.enet_monitor.shutdown_pipe ) != 0 ) {
		ERROR_DEFAULT("Cannot allocate a shutdown pipe. The program shutdown may be messy");
		Init_Pipe( in->master.enet_monitor.shutdown_pipe ) ;
	}
	if ( BAD( ENET_monitor_in_use(pin) ) ) {
		LEVEL_CONNECT("Second call for ENET scanning ignored") ;
		return gbBAD ;
	}

	if ( pthread_create(&thread, DEFAULT_THREAD_ATTR, ENET_monitor_loop, (void *) in) != 0 ) {
		ERROR_CALL("Cannot create the ENET monitoring program thread");
		return gbBAD ;
	}

	return gbGOOD ;
}
Esempio n. 30
0
int main(int argc, char *argv[])
{
	int c;

	/* Set up owlib */
	LibSetup(program_type_httpd);
	Setup_Systemd() ; // systemd?
	Setup_Launchd() ; // launchd?

	/* grab our executable name */
	ArgCopy( argc, argv ) ;

	while ((c = getopt_long(argc, argv, OWLIB_OPT, owopts_long, NULL)) != -1) {
		switch (c) {
		case 'V':
			fprintf(stderr, "%s version:\n\t" VERSION "\n", argv[0]);
			break;
		default:
			break;
		}
		if ( BAD( owopt(c, optarg) ) ) {
			ow_exit(0);			/* rest of message */
		}
	}

	/* non-option arguments */
	while (optind < argc) {
		ARG_Generic(argv[optind]);
		++optind;
	}

	switch (Globals.daemon_status) {
		case e_daemon_sd:
		case e_daemon_sd_done:
			// systemd done later
			break ;
		default:
			if (Outbound_Control.active == 0) {
				if (Globals.zero == zero_none) {
					LEVEL_DEFAULT("%s would be \"locked in\" so will quit.\nBonjour and Avahi not available.", argv[0]);
					ow_exit(1);
				} else {
					LEVEL_CONNECT("%s will use an ephemeral port", argv[0]) ;
				}
				ARG_Server(NULL);		// make an ephemeral assignment
			}
			break ;
	}

	/* become a daemon if not told otherwise */
	if ( BAD(EnterBackground()) ) {
		ow_exit(1);
	}

	/* Set up adapters and systemd */
	if ( BAD(LibStart(NULL)) ) {
		ow_exit(1);
	}

	set_exit_signal_handlers(exit_handler);
	set_signal_handlers(NULL);

	ServerProcess(Acceptor);

	LEVEL_DEBUG("ServerProcess done");
	ow_exit(0);
	LEVEL_DEBUG("owhttpd done");
	return 0;
}