Exemple #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;

 	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;

}
Exemple #2
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;
}
Exemple #3
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;
	 
}
Exemple #4
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;
}
Exemple #5
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;
}
Exemple #6
0
/*!
** @brief Accept a conection from a remote Xsocket
**
** The Xaccept system call is is only valid with Xsockets created with
** the XSOCK_STREAM transport type. It accepts the first available connection
** request for the listening socket, sockfd, creates a new connected socket,
** and returns a new Xsocket descriptor referring to that socket. The newly
** created socket is not in the listening state. The original socket
** sockfd is unaffected by this call.
**
** Xaccept does not currently have a non-blocking mode, and will block
** until a connection is made. 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
** Xaccept() to get a socket for that connection.
**
** @note Unlike standard sockets, there is currently no Xlisten function.
** Callers must create the listening socket by calling Xsocket with the
** XSOCK_STREAM transport_type and bind it to a source DAG with Xbind(). XAccept
** may then be called to wait for connections.
**
** @param sockfd	an Xsocket() previously created with the XSOCK_STREAM type,
** and bound to a local DAG with Xbind()
** @param addr if non-NULL, points to a block of memory that will contain the
** address of the peer on return
** @param addrlen on entry, contains the size of addr, on exit contains the actual
** size of the address. addr will be truncated, if the size passed in is smaller than
** the actual size.
**
** @returns a non-negative integer that is the new Xsocket id
** @returns -1 on error with errno set to an error compatible with those
** returned by the standard accept call.
*/
int Xlisten(int sockfd, int backlog)
{
	if (validateSocket(sockfd, XSOCK_STREAM, EOPNOTSUPP) < 0) {
		LOG("Xaccept is only valid with stream sockets.");
		return -1;
	}

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

	xia::X_Listen_Msg *x_listen_msg = xsm.mutable_x_listen();
	x_listen_msg->set_backlog(backlog);

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

	// we'll block waiting for click to tell us there's a pending connection
	if (click_status(sockfd, seq) < 0) {
		LOGF("Error getting status from Click: %s", strerror(errno));
		return -1;
	}

	return 0;
}
Exemple #7
0
/*
** get an integer sized parameter from click
*/
int ssoPutInt(int sockfd, int optname, const int *optval, socklen_t optlen)
{
	if (ssoCheckSize(&optlen, sizeof(int)) < 0)
		return -1;

	xia::XSocketMsg xsm;
	xsm.set_type(xia::XSETSOCKOPT);
	unsigned seq = seqNo(sockfd);
	xsm.set_sequence(seq);
	xia::X_Setsockopt_Msg *msg = xsm.mutable_x_setsockopt();
	msg->set_opt_type(optname);
	msg->set_int_opt(*optval);

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

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

	return 0;
}
Exemple #8
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;
}
Exemple #9
0
/*!
** @brief Initiate a connection on an Xsocket of type XSOCK_STREAM
**
** The Xconnect() call connects the socket referred to by sockfd to the
** SID specified by dDAG. It is only valid for use with sockets created
** with the XSOCK_STREAM Xsocket type.
**
** @note Xconnect() differs from the standard connect API in that it does
** not currently support use with Xsockets created with the XSOCK_DGRAM
** socket type.
**
** @param sockfd	The control socket
** @param addr	The address (SID) of the remote service to connect to.
** @param addrlen The length of addr
**
** @returns 0 on success
** @returns -1 on error with errno set to an error compatible with those
** returned by the standard connect call.
*/
int Xconnect(int sockfd, const sockaddr *addr, socklen_t addrlen)
{
	int rc;

	int numbytes;
	char buf[MAXBUFLEN];
	struct sockaddr_in their_addr;
	socklen_t addr_len;
	
	if (!addr || addrlen < sizeof(sockaddr_x)) {
		errno = EINVAL;
		return -1;
	}

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

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

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

	xia::X_Connect_Msg *x_connect_msg = xsm.mutable_x_connect();
	x_connect_msg->set_ddag(g.dag_string().c_str());

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

	// Waiting for SYNACK from destination server

	// FIXME: make this use protobufs
#if 1	
	addr_len = sizeof their_addr;
	if ((numbytes = recvfrom(sockfd, buf, MAXBUFLEN-1 , 0,
			(struct sockaddr *)&their_addr, &addr_len)) == -1) {
		LOGF("Error getting status from Click: %s", strerror(errno));
		return -1;
	}

	if (strcmp(buf, "^Connection-failed^") == 0) {
		errno = ECONNREFUSED;
		LOG("Connection Failed");
		return -1;	    
	} else {
		setConnected(sockfd, 1);
		return 0; 
	}
#endif
}
Exemple #10
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;
}
Exemple #11
0
void XselectCancel(int sock)
{
	xia::XSocketMsg xsm;
	xia::X_Poll_Msg *pollMsg = xsm.mutable_x_poll();

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

	click_send(sock, &xsm);
}
Exemple #12
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;
}
Exemple #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;

 	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;

}
Exemple #14
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;
	 
}
Exemple #15
0
int XupdateRV(int sockfd)
{
	int rc;
	char rvdag[MAX_RV_DAG_SIZE];
	if(XreadRVServerControlAddr(rvdag, MAX_RV_DAG_SIZE)) {
		// Silently skip rendezvous server update if there is no RV DAG
		//LOG("No rendezvous address, skipping update");
		return 0;
	}

	LOGF("Rendezvous location:%s", rvdag);

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

	xia::X_Updaterv_Msg *x_updaterv_msg = xsm.mutable_x_updaterv();
	x_updaterv_msg->set_rvdag(rvdag);

	if((rc = click_send(sockfd, &xsm)) < 0) {
		LOGF("Error asking Click transport to update RV: %s", strerror(errno));
		return -1;
	}
	return 0;
}
Exemple #16
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;
}
Exemple #17
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; 
}
Exemple #18
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);
}
Exemple #19
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;
}
Exemple #20
0
int click_get(int sock, unsigned seq, char *buf, unsigned buflen, xia::XSocketMsg *msg)
{
	int rc;

	if (isBlocking(sock)) {
		// make sure click knows if it should reply immediately or not
		msg->set_blocking(true);
	}

	while (1) {
		// see if another thread received and cached our packet
		if (0) {
//		if ((rc = getCachedPacket(sock, seq, buf, buflen)) > 0) {

			LOGF("Got cached response with sequence # %d\n", seq);
			std::string s(buf, rc);
			msg->ParseFromString(s);
			break;

		} else {

			bzero(buf, buflen);
			// we do this with a blocking socket even if the Xsocket is marked as nonblocking.
			// The UDP socket is treated as an API call rather than a sock so making it
			// non-blocking would cause problems
			rc = (_f_recvfrom)(sock, buf, buflen - 1 , 0, NULL, NULL);

//			LOGF("seq %d received %d bytes\n", seq, rc);

			if (rc < 0) {
				if (isBlocking(sock) || (errno != EWOULDBLOCK && errno != EAGAIN)) {
					LOGF("error(%d) getting reply data from click", errno);
				}
				rc = -1;
				break;

			} else {
				std::string s(buf, rc);
				msg->ParseFromString(s);
				assert(msg);
				unsigned sn = msg->sequence();

				if (sn == seq)
					break;

				// these are not the data you were looking for
				LOGF("Expected packet %u, received %u, replaying packet\n", seq, sn);
//				cachePacket(sock, sn, buf, buflen);
//				msg->PrintDebugString();

				// shove this back into click so the requester can get at it
				xia::X_Replay_Msg *xrm = msg->mutable_x_replay();
				xrm->set_sequence(msg->sequence());
				xrm->set_type(msg->type());

				msg->set_sequence(0);
				msg->set_type(xia::XREPLAY);

				click_send(sock, msg);

				msg->Clear();
			}
		}
	}

	return rc;
}
Exemple #21
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;
}
Exemple #22
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;
}
Exemple #23
0
/*!
** @brief Create an XIA socket
**
** Creates an XIA socket of the specified type. 
**
** @param family socket family, currently must be AF_XIA
** @param transport_type Valid values are: 
**	\n SOCK_STREAM for reliable communications (SID)
**	\n SOCK_DGRAM for a ligher weight connection, but with 
**	unguranteed delivery (SID)
**	\n XSOCK_CHUNK for getting/putting content chunks (CID)
**	\n SOCK_RAW for a raw socket that can have direct edits made to the header
** @param for posix compatibility, currently must be 0
**
** @returns socket id on success. 
** @returns -1 on failure with errno set to an error compatible with those
** from the standard socket call.
**
** @warning In the current implementation, the returned socket is 
** a normal UDP socket that is used to communicate with the click
** transport layer. Using this socket with normal unix socket
** calls (aside from select and poll) will cause unexpected behaviors. 
** Attempting to pass a socket created with the the standard socket function
** to the Xsocket API will have similar results.
**
*/
int Xsocket(int family, int transport_type, int protocol)
{
	struct sockaddr_in addr;
	xia::XSocketCallType type;
	int rc;
	int sockfd;

	if (family != AF_XIA) {
		LOG("error: the Xsockets API only supports the AF_XIA family");
		errno = EAFNOSUPPORT;
		return -1;
	}

	if (protocol != 0) {
		LOG("error: the protocol field is not currently used in the Xsocket API");
		errno = EINVAL;
		return -1;
	}

	/*if (transport_type & SOCK_NONBLOCK || transport_type & SOCK_CLOEXEC) {
		LOG("error: invalid flags passed as part of the treansport_type");
		errno = EINVAL;
		return -1;
		}*/

	switch (transport_type) {
		case SOCK_STREAM:
		case SOCK_DGRAM:
		case XSOCK_CHUNK:
		case SOCK_RAW:
			break;
		default:
			// invalid socket type requested
			LOG("error: invalid transport_type specified");
			errno = EINVAL;
			return -1;
	}

	if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
		LOGF("error creating Xsocket: %s", strerror(errno));
		return -1;
	}

	// bind to any random port number
	addr.sin_family = PF_INET;
	addr.sin_addr.s_addr = inet_addr("127.0.0.1");
	addr.sin_port = 0;

	// protobuf message
	xia::XSocketMsg xsm;
	xsm.set_type(xia::XSOCKET);
		
	xia::X_Socket_Msg *x_socket_msg = xsm.mutable_x_socket();
	x_socket_msg->set_type(transport_type);		
	
	if ((rc = click_send(sockfd, &xsm)) < 0) {
		LOGF("Error talking to Click: %s", strerror(errno));
		close(sockfd);
		return -1;
	}

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

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

	if (rc == 0) {
		allocSocketState(sockfd, transport_type);
		return sockfd;
	}

	// close the control socket since the underlying Xsocket is no good
	close(sockfd);
	return -1; 
}