Esempio n. 1
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;
	 
}
Esempio n. 2
0
int Protocol::getBoundAddress(
	AWE::Socket::Address* pAddress
	)
{
	AWE_CHECK_PTR( m_pSocket );

	// retrieve the bound port
	struct sockaddr_storage kSS;
	socklen_t iSockLength( static_cast< int >( sizeof( kSS ) ) );

	int iResult(
		::getsockname(
			m_pSocket->getSocket(),
			(struct sockaddr*)&kSS,
			&iSockLength
			)
		);

	if ( iResult != 0 )
	{
		return iResult;
	}

	struct sockaddr* pAddr = (struct sockaddr*)&kSS;
	socklen_t iAddrLength( static_cast< socklen_t >( sizeof( kSS ) ) );

	// convert to string
	char pAddressStr[ NI_MAXHOST ];
	char pPortStr[ NI_MAXSERV ];

	memset( pAddressStr, 0, NI_MAXHOST );
	memset( pPortStr, 0, NI_MAXSERV );

	iResult = ::getnameinfo(
		pAddr,
		iAddrLength,
		pAddressStr,
		NI_MAXHOST,
		pPortStr,
		NI_MAXSERV,
		NI_NUMERICHOST | NI_NUMERICSERV
		);

	if ( iResult != 0 )
	{
		return iResult;
	}

	int iSock( atoi( pPortStr ) );

	// convert string to addrinfo
	return pAddress->resolve(
		pAddr->sa_family,
		getProtocol(),
		getSocketType(),
		AI_NUMERICHOST,
		pAddressStr,
		iSock
		);
}
Esempio n. 3
0
int Protocol::createSocket( int iAF )
{
	AWE_CHECK_PTR( m_pSocket );
	AWE_ASSERT( m_pSocket->getSocket() == AWE_INVALID_SOCKET );

	switch( iAF )
	{
		// supported address families
		case AF_UNSPEC:
		case AF_INET:
#if defined(AWE_IPV6_ENABLED)
		case AF_INET6:
#endif
		{
			// do nothing
		} break;

		// unsupported address families
		default:
		{
			AWE_THROW( ProtocolException, "Unsupported address family" );
		} break;
	}

	return m_pSocket->createSocket( iAF, getSocketType(), getProtocol() );
}
Esempio n. 4
0
int XupdateAD(int sockfd, char *newad, char *new4id) {
  int rc;

  if (!newad) {
    LOG("new ad is NULL!");
    errno = EFAULT;
    return -1;
  }

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

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

  xia::X_Changead_Msg *x_changead_msg = xsm.mutable_x_changead();
  x_changead_msg->set_ad(newad);
  x_changead_msg->set_ip4id(new4id);
  
  if ((rc = click_send(sockfd, &xsm)) < 0) {
		LOGF("Error talking to Click: %s", strerror(errno));
		return -1;
  }

  return 0;
}
Esempio n. 5
0
int XupdateNameServerDAG(int sockfd, char *nsDAG) {
  int rc;

  if (!nsDAG) {
    LOG("new ad is NULL!");
    errno = EFAULT;
    return -1;
  }

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

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

  xia::X_Updatenameserverdag_Msg *x_updatenameserverdag_msg = xsm.mutable_x_updatenameserverdag();
  x_updatenameserverdag_msg->set_dag(nsDAG);
  
  if ((rc = click_control(sockfd, &xsm)) < 0) {
		LOGF("Error talking to Click: %s", strerror(errno));
		return -1;
  }

  return 0;
}
Esempio n. 6
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;
	 
}
Esempio n. 7
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;

}
Esempio n. 8
0
/*!
** @brief Close an Xsocket.
**
** Causes the XIA transport to tear down the underlying XIA socket state and
** also closes the UDP control socket used to talk to the transport.
**
** @param sockfd	The control socket
**
** @returns 0 on success
** @returns -1 on error with errno set to a value compatible with the standard
** close API call.
*/
int Xclose(int sockfd)
{
	xia::XSocketCallType type;
	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::XCLOSE);

	// set back to blocking just in case
	Xfcntl(sockfd, F_SETFL, 0);

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

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

	close(sockfd);
	freeSocketState(sockfd);
	return rc;
}
Esempio n. 9
0
/*!
** @brief Bind an Xsocket to a DAG.
**
** Assign the specified DAG to to the Xsocket referred to by sockfd. The DAG's
** final intent should be a valid SID.
** 
** It is necessary to assign a local DAG using Xbind() before an XSOCK_STREAM
** socket may receive connections (see accept()).
**
** An un-bound Xsocket will be given a random local SID that is currently not
** available to the application.
**
** @param sockfd	The control socket
** @param addr		The source service (local) DAG
** @param addrlen	The size of addr
**
** @returns 0 on success
** @returns -1 on error with errno set to an error compatible with those
** retuned by the standard bind call.
*/
int Xbind(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
{
	xia::XSocketCallType type;
	int rc;

	if (addrlen == 0) {
		errno = EINVAL;
		return -1;
	}

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

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

	Graph g((sockaddr_x*)addr);
	if (g.num_nodes() <= 0) {
		errno = EINVAL;
		return -1;
	}

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

	xia::X_Bind_Msg *x_bind_msg = xsm.mutable_x_bind();
	x_bind_msg->set_sdag(g.dag_string().c_str());

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

	// process the reply from click
	if ((rc = click_reply2(sockfd, &type)) < 0) {
		LOGF("Error getting status from Click: %s", strerror(errno));
		return -1;
	}

	if (type != xia::XBIND) {
		// something bad happened
		LOGF("Expected type %d, got %d", xia::XBIND, type);
		errno = ECLICKCONTROL;
		rc = -1;
	}

	// if rc is negative, errno will be set with an appropriate error code
	return rc;
}
Esempio n. 10
0
int validateSocket(int sock, int stype, int err)
{
	int st = getSocketType(sock);
	if (st == stype || st == XSOCK_RAW)
		return 0;
	else if (st == XSOCK_INVALID)
		errno = EBADF;
	else
		errno = err;

	return -1;
}
Esempio n. 11
0
/*!
** @brief Bind a Chunk Xsocket to a DAG.
**
** Assign the specified DAG to to the Xsocket referred to by sockfd. The DAG's
** final intent should be a valid SID. This only works with chunk sockets.
** 
**
** An un-bound Xsocket will be given a random local SID that is currently not
** available to the application.
**
** @param sockfd	The control socket
** @param addr		The source service (local) DAG
** @param addrlen	The size of addr
**
** @returns 0 on success
** @returns -1 on error with errno set to an error compatible with those
** retuned by the standard bind call.
*/
int XbindPush(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
{
	int rc;

	if (addrlen == 0) {
		errno = EINVAL;
		return -1;
	}

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

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

	Graph g((sockaddr_x*)addr);
	if (g.num_nodes() <= 0) {
		errno = EINVAL;
		return -1;
	}

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

	xia::X_BindPush_Msg *x_bindpush_msg = xsm.mutable_x_bindpush();
	x_bindpush_msg->set_sdag(g.dag_string().c_str());

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

	// process the reply from click
	if ((rc = click_status(sockfd, seq)) < 0) {
		LOGF("Error getting status from Click: %s", strerror(errno));
	}

	// if rc is negative, errno will be set with an appropriate error code
	return rc;
}
Esempio n. 12
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;

}
Esempio n. 13
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;
	 
}
Esempio n. 14
0
int Protocol::resolveAddress(
	Address* pAddress,
	AWE::Core::String const& sAddress,
	AWE::uint16 iPort
	)
{
	AWE_CHECK_PTR( pAddress );

	return pAddress->resolve(
		AF_UNSPEC,
		getProtocol(),
		getSocketType(),
		0,
		sAddress,
		iPort
		);
}
Esempio n. 15
0
int Protocol::resolveLocalAddress(
	Address* pAddress,
	AWE::uint16 iPort,
	int iAF
	)
{
	AWE_CHECK_PTR( pAddress );

	return pAddress->resolve(
		iAF,
		getProtocol(),
		getSocketType(),
		AI_PASSIVE,		// local address
		"",
		iPort
		);
}
Esempio n. 16
0
/*!
** @brief manipulate Xsocket
**
** Performs  one  of the operations described below on the open file descriptor sockfd.
** The operation is determined by cmd.
**
** Xfcntl() can take an optional third argument.  Whether or not this argument is required is
** determined by cmd.  The required argument type is indicated in parentheses after each cmd
** name (in most cases, the required type is int, and we identify  the  argument  using  the
** name arg), or void is specified if the argument is not required.
**
** File status flags
**	F_GETFL (void)
**		Get the file access mode and the file status flags; arg is ignored.
**
**	F_SETFL (int)
**		Currently only O_NONBLOCK is allowed
**
** @param sockfd a file descriptor create by Xsocket()
** @param cmd the command to execute
** @param arg the flag to set if cmd == F_GETFL, otherwise omitted
** @returns  socket flags if cmd == F_GETFL
** @returns 0 on success if cmd == F_SETFL
** @returns -1 on error with errno set to an error compatible with those
** returned by the standard fcntl call.
*/
int Xfcntl(int sockfd, int cmd, ...)
{
	int rc = 0;

	if (getSocketType(sockfd) == XSOCK_INVALID) {
		errno = EBADF;
		return -1;
	}

	switch(cmd) {
		case F_GETFL:
			rc = (_f_fcntl)(sockfd, cmd);
			if (rc >= 0 && isBlocking(sockfd))
				rc |= O_NONBLOCK;
			break;

		case F_SETFL:
		{
			va_list args;
			va_start(args, cmd);
			int f = va_arg(args, int);
			va_end(args);

			int block = (f & O_NONBLOCK) ? false : true;

			LOGF("Blocking set to %s", block ? "true" : "false");
			setBlocking(sockfd, block);
			rc = 0;

			if (f & ~O_NONBLOCK) {
				LOGF("unsupported flag(s) found (%s) ignoring...", fcntlFlags(f & ~O_NONBLOCK));
			}
			break;
		}
		default:
			LOGF("Invalid command specified to Xfcntl: %08x", cmd);
			rc = -1;
			break;
	}

	return rc;
}
Esempio n. 17
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);
}
Esempio n. 18
0
/* The config string should look like:
 * "action=AAA,type=TTT,description=DDD,sndHWM=SSS,rcvHWM=RRR,subscribe='xxx',subscribe='yyy'"
 * 
 */
static rsRetVal parseConfig(char* config, socket_info* info) {
    int nsubs = 0;
    
    char* binding;
    char* ptr1;
    for (binding = strtok_r(config, ",", &ptr1);
         binding != NULL;
         binding = strtok_r(NULL, ",", &ptr1)) {
        
        /* Each binding looks like foo=bar */
        char * sep = strchr(binding, '=');
        if (sep == NULL)
        {
            errmsg.LogError(0, NO_ERRCODE,
                            "Invalid argument format %s, ignoring ...",
                            binding);
            continue;
        }

        /* Replace '=' with '\0'. */
        *sep = '\0';

        char * val = sep + 1;

        if (strcmp(binding, "action") == 0) {
            info->action = getSocketAction(val);
        } else if (strcmp(binding, "type") == 0) {
            info->type = getSocketType(val);
        } else if (strcmp(binding, "description") == 0) {
            info->description = strdup(val);
        } else if (strcmp(binding, "sndHWM") == 0) {
            info->sndHWM = atoi(val);
        } else if (strcmp(binding, "rcvHWM") == 0) { 
            info->sndHWM = atoi(val);
        } else if (strcmp(binding, "subscribe") == 0) {
            /* Add the subscription value to the list.*/
            char * substr = NULL;
            substr = strdup(val);
            info->subscriptions = realloc(info->subscriptions, sizeof(char *) * nsubs + 1);
            info->subscriptions[nsubs] = substr;
            ++nsubs;
        } else if (strcmp(binding, "sndBuf") == 0) {
            info->sndBuf = atoi(val);
        } else if (strcmp(binding, "rcvBuf") == 0) {
            info->rcvBuf = atoi(val);
        } else if (strcmp(binding, "linger") == 0) {
            info->linger = atoi(val);
        } else if (strcmp(binding, "backlog") == 0) {
            info->backlog = atoi(val);
        } else if (strcmp(binding, "sndTimeout") == 0) {
            info->sndTimeout = atoi(val);
        } else if (strcmp(binding, "rcvTimeout") == 0) {
            info->rcvTimeout = atoi(val);
        } else if (strcmp(binding, "maxMsgSize") == 0) {
            info->maxMsgSize = atoi(val);
        } else if (strcmp(binding, "rate") == 0) {
            info->rate = atoi(val);
        } else if (strcmp(binding, "recoveryIVL") == 0) {
            info->recoveryIVL = atoi(val);
        } else if (strcmp(binding, "multicastHops") == 0) {
            info->multicastHops = atoi(val);
        } else if (strcmp(binding, "reconnectIVL") == 0) {
            info->reconnectIVL = atoi(val);
        } else if (strcmp(binding, "reconnectIVLMax") == 0) {
            info->reconnectIVLMax = atoi(val);
        } else if (strcmp(binding, "ipv4Only") == 0) {
            info->ipv4Only = atoi(val);
        } else if (strcmp(binding, "affinity") == 0) {
            info->affinity = atoi(val);
        } else {
            errmsg.LogError(0, NO_ERRCODE, "Unknown argument %s", binding);
            return RS_RET_INVALID_PARAMS;
        }
    }

    return RS_RET_OK;
}
Esempio n. 19
0
/*!
** @brief Xsocket implemention of the standard setsockopt function.
**
** Xsetsockopt is used to set options on the underlying Xsocket in
** the Click layer. It does not affect the actual socket passed in which
** used by the API to communicate with Click.
**
** Supported Options:
**	\n XOPT_HLIM	Sets the 'hop limit' (hlim) element of the XIA header to the
**		specified integer value. (Default is 250)
**	\n XOPT_NEXT_PROTO Sets the next proto field in the XIA header
**
** @param sockfd	The control socket
** @param optname	The socket option to set
** @param optval	A pointer to the value to set
** @param optlen	The length of the option being set
**
** @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 Xsetsockopt(int sockfd, int optname, const void *optval, socklen_t optlen)
{
	int rc;
	xia::XSocketCallType type;

	/* 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.
	*/
	if (getSocketType(sockfd) == XSOCK_INVALID) {
		errno = EBADF;
		return -1;
	}

	xia::XSocketMsg xsm;
	xsm.set_type(xia::XSETSOCKOPT);
	xia::X_Setsockopt_Msg *msg = xsm.mutable_x_setsockopt();
	msg->set_opt_type(optname);

	switch (optname) {
		case XOPT_HLIM:
		{
			if (!optval || optlen != sizeof(int)) {
				errno = EINVAL;
				return -1;
			}

			int hlim = *(const int *)optval;

			if (hlim < 0 || hlim > 255) {
				LOGF("HLIM (%d) out of range", hlim);
				errno = EINVAL;
				return -1;
			}
			msg->set_int_opt(hlim);
			break;
		}
		case XOPT_NEXT_PROTO:
		{
			if (!optval || optlen != sizeof(int)) {
				errno = EINVAL;
				return -1;
			}

			int next = *(const int *)optval;

			if (next != XPROTO_XCMP) {
				LOGF("Invalid next protocol specified (%d)", next);
				errno = EINVAL;
				return -1;
			}
			msg->set_int_opt(next);
			break;
		}

		default:
			errno = ENOPROTOOPT;
			return -1;
	}

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

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

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

	fcntl(sockfd, F_SETFL, flags);

	return rc;
}
Esempio n. 20
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;
}
Esempio n. 21
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
**	\n SO_TYPE 		Returns the type of socket (SOCK_STREAM, etc...)
**
** @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)
{
	int rc = 0;

	if (getSocketType(sockfd) == XSOCK_INVALID) {
		errno = EBADF;
		return -1;
	}

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

	switch (optname) {

		// get these values from click ******************************
		case XOPT_HLIM:
		case XOPT_NEXT_PROTO:
		case XOPT_ERROR_PEEK:
		case SO_ACCEPTCONN:
		case SO_ERROR:
			rc = ssoGetInt(sockfd, optname, (int *)optval, optlen);
			break;

		case SO_DEBUG:
			// stored in the API & in click, return from the API
			rc = ssoGetParam(getDebug(sockfd), optval, optlen);
			break;

		case SO_DOMAIN:
			// FIXME: conver this to AF_INET in wrapper
			rc = ssoGetParam(AF_XIA, optval, optlen);
			break;

		case SO_PROTOCOL:
			rc = ssoGetParam(getProtocol(sockfd), optval, optlen);
			break;

		case SO_TYPE:
			ssoGetParam(getSocketType(sockfd), optval, optlen);
			break;


		// SHOIULD IMPLEMENT! ***************************************
		// FIXME: implement these!
		case SO_SNDBUF:
		case SO_RCVBUF:
		case SO_SNDTIMEO:
		case SO_RCVTIMEO:
		case SO_LINGER:
			LOGF("Uh Oh, we need support for %s in XIA\n", optValue(optname));
			rc = -1;
			break;

		// FIXME: MAY NEED ******************************************

		case SO_BROADCAST:
			// FIXME: can we just go ahead and mark this as success?
			// or do we need to do something to check to see if bradcast DAGS are allowed on this socket?
			if (getSocketType(sockfd) == SOCK_DGRAM) {
				rc = -1;
				errno = ENOPROTOOPT;
				break;
			}
			// else silently ignore
			break;

		case SO_REUSEADDR:
			// just say it's not enabled
			ssoGetParam(0, optval, optlen);
			rc = 0;
			break;

		case SO_RCVLOWAT:
		case SO_SNDLOWAT:
			// Probably will never need to support this
			// return the default linux value of 1
			rc = ssoGetParam(1, optval, optlen);
			break;


		// CAN SAFELY IGNORE ****************************************

		case SO_KEEPALIVE:
			// we don't have keepalive so lie and say we do
			ssoGetParam(0, optval, optlen);
			rc = 0;
			break;

		case SO_BSDCOMPAT:
			// safe to mark as unsupported, being phased out on linux anyway
			errno = ENOPROTOOPT;
			rc = -1;
			break;

		// NOT SUPPORTED/DOESN"T MAKE SENSE IN XIA ******************
		case SO_BINDTODEVICE:	// should we support this one when we get multihoming?
		case SO_DONTROUTE:
		case SO_MARK:
		case SO_OOBINLINE:
		case SO_PASSCRED:
		case SO_PEERCRED:
		case SO_PRIORITY:
		case SO_RCVBUFFORCE:
		case SO_SNDBUFFORCE:
		case SO_TIMESTAMP:
		default:
			// return generic error
			LOGF("Option %s not supported in XIA\n", optValue(optname));
			errno = ENOPROTOOPT;
			rc = -1;
	}

	return rc;
}
Esempio n. 22
0
/*!
** @brief Xsocket implemention of the standard setsockopt function.
**
** Xsetsockopt is used to set options on the underlying Xsocket in
** the Click layer. It does not affect the actual socket passed in which
** used by the API to communicate with Click.
**
** Supported Options:
**	\n XOPT_HLIM	Sets the 'hop limit' (hlim) element of the XIA header to the
**		specified integer value. (Default is 250)
**	\n XOPT_NEXT_PROTO Sets the next proto field in the XIA header
**
** @param sockfd	The control socket
** @param optname	The socket option to set
** @param optval	A pointer to the value to set
** @param optlen	The length of the option being set
**
** @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 Xsetsockopt(int sockfd, int optname, const void *optval, socklen_t optlen)
{
	int rc = 0;

	/* 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.
	*/
	if (getSocketType(sockfd) == XSOCK_INVALID) {
		errno = EBADF;
		return -1;
	}

	if (!optval) {
		errno = EINVAL;
		return -1;
	}
	switch (optname) {

		// send these values to click *******************************

		case XOPT_HLIM:
		{
			int hlim = *(const int *)optval;

			if (hlim < 0 || hlim > 255) {
				LOGF("HLIM (%d) out of range", hlim);
				errno = EINVAL;
				rc = -1;
			} else {
				rc = ssoPutInt(sockfd, optname, (const int *)optval, optlen);
			}
			break;
		}

		case XOPT_NEXT_PROTO:
		{
			int next = *(const int *)optval;

			if (next != XPROTO_XCMP) {
				LOGF("Invalid next protocol specified (%d)", next);
				errno = EINVAL;
				rc = -1;
			} else {
				rc = ssoPutInt(sockfd, optname, (const int *)optval, optlen);
			}
			break;
		}

		case XOPT_BLOCK:
		{
			rc = ssoPutInt(sockfd, optname, (const int *)optval, optlen);
			break;
		}

		// this is handled in the API & in click ********************

		case SO_DEBUG:
			if (ssoCheckSize(&optlen, sizeof(int)) < 0) {
				rc = -1;
			}
			else {
				setDebug(sockfd, *(int *)optval);
				rc = ssoPutInt(sockfd, optname, (const int *)optval, optlen);
			}
			break;


		// SHOIULD IMPLEMENT! ***************************************
		// FIXME: implement these!
		case SO_SNDBUF:
		case SO_RCVBUF:
		case SO_SNDTIMEO:
		case SO_RCVTIMEO:
		case SO_LINGER:
		case SO_REUSEADDR:
			LOGF("Uh Oh, we need support for %s in XIA\n", optValue(optname));
			rc = 0;
			break;

		// FIXME: MAY NEED ******************************************

		case SO_BROADCAST:
			// FIXME: can we just go ahead and mark this as success?
			// or do we need to do something to check to see if bradcast DAGS are allowed on this socket?
			if (getSocketType(sockfd) == SOCK_DGRAM) {
				rc = -1;
				errno = ENOPROTOOPT;
				break;
			}
			// else silently ignore
			break;

		case SO_RCVLOWAT:
		case SO_SNDLOWAT:
			// Probably will never need to support this
			// return the default linux value of 1
			rc = 0;
			break;


		// CAN SAFELY IGNORE ****************************************

		case SO_KEEPALIVE:
			// we don't have keepalive so lie and say we did it
			rc = 0;
			break;

		case SO_BSDCOMPAT:
			// safe to mark as unsupported, being phased out on linux anyway
			errno = ENOPROTOOPT;
			rc = -1;
			break;

		// READ ONLY OPTIONS ****************************************
		case SO_ACCEPTCONN:
		case SO_DOMAIN:
		case SO_PROTOCOL:
		case SO_TYPE:
			LOGF("Option %s is read only\n", optValue(optname));
			errno = ENOPROTOOPT;
			rc = -1;
			break;

		// NOT SUPPORTED/DOESN"T MAKE SENSE IN XIA ******************
		case SO_BINDTODEVICE:	// should we support this one when we get multihoming?
		case SO_DONTROUTE:
		case SO_MARK:
		case SO_OOBINLINE:
		case SO_PASSCRED:
		case SO_PEERCRED:
		case SO_PRIORITY:
		case SO_RCVBUFFORCE:
		case SO_SNDBUFFORCE:
		case SO_TIMESTAMP:
		default:
			// return generic error
			LOGF("Option %s not supported in XIA\n", optValue(optname));
			errno = ENOPROTOOPT;
			rc = -1;
	}

	return rc;
}
Esempio n. 23
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;
}
Esempio n. 24
0
AWE::int32 DatagramProtocol::receiveFrom(
	Address* pAddress,
	AWE::int8* pData,
	AWE::uint32 iMaxLength
	)
{
	AWE_CHECK_PTR( pAddress );
	AWE_CHECK_PTR( pData );
	AWE_CHECK_PTR( m_pSocket );
	AWE_ASSERT( m_pSocket->getSocket() != AWE_INVALID_SOCKET );

	sockaddr_storage kSS;
	socklen_t iSSLen( sizeof( kSS ) );
	//memset( &kSS, 0, iSSLen );

	// http://msdn.microsoft.com/en-us/library/ms740120(VS.85).aspx
	int iResult(
		::recvfrom(
			m_pSocket->getSocket(),	// socket
			pData,					// buffer
			iMaxLength,				// max buffer length
			0,						// flags
			(struct sockaddr*)&kSS,	// address
			&iSSLen					// address length
			)
		);

	if ( iResult < 0 )
	{
		return iResult;
	}
	else if ( iResult == 0 )
	{
		// 0 indicates connection closed
		return iResult;//(AWE::int32)AWE::Socket::Error::ConnectionClosed;
	}

	// successfully received data
	// convert incoming address to something we can use
	struct sockaddr* pAddr = (struct sockaddr*)&kSS;
	socklen_t iAddrLength( static_cast< socklen_t >( sizeof( kSS ) ) );

	// convert to string
	char pAddressStr[ NI_MAXHOST ];
	char pPortStr[ NI_MAXSERV ];

	memset( pAddressStr, 0, NI_MAXHOST );
	memset( pPortStr, 0, NI_MAXSERV );

	int iResolveResult(
		::getnameinfo(
			pAddr,
			iAddrLength,
			pAddressStr,
			NI_MAXHOST,
			pPortStr,
			NI_MAXSERV,
			NI_NUMERICHOST | NI_NUMERICSERV
			)
		);

	if ( iResolveResult != 0 )
	{
		return iResolveResult;
	}

	int iSock( atoi( pPortStr ) );

	// convert string to addrinfo
	iResolveResult = pAddress->resolve(
		pAddr->sa_family,
		getProtocol(),
		getSocketType(),
		AI_NUMERICHOST,
		pAddressStr,
		iSock
		);

	if ( iResolveResult != 0 )
	{
		return iResolveResult;
	}

	// return the amount of data received
	return iResult;
}