Ejemplo n.º 1
0
/*
** get an integer sized parameter from click
*/
int ssoGetInt(int sockfd, int optname, int *optval, socklen_t *optlen)
{
	if (ssoCheckSize(optlen, sizeof(int)) < 0)
		return -1;

	xia::XSocketMsg xsm;
	xsm.set_type(xia::XGETSOCKOPT);
	unsigned seq = seqNo(sockfd);
	xsm.set_sequence(seq);
	xia::X_Getsockopt_Msg *msg = xsm.mutable_x_getsockopt();
	msg->set_opt_type(optname);

	if (click_send(sockfd, &xsm) < 0) {
		LOGF("Error talking to Click: %s", strerror(errno));
		return -1;
	}

	xsm.Clear();
	if (click_reply(sockfd, seq, &xsm) < 0) {
		LOGF("Error getting status from Click: %s", strerror(errno));
		return -1;
	}

	msg = xsm.mutable_x_getsockopt();
	*optval = msg->int_opt();
	*optlen = sizeof(int);

	// FIXME: get return code from protobuf
	return 0;
}
Ejemplo n.º 2
0
/*!
** @tell if this node is an XIA-IPv4 dual-stack router
**
**
** @param sockfd an Xsocket (may be of any type XSOCK_STREAM, etc...)
**
** @returns 1 if this is an XIA-IPv4 dual-stack router 
** @returns 0 if this is an XIA router
** @returns -1 on failure with errno set
**
*/
int XisDualStackRouter(int sockfd) {
  	int rc;
  	char UDPbuf[MAXBUFLEN];
  	
 	if (getSocketType(sockfd) == XSOCK_INVALID) {
   	 	LOG("The socket is not a valid Xsocket");
   	 	errno = EBADF;
  		return -1;
 	}

 	xia::XSocketMsg xsm;
  	xsm.set_type(xia::XISDUALSTACKROUTER);
  
  	if ((rc = click_send(sockfd, &xsm)) < 0) {
		LOGF("Error talking to Click: %s", strerror(errno));
		return -1;
  	}

	if ((rc = click_reply(sockfd, UDPbuf, sizeof(UDPbuf))) < 0) {
		LOGF("Error retrieving status from Click: %s", strerror(errno));
		return -1;
	}

	xia::XSocketMsg xsm1;
	xsm1.ParseFromString(UDPbuf);
	if (xsm1.type() == xia::XISDUALSTACKROUTER) {
		xia::X_IsDualStackRouter_Msg *_msg = xsm1.mutable_x_isdualstackrouter();
		rc = _msg->flag();
	} else {
		rc = -1;
	}	
	return rc;
	 
}
Ejemplo n.º 3
0
/*!
** @brief Receive data from an Xsocket
**
** Xrecv() retrieves data from a connected Xsocket of type XSOCK_STREAM.
** sockfd must have previously been connected via Xaccept() or
** Xconnect().
**
** Xrecv() does not currently have a non-blocking mode, and will block
** until a data is available on sockfd. However, the standard socket API
** calls select and poll may be used with the Xsocket. Either function
** will deliver a readable event when a new connection is attempted and
** you may then call Xrecv() to get the data.
**
** NOTE: in cases where more data is received than specified by the caller,
** the excess data will be stored at the API level. Subsequent Xrecv calls
** return the stored data until it is drained, and will then resume requesting
** data from the transport.
**
** @param sockfd The socket to receive with
** @param rbuf where to put the received data
** @param len maximum amount of data to receive. the amount of data
** returned may be less than len bytes.
** @param flags (This is not currently used but is kept to be compatible
** with the standard sendto socket call).
**
** @returns the number of bytes received, which may be less than the number
** requested by the caller
** @returns -1 on failure with errno set to an error compatible with the standard
** recv call.
*/
int Xrecv(int sockfd, void *rbuf, size_t len, int flags)
{
	int numbytes;
	char UDPbuf[MAXBUFLEN];
	
	if (flags) {
		errno = EOPNOTSUPP;
		return -1;
	}

	if (len == 0)
		return 0;

	if (!rbuf) {
		LOG("buffer pointer is null!\n");
		errno = EFAULT;
		return -1;
	}

	if (validateSocket(sockfd, XSOCK_STREAM, EOPNOTSUPP) < 0) {
		LOGF("Socket %d must be a stream socket", sockfd);
		return -1;
	}

	if (!isConnected(sockfd)) {
		LOGF("Socket %d is not connected", sockfd);
		errno = ENOTCONN;
		return -1;
	}

	// see if we have bytes leftover from a previous Xrecv call
	if ((numbytes = getSocketData(sockfd, (char *)rbuf, len)) > 0)
		return numbytes;

	if ((numbytes = click_reply(sockfd, UDPbuf, sizeof(UDPbuf))) < 0) {
		LOGF("Error retrieving recv data from Click: %s", strerror(errno));
		return -1;
	}

	std::string str(UDPbuf, numbytes);
	xia::XSocketMsg xsm;

	xsm.ParseFromString(str);

	xia::X_Recv_Msg *msg = xsm.mutable_x_recv();
	unsigned paylen = msg->payload().size();
	const char *payload = msg->payload().c_str();

	if (paylen <= len)
		memcpy(rbuf, payload, paylen);
	else {
		// we got back more data than the caller requested
		// stash the extra away for subsequent Xrecv calls
		memcpy(rbuf, payload, len);
		paylen -= len;
		setSocketData(sockfd, payload + len, paylen);
		paylen = len;
	}
	return paylen;
}
Ejemplo n.º 4
0
/*!
** @brief Block waiting for notification that the network interface has changed state.
**
** WARNING: THIS IS A STOPGAP API THAT WILL BE REPLACED ONCE WE DETERMIN WHAT
** THE LONGERM NOTIFICATION MECHANISM LOOKS LIKE. BE PREPARED FOR THIS CALL
** TO BE DEPRECATED OR MODIFIED
**
** Blocks and waits for for click to return a status when the XHCP client daemon
** changes the AD or other network parameters. Multiple applications or threads
** may call this API, and all will be nofitied when a change occurs.
**
** Do not call Xfork while blocking on this function. Only one of the processes will
** properly recieve the notification.
**
** @returns 0 on success
** @returns -1 on error with errno set
*/
int Xnotify(void)
{
	int rc = -1;
	int sock = 0;

	xia::XSocketMsg xsm;
	//xia::X_Notify_Msg *xnm;
	xsm.set_type(xia::XNOTIFY);
	xsm.set_sequence(0);

	sock = MakeApiSocket(SOCK_DGRAM);

	if ((rc = click_send(sock, &xsm)) < 0) {
		LOGF("Error talking to Click: %s", strerror(errno));
		goto done;

	} else if ((rc = click_reply(sock, 0, &xsm)) < 0) {
		LOGF("Error getting status from Click: %s", strerror(errno));
	}

done:
	if (sock > 0) {
		freeSocketState(sock);
		(_f_close)(sock);
	}

	return rc;
}
Ejemplo n.º 5
0
int XreadNameServerDAG(int sockfd, char *nsDAG) {
  	int rc;
  	char UDPbuf[MAXBUFLEN];
  	
 	if (getSocketType(sockfd) == XSOCK_INVALID) {
   	 	LOG("The socket is not a valid Xsocket");
   	 	errno = EBADF;
  		return -1;
 	}

 	xia::XSocketMsg xsm;
  	xsm.set_type(xia::XREADNAMESERVERDAG);
  
  	if ((rc = click_control(sockfd, &xsm)) < 0) {
		LOGF("Error talking to Click: %s", strerror(errno));
		return -1;
  	}

	if ((rc = click_reply(sockfd, UDPbuf, sizeof(UDPbuf))) < 0) {
		LOGF("Error retrieving status from Click: %s", strerror(errno));
		return -1;
	}

	xia::XSocketMsg xsm1;
	xsm1.ParseFromString(UDPbuf);
	if (xsm1.type() == xia::XREADNAMESERVERDAG) {
		xia::X_ReadNameServerDag_Msg *_msg = xsm1.mutable_x_readnameserverdag();
		strcpy(nsDAG, (_msg->dag()).c_str() );
	} else {
		rc = -1;
	}	
	return rc;
	 
}
Ejemplo n.º 6
0
/*!
** @tell if this node is an XIA-IPv4 dual-stack router
**
**
** @param sockfd an Xsocket (may be of any type XSOCK_STREAM, etc...)
**
** @returns 1 if this is an XIA-IPv4 dual-stack router
** @returns 0 if this is an XIA router
** @returns -1 on failure with errno set
**
*/
int XisDualStackRouter(int sockfd) {
  	int rc;

 	if (getSocketType(sockfd) == XSOCK_INVALID) {
   	 	LOG("The socket is not a valid Xsocket");
   	 	errno = EBADF;
  		return -1;
 	}

 	xia::XSocketMsg xsm;
  	xsm.set_type(xia::XISDUALSTACKROUTER);
  	unsigned seq = seqNo(sockfd);
  	xsm.set_sequence(seq);

  	if ((rc = click_send(sockfd, &xsm)) < 0) {
		LOGF("Error talking to Click: %s", strerror(errno));
		return -1;
  	}

	xia::XSocketMsg xsm1;
	if ((rc = click_reply(sockfd, seq, &xsm1)) < 0) {
		LOGF("Error retrieving status from Click: %s", strerror(errno));
		return -1;
	}

	if (xsm1.type() == xia::XISDUALSTACKROUTER) {
		xia::X_IsDualStackRouter_Msg *_msg = xsm1.mutable_x_isdualstackrouter();
		rc = _msg->flag();
	} else {
		rc = -1;
	}
	return rc;

}
Ejemplo n.º 7
0
/*!
** @brief retrieve the AD and HID associated with this socket.
**
** The HID and AD are assigned by the XIA stack. This call retrieves them
** so that they can be used for creating DAGs or for other purposes in user
** applications.
**
** @param sockfd an Xsocket (may be of any type XSOCK_STREAM, etc...)
** @param localhostAD buffer to receive the AD for this host
** @param lenAD size of the localhostAD buffer
** @param localhostHID buffer to receive the HID for this host
** @param lenHID size of the localhostHID buffer
**
** @returns 0 on success
** @returns -1 on failure with errno set
**
*/
int XreadLocalHostAddr(int sockfd, char *localhostAD, unsigned lenAD, char *localhostHID, unsigned lenHID, char *local4ID, unsigned len4ID) {
  	int rc;

 	if (getSocketType(sockfd) == XSOCK_INVALID) {
		LOGF("The socket %d is not a valid Xsocket", sockfd);
   	 	errno = EBADF;
  		return -1;
 	}

	if (localhostAD == NULL || localhostHID == NULL || local4ID == NULL) {
		LOG("NULL pointer!");
		errno = EINVAL;
		return -1;
	}

 	xia::XSocketMsg xsm;
  	xsm.set_type(xia::XREADLOCALHOSTADDR);
  	unsigned seq = seqNo(sockfd);
	xsm.set_sequence(seq);

  	if ((rc = click_send(sockfd, &xsm)) < 0) {
		LOGF("Error talking to Click: %s", strerror(errno));
		return -1;
  	}

	xia::XSocketMsg xsm1;
	if ((rc = click_reply(sockfd, seq, &xsm1)) < 0) {
		LOGF("Error retrieving status from Click: %s", strerror(errno));
		return -1;
	}

	if (xsm1.type() == xia::XREADLOCALHOSTADDR) {
		xia::X_ReadLocalHostAddr_Msg *_msg = xsm1.mutable_x_readlocalhostaddr();
		strncpy(localhostAD, (_msg->ad()).c_str(), lenAD);
		strncpy(localhostHID, (_msg->hid()).c_str(), lenHID);
		strncpy(local4ID, (_msg->ip4id()).c_str(), len4ID);
		// put in null terminators in case buffers were too short
		localhostAD[lenAD - 1] = 0;
		localhostHID[lenHID - 1] = 0;
		local4ID[len4ID - 1] = 0;
		rc = 0;
	} else {
		LOG("XreadlocalHostAddr: ERROR: Invalid response for XREADLOCALHOSTADDR request");
		rc = -1;
	}
	return rc;

}
Ejemplo n.º 8
0
/*!
** @brief retrieve the AD and HID associated with this socket.
**
** The HID and AD are assigned by the XIA stack. This call retrieves them
** so that they can be used for creating DAGs or for other purposes in user
** applications.
**
** @param sockfd an Xsocket (may be of any type XSOCK_STREAM, etc...)
** @param localhostAD buffer to receive the AD for this host
** @param lenAD size of the localhostAD buffer
** @param localhostHID buffer to receive the HID for this host
** @param lenHID size of the localhostHID buffer
**
** @returns 0 on success
** @returns -1 on failure with errno set
**
*/
int XreadLocalHostAddr(int sockfd, char *localhostAD, unsigned lenAD, char *localhostHID, unsigned lenHID, char *local4ID, unsigned len4ID) {
  	int rc;
  	char UDPbuf[MAXBUFLEN];
  	
 	if (getSocketType(sockfd) == XSOCK_INVALID) {
   	 	LOG("The socket is not a valid Xsocket");
   	 	errno = EBADF;
  		return -1;
 	}

	if (localhostAD == NULL || localhostHID == NULL || local4ID == NULL) {
		LOG("NULL pointer!");
		errno = EINVAL;
		return -1;
	}

 	xia::XSocketMsg xsm;
  	xsm.set_type(xia::XREADLOCALHOSTADDR);
  
  	if ((rc = click_send(sockfd, &xsm)) < 0) {
		LOGF("Error talking to Click: %s", strerror(errno));
		return -1;
  	}

	if ((rc = click_reply(sockfd, UDPbuf, sizeof(UDPbuf))) < 0) {
		LOGF("Error retrieving status from Click: %s", strerror(errno));
		return -1;
	}

	xia::XSocketMsg xsm1;
	xsm1.ParseFromString(UDPbuf);
	if (xsm1.type() == xia::XREADLOCALHOSTADDR) {
		xia::X_ReadLocalHostAddr_Msg *_msg = xsm1.mutable_x_readlocalhostaddr();
		strncpy(localhostAD, (_msg->ad()).c_str(), lenAD);
		strncpy(localhostHID, (_msg->hid()).c_str(), lenHID);
		strncpy(local4ID, (_msg->ip4id()).c_str(), len4ID);
		// put in null terminators in case buffers were too short
		localhostAD[lenAD - 1] = 0;
		localhostHID[lenHID - 1] = 0;
		local4ID[len4ID - 1] = 0;
		rc = 0;
	} else {
		rc = -1;
	}	
	return rc;
	 
}
Ejemplo n.º 9
0
/*!
** @brief Get the full DAG of the local socket.
**
** @param sockfd An Xsocket of type SOCK_STREAM
** @param dag A sockaddr to hold the returned DAG.
** @param len On input contans the size of the sockaddr,
**  on output contains sizeof(sockaddr_x).
**
** @returns 0 on success
** @returns -1 on failure with errno set
** @returns errno = EFAULT if dag is NULL
** @returns errno = EOPNOTSUPP if sockfd is not of type XSSOCK_STREAM
** @returns errno = ENOTCONN if sockfd is not in a connected state
**
*/
int Xgetsockname(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
{
	int rc;
	int flags;
	char buf[MAXBUFLEN];

	if (!addr || !addrlen) {
		LOG("pointer is null!\n");
		errno = EFAULT;
		return -1;
	}

	if (*addrlen < sizeof(sockaddr_x)) {
		errno = EINVAL;
		return -1;
	}

	if (validateSocket(sockfd, XSOCK_STREAM, EOPNOTSUPP) < 0) {
		LOG("Xgetsockname is only valid with stream sockets.");
		return -1;
	}

	if (connState(sockfd) != CONNECTED) {
		LOGF("Socket %d is not connected", sockfd);
		errno = ENOTCONN;
		return -1;
	}

	xia::XSocketMsg xsm;
	xsm.set_type(xia::XGETSOCKNAME);

	flags = Xfcntl(sockfd, F_GETFL);
	fcntl(sockfd, F_SETFL, flags & ~O_NONBLOCK);

	// send the protobuf containing the user data to click
    if ((rc = click_send(sockfd, &xsm)) < 0) {
		LOGF("Error talking to Click: %s", strerror(errno));
		fcntl(sockfd, F_SETFL, flags);
		return -1;
	}

	// get the dag
	// FIXME: loop here till done or error
	if ((rc = click_reply(sockfd, xia::XGETSOCKNAME, buf, sizeof(buf))) < 0) {
		LOGF("Error retrieving status from Click: %s", strerror(errno));
		fcntl(sockfd, F_SETFL, flags);
		return -1;
	}

	fcntl(sockfd, F_SETFL, flags);

	xsm.Clear();
	xsm.ParseFromString(buf);

	if (xsm.type() != xia::XGETSOCKNAME) {
		LOGF("error: expected %d, got %d\n", xia::XGETPEERNAME, xsm.type());
		return -1;
	}

	xia::X_GetSockname_Msg *msg = xsm.mutable_x_getsockname();

	Graph g(msg->dag().c_str());

	g.fill_sockaddr((sockaddr_x*)addr);
	*addrlen = sizeof(sockaddr_x);

	return 0;
}
Ejemplo n.º 10
0
/*!
** @brief Xsocket implemention of the standard getsockopt function.
**
** Xgetsockopt is used to retrieve the settings of the underlying Xsocket
** in the Click layer. It does not access the settings of the actual
** socket passed in which is used by the API to communicate with Click.
**
** Supported Options:
**	\n XOPT_HLIM	Retrieves the 'hop limit' element of the XIA header as an integer value
**	\n XOPT_NEXT_PROTO Gets the next proto field in the XIA header
**
** @param sockfd	The control socket
** @param optname	The socket option to set (currently must be IP_TTL)
** @param optval	A pointer to the value to retrieve
** @param optlen	A pointer to the length of optval. On input this
**	should be set to the length of the data passed in. If optlen is not
**	large enough, Xgetsockopt will set it to the size needed and return
**	with errno set to EINVAL. If larger than needed, Xgetsockopt will set
**	it to the actual length of the returned data.
**
** @returns  0 on success
** @returns -1 on error with errno set
** @returns errno values:
** @returns EBADF: The socket descriptor is invalid
** @returns EINVAL: Either optval is null, or optlen is invalid, or optval is out of range
** @returns ENOPROTOOPT: the specified optname is not recognized
*/
int Xgetsockopt(int sockfd, int optname, void *optval, socklen_t *optlen)
{
	char buf[MAXBUFLEN];

	/* TODO: we may need to check the type of the socket at some point, but for now
	** treat them all the same as far as options go.
	**
	** Should we add a validate socket function that takes the expected type?
	*/
	if (getSocketType(sockfd) == XSOCK_INVALID) {
		errno = EBADF;
		return -1;
	}

	if (!optval || !optlen) {
		errno = EINVAL;
		return -1;
	}

	xia::XSocketMsg xsm;
	xsm.set_type(xia::XGETSOCKOPT);
	xia::X_Getsockopt_Msg *msg = xsm.mutable_x_getsockopt();
	msg->set_opt_type(optname);

	switch (optname) {
		case SO_ERROR:
		{
			if (*optlen < sizeof(int)) {
				*optlen = sizeof(int);
				errno = EINVAL;
				return -1;
			}

			*(int *)optval = getError(sockfd);
			break;
		}

		case XOPT_HLIM:
		{
			if (*optlen < sizeof(int)) {
				*optlen = sizeof(int);
				errno = EINVAL;
				return -1;
			}

			int flags = fcntl(sockfd, F_GETFL);
			fcntl(sockfd, F_SETFL, flags &= ~O_NONBLOCK);

			if (click_send(sockfd, &xsm) < 0) {
				LOGF("Error talking to Click: %s", strerror(errno));
				fcntl(sockfd, F_SETFL, flags);
				return -1;
			}

			xia::XSocketMsg reply;
			if (click_reply(sockfd, xia::XGETSOCKOPT, buf, sizeof(buf)) < 0) {
				LOGF("Error getting status from Click: %s", strerror(errno));
				fcntl(sockfd, F_SETFL, flags);
				return -1;
			}

			fcntl(sockfd, F_SETFL, flags);

			xsm.Clear();
			xsm.ParseFromString(buf);
			xia::X_Getsockopt_Msg *msg = xsm.mutable_x_getsockopt();

			int hlim = msg->int_opt();
			*optlen = sizeof(int);
			*(int *)optval = hlim;
			break;
		}

		case XOPT_NEXT_PROTO:
		{
			if (*optlen < sizeof(int)) {
				*optlen = sizeof(int);
				errno = EINVAL;
				return -1;
			}

			int flags = fcntl(sockfd, F_GETFL);
			fcntl(sockfd, F_SETFL, flags &= ~O_NONBLOCK);

			if (click_send(sockfd, &xsm) < 0) {
				fcntl(sockfd, F_SETFL, flags);
				LOGF("Error talking to Click: %s", strerror(errno));
				return -1;
			}

			xia::XSocketMsg reply;
			if (click_reply(sockfd, xia::XGETSOCKOPT, buf, sizeof(buf)) < 0) {
				fcntl(sockfd, F_SETFL, flags);
				LOGF("Error getting status from Click: %s", strerror(errno));
				return -1;
			}

			fcntl(sockfd, F_SETFL, flags);

			xsm.Clear();
			xsm.ParseFromString(buf);
			xia::X_Getsockopt_Msg *msg = xsm.mutable_x_getsockopt();

			int nxt = msg->int_opt();
			*optlen = sizeof(int);
			*(int *)optval = nxt;
			break;
		}

		default:
			errno = ENOPROTOOPT;
			return -1;
	}

	return 0;
}
Ejemplo n.º 11
0
/*!
** @brief waits for one of a set of Xsockets to become ready to perform I/O.
**
** Xsocket specific version of poll. See the poll man page for more detailed information.
** This function is compatible with Xsockets as well as regular sockets and fds. Xsockets
** are polled via click, and regular sockets and fds are handled through the normal poll
** API.
**
** #include <sys/poll.h>
**
** @param ufds array of pollfds indicating sockets and states to check for
** @param nfds number of entries in ufds
** \n socket ids specified as 0 or negative will be ignored
** \n valid flags for events are POLLIN | POLLOUT | POLLERR
** \n revents contains the returned flags and can be POLLIN | POLLOUT | POLLERR | POLLINVAL | POLLHUP
** @param timeout number of milliseconds to wait for an event to happen
**
** @returns 0 if timeout occured
** @returns a positive integer indicating the number of sockets with return events
** @retuns -1 with errno set if an error occured
*/
int Xpoll(struct pollfd *ufds, unsigned nfds, int timeout)
{
	int rc;
	int sock = 0;
	int nxfds = 0;
	int xrc = 0;

	if (nfds == 0) {
		// it's just a timer
		return 	(_f_poll)(ufds, nfds, timeout);

	} else if (ufds == NULL) {
		errno = EFAULT;
		return -1;
	}

	struct pollfd *rfds = (struct pollfd*)calloc(nfds + 1, sizeof(struct pollfd));
	Sock2Port *s2p = (Sock2Port*)calloc(nfds, sizeof(Sock2Port));

	memcpy(rfds, ufds, nfds * sizeof(struct pollfd));

	xia::XSocketMsg xsm;
	xia::X_Poll_Msg *pollMsg = xsm.mutable_x_poll();

	for (unsigned i = 0; i < nfds; i++) {

		ufds[i].revents = 0;

		if (ufds[i].fd > 0 && (ufds[i].events != 0)) {
			if (getSocketType(ufds[i].fd) != XSOCK_INVALID) {
				// add the Xsocket to the xpoll struct
				// TODO: should this work for Content sockets?

				xia::X_Poll_Msg::PollFD *pfd = pollMsg->add_pfds();

				// find the port number associated with this Xsocket
				struct sockaddr_in sin;
				socklen_t slen = sizeof(sin);
				(_f_getsockname)(ufds[i].fd, (struct sockaddr*)&sin, &slen);
				// LOGF("XSocket! sock %d, port %d, flags %x\n", ufds[i].fd, ntohs(sin.sin_port), ufds[i].events);

				pfd->set_port(sin.sin_port);
				s2p[i].fd = ufds[i].fd;
				s2p[i].port = sin.sin_port;

				// FIXME: hack for curl - think about better ways to deal with this
				if (ufds[i].events & POLLRDNORM || ufds[i].events & POLLRDBAND) {
					ufds[i].events |= POLLIN;
				}

				if (ufds[i].events & POLLWRNORM || ufds[i].events & POLLWRBAND) {
					ufds[i].events |= POLLOUT;
				}

				pfd->set_flags(ufds[i].events);

				nxfds++;

				// disable the socket in the real poll list
				rfds[i].fd = -rfds[i].fd;

			} else {
				s2p[i].fd = s2p[i].port = 0;
			}
		}
	}

	if (nxfds == 0) {
		// there are no Xsocket to poll for, just do a straight poll with the original data
		rc = (_f_poll)(ufds, nfds, timeout);
		goto done;
	}

	xsm.set_type(xia::XPOLL);
	xsm.set_sequence(0);
	pollMsg->set_nfds(nxfds);
	pollMsg->set_type(xia::X_Poll_Msg::DOPOLL);

	// Real sockets in the Poll message are set to 0. They are left in the list to make processing easier

	// the rfds (Real fd) list has the fds flipped negative for the xsockets so they will be ignored
	//  for the same reason

	sock = MakeApiSocket(SOCK_DGRAM);

	click_send(sock, &xsm);

	// now we need to do a real poll
	// it will trigger once click generates an xpoll event or pone of the external fds has an event

	// add the poll control socket
	rfds[nfds].fd = sock;
	rfds[nfds].events = POLLIN;
	rfds[nfds].revents = 0;

	rc = (_f_poll)(rfds, nfds + 1, timeout);

	if (rc > 0) {
		// go through and update the fds in the output
		for (unsigned i = 0; i < nfds; i++)
			ufds[i].revents = rfds[i].revents;

		// now do click events if any
		if (rfds[nfds].revents != 0) {

			if (click_reply(sock, 0, &xsm) < 0) {
				LOG("Error getting data from Click\n");
				rc = -1;
				goto done;
			}

			xia::X_Poll_Msg *pout = xsm.mutable_x_poll();
			xrc = pout->nfds();

			// loop thru returned xsockets
			for (int i = 0; i < xrc; i++) {
				const xia::X_Poll_Msg::PollFD& pfd_out = pout->pfds(i);
				unsigned port = pfd_out.port();
				unsigned flags = pfd_out.flags();

				//LOGF("poll returned x%0x for %d\n", flags, port);

				// find the associated socket
				int fd = 0;
				for (unsigned j = 0; j < nfds; j++) {
					if (port == s2p[j].port) {
						fd = s2p[j].fd;
						break;
					}
				}

				// find the socket in the original poll & update the revents field
				for (unsigned j = 0; j < nfds; j++) {
					if (ufds[j].fd == fd) {

						// if a non-blocking connect is in progress, set connected state appropriately
						if (flags && POLLOUT) {
							setNBConnState(fd);
						}

						// FIXME: hack for curl - think about better ways to deal with this
						if (flags && POLLIN && (ufds[i].events &  POLLRDNORM || ufds[i].events & POLLRDBAND)) {
							flags |= (POLLRDNORM | POLLRDBAND);
						}

						if (flags && POLLOUT && (ufds[i].events & POLLWRNORM || ufds[i].events & POLLWRBAND)) {
							flags |= (POLLWRNORM | POLLWRBAND);
						}

						ufds[j].revents = flags;
						break;
					}
				}
			}

		} else {
			// we need to tell click to cancel the Xpoll event
			xsm.Clear();
			xsm.set_type(xia::XPOLL);
			xsm.set_sequence(0);
			pollMsg = xsm.mutable_x_poll();
			pollMsg->set_type(xia::X_Poll_Msg::CANCEL);
			pollMsg->set_nfds(0);

			click_send(sock, &xsm);
		}

		// rc is the number of fds returned by poll + plus number of sockets found by click
		//  minus the event for the control socket
		if (xrc > 0)
			rc += xrc - 1;
	}

done:
	int eno = errno;
	if (sock > 0) {
		freeSocketState(sock);
		(_f_close)(sock);
	}
	free(rfds);
	free(s2p);
	errno = eno;
	return rc;
}
Ejemplo n.º 12
0
/*!
** @brief waits for one of a set of Xsockets to become ready to perform I/O.
**
** Xsocket specific version of select. See the select man page for more detailed information.
** This function is compatible with Xsockets as well as regular sockets and fds. Xsockets
** are handled with the Xpoll APIs via click, and regular sockets and fds are handled 
** through the normal select API.
**
** @param ndfs The highest socket number contained in the fd_sets plus 1
** @param readfds fd_set containing sockets to check for readability
** @param writefds fd_set containing sockets to check for writability
** @param errorfds fd_set containing sockets to check for errors
** @param timeout amount of time to wait for a socket to change state
** @returns greater than 0, number of sockets ready
** @returns 0 if the timeout expired
** @returns less than 0 if an error occurs
** @warning this function is only valid for stream and datagram sockets. 
*/
int Xselect(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *timeout)
{
	fd_set rfds;
	fd_set wfds;
	fd_set efds;
	fd_set immediate_fds;
	unsigned nx = 0;
	int xrc = 0;
	int sock = 0;
	int largest = 0;
	int count = 0;
	int rc = 0;

	FD_ZERO(&rfds);
	FD_ZERO(&wfds);
	FD_ZERO(&efds);
	FD_ZERO(&immediate_fds);

	// if the fd sets are sparse, this will waste space especially if nfds is large
	Sock2Port *s2p = (Sock2Port*)calloc(nfds, sizeof(Sock2Port));

	// create protobuf message
	xia::XSocketMsg xsm;
	xsm.set_type(xia::XPOLL);
	xsm.set_sequence(0);
	xia::X_Poll_Msg *pollMsg = xsm.mutable_x_poll();
	pollMsg->set_type(xia::X_Poll_Msg::DOPOLL);

	for (int i = 0; i < nfds; i++) {

		int flags = 0;
		int r = 0;
		int w = 0;
		int e = 0;

		if (readfds && FD_ISSET(i, readfds)) {
			flags |= POLLIN;
			r = i;
		}
		if (writefds && FD_ISSET(i, writefds)) {
			flags |= POLLOUT;
			w = i;
		}
		if (errorfds && FD_ISSET(i, errorfds)) {
			flags |= POLLERR;
			e = i;
		}

		// is it an xsocket
		if (flags && getSocketType(i) != XSOCK_INVALID) {

			// we found an Xsocket, do the Xpoll magic
			nx++;

			xia::X_Poll_Msg::PollFD *pfd = pollMsg->add_pfds();

			// find the port number associated with this Xsocket
			struct sockaddr_in sin;
			socklen_t slen = sizeof(sin);
			(_f_getsockname)(i, (struct sockaddr*)&sin, &slen);
			//printf("sock %d, port %d, flags %x\n", ufds[i].fd, ntohs(sin.sin_port), ufds[i].events);

			pfd->set_port(sin.sin_port);
			s2p[i].fd = i;
			s2p[i].port = sin.sin_port;

			pfd->set_flags(flags);

		} else {
			if (i > largest)
				largest = i;

			// it's a regular fd, put it into the select fdsets
			if (r != 0)
				FD_SET(i, &rfds);
			if (w != 0)
				FD_SET(i, &wfds);
			if (e != 0)
				FD_SET(i, &efds);

			s2p[i].fd = s2p[i].port = 0;
		}
	}

	if (nx == 0) {
		// there were no xsockets in the FD_SETS, just do a normal select
		rc = (_f_select)(nfds, readfds, writefds, errorfds, timeout);
		goto done;
	}

	sock = MakeApiSocket(SOCK_DGRAM);

	pollMsg->set_type(xia::X_Poll_Msg::DOPOLL);
	pollMsg->set_nfds(nx);

	click_send(sock, &xsm);

	// add the control socket to the select read fdset
	if (sock > largest)
		largest = sock;
	FD_SET(sock, &rfds);

	rc = (_f_select)(largest + 1, &rfds, (writefds != NULL ? &wfds : NULL), (errorfds != NULL ? &efds : NULL), timeout);

	// reset the bit arrays for the return to caller
	if (readfds)
		FD_ZERO(readfds);
	if (writefds)
		FD_ZERO(writefds);
	if (errorfds)
		FD_ZERO(errorfds);

	// fill the fdsets in with the triggered sockets/fds
	count = 0;
	if (rc > 0) {

		// get the regular fds
		for (int i = 0; i < largest; i++) {
			if (i != sock) {
				if (readfds && FD_ISSET(i, &rfds)) {
					FD_SET(i, readfds);
					count++;
				}
				if (writefds && FD_ISSET(i, &wfds)) {
					FD_SET(i, writefds);
					count++;
				}
				if (errorfds && FD_ISSET(i, &efds)) {
					FD_SET(i, errorfds);
					count++;
				}
			}
		}

		if (FD_ISSET(sock, &rfds)) {
			// we have Xsockets data

			xsm.Clear();
			if (click_reply(sock, 0, &xsm) < 0) {
				LOG("Error getting data from Click\n");
				rc = -1;
				goto done;
			}

			xia::X_Poll_Msg *pout = xsm.mutable_x_poll();
			xrc = pout->nfds();

			for (int i = 0; i < xrc; i++) {
				const xia::X_Poll_Msg::PollFD& pfd_out = pout->pfds(i);
				int flags = pfd_out.flags();
				unsigned port = pfd_out.port();

				int fd = 0;
				for (int j = 0; j < nfds; j++) {
					if (port == s2p[j].port) {
						fd = s2p[j].fd;
						break;
					}
				}

				// printf("socket %d out flags:%08x\n", pfds[i].fd, pfds[i].revents);
				if (readfds && (flags & POLLIN)) {
					FD_SET(fd, readfds);
					count++;
				}
				if (writefds && (flags & POLLOUT)) {
					FD_SET(fd, writefds);
					count++;

					// if a non-blocking connect is in progress, set connected state appropriately
					setNBConnState(fd);
				}
				if (errorfds && (flags & POLLERR)) {
					FD_SET(fd, errorfds);
					count++;
				}
			}

		} else {
			// we need to tell click to cancel the Xpoll event
			XselectCancel(sock);
		}
	} else {
		XselectCancel(sock);
	}

done:
	int eno = errno;
	if (sock > 0) {
		freeSocketState(sock);
		(_f_close)(sock);
	}
	free(s2p);
	errno = eno;
	return (rc <= 0 ? rc : count);
}
Ejemplo n.º 13
0
/*
** @brief Checks the status for each of the requested CIDs.
**
** XgetChunkStatuses updates the cDAGv list with the status for each
** of the requested CIDs. An overall status value is returned, and
** the cDAGv list can be examined to check the status of each individual CID.
**
** @note This function Should be called after calling XrequestChunk() or 
** XrequestChunks(). Otherwise the content chunk will never be loaded into
** the content cache and will result in a REQUEST_FAILED error.
**
** @param sockfd - the control socket (must be of type XSOCK_CHUNK)
** @param cDAGv - list of CIDs to check. On return, also  contains the status for 
** each of the specified CIDs.
** @param numCIDs - number of CIDs in cDAGv
**
** @returns a bitfield indicating the status of the chunks.
** @returns if return equals READY_TO_READ, all chunks are avilable to read
** @returns otherwise the return value contains a bitfield of status codes
** @returns if REQUEST_FAILED is set, one or more of the requested chunks could not be found
** @returns if WAITING_FOR_CHUNK is set, one or more of the requested chunks is still in transit
** @returns if INVALID_HASH is set, the content of one or more chunks does not match the hash in the CID
** @returns REQUEST_FAILED if one of the specified chunks has not been requested,
** @returns -1  if a socket error occurs. In that case errno is set with the appropriate code.
*/
int XgetChunkStatuses(int sockfd, ChunkStatus *statusList, int numCIDs)
{
	int rc;
	char buffer[MAXBUFLEN];
	
	const char *buf="CID list request status query";//Maybe send more useful information here.

	if (validateSocket(sockfd, XSOCK_CHUNK, EAFNOSUPPORT) < 0) {
		LOGF("Socket %d must be a chunk socket\n", sockfd);
		return -1;
	}
	
	if (numCIDs == 0)
		return 0;

	if (!statusList) {
		LOG("statusList is null!");
		errno = EFAULT;
		return -1;
	}

	// protobuf message
	xia::XSocketMsg xsm;
	xsm.set_type(xia::XGETCHUNKSTATUS);

	xia::X_Getchunkstatus_Msg *x_getchunkstatus_msg = xsm.mutable_x_getchunkstatus();
  
	for (int i = 0; i < numCIDs; i++) {
		if (statusList[i].cid) {
			x_getchunkstatus_msg->add_dag(statusList[i].cid);
		} else {
			LOGF("cDAGv[%d] is NULL", i);
		}
	}

	if (x_getchunkstatus_msg->dag_size() == 0) {
		LOG("no dags were specified!");
		errno = EFAULT;
		return -1;
	}

	x_getchunkstatus_msg->set_payload((const char*)buf, strlen(buf) + 1);

	std::string p_buf;
	xsm.SerializeToString(&p_buf);

	if ((rc = click_send(sockfd, &xsm)) < 0) {
		LOGF("Error talking to Click: %s", strerror(errno));
		return -1;
	}
     	 
	if ((rc = click_reply(sockfd, buffer, sizeof(buffer))) < 0) {
		LOGF("Error retrieving status from Click: %s", strerror(errno));
		return -1;
	}

	xia::XSocketMsg xia_socket_msg1;
	xia_socket_msg1.ParseFromString(buffer);

	if (xia_socket_msg1.type() == xia::XGETCHUNKSTATUS) {
		
		xia::X_Getchunkstatus_Msg *x_getchunkstatus_msg1 = xia_socket_msg1.mutable_x_getchunkstatus();
		    
		char status_tmp[100];
		int status_for_all = READY_TO_READ;
		
		for (int i = 0; i < numCIDs; i++) {
			strcpy(status_tmp, x_getchunkstatus_msg1->status(i).c_str());
		    	
			if (strcmp(status_tmp, "WAITING") == 0) {
				statusList[i].status = WAITING_FOR_CHUNK;
				
				status_for_all &= ~READY_TO_READ;
				status_for_all |= WAITING_FOR_CHUNK;

			} else if (strcmp(status_tmp, "INVALID_HASH") == 0) {
				statusList[i].status = INVALID_HASH;

				status_for_all &= ~READY_TO_READ;
				status_for_all |= INVALID_HASH;
		    		
			} else if (strcmp(status_tmp, "READY") == 0) {
				statusList[i].status = READY_TO_READ;
		    	
			} else if (strcmp(status_tmp, "FAILED") == 0) {
				statusList[i].status = REQUEST_FAILED;

				status_for_all &= ~READY_TO_READ;
				status_for_all |= REQUEST_FAILED;
			
			} else {
				statusList[i].status = REQUEST_FAILED;
				status_for_all &= ~READY_TO_READ;
				status_for_all |= REQUEST_FAILED;
			}
		}
		    
		rc = status_for_all;
	} else
		rc = -1;
	
	return rc; 
}