Beispiel #1
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;
}
Beispiel #2
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;
}
Beispiel #3
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;
}
Beispiel #4
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; 
}
Beispiel #5
0
/*!
** @brief request that a list of content chunks be loaded into the local 
** machine's content cache.
**
** XrequestChunks() is called by a client application to load a content chunk 
** into the XIA content cache. It does not return the requested data, it only
** causes the chunk to be loaded into the local content cache. XgetChunkStatuses() 
** may be called to get the status of the chunk to determine when it becomes 
** available. Once the chunk is ready to be read, XreadChunk() should be called 
** get the actual content chunk data.
**
** XrequestChunk() can be used when only a single chunk is requested.
**
** @param sockfd the control socket (must be of type XSOCK_CHUNK)
** @param chunks A list of content DAGs to retrieve
** @param numChunks number of CIDs in the chunk list
**
** @returns 0 on success
** @returns -1 if one or more of the requested chunks could not be located 
** or a socket error occurred. If the error is a socket error, errno set 
** will be set with an appropriate code.
*/
int XrequestChunks(int sockfd, const ChunkStatus *chunks, int numChunks)
{
	int rc;
	const char *buf="Chunk request";//Maybe send more useful information here.

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

	if (numChunks == 0)
		return 0;

	if (!chunks) {
		LOG("null pointer error!");
		errno = EFAULT;
		return -1;
	}
	
	// If the DAG list is too long for a UDP packet to click, replace with multiple calls
	if (numChunks > 300) //TODO: Make this more precise
	{
		rc = 0;
		int i;
		for (i = 0; i < numChunks; i += 300)
		{
			int num = (numChunks-i > 300) ? 300 : numChunks-i;
			int rv = XrequestChunks(sockfd, &chunks[i], num);

			if (rv == -1) {
				perror("XrequestChunk(): requestChunk failed");
				return(-1);
			} else {
				rc += rv;
			}
		}

		return rc;
	}
	
	xia::XSocketMsg xsm;
	xsm.set_type(xia::XREQUESTCHUNK);

	xia::X_Requestchunk_Msg *x_requestchunk_msg = xsm.mutable_x_requestchunk();
  
	for (int i = 0; i < numChunks; i++) {
		if (chunks[i].cid != NULL)
			x_requestchunk_msg->add_dag(chunks[i].cid);
		else {
			LOGF("NULL pointer at chunks[%d]\n", i);
		}
	}

	if (x_requestchunk_msg->dag_size() == 0) {
		// FIXME: what error should this relate to?
		errno = EFAULT;
		LOG("No dags specified\n");
		return -1;
	}

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

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

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

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

	return 0;
}