/*! ** @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; }
/*! ** @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; }
/*! ** @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; }
/*! ** @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; }
/*! ** @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; }