예제 #1
0
static int
_rti_iterator_arg_empty_init(_rti_iterator_arg _param) {
	int x = 0;
	int y = 0;

	_param->empty.values = rtalloc(sizeof(double *) * _param->dimension.rows);
	_param->empty.nodata = rtalloc(sizeof(int *) * _param->dimension.rows);
	if (_param->empty.values == NULL || _param->empty.nodata == NULL) {
		rterror("_rti_iterator_arg_empty_init: Could not allocate memory for empty values and NODATA");
		return 0;
	}

	for (y = 0; y < _param->dimension.rows; y++) {
		_param->empty.values[y] = rtalloc(sizeof(double) * _param->dimension.columns);
		_param->empty.nodata[y] = rtalloc(sizeof(int) * _param->dimension.columns);

		if (_param->empty.values[y] == NULL || _param->empty.nodata[y] == NULL) {
			rterror("_rti_iterator_arg_empty_init: Could not allocate memory for elements of empty values and NODATA");
			return 0;
		}

		for (x = 0; x < _param->dimension.columns; x++) {
			_param->empty.values[y][x] = 0;
			_param->empty.nodata[y][x] = 1;
		}
	}

	return 1;
}
예제 #2
0
rt_band cu_add_band(rt_raster raster, rt_pixtype pixtype, int hasnodata, double nodataval) {
	void* mem = NULL;
	int32_t bandNum = 0;
	size_t datasize = 0;
	rt_band band = NULL;
	uint16_t width = 0;
	uint16_t height = 0;

	width = rt_raster_get_width(raster);
	height = rt_raster_get_height(raster);

	datasize = rt_pixtype_size(pixtype) * width * height;
	mem = rtalloc(datasize);
	CU_ASSERT(mem != NULL);

	if (hasnodata)
		memset(mem, nodataval, datasize);
	else
		memset(mem, 0, datasize);

	band = rt_band_new_inline(width, height, pixtype, hasnodata, nodataval, mem);
	CU_ASSERT(band != NULL);
	rt_band_set_ownsdata_flag(band, 1);

	bandNum = rt_raster_add_band(raster, band, rt_raster_get_num_bands(raster));
	CU_ASSERT(bandNum >= 0);

	return band;
}
예제 #3
0
static _rti_colormap_arg
_rti_colormap_arg_init(rt_raster raster) {
	_rti_colormap_arg arg = NULL;

	arg = rtalloc(sizeof(struct _rti_colormap_arg_t));
	if (arg == NULL) {
		rterror("_rti_colormap_arg_init: Could not allocate memory for _rti_color_arg");
		return NULL;
	}

	arg->band = NULL;
	arg->nodataentry = NULL;
	arg->hasnodata = 0;
	arg->nodataval = 0;

	if (raster == NULL)
		arg->raster = NULL;
	/* raster provided */
	else {
		arg->raster = rt_raster_clone(raster, 0);
		if (arg->raster == NULL) {
			rterror("_rti_colormap_arg_init: Could not create output raster");
			return NULL;
		}
	}

	arg->nexpr = 0;
	arg->expr = NULL;

	arg->npos = 0;
	arg->pos = NULL;

	return arg;
}
예제 #4
0
static void test_raster_replace_band() {
	rt_raster raster;
	rt_band band;
	rt_band rband;
	void* mem;
	size_t datasize;
	uint16_t width;
	uint16_t height;
	double nodata;

	raster = rt_raster_new(10, 10);
	CU_ASSERT(raster != NULL); /* or we're out of virtual memory */
	band = cu_add_band(raster, PT_8BUI, 0, 0);
	CU_ASSERT(band != NULL);
	band = cu_add_band(raster, PT_8BUI, 1, 255);
	CU_ASSERT(band != NULL);

	width = rt_raster_get_width(raster);
	height = rt_raster_get_height(raster);

	datasize = rt_pixtype_size(PT_8BUI) * width * height;
	mem = rtalloc(datasize);
	band = rt_band_new_inline(width, height, PT_8BUI, 1, 1, mem);
	CU_ASSERT(band != NULL);
	rt_band_set_ownsdata_flag(band, 1);

	rband = rt_raster_replace_band(raster, band, 0);
	CU_ASSERT(rband != NULL);
	rt_band_get_nodata(rt_raster_get_band(raster, 0), &nodata);
	CU_ASSERT_DOUBLE_EQUAL(nodata, 1, DBL_EPSILON);

	rt_band_destroy(rband);
	cu_free_raster(raster);
}
예제 #5
0
static int
_rti_iterator_arg_callback_init(_rti_iterator_arg _param) {
	int i = 0;

	_param->arg = rtalloc(sizeof(struct rt_iterator_arg_t));
	if (_param->arg == NULL) {
		rterror("_rti_iterator_arg_callback_init: Could not allocate memory for rt_iterator_arg");
		return 0;
	}

	_param->arg->values = NULL;
	_param->arg->nodata = NULL;
	_param->arg->src_pixel = NULL;

	/* initialize argument components */
	_param->arg->values = rtalloc(sizeof(double **) * _param->count);
	_param->arg->nodata = rtalloc(sizeof(int **) * _param->count);
	_param->arg->src_pixel = rtalloc(sizeof(int *) * _param->count);
	if (_param->arg->values == NULL || _param->arg->nodata == NULL || _param->arg->src_pixel == NULL) {
		rterror("_rti_iterator_arg_callback_init: Could not allocate memory for element of rt_iterator_arg");
		return 0;
	}
	memset(_param->arg->values, 0, sizeof(double **) * _param->count);
	memset(_param->arg->nodata, 0, sizeof(int **) * _param->count);

	/* initialize pos */
	for (i = 0; i < _param->count; i++) {

		_param->arg->src_pixel[i] = rtalloc(sizeof(int) * 2);
		if (_param->arg->src_pixel[i] == NULL) {
			rterror("_rti_iterator_arg_callback_init: Could not allocate memory for position elements of rt_iterator_arg");
			return 0;
		}
		memset(_param->arg->src_pixel[i], 0, sizeof(int) * 2);
	}

	_param->arg->rasters = _param->count;
	_param->arg->rows = _param->dimension.rows;
	_param->arg->columns = _param->dimension.columns;

	_param->arg->dst_pixel[0] = 0;
	_param->arg->dst_pixel[1] = 0;

	return 1;
}
예제 #6
0
파일: cu_gdal.c 프로젝트: ahinz/postgis
static void test_gdal_rasterize() {
	rt_raster raster;
	char srs[] = "PROJCS[\"unnamed\",GEOGCS[\"unnamed ellipse\",DATUM[\"unknown\",SPHEROID[\"unnamed\",6370997,0]],PRIMEM[\"Greenwich\",0],UNIT[\"degree\",0.0174532925199433]],PROJECTION[\"Lambert_Azimuthal_Equal_Area\"],PARAMETER[\"latitude_of_center\",45],PARAMETER[\"longitude_of_center\",-100],PARAMETER[\"false_easting\",0],PARAMETER[\"false_northing\",0],UNIT[\"Meter\",1],AUTHORITY[\"EPSG\",\"2163\"]]";
	const char wkb_hex[] = "010300000001000000050000000000000080841ec100000000600122410000000080841ec100000000804f22410000000040e81dc100000000804f22410000000040e81dc100000000600122410000000080841ec10000000060012241";
	const char *pos = wkb_hex;
	unsigned char *wkb = NULL;
	int wkb_len = 0;
	int i;
	double scale_x = 100;
	double scale_y = -100;

	rt_pixtype pixtype[] = {PT_8BUI};
	double init[] = {0};
	double value[] = {1};
	double nodata[] = {0};
	uint8_t nodata_mask[] = {1};

	/* hex to byte */
	wkb_len = (int) ceil(((double) strlen(wkb_hex)) / 2);
	wkb = (unsigned char *) rtalloc(sizeof(unsigned char) * wkb_len);
	for (i = 0; i < wkb_len; i++) {
		sscanf(pos, "%2hhx", &wkb[i]);
		pos += 2;
	}

	raster = rt_raster_gdal_rasterize(
		wkb,
		wkb_len, srs,
		1, pixtype,
		init, value,
		nodata, nodata_mask,
		NULL, NULL,
		&scale_x, &scale_y,
		NULL, NULL,
		NULL, NULL,
		NULL, NULL,
		NULL
	);

	CU_ASSERT(raster != NULL);
	CU_ASSERT_EQUAL(rt_raster_get_width(raster), 100);
	CU_ASSERT_EQUAL(rt_raster_get_height(raster), 100);
	CU_ASSERT_NOT_EQUAL(rt_raster_get_num_bands(raster), 0);
	CU_ASSERT_DOUBLE_EQUAL(rt_raster_get_x_offset(raster), -500000, DBL_EPSILON);
	CU_ASSERT_DOUBLE_EQUAL(rt_raster_get_y_offset(raster), 600000, DBL_EPSILON);

	rtdealloc(wkb);
	cu_free_raster(raster);
}
예제 #7
0
static void
mpls_forward(struct mbuf *m)
{
	struct sockaddr_mpls *smpls;
	struct mpls *mpls;
	struct route *cache_rt = &mplsforward_rt[mycpuid];
	mpls_label_t label;
	struct ifnet *ifp;
	struct sockaddr *dst;
	int error;

	KASSERT(m->m_len >= sizeof(struct mpls),
	    ("mpls_forward: mpls header not in one mbuf"));

	mpls = mtod(m, struct mpls *);
	label = MPLS_LABEL(ntohl(mpls->mpls_shim));

	smpls = (struct sockaddr_mpls *) &cache_rt->ro_dst;
	if (cache_rt->ro_rt == NULL || smpls->smpls_label != label) {
		if (cache_rt->ro_rt != NULL) {
			RTFREE(cache_rt->ro_rt);
			cache_rt->ro_rt = NULL;
		}
		smpls->smpls_family = AF_MPLS;
		smpls->smpls_len = sizeof(struct sockaddr_mpls);
		smpls->smpls_label = htonl(label);
		rtalloc(cache_rt);
		if (cache_rt->ro_rt == NULL) {
			/* route not found */
			return;
		}
	}

	ifp = cache_rt->ro_rt->rt_ifp;
	dst = cache_rt->ro_rt->rt_gateway;
	error = mpls_output(m, cache_rt->ro_rt);
	if (error)
		goto bad;
	error = (*ifp->if_output)(ifp, m, dst, cache_rt->ro_rt);
	if (error)
		goto bad;
	mplsstat.mplss_forwarded++;

	return;
bad:
	m_freem(m);
}
예제 #8
0
static _rti_iterator_arg
_rti_iterator_arg_init() {
	_rti_iterator_arg _param;

	_param = rtalloc(sizeof(struct _rti_iterator_arg_t));
	if (_param == NULL) {
		rterror("_rti_iterator_arg_init: Could not allocate memory for _rti_iterator_arg");
		return NULL;
	}

	_param->count = 0;

	_param->raster = NULL;
	_param->isempty = NULL;
	_param->offset = NULL;
	_param->width = NULL;
	_param->height = NULL;

	_param->band.rtband = NULL;
	_param->band.hasnodata = NULL;
	_param->band.isnodata = NULL;
	_param->band.nodataval = NULL;
	_param->band.minval = NULL;

	_param->distance.x = 0;
	_param->distance.y = 0;

	_param->dimension.rows = 0;
	_param->dimension.columns = 0;

	_param->empty.values = NULL;
	_param->empty.nodata = NULL;

	_param->arg = NULL;

	return _param;
}
예제 #9
0
파일: in6_src.c 프로젝트: ajinkya93/OpenBSD
/*
 * Return an IPv6 address, which is the most appropriate for a given
 * destination and user specified options.
 * If necessary, this function lookups the routing table and returns
 * an entry to the caller for later use.
 */
int
in6_selectsrc(struct in6_addr **in6src, struct sockaddr_in6 *dstsock,
    struct ip6_pktopts *opts, struct ip6_moptions *mopts,
    struct route_in6 *ro, struct in6_addr *laddr, u_int rtableid)
{
	struct ifnet *ifp = NULL;
	struct in6_addr *dst;
	struct in6_ifaddr *ia6 = NULL;
	struct in6_pktinfo *pi = NULL;
	int	error;

	dst = &dstsock->sin6_addr;

	/*
	 * If the source address is explicitly specified by the caller,
	 * check if the requested source address is indeed a unicast address
	 * assigned to the node, and can be used as the packet's source
	 * address.  If everything is okay, use the address as source.
	 */
	if (opts && (pi = opts->ip6po_pktinfo) &&
	    !IN6_IS_ADDR_UNSPECIFIED(&pi->ipi6_addr)) {
		struct sockaddr_in6 sa6;

		/* get the outgoing interface */
		error = in6_selectif(dstsock, opts, mopts, ro, &ifp, rtableid);
		if (error)
			return (error);

		bzero(&sa6, sizeof(sa6));
		sa6.sin6_family = AF_INET6;
		sa6.sin6_len = sizeof(sa6);
		sa6.sin6_addr = pi->ipi6_addr;

		if (ifp && IN6_IS_SCOPE_EMBED(&sa6.sin6_addr))
			sa6.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
		if_put(ifp); /* put reference from in6_selectif */

		ia6 = ifatoia6(ifa_ifwithaddr(sin6tosa(&sa6), rtableid));
		if (ia6 == NULL ||
		    (ia6->ia6_flags & (IN6_IFF_ANYCAST | IN6_IFF_NOTREADY)))
			return (EADDRNOTAVAIL);

		pi->ipi6_addr = sa6.sin6_addr; /* XXX: this overrides pi */

		*in6src = &pi->ipi6_addr;
		return (0);
	}

	/*
	 * If the source address is not specified but the socket(if any)
	 * is already bound, use the bound address.
	 */
	if (laddr && !IN6_IS_ADDR_UNSPECIFIED(laddr)) {
		*in6src = laddr;
		return (0);
	}

	/*
	 * If the caller doesn't specify the source address but
	 * the outgoing interface, use an address associated with
	 * the interface.
	 */
	if (pi && pi->ipi6_ifindex) {
		ifp = if_get(pi->ipi6_ifindex);
		if (ifp == NULL)
			return (ENXIO); /* XXX: better error? */

		ia6 = in6_ifawithscope(ifp, dst, rtableid);
		if_put(ifp);

		if (ia6 == NULL)
			return (EADDRNOTAVAIL);

		*in6src = &ia6->ia_addr.sin6_addr;
		return (0);
	}

	/*
	 * If the destination address is a link-local unicast address or
	 * a link/interface-local multicast address, and if the outgoing
	 * interface is specified by the sin6_scope_id filed, use an address
	 * associated with the interface.
	 * XXX: We're now trying to define more specific semantics of
	 *      sin6_scope_id field, so this part will be rewritten in
	 *      the near future.
	 */
	if ((IN6_IS_ADDR_LINKLOCAL(dst) || IN6_IS_ADDR_MC_LINKLOCAL(dst) ||
	     IN6_IS_ADDR_MC_INTFACELOCAL(dst)) && dstsock->sin6_scope_id) {
		ifp = if_get(dstsock->sin6_scope_id);
		if (ifp == NULL)
			return (ENXIO); /* XXX: better error? */

		ia6 = in6_ifawithscope(ifp, dst, rtableid);
		if_put(ifp);

		if (ia6 == NULL)
			return (EADDRNOTAVAIL);

		*in6src = &ia6->ia_addr.sin6_addr;
		return (0);
	}

	/*
	 * If the destination address is a multicast address and
	 * the outgoing interface for the address is specified
	 * by the caller, use an address associated with the interface.
	 * Even if the outgoing interface is not specified, we also
	 * choose a loopback interface as the outgoing interface.
	 */
	if (IN6_IS_ADDR_MULTICAST(dst)) {
		ifp = mopts ? if_get(mopts->im6o_ifidx) : NULL;

		if (!ifp && dstsock->sin6_scope_id)
			ifp = if_get(htons(dstsock->sin6_scope_id));

		if (ifp) {
			ia6 = in6_ifawithscope(ifp, dst, rtableid);
			if_put(ifp);

			if (ia6 == NULL)
				return (EADDRNOTAVAIL);

			*in6src = &ia6->ia_addr.sin6_addr;
			return (0);
		}
	}

	/*
	 * If route is known or can be allocated now,
	 * our src addr is taken from the i/f, else punt.
	 */
	if (ro) {
		if (!rtisvalid(ro->ro_rt) || (ro->ro_tableid != rtableid) ||
		    !IN6_ARE_ADDR_EQUAL(&ro->ro_dst.sin6_addr, dst)) {
			rtfree(ro->ro_rt);
			ro->ro_rt = NULL;
		}
		if (ro->ro_rt == NULL) {
			struct sockaddr_in6 *sa6;

			/* No route yet, so try to acquire one */
			bzero(&ro->ro_dst, sizeof(struct sockaddr_in6));
			ro->ro_tableid = rtableid;
			sa6 = &ro->ro_dst;
			sa6->sin6_family = AF_INET6;
			sa6->sin6_len = sizeof(struct sockaddr_in6);
			sa6->sin6_addr = *dst;
			sa6->sin6_scope_id = dstsock->sin6_scope_id;
			ro->ro_rt = rtalloc(sin6tosa(&ro->ro_dst),
			    RT_RESOLVE, ro->ro_tableid);
		}

		/*
		 * in_pcbconnect() checks out IFF_LOOPBACK to skip using
		 * the address. But we don't know why it does so.
		 * It is necessary to ensure the scope even for lo0
		 * so doesn't check out IFF_LOOPBACK.
		 */

		if (ro->ro_rt) {
			ifp = if_get(ro->ro_rt->rt_ifidx);
			if (ifp != NULL) {
				ia6 = in6_ifawithscope(ifp, dst, rtableid);
				if_put(ifp);
			}
			if (ia6 == NULL) /* xxx scope error ?*/
				ia6 = ifatoia6(ro->ro_rt->rt_ifa);
		}
		if (ia6 == NULL)
			return (EHOSTUNREACH);	/* no route */

		*in6src = &ia6->ia_addr.sin6_addr;
		return (0);
	}

	return (EADDRNOTAVAIL);
}
예제 #10
0
int
in_pcbladdr(struct inpcb *inp, struct mbuf *nam, struct sockaddr_in **plocal_sin)
{
	struct in_ifaddr *ia;
	register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);

	if (nam->m_len != sizeof (*sin))
		return (EINVAL);
	if (sin->sin_family != AF_INET)
		return (EAFNOSUPPORT);
	if (sin->sin_port == 0)
		return (EADDRNOTAVAIL);
	if (in_ifaddr) {
		/*
		 * If the destination address is INADDR_ANY,
		 * use the primary local address.
		 * If the supplied address is INADDR_BROADCAST,
		 * and the primary interface supports broadcast,
		 * choose the broadcast address for that interface.
		 */
#define	satosin(sa)	((struct sockaddr_in *)(sa))
#define sintosa(sin)	((struct sockaddr *)(sin))
#define ifatoia(ifa)	((struct in_ifaddr *)(ifa))
		if (sin->sin_addr.s_addr == INADDR_ANY)
		    sin->sin_addr = IA_SIN(in_ifaddr)->sin_addr;
		else if (sin->sin_addr.s_addr == (u_long)INADDR_BROADCAST &&
		  (in_ifaddr->ia_ifp->if_flags & IFF_BROADCAST))
		    sin->sin_addr = satosin(&in_ifaddr->ia_broadaddr)->sin_addr;
	}
	if (inp->inp_laddr.s_addr == INADDR_ANY) {
		register struct route *ro;

		ia = (struct in_ifaddr *)0;
		/*
		 * If route is known or can be allocated now,
		 * our src addr is taken from the i/f, else punt.
		 */
		ro = &inp->inp_route;
		if (ro->ro_rt &&
		    (satosin(&ro->ro_dst)->sin_addr.s_addr !=
			sin->sin_addr.s_addr ||
		    inp->inp_socket->so_options & SO_DONTROUTE)) {
			RTFREE(ro->ro_rt);
			ro->ro_rt = (struct rtentry *)0;
		}
		if ((inp->inp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/
		    (ro->ro_rt == (struct rtentry *)0 ||
		    ro->ro_rt->rt_ifp == (struct ifnet *)0)) {
			/* No route yet, so try to acquire one */
			ro->ro_dst.sa_family = AF_INET;
			ro->ro_dst.sa_len = sizeof(struct sockaddr_in);
			((struct sockaddr_in *) &ro->ro_dst)->sin_addr =
				sin->sin_addr;
			rtalloc(ro);
		}
		/*
		 * If we found a route, use the address
		 * corresponding to the outgoing interface
		 * unless it is the loopback (in case a route
		 * to our address on another net goes to loopback).
		 */
		if (ro->ro_rt && !(ro->ro_rt->rt_ifp->if_flags & IFF_LOOPBACK))
			ia = ifatoia(ro->ro_rt->rt_ifa);
		if (ia == 0) {
			u_short fport = sin->sin_port;

			sin->sin_port = 0;
			ia = ifatoia(ifa_ifwithdstaddr(sintosa(sin)));
			if (ia == 0)
				ia = ifatoia(ifa_ifwithnet(sintosa(sin)));
			sin->sin_port = fport;
			if (ia == 0)
				ia = in_ifaddr;
			if (ia == 0)
				return (EADDRNOTAVAIL);
		}
		/*
		 * If the destination address is multicast and an outgoing
		 * interface has been set as a multicast option, use the
		 * address of that interface as our source address.
		 */
		if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr)) &&
		    inp->inp_moptions != NULL) {
			struct ip_moptions *imo;
			struct ifnet *ifp;

			imo = inp->inp_moptions;
			if (imo->imo_multicast_ifp != NULL) {
				ifp = imo->imo_multicast_ifp;
				for (ia = in_ifaddr; ia; ia = ia->ia_next)
					if (ia->ia_ifp == ifp)
						break;
				if (ia == 0)
					return (EADDRNOTAVAIL);
			}
		}
	/*
	 * Don't do pcblookup call here; return interface in plocal_sin
	 * and exit to caller, that will do the lookup.
	 */
		*plocal_sin = &ia->ia_addr;

	}
	return(0);
}
예제 #11
0
int
ipx_outputfl(struct mbuf *m0, struct route *ro, int flags)
{
	struct ipx *ipx = mtod(m0, struct ipx *);
	struct ifnet *ifp = NULL;
	int error = 0;
	struct sockaddr_ipx *dst;
	struct route ipxroute;

	/*
	 * Route packet.
	 */
	if (ro == NULL) {
		ro = &ipxroute;
		bzero((caddr_t)ro, sizeof(*ro));
	}
	dst = (struct sockaddr_ipx *)&ro->ro_dst;
	if (ro->ro_rt == NULL) {
		dst->sipx_family = AF_IPX;
		dst->sipx_len = sizeof(*dst);
		dst->sipx_addr = ipx->ipx_dna;
		dst->sipx_addr.x_port = 0;
		/*
		 * If routing to interface only,
		 * short circuit routing lookup.
		 */
		if (flags & IPX_ROUTETOIF) {
			struct ipx_ifaddr *ia = ipx_iaonnetof(&ipx->ipx_dna);

			if (ia == NULL) {
				ipxstat.ipxs_noroute++;
				error = ENETUNREACH;
				goto bad;
			}
			ifp = ia->ia_ifp;
			goto gotif;
		}
		rtalloc(ro);
	} else if ((ro->ro_rt->rt_flags & RTF_UP) == 0) {
		/*
		 * The old route has gone away; try for a new one.
		 */
		rtfree(ro->ro_rt);
		ro->ro_rt = NULL;
		rtalloc(ro);
	}
	if (ro->ro_rt == NULL || (ifp = ro->ro_rt->rt_ifp) == NULL) {
		ipxstat.ipxs_noroute++;
		error = ENETUNREACH;
		goto bad;
	}
	ro->ro_rt->rt_use++;
	if (ro->ro_rt->rt_flags & (RTF_GATEWAY|RTF_HOST))
		dst = (struct sockaddr_ipx *)ro->ro_rt->rt_gateway;
gotif:
	/*
	 * Look for multicast addresses and
	 * and verify user is allowed to send
	 * such a packet.
	 */
	if (dst->sipx_addr.x_host.c_host[0]&1) {
		if ((ifp->if_flags & (IFF_BROADCAST | IFF_LOOPBACK)) == 0) {
			error = EADDRNOTAVAIL;
			goto bad;
		}
		if ((flags & IPX_ALLOWBROADCAST) == 0) {
			error = EACCES;
			goto bad;
		}
		m0->m_flags |= M_BCAST;
	}

	if (htons(ipx->ipx_len) <= ifp->if_mtu) {
		ipxstat.ipxs_localout++;
		if (ipx_copy_output) {
			ipx_watch_output(m0, ifp);
		}
		error = ifp->if_output(ifp, m0, (struct sockaddr *)dst,
				       ro->ro_rt);
		goto done;
	} else {
		ipxstat.ipxs_mtutoosmall++;
		error = EMSGSIZE;
	}
bad:
	if (ipx_copy_output) {
		ipx_watch_output(m0, ifp);
	}
	m_freem(m0);
done:
	if (ro == &ipxroute && (flags & IPX_ROUTETOIF) == 0 &&
	    ro->ro_rt != NULL) {
		RTFREE(ro->ro_rt);
		ro->ro_rt = NULL;
	}
	return (error);
}
예제 #12
0
/**
 * n-raster iterator.
 * The raster returned should be freed by the caller
 *
 * @param itrset : set of rt_iterator objects.
 * @param itrcount : number of objects in itrset.
 * @param extenttype : type of extent for the output raster.
 * @param customextent : raster specifying custom extent.
 * is only used if extenttype is ET_CUSTOM.
 * @param pixtype : the desired pixel type of the output raster's band.
 * @param hasnodata : indicates if the band has nodata value
 * @param nodataval : the nodata value, will be appropriately
 * truncated to fit the pixtype size.
 * @param distancex : the number of pixels around the specified pixel
 * along the X axis
 * @param distancey : the number of pixels around the specified pixel
 * along the Y axis
 * @param mask : the object of mask
 * @param userarg : pointer to any argument that is passed as-is to callback.
 * @param callback : callback function for actual processing of pixel values.
 * @param *rtnraster : return one band raster from iterator process
 *
 * The callback function _must_ have the following signature.
 *
 *    int FNAME(rt_iterator_arg arg, void *userarg, double *value, int *nodata)
 *
 * The callback function _must_ return zero (error) or non-zero (success)
 * indicating whether the function ran successfully.
 * The parameters passed to the callback function are as follows.
 *
 * - rt_iterator_arg arg: struct containing pixel values, NODATA flags and metadata
 * - void *userarg: NULL or calling function provides to rt_raster_iterator() for use by callback function
 * - double *value: value of pixel to be burned by rt_raster_iterator()
 * - int *nodata: flag (0 or 1) indicating that pixel to be burned is NODATA
 *
 * @return ES_NONE on success, ES_ERROR on error
 */
rt_errorstate
rt_raster_iterator(
	rt_iterator itrset, uint16_t itrcount,
	rt_extenttype extenttype, rt_raster customextent,
	rt_pixtype pixtype,
	uint8_t hasnodata, double nodataval,
	uint16_t distancex, uint16_t distancey,
	rt_mask mask,
	void *userarg,
	int (*callback)(
		rt_iterator_arg arg,
		void *userarg,
		double *value,
		int *nodata
	),
	rt_raster *rtnraster
) {
	/* output raster */
	rt_raster rtnrast = NULL;
	/* output raster's band */
	rt_band rtnband = NULL;

	/* working raster */
	rt_raster rast = NULL;

	_rti_iterator_arg _param = NULL;
	int allnull = 0;
	int allempty = 0;
	int aligned = 0;
	double offset[4] = {0.};
	rt_pixel npixels;

	int i = 0;
	int status = 0;
	int inextent = 0;
	int x = 0;
	int y = 0;
	int _x = 0;
	int _y = 0;

	int _width = 0;
	int _height = 0;

	double minval;
	double value;
	int isnodata;
	int nodata;

	RASTER_DEBUG(3, "Starting...");

	assert(itrset != NULL && itrcount > 0);
	assert(rtnraster != NULL);

	/* init rtnraster to NULL */
	*rtnraster = NULL;

	/* check that callback function is not NULL */
	if (callback == NULL) {
		rterror("rt_raster_iterator: Callback function not provided");
		return ES_ERROR;
	}

	/* check that custom extent is provided if extenttype = ET_CUSTOM */
	if (extenttype == ET_CUSTOM && rt_raster_is_empty(customextent)) {
		rterror("rt_raster_iterator: Custom extent cannot be empty if extent type is ET_CUSTOM");
		return ES_ERROR;
	}

	/* check that pixtype != PT_END */
	if (pixtype == PT_END) {
		rterror("rt_raster_iterator: Pixel type cannot be PT_END");
		return ES_ERROR;
	}

	/* initialize _param */
	if ((_param = _rti_iterator_arg_init()) == NULL) {
		rterror("rt_raster_iterator: Could not initialize internal variables");
		return ES_ERROR;
	}

	/* fill _param */
	if (!_rti_iterator_arg_populate(_param, itrset, itrcount, distancex, distancey, &allnull, &allempty)) {
		rterror("rt_raster_iterator: Could not populate for internal variables");
		_rti_iterator_arg_destroy(_param);
		return ES_ERROR;
	}

	/* shortcut if all null, return NULL */
	if (allnull == itrcount) {
		RASTER_DEBUG(3, "all rasters are NULL, returning NULL");

		_rti_iterator_arg_destroy(_param);

		return ES_NONE;
	}
	/* shortcut if all empty, return empty raster */
	else if (allempty == itrcount) {
		RASTER_DEBUG(3, "all rasters are empty, returning empty raster");

		_rti_iterator_arg_destroy(_param);

		rtnrast = rt_raster_new(0, 0);
		if (rtnrast == NULL) {
			rterror("rt_raster_iterator: Could not create empty raster");
			return ES_ERROR;
		}
		rt_raster_set_scale(rtnrast, 0, 0);

		*rtnraster = rtnrast;
		return ES_NONE;
	}

	/* check that all rasters are aligned */
	RASTER_DEBUG(3, "checking alignment of all rasters");
	rast = NULL;

	/* find raster to use as reference */
	/* use custom if provided */
	if (extenttype == ET_CUSTOM) {
		RASTER_DEBUG(4, "using custom extent as reference raster");
		rast = customextent;
	}
	/* use first valid one in _param->raster */
	else {
		for (i = 0; i < itrcount; i++) {
			if (!_param->isempty[i]) {
				RASTER_DEBUGF(4, "using raster at index %d as reference raster", i);
				rast = _param->raster[i];
				break;
			}
		}
	}

	/* no rasters found, SHOULD NEVER BE HERE! */
	if (rast == NULL) {
		rterror("rt_raster_iterator: Could not find reference raster to use for alignment tests");

		_rti_iterator_arg_destroy(_param);

		return ES_ERROR;
	}

	do {
		aligned = 1;

		/* check custom first if set. also skip if rasters are the same */
		if (extenttype == ET_CUSTOM && rast != customextent) {
			if (rt_raster_same_alignment(rast, customextent, &aligned, NULL) != ES_NONE) {
				rterror("rt_raster_iterator: Could not test for alignment between reference raster and custom extent");

				_rti_iterator_arg_destroy(_param);

				return ES_ERROR;
			}

			RASTER_DEBUGF(5, "custom extent alignment: %d", aligned);
			if (!aligned)
				break;
		}

		for (i = 0; i < itrcount; i++) {
			/* skip NULL rasters and if rasters are the same */
			if (_param->isempty[i] || rast == _param->raster[i])
				continue;

			if (rt_raster_same_alignment(rast, _param->raster[i], &aligned, NULL) != ES_NONE) {
				rterror("rt_raster_iterator: Could not test for alignment between reference raster and raster %d", i);

				_rti_iterator_arg_destroy(_param);

				return ES_ERROR;
			}
			RASTER_DEBUGF(5, "raster at index %d alignment: %d", i, aligned);

			/* abort checking since a raster isn't aligned */
			if (!aligned)
				break;
		}
	}
	while (0);

	/* not aligned, error */
	if (!aligned) {
		rterror("rt_raster_iterator: The set of rasters provided (custom extent included, if appropriate) do not have the same alignment");

		_rti_iterator_arg_destroy(_param);

		return ES_ERROR;
	}

	/* use extenttype to build output raster (no bands though) */
	i = -1;
	switch (extenttype) {
		case ET_INTERSECTION:
		case ET_UNION:
			/* make copy of first "real" raster */
			rtnrast = rtalloc(sizeof(struct rt_raster_t));
			if (rtnrast == NULL) {
				rterror("rt_raster_iterator: Could not allocate memory for output raster");

				_rti_iterator_arg_destroy(_param);

				return ES_ERROR;
			}

			for (i = 0; i < itrcount; i++) {
				if (!_param->isempty[i]) {
					memcpy(rtnrast, _param->raster[i], sizeof(struct rt_raster_serialized_t));
					break;
				}
			}
			rtnrast->numBands = 0;
			rtnrast->bands = NULL;

			/* get extent of output raster */
			rast = NULL;
			for (i = i + 1; i < itrcount; i++) {
				if (_param->isempty[i])
					continue;

				status = rt_raster_from_two_rasters(rtnrast, _param->raster[i], extenttype, &rast, NULL);
				rtdealloc(rtnrast);

				if (rast == NULL || status != ES_NONE) {
					rterror("rt_raster_iterator: Could not compute %s extent of rasters",
						extenttype == ET_UNION ? "union" : "intersection"
					);

					_rti_iterator_arg_destroy(_param);

					return ES_ERROR;
				}
				else if (rt_raster_is_empty(rast)) {
					rtinfo("rt_raster_iterator: Computed raster for %s extent is empty",
						extenttype == ET_UNION ? "union" : "intersection"
					);

					_rti_iterator_arg_destroy(_param);

					*rtnraster = rast;
					return ES_NONE;
				}

				rtnrast = rast;
				rast = NULL;
			}

			break;
		/*
			first, second and last have similar checks
			and continue into custom
		*/
		case ET_FIRST:
			i = 0;
		case ET_SECOND:
			if (i < 0) {
				if (itrcount < 2)
					i = 0;
				else
					i = 1;
			}
		case ET_LAST:
			if (i < 0) i = itrcount - 1;
			
			/* input raster is null, return NULL */
			if (_param->raster[i] == NULL) {
				RASTER_DEBUGF(3, "returning NULL as %s raster is NULL and extent type is ET_%s",
					(i == 0 ? "first" : (i == 1 ? "second" : "last")),
					(i == 0 ? "FIRST" : (i == 1 ? "SECOND" : "LAST"))
				);

				_rti_iterator_arg_destroy(_param);

				return ES_NONE;
			}
			/* input raster is empty, return empty raster */
			else if (_param->isempty[i]) {
				RASTER_DEBUGF(3, "returning empty raster as %s raster is empty and extent type is ET_%s",
					(i == 0 ? "first" : (i == 1 ? "second" : "last")),
					(i == 0 ? "FIRST" : (i == 1 ? "SECOND" : "LAST"))
				);

				_rti_iterator_arg_destroy(_param);

				rtnrast = rt_raster_new(0, 0);
				if (rtnrast == NULL) {
					rterror("rt_raster_iterator: Could not create empty raster");
					return ES_ERROR;
				}
				rt_raster_set_scale(rtnrast, 0, 0);

				*rtnraster = rtnrast;
				return ES_NONE;
			}
		/* copy the custom extent raster */
		case ET_CUSTOM:
			rtnrast = rtalloc(sizeof(struct rt_raster_t));
			if (rtnrast == NULL) {
				rterror("rt_raster_iterator: Could not allocate memory for output raster");

				_rti_iterator_arg_destroy(_param);

				return ES_ERROR;
			}

			switch (extenttype) {
				case ET_CUSTOM:
					memcpy(rtnrast, customextent, sizeof(struct rt_raster_serialized_t));
					break;
				/* first, second, last */
				default:
					memcpy(rtnrast, _param->raster[i], sizeof(struct rt_raster_serialized_t));
					break;
			}
			rtnrast->numBands = 0;
			rtnrast->bands = NULL;
			break;
	}

	_width = rt_raster_get_width(rtnrast);
	_height = rt_raster_get_height(rtnrast);

	RASTER_DEBUGF(4, "rtnrast (width, height, ulx, uly, scalex, scaley, skewx, skewy, srid) = (%d, %d, %f, %f, %f, %f, %f, %f, %d)",
		_width,
		_height,
		rt_raster_get_x_offset(rtnrast),
		rt_raster_get_y_offset(rtnrast),
		rt_raster_get_x_scale(rtnrast),
		rt_raster_get_y_scale(rtnrast),
		rt_raster_get_x_skew(rtnrast),
		rt_raster_get_y_skew(rtnrast),
		rt_raster_get_srid(rtnrast)
	);

	/* init values and NODATA for use with empty rasters */
	if (!_rti_iterator_arg_empty_init(_param)) {
		rterror("rt_raster_iterator: Could not initialize empty values and NODATA");

		_rti_iterator_arg_destroy(_param);
		rt_raster_destroy(rtnrast);
		
		return ES_ERROR;
	}

	/* create output band */
	if (rt_raster_generate_new_band(
		rtnrast,
		pixtype,
		nodataval,
		hasnodata, nodataval,
		0
	) < 0) {
		rterror("rt_raster_iterator: Could not add new band to output raster");

		_rti_iterator_arg_destroy(_param);
		rt_raster_destroy(rtnrast);

		return ES_ERROR;
	}

	/* get output band */
	rtnband = rt_raster_get_band(rtnrast, 0);
	if (rtnband == NULL) {
		rterror("rt_raster_iterator: Could not get new band from output raster");

		_rti_iterator_arg_destroy(_param);
		rt_raster_destroy(rtnrast);

		return ES_ERROR;
	}

	/* output band's minimum value */
	minval = rt_band_get_min_value(rtnband);

	/* initialize argument for callback function */
	if (!_rti_iterator_arg_callback_init(_param)) {
		rterror("rt_raster_iterator: Could not initialize callback function argument");

		_rti_iterator_arg_destroy(_param);
		rt_band_destroy(rtnband);
		rt_raster_destroy(rtnrast);

		return ES_ERROR;
	}

	/* fill _param->offset */
	for (i = 0; i < itrcount; i++) {
		if (_param->isempty[i])
			continue;

		status = rt_raster_from_two_rasters(rtnrast, _param->raster[i], ET_FIRST, &rast, offset);
		rtdealloc(rast);
		if (status != ES_NONE) {
			rterror("rt_raster_iterator: Could not compute raster offsets");

			_rti_iterator_arg_destroy(_param);
			rt_band_destroy(rtnband);
			rt_raster_destroy(rtnrast);

			return ES_ERROR;
		}

		_param->offset[i][0] = offset[2];
		_param->offset[i][1] = offset[3];
		RASTER_DEBUGF(4, "rast %d offset: %f %f", i, offset[2], offset[3]);
	}

	/* loop over each pixel (POI) of output raster */
	/* _x,_y are for output raster */
	/* x,y are for input raster */
	for (_y = 0; _y < _height; _y++) {
		for (_x = 0; _x < _width; _x++) {
			RASTER_DEBUGF(4, "iterating output pixel (x, y) = (%d, %d)", _x, _y);
			_param->arg->dst_pixel[0] = _x;
			_param->arg->dst_pixel[1] = _y;

			/* loop through each input raster */
			for (i = 0; i < itrcount; i++) {
				RASTER_DEBUGF(4, "raster %d", i);

				/*
					empty raster
					OR band does not exist and flag set to use NODATA
					OR band is NODATA
				*/
				if (
					_param->isempty[i] ||
					(_param->band.rtband[i] == NULL && itrset[i].nbnodata) ||
					_param->band.isnodata[i]
				) {
					RASTER_DEBUG(4, "empty raster, band does not exist or band is NODATA. using empty values and NODATA");
					
					x = _x;
					y = _y;

					_param->arg->values[i] = _param->empty.values;
					_param->arg->nodata[i] = _param->empty.nodata;

					continue;
				}

				/* input raster's X,Y */
				x = _x - (int) _param->offset[i][0];
				y = _y - (int) _param->offset[i][1];
				RASTER_DEBUGF(4, "source pixel (x, y) = (%d, %d)", x, y);

				_param->arg->src_pixel[i][0] = x;
				_param->arg->src_pixel[i][1] = y;

				/* neighborhood */
				npixels = NULL;
				status = 0;
				if (distancex > 0 && distancey > 0) {
					RASTER_DEBUG(4, "getting neighborhood");

					status = rt_band_get_nearest_pixel(
						_param->band.rtband[i],
						x, y,
						distancex, distancey,
						1,
						&npixels
					);
					if (status < 0) {
						rterror("rt_raster_iterator: Could not get pixel neighborhood");

						_rti_iterator_arg_destroy(_param);
						rt_band_destroy(rtnband);
						rt_raster_destroy(rtnrast);

						return ES_ERROR;
					}
				}

				/* get value of POI */
				/* get pixel's value */
				if (
					(x >= 0 && x < _param->width[i]) &&
					(y >= 0 && y < _param->height[i])
				) {
					RASTER_DEBUG(4, "getting value of POI");
					if (rt_band_get_pixel(
						_param->band.rtband[i],
						x, y,
						&value,
						&isnodata
					) != ES_NONE) {
						rterror("rt_raster_iterator: Could not get the pixel value of band");

						_rti_iterator_arg_destroy(_param);
						rt_band_destroy(rtnband);
						rt_raster_destroy(rtnrast);

						return ES_ERROR;
					}
					inextent = 1;
				}
				/* outside band extent, set to NODATA */
				else {
					RASTER_DEBUG(4, "Outside band extent, setting value to NODATA");
					/* has NODATA, use NODATA */
					if (_param->band.hasnodata[i])
						value = _param->band.nodataval[i];
					/* no NODATA, use min possible value */
					else
						value = _param->band.minval[i];

					inextent = 0;
					isnodata = 1;
				}

				/* add pixel to neighborhood */
				status++;
				if (status > 1)
					npixels = (rt_pixel) rtrealloc(npixels, sizeof(struct rt_pixel_t) * status);
				else
					npixels = (rt_pixel) rtalloc(sizeof(struct rt_pixel_t));

				if (npixels == NULL) {
					rterror("rt_raster_iterator: Could not reallocate memory for neighborhood");

					_rti_iterator_arg_destroy(_param);
					rt_band_destroy(rtnband);
					rt_raster_destroy(rtnrast);

					return ES_ERROR;
				}

				npixels[status - 1].x = x;
				npixels[status - 1].y = y;
				npixels[status - 1].nodata = 1;
				npixels[status - 1].value = value;

				/* set nodata flag */
				if ((!_param->band.hasnodata[i] && inextent) || !isnodata) {
					npixels[status - 1].nodata = 0;
				}
				RASTER_DEBUGF(4, "value, nodata: %f, %d", value, npixels[status - 1].nodata);

				/* convert set of rt_pixel to 2D array */
				status = rt_pixel_set_to_array(
					npixels, status,mask,
					x, y,
					distancex, distancey,
					&(_param->arg->values[i]),
					&(_param->arg->nodata[i]),
					NULL, NULL
				);
				rtdealloc(npixels);
				if (status != ES_NONE) {
					rterror("rt_raster_iterator: Could not create 2D array of neighborhood");

					_rti_iterator_arg_destroy(_param);
					rt_band_destroy(rtnband);
					rt_raster_destroy(rtnrast);

					return ES_ERROR;
				}
			}
	
			/* callback */
			RASTER_DEBUG(4, "calling callback function");
			value = 0;
			nodata = 0;
			status = callback(_param->arg, userarg, &value, &nodata);

			/* free memory from callback */
			_rti_iterator_arg_callback_clean(_param);

			/* handle callback status */
			if (status == 0) {
				rterror("rt_raster_iterator: Callback function returned an error");

				_rti_iterator_arg_destroy(_param);
				rt_band_destroy(rtnband);
				rt_raster_destroy(rtnrast);

				return ES_ERROR;
			}

			/* burn value to pixel */
			status = 0;
			if (!nodata) {
				status = rt_band_set_pixel(rtnband, _x, _y, value, NULL);
				RASTER_DEBUGF(4, "burning pixel (%d, %d) with value: %f", _x, _y, value);
			}
			else if (!hasnodata) {
				status = rt_band_set_pixel(rtnband, _x, _y, minval, NULL);
				RASTER_DEBUGF(4, "burning pixel (%d, %d) with minval: %f", _x, _y, minval);
			}
			else {
				RASTER_DEBUGF(4, "NOT burning pixel (%d, %d)", _x, _y);
			}
			if (status != ES_NONE) {
				rterror("rt_raster_iterator: Could not set pixel value");

				_rti_iterator_arg_destroy(_param);
				rt_band_destroy(rtnband);
				rt_raster_destroy(rtnrast);

				return ES_ERROR;
			}
		}
	}

	/* lots of cleanup */
	_rti_iterator_arg_destroy(_param);

	*rtnraster = rtnrast;
	return ES_NONE;
}
예제 #13
0
static int
_rti_iterator_arg_populate(
	_rti_iterator_arg _param,
	rt_iterator itrset, uint16_t itrcount,
	uint16_t distancex, uint16_t distancey,
	int *allnull, int *allempty
) {
	int i = 0;
	int hasband = 0;

	_param->count = itrcount;
	_param->distance.x = distancex;
	_param->distance.y = distancey;
	_param->dimension.columns = distancex * 2 + 1;
	_param->dimension.rows = distancey * 2 + 1;

	/* allocate memory for children */
	_param->raster = rtalloc(sizeof(rt_raster) * itrcount);
	_param->isempty = rtalloc(sizeof(int) * itrcount);
	_param->width = rtalloc(sizeof(int) * itrcount);
	_param->height = rtalloc(sizeof(int) * itrcount);

	_param->offset = rtalloc(sizeof(double *) * itrcount);

	_param->band.rtband = rtalloc(sizeof(rt_band) * itrcount);
	_param->band.hasnodata = rtalloc(sizeof(int) * itrcount);
	_param->band.isnodata = rtalloc(sizeof(int) * itrcount);
	_param->band.nodataval = rtalloc(sizeof(double) * itrcount);
	_param->band.minval = rtalloc(sizeof(double) * itrcount);

	if (
		_param->raster == NULL ||
		_param->isempty == NULL ||
		_param->width == NULL ||
		_param->height == NULL ||
		_param->offset == NULL ||
		_param->band.rtband == NULL ||
		_param->band.hasnodata == NULL ||
		_param->band.isnodata == NULL ||
		_param->band.nodataval == NULL ||
		_param->band.minval == NULL
	) {
		rterror("_rti_iterator_arg_populate: Could not allocate memory for children of _rti_iterator_arg");
		return 0;
	}

	*allnull = 0;
	*allempty = 0;

	/*
		check input rasters
			not empty, band # is valid
			copy raster pointers and set flags
	*/
	for (i = 0; i < itrcount; i++) {
		/* initialize elements */
		_param->raster[i] = NULL;
		_param->isempty[i] = 0;
		_param->width[i] = 0;
		_param->height[i] = 0;

		_param->offset[i] = NULL;

		_param->band.rtband[i] = NULL;
		_param->band.hasnodata[i] = 0;
		_param->band.isnodata[i] = 0;
		_param->band.nodataval[i] = 0;
		_param->band.minval[i] = 0;

		/* set isempty */
		if (itrset[i].raster == NULL) {
			_param->isempty[i] = 1;

			(*allnull)++;
			(*allempty)++;

			continue;
		}
		else if (rt_raster_is_empty(itrset[i].raster)) {
			_param->isempty[i] = 1;

			(*allempty)++;

			continue;
		}

		/* check band number */
		hasband = rt_raster_has_band(itrset[i].raster, itrset[i].nband);
		if (!hasband) {
			if (!itrset[i].nbnodata) {
				rterror("_rti_iterator_arg_populate: Band %d not found for raster %d", itrset[i].nband, i);
				return 0;
			}
			else {
				RASTER_DEBUGF(4, "Band %d not found for raster %d. Using NODATA", itrset[i].nband, i);
			}
		}

		_param->raster[i] = itrset[i].raster;
		if (hasband) {
			_param->band.rtband[i] = rt_raster_get_band(itrset[i].raster, itrset[i].nband);
			if (_param->band.rtband[i] == NULL) {
				rterror("_rti_iterator_arg_populate: Could not get band %d for raster %d", itrset[i].nband, i);
				return 0;
			}

			/* hasnodata */
			_param->band.hasnodata[i] = rt_band_get_hasnodata_flag(_param->band.rtband[i]);

			/* hasnodata = TRUE */
			if (_param->band.hasnodata[i]) {
				/* nodataval */
				rt_band_get_nodata(_param->band.rtband[i], &(_param->band.nodataval[i]));

				/* isnodata */
				_param->band.isnodata[i] = rt_band_get_isnodata_flag(_param->band.rtband[i]);
			}
			/* hasnodata = FALSE */
			else {
				/* minval */
				_param->band.minval[i] = rt_band_get_min_value(_param->band.rtband[i]);
			}
		}

		/* width, height */
		_param->width[i] = rt_raster_get_width(_param->raster[i]);
		_param->height[i] = rt_raster_get_height(_param->raster[i]);

		/* init offset */
		_param->offset[i] = rtalloc(sizeof(double) * 2);
		if (_param->offset[i] == NULL) {
			rterror("_rti_iterator_arg_populate: Could not allocate memory for offsets");
			return 0;
		}
	}

	return 1;
}
예제 #14
0
/**
 * Returns new band with values reclassified
 *
 * @param srcband : the band who's values will be reclassified
 * @param pixtype : pixel type of the new band
 * @param hasnodata : indicates if the band has a nodata value
 * @param nodataval : nodata value for the new band
 * @param exprset : array of rt_reclassexpr structs
 * @param exprcount : number of elements in expr
 *
 * @return a new rt_band or NULL on error
 */
rt_band
rt_band_reclass(
	rt_band srcband, rt_pixtype pixtype,
	uint32_t hasnodata, double nodataval,
	rt_reclassexpr *exprset, int exprcount
) {
	rt_band band = NULL;
	uint32_t width = 0;
	uint32_t height = 0;
	int numval = 0;
	int memsize = 0;
	void *mem = NULL;
	uint32_t src_hasnodata = 0;
	double src_nodataval = 0.0;
	int isnodata = 0;

	int rtn;
	uint32_t x;
	uint32_t y;
	int i;
	double or = 0;
	double ov = 0;
	double nr = 0;
	double nv = 0;
	int do_nv = 0;
	rt_reclassexpr expr = NULL;

	assert(NULL != srcband);
	assert(NULL != exprset && exprcount > 0);
	RASTER_DEBUGF(4, "exprcount = %d", exprcount);
	RASTER_DEBUGF(4, "exprset @ %p", exprset);

	/* source nodata */
	src_hasnodata = rt_band_get_hasnodata_flag(srcband);
	if (src_hasnodata)
		rt_band_get_nodata(srcband, &src_nodataval);

	/* size of memory block to allocate */
	width = rt_band_get_width(srcband);
	height = rt_band_get_height(srcband);
	numval = width * height;
	memsize = rt_pixtype_size(pixtype) * numval;
	mem = (int *) rtalloc(memsize);
	if (!mem) {
		rterror("rt_band_reclass: Could not allocate memory for band");
		return 0;
	}

	/* initialize to zero */
	if (!hasnodata) {
		memset(mem, 0, memsize);
	}
	/* initialize to nodataval */
	else {
		int32_t checkvalint = 0;
		uint32_t checkvaluint = 0;
		double checkvaldouble = 0;
		float checkvalfloat = 0;

		switch (pixtype) {
			case PT_1BB:
			{
				uint8_t *ptr = mem;
				uint8_t clamped_initval = rt_util_clamp_to_1BB(nodataval);
				for (i = 0; i < numval; i++)
					ptr[i] = clamped_initval;
				checkvalint = ptr[0];
				break;
			}
			case PT_2BUI:
			{
				uint8_t *ptr = mem;
				uint8_t clamped_initval = rt_util_clamp_to_2BUI(nodataval);
				for (i = 0; i < numval; i++)
					ptr[i] = clamped_initval;
				checkvalint = ptr[0];
				break;
			}
			case PT_4BUI:
			{
				uint8_t *ptr = mem;
				uint8_t clamped_initval = rt_util_clamp_to_4BUI(nodataval);
				for (i = 0; i < numval; i++)
					ptr[i] = clamped_initval;
				checkvalint = ptr[0];
				break;
			}
			case PT_8BSI:
			{
				int8_t *ptr = mem;
				int8_t clamped_initval = rt_util_clamp_to_8BSI(nodataval);
				for (i = 0; i < numval; i++)
					ptr[i] = clamped_initval;
				checkvalint = ptr[0];
				break;
			}
			case PT_8BUI:
			{
				uint8_t *ptr = mem;
				uint8_t clamped_initval = rt_util_clamp_to_8BUI(nodataval);
				for (i = 0; i < numval; i++)
					ptr[i] = clamped_initval;
				checkvalint = ptr[0];
				break;
			}
			case PT_16BSI:
			{
				int16_t *ptr = mem;
				int16_t clamped_initval = rt_util_clamp_to_16BSI(nodataval);
				for (i = 0; i < numval; i++)
					ptr[i] = clamped_initval;
				checkvalint = ptr[0];
				break;
			}
			case PT_16BUI:
			{
				uint16_t *ptr = mem;
				uint16_t clamped_initval = rt_util_clamp_to_16BUI(nodataval);
				for (i = 0; i < numval; i++)
					ptr[i] = clamped_initval;
				checkvalint = ptr[0];
				break;
			}
			case PT_32BSI:
			{
				int32_t *ptr = mem;
				int32_t clamped_initval = rt_util_clamp_to_32BSI(nodataval);
				for (i = 0; i < numval; i++)
					ptr[i] = clamped_initval;
				checkvalint = ptr[0];
				break;
			}
			case PT_32BUI:
			{
				uint32_t *ptr = mem;
				uint32_t clamped_initval = rt_util_clamp_to_32BUI(nodataval);
				for (i = 0; i < numval; i++)
					ptr[i] = clamped_initval;
				checkvaluint = ptr[0];
				break;
			}
			case PT_32BF:
			{
				float *ptr = mem;
				float clamped_initval = rt_util_clamp_to_32F(nodataval);
				for (i = 0; i < numval; i++)
					ptr[i] = clamped_initval;
				checkvalfloat = ptr[0];
				break;
			}
			case PT_64BF:
			{
				double *ptr = mem;
				for (i = 0; i < numval; i++)
					ptr[i] = nodataval;
				checkvaldouble = ptr[0];
				break;
			}
			default:
			{
				rterror("rt_band_reclass: Unknown pixeltype %d", pixtype);
				rtdealloc(mem);
				return 0;
			}
		}

		/* Overflow checking */
		rt_util_dbl_trunc_warning(
			nodataval,
			checkvalint, checkvaluint,
			checkvalfloat, checkvaldouble,
			pixtype
		);
	}
	RASTER_DEBUGF(3, "rt_band_reclass: width = %d height = %d", width, height);

	band = rt_band_new_inline(width, height, pixtype, hasnodata, nodataval, mem);
	if (!band) {
		rterror("rt_band_reclass: Could not create new band");
		rtdealloc(mem);
		return 0;
	}
	rt_band_set_ownsdata_flag(band, 1); /* we DO own this data!!! */
	RASTER_DEBUGF(3, "rt_band_reclass: new band @ %p", band);

	for (x = 0; x < width; x++) {
		for (y = 0; y < height; y++) {
			rtn = rt_band_get_pixel(srcband, x, y, &ov, &isnodata);

			/* error getting value, skip */
			if (rtn != ES_NONE) {
				RASTER_DEBUGF(3, "Cannot get value at %d, %d", x, y);
				continue;
			}
			RASTER_DEBUGF(4, "(x, y, ov, isnodata) = (%d, %d, %f, %d)", x, y, ov, isnodata);

			do {
				do_nv = 0;

				/* no data*/
				if (hasnodata && isnodata) {
					do_nv = 1;
					break;
				}

				for (i = 0; i < exprcount; i++) {
					expr = exprset[i];

					/* ov matches min and max*/
					if (
						FLT_EQ(expr->src.min, ov) &&
						FLT_EQ(expr->src.max, ov)
					) {
						do_nv = 1;
						break;
					}

					/* process min */
					if ((
						expr->src.exc_min && (
							expr->src.min > ov ||
							FLT_EQ(expr->src.min, ov)
						)) || (
						expr->src.inc_min && (
							expr->src.min < ov ||
							FLT_EQ(expr->src.min, ov)
						)) || (
						expr->src.min < ov
					)) {
						/* process max */
						if ((
							expr->src.exc_max && (
								ov > expr->src.max ||
								FLT_EQ(expr->src.max, ov)
							)) || (
								expr->src.inc_max && (
								ov < expr->src.max ||
								FLT_EQ(expr->src.max, ov)
							)) || (
							ov < expr->src.max
						)) {
							do_nv = 1;
							break;
						}
					}
				}
			}
			while (0);

			/* no expression matched, do not continue */
			if (!do_nv) continue;
			RASTER_DEBUGF(3, "Using exprset[%d] unless NODATA", i);

			/* converting a value from one range to another range
			OldRange = (OldMax - OldMin)
			NewRange = (NewMax - NewMin)
			NewValue = (((OldValue - OldMin) * NewRange) / OldRange) + NewMin
			*/

			/* NODATA */
			if (hasnodata && isnodata) {
				nv = nodataval;
			}
			/*
				"src" min and max is the same, prevent division by zero
				set nv to "dst" min, which should be the same as "dst" max
			*/
			else if (FLT_EQ(expr->src.max, expr->src.min)) {
				nv = expr->dst.min;
			}
			else {
				or = expr->src.max - expr->src.min;
				nr = expr->dst.max - expr->dst.min;
				nv = (((ov - expr->src.min) * nr) / or) + expr->dst.min;

				/* if dst range is from high to low */
				if (expr->dst.min > expr->dst.max) {
					if (nv > expr->dst.min)
						nv = expr->dst.min;
					else if (nv < expr->dst.max)
						nv = expr->dst.max;
				}
				/* if dst range is from low to high */
				else {
					if (nv < expr->dst.min)
						nv = expr->dst.min;
					else if (nv > expr->dst.max)
						nv = expr->dst.max;
				}
			}

			/* round the value for integers */
			switch (pixtype) {
				case PT_1BB:
				case PT_2BUI:
				case PT_4BUI:
				case PT_8BSI:
				case PT_8BUI:
				case PT_16BSI:
				case PT_16BUI:
				case PT_32BSI:
				case PT_32BUI:
					nv = round(nv);
					break;
				default:
					break;
			}

			RASTER_DEBUGF(4, "(%d, %d) ov: %f or: %f - %f nr: %f - %f nv: %f"
				, x
				, y
				, ov
				, (NULL != expr) ? expr->src.min : 0
				, (NULL != expr) ? expr->src.max : 0
				, (NULL != expr) ? expr->dst.min : 0
				, (NULL != expr) ? expr->dst.max : 0
				, nv
			);
			if (rt_band_set_pixel(band, x, y, nv, NULL) != ES_NONE) {
				rterror("rt_band_reclass: Could not assign value to new band");
				rt_band_destroy(band);
				rtdealloc(mem);
				return 0;
			}

			expr = NULL;
		}
	}

	return band;
}
예제 #15
0
/**
 * Returns a new raster with up to four 8BUI bands (RGBA) from
 * applying a colormap to the user-specified band of the
 * input raster.
 *
 * @param raster: input raster
 * @param nband: 0-based index of the band to process with colormap
 * @param colormap: rt_colormap object of colormap to apply to band
 *
 * @return new raster or NULL on error
 */
rt_raster rt_raster_colormap(
	rt_raster raster, int nband,
	rt_colormap colormap
) {
	_rti_colormap_arg arg = NULL;
	rt_raster rtnraster = NULL;
	rt_band band = NULL;
	int i = 0;
	int j = 0;
	int k = 0;

	assert(colormap != NULL);

	/* empty raster */
	if (rt_raster_is_empty(raster))
		return NULL;

	/* no colormap entries */
	if (colormap->nentry < 1) {
		rterror("rt_raster_colormap: colormap must have at least one entry");
		return NULL;
	}

	/* nband is valid */
	if (!rt_raster_has_band(raster, nband)) {
		rterror("rt_raster_colormap: raster has no band at index %d", nband);
		return NULL;
	}

	band = rt_raster_get_band(raster, nband);
	if (band == NULL) {
		rterror("rt_raster_colormap: Could not get band at index %d", nband);
		return NULL;
	}

	/* init internal variables */
	arg = _rti_colormap_arg_init(raster);
	if (arg == NULL) {
		rterror("rt_raster_colormap: Could not initialize internal variables");
		return NULL;
	}

	/* handle NODATA */
	if (rt_band_get_hasnodata_flag(band)) {
		arg->hasnodata = 1;
		rt_band_get_nodata(band, &(arg->nodataval));
	}

	/* # of colors */
	if (colormap->ncolor < 1) {
		rterror("rt_raster_colormap: At least one color must be provided");
		_rti_colormap_arg_destroy(arg);
		return NULL;
	}
	else if (colormap->ncolor > 4) {
		rtinfo("More than four colors indicated. Using only the first four colors");
		colormap->ncolor = 4;
	}

	/* find non-NODATA entries */
	arg->npos = 0;
	arg->pos = rtalloc(sizeof(uint16_t) * colormap->nentry);
	if (arg->pos == NULL) {
		rterror("rt_raster_colormap: Could not allocate memory for valid entries");
		_rti_colormap_arg_destroy(arg);
		return NULL;
	}
	for (i = 0, j = 0; i < colormap->nentry; i++) {
		/* special handling for NODATA entries */
		if (colormap->entry[i].isnodata) {
			/* first NODATA entry found, use it */
			if (arg->nodataentry == NULL)
				arg->nodataentry = &(colormap->entry[i]);
			else
				rtwarn("More than one colormap entry found for NODATA value. Only using first NOTDATA entry");

			continue;
		}

		(arg->npos)++;
		arg->pos[j++] = i;
	}

	/* INTERPOLATE and only one non-NODATA entry */
	if (colormap->method == CM_INTERPOLATE && arg->npos < 2) {
		rtinfo("Method INTERPOLATE requires at least two non-NODATA colormap entries. Using NEAREST instead");
		colormap->method = CM_NEAREST;
	}

	/* NODATA entry but band has no NODATA value */
	if (!arg->hasnodata && arg->nodataentry != NULL) {
		rtinfo("Band at index %d has no NODATA value. Ignoring NODATA entry", nband);
		arg->nodataentry = NULL;
	}

	/* allocate expr */
	arg->nexpr = arg->npos;

	/* INTERPOLATE needs one less than the number of entries */
	if (colormap->method == CM_INTERPOLATE)
		arg->nexpr -= 1;
	/* EXACT requires a no matching expression */
	else if (colormap->method == CM_EXACT)
		arg->nexpr += 1;

	/* NODATA entry exists, add expression */
	if (arg->nodataentry != NULL)
		arg->nexpr += 1;
	arg->expr = rtalloc(sizeof(rt_reclassexpr) * arg->nexpr);
	if (arg->expr == NULL) {
		rterror("rt_raster_colormap: Could not allocate memory for reclass expressions");
		_rti_colormap_arg_destroy(arg);
		return NULL;
	}
	RASTER_DEBUGF(4, "nexpr = %d", arg->nexpr);
	RASTER_DEBUGF(4, "expr @ %p", arg->expr);

	for (i = 0; i < arg->nexpr; i++) {
		arg->expr[i] = rtalloc(sizeof(struct rt_reclassexpr_t));
		if (arg->expr[i] == NULL) {
			rterror("rt_raster_colormap: Could not allocate memory for reclass expression");
			_rti_colormap_arg_destroy(arg);
			return NULL;
		}
	}

	/* reclassify bands */
	/* by # of colors */
	for (i = 0; i < colormap->ncolor; i++) {
		k = 0;

		/* handle NODATA entry first */
		if (arg->nodataentry != NULL) {
			arg->expr[k]->src.min = arg->nodataentry->value;
			arg->expr[k]->src.max = arg->nodataentry->value;
			arg->expr[k]->src.inc_min = 1;
			arg->expr[k]->src.inc_max = 1;
			arg->expr[k]->src.exc_min = 0;
			arg->expr[k]->src.exc_max = 0;

			arg->expr[k]->dst.min = arg->nodataentry->color[i];
			arg->expr[k]->dst.max = arg->nodataentry->color[i];

			arg->expr[k]->dst.inc_min = 1;
			arg->expr[k]->dst.inc_max = 1;
			arg->expr[k]->dst.exc_min = 0;
			arg->expr[k]->dst.exc_max = 0;

			RASTER_DEBUGF(4, "NODATA expr[%d]->src (min, max, in, ix, en, ex) = (%f, %f, %d, %d, %d, %d)",
				k,
				arg->expr[k]->src.min,
				arg->expr[k]->src.max,
				arg->expr[k]->src.inc_min,
				arg->expr[k]->src.inc_max,
				arg->expr[k]->src.exc_min,
				arg->expr[k]->src.exc_max
			);
			RASTER_DEBUGF(4, "NODATA expr[%d]->dst (min, max, in, ix, en, ex) = (%f, %f, %d, %d, %d, %d)",
				k,
				arg->expr[k]->dst.min,
				arg->expr[k]->dst.max,
				arg->expr[k]->dst.inc_min,
				arg->expr[k]->dst.inc_max,
				arg->expr[k]->dst.exc_min,
				arg->expr[k]->dst.exc_max
			);

			k++;
		}

		/* by non-NODATA entry */
		for (j = 0; j < arg->npos; j++) {
			if (colormap->method == CM_INTERPOLATE) {
				if (j == arg->npos - 1)
					continue;

				arg->expr[k]->src.min = colormap->entry[arg->pos[j + 1]].value;
				arg->expr[k]->src.inc_min = 1;
				arg->expr[k]->src.exc_min = 0;

				arg->expr[k]->src.max = colormap->entry[arg->pos[j]].value;
				arg->expr[k]->src.inc_max = 1;
				arg->expr[k]->src.exc_max = 0;

				arg->expr[k]->dst.min = colormap->entry[arg->pos[j + 1]].color[i];
				arg->expr[k]->dst.max = colormap->entry[arg->pos[j]].color[i];

				arg->expr[k]->dst.inc_min = 1;
				arg->expr[k]->dst.exc_min = 0;

				arg->expr[k]->dst.inc_max = 1;
				arg->expr[k]->dst.exc_max = 0;
			}
			else if (colormap->method == CM_NEAREST) {

				/* NOT last entry */
				if (j != arg->npos - 1) {
					arg->expr[k]->src.min = ((colormap->entry[arg->pos[j]].value - colormap->entry[arg->pos[j + 1]].value) / 2.) + colormap->entry[arg->pos[j + 1]].value;
					arg->expr[k]->src.inc_min = 0;
					arg->expr[k]->src.exc_min = 0;
				}
				/* last entry */
				else {
					arg->expr[k]->src.min = colormap->entry[arg->pos[j]].value;
					arg->expr[k]->src.inc_min = 1;
					arg->expr[k]->src.exc_min = 1;
				}

				/* NOT first entry */
				if (j > 0) {
					arg->expr[k]->src.max = arg->expr[k - 1]->src.min;
					arg->expr[k]->src.inc_max = 1;
					arg->expr[k]->src.exc_max = 0;
				}
				/* first entry */
				else {
					arg->expr[k]->src.max = colormap->entry[arg->pos[j]].value;
					arg->expr[k]->src.inc_max = 1;
					arg->expr[k]->src.exc_max = 1;
				}

				arg->expr[k]->dst.min = colormap->entry[arg->pos[j]].color[i];
				arg->expr[k]->dst.inc_min = 1;
				arg->expr[k]->dst.exc_min = 0;

				arg->expr[k]->dst.max = colormap->entry[arg->pos[j]].color[i];
				arg->expr[k]->dst.inc_max = 1;
				arg->expr[k]->dst.exc_max = 0;
			}
			else if (colormap->method == CM_EXACT) {
				arg->expr[k]->src.min = colormap->entry[arg->pos[j]].value;
				arg->expr[k]->src.inc_min = 1;
				arg->expr[k]->src.exc_min = 0;

				arg->expr[k]->src.max = colormap->entry[arg->pos[j]].value;
				arg->expr[k]->src.inc_max = 1;
				arg->expr[k]->src.exc_max = 0;

				arg->expr[k]->dst.min = colormap->entry[arg->pos[j]].color[i];
				arg->expr[k]->dst.inc_min = 1;
				arg->expr[k]->dst.exc_min = 0;

				arg->expr[k]->dst.max = colormap->entry[arg->pos[j]].color[i];
				arg->expr[k]->dst.inc_max = 1;
				arg->expr[k]->dst.exc_max = 0;
			}

			RASTER_DEBUGF(4, "expr[%d]->src (min, max, in, ix, en, ex) = (%f, %f, %d, %d, %d, %d)",
				k,
				arg->expr[k]->src.min,
				arg->expr[k]->src.max,
				arg->expr[k]->src.inc_min,
				arg->expr[k]->src.inc_max,
				arg->expr[k]->src.exc_min,
				arg->expr[k]->src.exc_max
			);

			RASTER_DEBUGF(4, "expr[%d]->dst (min, max, in, ix, en, ex) = (%f, %f, %d, %d, %d, %d)",
				k,
				arg->expr[k]->dst.min,
				arg->expr[k]->dst.max,
				arg->expr[k]->dst.inc_min,
				arg->expr[k]->dst.inc_max,
				arg->expr[k]->dst.exc_min,
				arg->expr[k]->dst.exc_max
			);

			k++;
		}

		/* EXACT has one last expression for catching all uncaught values */
		if (colormap->method == CM_EXACT) {
			arg->expr[k]->src.min = 0;
			arg->expr[k]->src.inc_min = 1;
			arg->expr[k]->src.exc_min = 1;

			arg->expr[k]->src.max = 0;
			arg->expr[k]->src.inc_max = 1;
			arg->expr[k]->src.exc_max = 1;

			arg->expr[k]->dst.min = 0;
			arg->expr[k]->dst.inc_min = 1;
			arg->expr[k]->dst.exc_min = 0;

			arg->expr[k]->dst.max = 0;
			arg->expr[k]->dst.inc_max = 1;
			arg->expr[k]->dst.exc_max = 0;

			RASTER_DEBUGF(4, "expr[%d]->src (min, max, in, ix, en, ex) = (%f, %f, %d, %d, %d, %d)",
				k,
				arg->expr[k]->src.min,
				arg->expr[k]->src.max,
				arg->expr[k]->src.inc_min,
				arg->expr[k]->src.inc_max,
				arg->expr[k]->src.exc_min,
				arg->expr[k]->src.exc_max
			);

			RASTER_DEBUGF(4, "expr[%d]->dst (min, max, in, ix, en, ex) = (%f, %f, %d, %d, %d, %d)",
				k,
				arg->expr[k]->dst.min,
				arg->expr[k]->dst.max,
				arg->expr[k]->dst.inc_min,
				arg->expr[k]->dst.inc_max,
				arg->expr[k]->dst.exc_min,
				arg->expr[k]->dst.exc_max
			);

			k++;
		}

		/* call rt_band_reclass */
		arg->band = rt_band_reclass(band, PT_8BUI, 0, 0, arg->expr, arg->nexpr);
		if (arg->band == NULL) {
			rterror("rt_raster_colormap: Could not reclassify band");
			_rti_colormap_arg_destroy(arg);
			return NULL;
		}

		/* add reclassified band to raster */
		if (rt_raster_add_band(arg->raster, arg->band, rt_raster_get_num_bands(arg->raster)) < 0) {
			rterror("rt_raster_colormap: Could not add reclassified band to output raster");
			_rti_colormap_arg_destroy(arg);
			return NULL;
		}
	}

	rtnraster = arg->raster;
	arg->raster = NULL;
	_rti_colormap_arg_destroy(arg);

	return rtnraster;
}
예제 #16
0
static int
tcp_connect_oncpu(struct tcpcb *tp, int flags, struct mbuf *m,
		  struct sockaddr_in *sin, struct sockaddr_in *if_sin)
{
	struct inpcb *inp = tp->t_inpcb, *oinp;
	struct socket *so = inp->inp_socket;
	struct route *ro = &inp->inp_route;

	oinp = in_pcblookup_hash(&tcbinfo[mycpu->gd_cpuid],
				 sin->sin_addr, sin->sin_port,
				 (inp->inp_laddr.s_addr != INADDR_ANY ?
				  inp->inp_laddr : if_sin->sin_addr),
				inp->inp_lport, 0, NULL);
	if (oinp != NULL) {
		m_freem(m);
		return (EADDRINUSE);
	}
	if (inp->inp_laddr.s_addr == INADDR_ANY)
		inp->inp_laddr = if_sin->sin_addr;
	inp->inp_faddr = sin->sin_addr;
	inp->inp_fport = sin->sin_port;
	inp->inp_cpcbinfo = &tcbinfo[mycpu->gd_cpuid];
	in_pcbinsconnhash(inp);

	/*
	 * We are now on the inpcb's owner CPU, if the cached route was
	 * freed because the rtentry's owner CPU is not the current CPU
	 * (e.g. in tcp_connect()), then we try to reallocate it here with
	 * the hope that a rtentry may be cloned from a RTF_PRCLONING
	 * rtentry.
	 */
	if (!(inp->inp_socket->so_options & SO_DONTROUTE) && /*XXX*/
	    ro->ro_rt == NULL) {
		bzero(&ro->ro_dst, sizeof(struct sockaddr_in));
		ro->ro_dst.sa_family = AF_INET;
		ro->ro_dst.sa_len = sizeof(struct sockaddr_in);
		((struct sockaddr_in *)&ro->ro_dst)->sin_addr =
			sin->sin_addr;
		rtalloc(ro);
	}

	/*
	 * Now that no more errors can occur, change the protocol processing
	 * port to the current thread (which is the correct thread).
	 *
	 * Create TCP timer message now; we are on the tcpcb's owner
	 * CPU/thread.
	 */
	tcp_create_timermsg(tp, &curthread->td_msgport);

	/*
	 * Compute window scaling to request.  Use a larger scaling then
	 * needed for the initial receive buffer in case the receive buffer
	 * gets expanded.
	 */
	if (tp->request_r_scale < TCP_MIN_WINSHIFT)
		tp->request_r_scale = TCP_MIN_WINSHIFT;
	while (tp->request_r_scale < TCP_MAX_WINSHIFT &&
	       (TCP_MAXWIN << tp->request_r_scale) < so->so_rcv.ssb_hiwat
	) {
		tp->request_r_scale++;
	}

	soisconnecting(so);
	tcpstat.tcps_connattempt++;
	tp->t_state = TCPS_SYN_SENT;
	tcp_callout_reset(tp, tp->tt_keep, tcp_keepinit, tcp_timer_keep);
	tp->iss = tcp_new_isn(tp);
	tcp_sendseqinit(tp);
	if (m) {
		ssb_appendstream(&so->so_snd, m);
		m = NULL;
		if (flags & PRUS_OOB)
			tp->snd_up = tp->snd_una + so->so_snd.ssb_cc;
	}

	/*
	 * Close the send side of the connection after
	 * the data is sent if flagged.
	 */
	if ((flags & (PRUS_OOB|PRUS_EOF)) == PRUS_EOF) {
		socantsendmore(so);
		tp = tcp_usrclosed(tp);
	}
	return (tcp_output(tp));
}
예제 #17
0
파일: ddp_output.c 프로젝트: MarginC/kame
int
ddp_route( struct mbuf *m, struct route *ro)
{
    struct sockaddr_at	gate;
    struct elaphdr	*elh;
    struct mbuf		*m0;
    struct at_ifaddr	*aa = NULL;
    struct ifnet	*ifp = NULL;
    u_short		net;

#if 0
    /* Check for net zero, node zero ("myself") */
    if (satosat(&ro->ro_dst)->sat_addr.s_net == ATADDR_ANYNET
        && satosat(&ro->ro_dst)->sat_addr.s_node == ATADDR_ANYNODE) {
	    /* Find the loopback interface */
    }
#endif

    /*
     * if we have a route, find the ifa that refers to this route.
     * I.e The ifa used to get to the gateway.
     */
    if ( (ro->ro_rt == NULL)
    || ( ro->ro_rt->rt_ifa == NULL )
    || ( (ifp = ro->ro_rt->rt_ifa->ifa_ifp) == NULL )) {
	rtalloc(ro);
    }
    if ( (ro->ro_rt != NULL)
    && ( ro->ro_rt->rt_ifa )
    && ( ifp = ro->ro_rt->rt_ifa->ifa_ifp )) {
	net = ntohs(satosat(ro->ro_rt->rt_gateway)->sat_addr.s_net);
	for ( aa = at_ifaddr; aa; aa = aa->aa_next ) {
	    if (((net == 0) || (aa->aa_ifp == ifp)) &&
		    net >= ntohs( aa->aa_firstnet ) &&
		    net <= ntohs( aa->aa_lastnet )) {
		break;
	    }
	}
    } else {
	m_freem( m );
#ifdef NETATALK_DEBUG
	if (ro->ro_rt == NULL)
	    printf ("ddp_route: no ro_rt.\n");
	else if (ro->ro_rt->rt_ifa == NULL)
	    printf ("ddp_route: no ro_rt->rt_ifa\n");
	else
	    printf ("ddp_route: no ro_rt->rt_ifa->ifa_ifp\n");
#endif
	return( ENETUNREACH );
    }

    if ( aa == NULL ) {
#ifdef NETATALK_DEBUG
	printf( "ddp_route: no atalk address found for %s%d\n", 
	    ifp->if_name, ifp->if_unit);
#endif
	m_freem( m );
	return( ENETUNREACH );
    }

    /*
     * if the destination address is on a directly attached node use that,
     * else use the official gateway.
     */
    if ( ntohs( satosat( &ro->ro_dst )->sat_addr.s_net ) >=
	    ntohs( aa->aa_firstnet ) &&
	    ntohs( satosat( &ro->ro_dst )->sat_addr.s_net ) <=
	    ntohs( aa->aa_lastnet )) {
	gate = *satosat( &ro->ro_dst );
    } else {
	gate = *satosat( ro->ro_rt->rt_gateway );
    }

    /*
     * There are several places in the kernel where data is added to
     * an mbuf without ensuring that the mbuf pointer is aligned.
     * This is bad for transition routing, since phase 1 and phase 2
     * packets end up poorly aligned due to the three byte elap header.
     */
    if ( !(aa->aa_flags & AFA_PHASE2) ) {
	MGET( m0, M_TRYWAIT, MT_HEADER );
	if ( m0 == 0 ) {
	    m_freem( m );
	    printf("ddp_route: no buffers\n");
	    return( ENOBUFS );
	}
#ifdef MAC
	mac_create_mbuf_from_mbuf(m, m0);
#endif
	m0->m_next = m;
	/* XXX perhaps we ought to align the header? */
	m0->m_len = SZ_ELAPHDR;
	m = m0;

	elh = mtod( m, struct elaphdr *);
	elh->el_snode = satosat( &aa->aa_addr )->sat_addr.s_node;
	elh->el_type = ELAP_DDPEXTEND;
	elh->el_dnode = gate.sat_addr.s_node;
    }
예제 #18
0
파일: frag6.c 프로젝트: sendwave/xnu
/*
 * Fragment input
 * NOTE: this function is called with the inet6_domain_mutex held from ip6_input.
 * 	 inet6_domain_mutex is protecting he frag6 queue manipulation.
 */
int
frag6_input(struct mbuf **mp, int *offp, int proto)
{
#pragma unused(proto)
    struct mbuf *m = *mp, *t;
    struct ip6_hdr *ip6;
    struct ip6_frag *ip6f;
    struct ip6q *q6;
    struct ip6asfrag *af6, *ip6af, *af6dwn;
    int offset = *offp, nxt, i, next;
    int first_frag = 0;
    int fragoff, frgpartlen;	/* must be larger than u_int16_t */
    struct ifnet *dstifp;
    struct ifaddr *ifa = NULL;
    u_int8_t ecn, ecn0;

#ifdef IN6_IFSTAT_STRICT
    struct route_in6 ro;
    struct sockaddr_in6 *dst;
#endif

    /* Expect 32-bit aligned data pointer on strict-align platforms */
    MBUF_STRICT_DATA_ALIGNMENT_CHECK_32(m);

    ip6 = mtod(m, struct ip6_hdr *);
#ifndef PULLDOWN_TEST
    IP6_EXTHDR_CHECK(m, offset, sizeof(struct ip6_frag), return IPPROTO_DONE);
    ip6f = (struct ip6_frag *)((caddr_t)ip6 + offset);
#else
    IP6_EXTHDR_GET(ip6f, struct ip6_frag *, m, offset, sizeof(*ip6f));
    if (ip6f == NULL)
        return IPPROTO_DONE;
#endif

    dstifp = NULL;
#ifdef IN6_IFSTAT_STRICT
    /* find the destination interface of the packet. */
    bzero(&ro, sizeof (ro));
    dst = (struct sockaddr_in6 *)&ro.ro_dst;
    dst->sin6_family = AF_INET6;
    dst->sin6_len = sizeof (struct sockaddr_in6);
    dst->sin6_addr = ip6->ip6_dst;

    rtalloc((struct route *)&ro);
    if (ro.ro_rt != NULL) {
        RT_LOCK(ro.ro_rt);
        if ((ifa = ro.ro_rt->rt_ifa) != NULL) {
            IFA_ADDREF(ifa);
            dstifp = ((struct in6_ifaddr *)ro.ro_rt->rt_ifa)->ia_ifp;
        }
        RT_UNLOCK(ro.ro_rt);
        rtfree(ro.ro_rt);
        ro.ro_rt = NULL;
    }
#else
    /* we are violating the spec, this is not the destination interface */
    if ((m->m_flags & M_PKTHDR) != 0)
        dstifp = m->m_pkthdr.rcvif;
#endif

    /* jumbo payload can't contain a fragment header */
    if (ip6->ip6_plen == 0) {
        icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER, offset);
        in6_ifstat_inc(dstifp, ifs6_reass_fail);
        if (ifa != NULL)
            IFA_REMREF(ifa);
        return IPPROTO_DONE;
    }

    /*
     * check whether fragment packet's fragment length is
     * multiple of 8 octets.
     * sizeof(struct ip6_frag) == 8
     * sizeof(struct ip6_hdr) = 40
     */
    if ((ip6f->ip6f_offlg & IP6F_MORE_FRAG) &&
            (((ntohs(ip6->ip6_plen) - offset) & 0x7) != 0)) {
        icmp6_error(m, ICMP6_PARAM_PROB,
                    ICMP6_PARAMPROB_HEADER,
                    offsetof(struct ip6_hdr, ip6_plen));
        in6_ifstat_inc(dstifp, ifs6_reass_fail);
        if (ifa != NULL)
            IFA_REMREF(ifa);
        return IPPROTO_DONE;
    }

    ip6stat.ip6s_fragments++;
    in6_ifstat_inc(dstifp, ifs6_reass_reqd);

    /* offset now points to data portion */
    offset += sizeof(struct ip6_frag);

    frag6_doing_reass = 1;

    /*
     * Enforce upper bound on number of fragments.
     * If maxfrag is 0, never accept fragments.
     * If maxfrag is -1, accept all fragments without limitation.
     */
    if (ip6_maxfrags < 0)
        ;
    else if (frag6_nfrags >= (u_int)ip6_maxfrags)
        goto dropfrag;

    for (q6 = ip6q.ip6q_next; q6 != &ip6q; q6 = q6->ip6q_next)
        if (ip6f->ip6f_ident == q6->ip6q_ident &&
                IN6_ARE_ADDR_EQUAL(&ip6->ip6_src, &q6->ip6q_src) &&
                IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &q6->ip6q_dst))
            break;

    if (q6 == &ip6q) {
        /*
         * the first fragment to arrive, create a reassembly queue.
         */
        first_frag = 1;

        /*
         * Enforce upper bound on number of fragmented packets
         * for which we attempt reassembly;
         * If maxfrag is 0, never accept fragments.
         * If maxfrag is -1, accept all fragments without limitation.
         */
        if (ip6_maxfragpackets < 0)
            ;
        else if (frag6_nfragpackets >= (u_int)ip6_maxfragpackets)
            goto dropfrag;
        frag6_nfragpackets++;
        q6 = (struct ip6q *)_MALLOC(sizeof(struct ip6q), M_FTABLE,
                                    M_DONTWAIT);
        if (q6 == NULL)
            goto dropfrag;
        bzero(q6, sizeof(*q6));

        frag6_insque(q6, &ip6q);

        /* ip6q_nxt will be filled afterwards, from 1st fragment */
        q6->ip6q_down	= q6->ip6q_up = (struct ip6asfrag *)q6;
#ifdef notyet
        q6->ip6q_nxtp	= (u_char *)nxtp;
#endif
        q6->ip6q_ident	= ip6f->ip6f_ident;
        q6->ip6q_ttl 	= IPV6_FRAGTTL;
        q6->ip6q_src	= ip6->ip6_src;
        q6->ip6q_dst	= ip6->ip6_dst;
        q6->ip6q_ecn	=
            (ntohl(ip6->ip6_flow) >> 20) & IPTOS_ECN_MASK;
        q6->ip6q_unfrglen = -1;	/* The 1st fragment has not arrived. */

        q6->ip6q_nfrag	= 0;
    }
예제 #19
0
/*
 * Connect from a socket to a specified address.
 * Both address and port must be specified in argument slpx.
 * If don't have a local address for this socket yet,
 * then pick one.
 */
int Lpx_PCB_connect( struct lpxpcb *lpxp,
                    struct sockaddr *nam,
                    struct proc *td )
{
    struct lpx_ifaddr *ia = NULL;
    register struct sockaddr_lpx *slpx = (struct sockaddr_lpx *)nam;
    register struct lpx_addr *dst;
    register struct route *ro;
    struct ifnet *ifp;
	struct lpx_addr laddr;

    DEBUG_CALL(4, ("Lpx_PCB_connect\n"));

    if (nam == NULL) {
      return(EINVAL);
    }

    DEBUG_CALL(2, ("slpx->sipx_addr.x_net = %x\n", slpx->sipx_addr.x_net));

    if (slpx->slpx_family != AF_LPX)
        return (EAFNOSUPPORT);
    if (slpx->slpx_port == 0 || lpx_nullhost(slpx->sipx_addr))
        return (EADDRNOTAVAIL);
    /*
     * If we haven't bound which network number to use as ours,
     * we will use the number of the outgoing interface.
     * This depends on having done a routing lookup, which
     * we will probably have to do anyway, so we might
     * as well do it now.  On the other hand if we are
     * sending to multiple destinations we may have already
     * done the lookup, so see if we can use the route
     * from before.  In any case, we only
     * chose a port number once, even if sending to multiple
     * destinations.
     */
    ro = &lpxp->lpxp_route;
    dst = &satolpx_addr(ro->ro_dst);
    if (lpxp->lpxp_socket->so_options & SO_DONTROUTE)
        goto flush;
    if (!lpx_neteq(lpxp->lpxp_lastdst, slpx->sipx_addr))
        goto flush;
    if (!lpx_hosteq(lpxp->lpxp_lastdst, slpx->sipx_addr)) {
        if (ro->ro_rt != NULL && !(ro->ro_rt->rt_flags & RTF_HOST)) {
            /* can patch route to avoid rtalloc */
            *dst = slpx->sipx_addr;
        } else {
    flush:
        if (ro->ro_rt != NULL)
                RTFREE(ro->ro_rt);
            ro->ro_rt = NULL;
        }
    }/* else cached route is ok; do nothing */
    lpxp->lpxp_lastdst = slpx->sipx_addr;
    if ((lpxp->lpxp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/
        (ro->ro_rt == NULL || ro->ro_rt->rt_ifp == NULL)) {
            /* No route yet, so try to acquire one */
            ro->ro_dst.sa_family = AF_LPX;
            ro->ro_dst.sa_len = sizeof(ro->ro_dst);
            *dst = slpx->sipx_addr;
            dst->x_port = 0;
            rtalloc(ro);
			
			DEBUG_CALL(4, ("Lpx_PCB_connect RO 1\n"));
        }
    if (lpx_neteqnn(lpxp->lpxp_laddr.x_net, lpx_zeronet)) {
        
		DEBUG_CALL(4, ("Lpx_PCB_connect RO 2\n"));
		
		/* 
         * If route is known or can be allocated now,
         * our src addr is taken from the i/f, else punt.
         */

        /*
         * If we found a route, use the address
         * corresponding to the outgoing interface
         */
        ia = NULL;
        if (ro->ro_rt != NULL && (ifp = ro->ro_rt->rt_ifp) != NULL)
            for (ia = lpx_ifaddr; ia != NULL; ia = ia->ia_next)
                if (ia->ia_ifp == ifp)
                    break;
        if (ia == NULL) {
           // u_short fport = slpx->sipx_addr.x_port;
            //slpx->sipx_addr.x_port = 0;
            ia = (struct lpx_ifaddr *)
                ifa_ifwithaddr((struct sockaddr *)&lpxp->lpxp_laddr);
            //slpx->sipx_addr.x_port = fport;

			// BUG BUG BUG!!! 
            if (ia == NULL)
                ia = Lpx_CTL_iaonnetof(&slpx->sipx_addr);
            if (ia == NULL)
                ia = lpx_ifaddr;
            if (ia == NULL)
                return (EADDRNOTAVAIL);
        }
        lpxp->lpxp_laddr.x_net = satolpx_addr(ia->ia_addr).x_net;
    }
    if (lpx_nullhost(lpxp->lpxp_laddr)) {
		
		DEBUG_CALL(4, ("Lpx_PCB_connect RO 3\n"));
		
        /* 
         * If route is known or can be allocated now,
         * our src addr is taken from the i/f, else punt.
         */

        /*
         * If we found a route, use the address
         * corresponding to the outgoing interface
         */
        ia = NULL;
        if (ro->ro_rt != NULL && (ifp = ro->ro_rt->rt_ifp) != NULL)
            for (ia = lpx_ifaddr; ia != NULL; ia = ia->ia_next)
                if (ia->ia_ifp == ifp)
                    break;
        if (ia == NULL) {
            u_short fport = slpx->sipx_addr.x_port;
            slpx->sipx_addr.x_port = 0;
            ia = (struct lpx_ifaddr *)
                ifa_ifwithdstaddr((struct sockaddr *)slpx);
            slpx->sipx_addr.x_port = fport;
			// BUG BUG BUG!!!
			
            if (ia == NULL)
                ia = Lpx_CTL_iaonnetof(&slpx->sipx_addr);
            if (ia == NULL)
                ia = lpx_ifaddr;
            if (ia == NULL)
                return (EADDRNOTAVAIL);
        }
        lpxp->lpxp_laddr.x_host = satolpx_addr(ia->ia_addr).x_host;
    }

	DEBUG_CALL(4, ("Lpx_PCB_connect: 4.\n"));

	laddr.x_port = lpxp->lpxp_lport;

    if (Lpx_PCB_lookup(&slpx->sipx_addr, &laddr, 0))
        return (EADDRINUSE);
    if (lpxp->lpxp_lport == 0)
        Lpx_PCB_bind(lpxp, (struct sockaddr *)NULL, td);

    /* XXX just leave it zero if we can't find a route */

    lpxp->lpxp_faddr = slpx->sipx_addr;
    /* Includes lpxp->lpxp_fport = slpx->slpx_port; */
    return (0);
}
예제 #20
0
static int
at_pcbconnect(struct ddpcb *ddp, struct sockaddr *addr, struct proc *p)
{
    struct sockaddr_at	*sat = (struct sockaddr_at *)addr;
    struct route	*ro;
    struct at_ifaddr	*aa = 0;
    struct ifnet	*ifp;
    u_short		hintnet = 0, net;

    if (sat->sat_family != AF_APPLETALK) {
	return(EAFNOSUPPORT);
    }

    /*
     * Under phase 2, network 0 means "the network".  We take "the
     * network" to mean the network the control block is bound to.
     * If the control block is not bound, there is an error.
     */
    if ( sat->sat_addr.s_net == ATADDR_ANYNET
		&& sat->sat_addr.s_node != ATADDR_ANYNODE ) {
	if ( ddp->ddp_lsat.sat_port == ATADDR_ANYPORT ) {
	    return( EADDRNOTAVAIL );
	}
	hintnet = ddp->ddp_lsat.sat_addr.s_net;
    }

    ro = &ddp->ddp_route;
    /*
     * If we've got an old route for this pcb, check that it is valid.
     * If we've changed our address, we may have an old "good looking"
     * route here.  Attempt to detect it.
     */
    if ( ro->ro_rt ) {
	if ( hintnet ) {
	    net = hintnet;
	} else {
	    net = sat->sat_addr.s_net;
	}
	aa = 0;
	if ((ifp = ro->ro_rt->rt_ifp) != NULL) {
	    for ( aa = at_ifaddr; aa; aa = aa->aa_next ) {
		if ( aa->aa_ifp == ifp &&
			ntohs( net ) >= ntohs( aa->aa_firstnet ) &&
			ntohs( net ) <= ntohs( aa->aa_lastnet )) {
		    break;
		}
	    }
	}
	if ( aa == NULL || ( satosat( &ro->ro_dst )->sat_addr.s_net !=
		( hintnet ? hintnet : sat->sat_addr.s_net ) ||
		satosat( &ro->ro_dst )->sat_addr.s_node !=
		sat->sat_addr.s_node )) {
	    RTFREE( ro->ro_rt );
	    ro->ro_rt = (struct rtentry *)0;
	}
    }

    /*
     * If we've got no route for this interface, try to find one.
     */
    if ( ro->ro_rt == (struct rtentry *)0 ||
	 ro->ro_rt->rt_ifp == (struct ifnet *)0 ) {
	ro->ro_dst.sa_len = sizeof( struct sockaddr_at );
	ro->ro_dst.sa_family = AF_APPLETALK;
	if ( hintnet ) {
	    satosat( &ro->ro_dst )->sat_addr.s_net = hintnet;
	} else {
	    satosat( &ro->ro_dst )->sat_addr.s_net = sat->sat_addr.s_net;
	}
	satosat( &ro->ro_dst )->sat_addr.s_node = sat->sat_addr.s_node;
	rtalloc( ro );
    }

    /*
     * Make sure any route that we have has a valid interface.
     */
    aa = 0;
    if ( ro->ro_rt && ( ifp = ro->ro_rt->rt_ifp )) {
	for ( aa = at_ifaddr; aa; aa = aa->aa_next ) {
	    if ( aa->aa_ifp == ifp ) {
		break;
	    }
	}
    }
    if ( aa == 0 ) {
	return( ENETUNREACH );
    }

    ddp->ddp_fsat = *sat;
    if ( ddp->ddp_lsat.sat_port == ATADDR_ANYPORT ) {
	return(at_pcbsetaddr(ddp, (struct sockaddr *)0, p));
    }
    return( 0 );
}
예제 #21
0
int
ns_output(struct mbuf *m0, ...)
{
	struct route *ro;
	int flags;
	struct idp *idp = mtod(m0, struct idp *);
	struct ifnet *ifp = 0;
	int error = 0;
	struct route idproute;
	struct sockaddr_ns *dst;
	va_list ap;

	va_start(ap, m0);
	ro = va_arg(ap, struct route *);
	flags = va_arg(ap, int);
	va_end(ap);

	if (ns_hold_output) {
		if (ns_lastout) {
			(void)m_free(ns_lastout);
		}
		ns_lastout = m_copy(m0, 0, (int)M_COPYALL);
	}
	/*
	 * Route packet.
	 */
	if (ro == 0) {
		ro = &idproute;
		bzero((caddr_t)ro, sizeof (*ro));
	}
	dst = satosns(&ro->ro_dst);
	if (ro->ro_rt == 0) {
		dst->sns_family = AF_NS;
		dst->sns_len = sizeof (*dst);
		dst->sns_addr = idp->idp_dna;
		dst->sns_addr.x_port = 0;
		/*
		 * If routing to interface only,
		 * short circuit routing lookup.
		 */
		if (flags & NS_ROUTETOIF) {
			struct ns_ifaddr *ia = ns_iaonnetof(&idp->idp_dna);

			if (ia == 0) {
				error = ENETUNREACH;
				goto bad;
			}
			ifp = ia->ia_ifp;
			goto gotif;
		}
		rtalloc(ro);
	} else if ((ro->ro_rt->rt_flags & RTF_UP) == 0) {
		/*
		 * The old route has gone away; try for a new one.
		 */
		rtfree(ro->ro_rt);
		ro->ro_rt = NULL;
		rtalloc(ro);
	}
	if (ro->ro_rt == 0 || (ifp = ro->ro_rt->rt_ifp) == 0) {
		error = ENETUNREACH;
		goto bad;
	}
	ro->ro_rt->rt_use++;
	if (ro->ro_rt->rt_flags & (RTF_GATEWAY|RTF_HOST))
		dst = satosns(ro->ro_rt->rt_gateway);
gotif:

	/*
	 * Look for multicast addresses and
	 * and verify user is allowed to send
	 * such a packet.
	 */
	if (dst->sns_addr.x_host.c_host[0]&1) {
		if ((ifp->if_flags & IFF_BROADCAST) == 0) {
			error = EADDRNOTAVAIL;
			goto bad;
		}
		if ((flags & NS_ALLOWBROADCAST) == 0) {
			error = EACCES;
			goto bad;
		}
	}

	if (htons(idp->idp_len) <= ifp->if_mtu) {
		ns_output_cnt++;
		if (ns_copy_output) {
			ns_watch_output(m0, ifp);
		}
		error = (*ifp->if_output)(ifp, m0, snstosa(dst), ro->ro_rt);
		goto done;
	} else error = EMSGSIZE;


bad:
	if (ns_copy_output) {
		ns_watch_output(m0, ifp);
	}
	m_freem(m0);
done:
	if (ro == &idproute && (flags & NS_ROUTETOIF) == 0 && ro->ro_rt) {
		RTFREE(ro->ro_rt);
		ro->ro_rt = 0;
	}
	return (error);
}
예제 #22
0
static int wdbUdpSockRcvfrom
    (
    WDB_COMM_ID commId,
    caddr_t	addr,
    uint_t	len,
    struct sockaddr_in *pSockAddr,
    struct timeval *tv
    )
    {
    uint_t		nBytes;
    int 		addrLen = sizeof (struct sockaddr_in);
    struct fd_set	readFds;
    static struct route	theRoute;
    struct sockaddr_in 	sockAddr;

    /* wait for data with a timeout */

    FD_ZERO (&readFds);
    FD_SET  (wdbUdpSock, &readFds);

    if (select (wdbUdpSock + 1, &readFds, NULL, NULL, tv) < 0)
        {
        printErr ("wdbUdpSockLib: select failed!\n");
        return (0);
        }

    if (!FD_ISSET (wdbUdpSock, &readFds))
        {
        return (0);             /* select timed out */
        }

    /* read the data */

    nBytes   = recvfrom (wdbUdpSock, addr, len, 0,
			(struct sockaddr  *)pSockAddr, &addrLen);

    if (nBytes < 4)
	return (0);

    /* 
     * The following is a fix for SPR #4645 (the agent does
     * not report the correct MTU to the host). We lower
     * the value of the global variable wdbCommMtu if a packet
     * arrives via an interface with a smaller MTU.
     *
     * XXX This fix has some problems:
     *   1) it uses rtalloc, which is not an approved interface.
     *      Note: rtalloc doesn't seem to like having the port number
     *            in the socket address.
     *   2) it assumes all agent packets arrive via the same netif.
     *   3) it doesn't take into account intermediate MTUs in a WAN.
     * The right fix for (3) would be to use an MTU-discovey
     * algorithm (e.g. send larger and larger IP datagrams with the
     * "don't fragment" flag until an ICMP error is returned).
     */

    if (theRoute.ro_rt == NULL)
	{
	sockAddr = *pSockAddr;
	sockAddr.sin_port = 0;
	theRoute.ro_dst = * (struct sockaddr *) &sockAddr;
	rtalloc (&theRoute);
	if (theRoute.ro_rt != NULL)
	    {
	    if (wdbCommMtu > theRoute.ro_rt->rt_ifp->if_mtu)
		wdbCommMtu = theRoute.ro_rt->rt_ifp->if_mtu;
	    rtfree (theRoute.ro_rt);
	    }
	}

    return (nBytes);
    }