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