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