/*! ** @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; }
static int getSocketUnix(const char *path) { char* e = getenv(X0_LISTEN_FDS); if (!e) return -1; int fd = -1; e = strdup(e); char* s1 = nullptr; while (char* token = strtok_r(e, ";", &s1)) { e = nullptr; char* s2 = nullptr; char* vaddr = strtok_r(token, ",", &s2); if (strcmp(vaddr, path) != 0) continue; char* vfd = strtok_r(nullptr, ",", &s2); fd = atoi(vfd); if (validateSocket(fd) < 0) goto err; goto done; } err: fd = -1; done: free(e); return fd; }
/*! ** @brief Receive data from an Xsocket ** ** Xrecv() retrieves data from a connected Xsocket of type XSOCK_STREAM. ** sockfd must have previously been connected via Xaccept() or ** Xconnect(). ** ** Xrecv() does not currently have a non-blocking mode, and will block ** until a data is available on sockfd. 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 Xrecv() to get the data. ** ** NOTE: in cases where more data is received than specified by the caller, ** the excess data will be stored at the API level. Subsequent Xrecv calls ** return the stored data until it is drained, and will then resume requesting ** data from the transport. ** ** @param sockfd The socket to receive with ** @param rbuf where to put the received data ** @param len maximum amount of data to receive. the amount of data ** returned may be less than len bytes. ** @param flags (This is not currently used but is kept to be compatible ** with the standard sendto socket call). ** ** @returns the number of bytes received, which may be less than the number ** requested by the caller ** @returns -1 on failure with errno set to an error compatible with the standard ** recv call. */ int Xrecv(int sockfd, void *rbuf, size_t len, int flags) { int numbytes; char UDPbuf[MAXBUFLEN]; if (flags) { errno = EOPNOTSUPP; return -1; } if (len == 0) return 0; if (!rbuf) { LOG("buffer pointer is null!\n"); errno = EFAULT; return -1; } if (validateSocket(sockfd, XSOCK_STREAM, EOPNOTSUPP) < 0) { LOGF("Socket %d must be a stream socket", sockfd); return -1; } if (!isConnected(sockfd)) { LOGF("Socket %d is not connected", sockfd); errno = ENOTCONN; return -1; } // see if we have bytes leftover from a previous Xrecv call if ((numbytes = getSocketData(sockfd, (char *)rbuf, len)) > 0) return numbytes; if ((numbytes = click_reply(sockfd, UDPbuf, sizeof(UDPbuf))) < 0) { LOGF("Error retrieving recv data from Click: %s", strerror(errno)); return -1; } std::string str(UDPbuf, numbytes); xia::XSocketMsg xsm; xsm.ParseFromString(str); xia::X_Recv_Msg *msg = xsm.mutable_x_recv(); unsigned paylen = msg->payload().size(); const char *payload = msg->payload().c_str(); if (paylen <= len) memcpy(rbuf, payload, paylen); else { // we got back more data than the caller requested // stash the extra away for subsequent Xrecv calls memcpy(rbuf, payload, len); paylen -= len; setSocketData(sockfd, payload + len, paylen); paylen = len; } return paylen; }
/*! ** @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 }
void startServer(int port,int (*fnPtr)(int, char*, int)) { struct epoll_event *events; int socketFD; int epollFD; socketFD = validateSocket(port); bindandListenSocket(socketFD); epollFD = createEPoll(); setEPollSocket(epollFD, socketFD, &events); eventLoop(socketFD, epollFD, events, fnPtr); close(socketFD); }
/*! ** @brief Sends a datagram message on an Xsocket ** ** Xsendto sends a datagram to the specified address. The final intent of ** the address should be a valid SID. ** ** Unlike a standard socket, Xsendto() is only valid on Xsockets of ** type XSOCK_DGRAM. ** ** If the buffer is too large, Xsendto() will truncate the message and ** send what it can. This is different from the standard sendto which returns ** an error. ** ** @param sockfd The socket to send the data on ** @param buf the data to send ** @param len lenngth of the data to send. The ** Xsendto api is limited to sending at most XIA_MAXBUF bytes. ** @param flags (This is not currently used but is kept to be compatible ** with the standard sendto socket call. ** @param dDAG address (SID) to send the datagram to ** @param dlen length of the DAG, currently unused ** ** @returns number of bytes sent on success ** @returns -1 on failure with errno set to an error compatible with those ** returned by the standard sendto call. ** */ int Xsendto(int sockfd,const void *buf, size_t len, int /*flags*/, char* dDAG, size_t /*dlen*/) { int rc; if (len == 0) return 0; if (!buf || !dDAG) { LOG("null pointer!\n"); errno = EFAULT; return -1; } if (validateSocket(sockfd, XSOCK_DGRAM, EOPNOTSUPP) < 0) { LOGF("Socket %d must be a datagram socket", sockfd); return -1; } // if buf is too big, send only what we can if (len > XIA_MAXBUF) { LOGF("truncating... requested size (%d) is larger than XIA_MAXBUF (%d)\n", len, XIA_MAXBUF); len = XIA_MAXBUF; } xia::XSocketMsg xsm; xsm.set_type(xia::XSENDTO); xia::X_Sendto_Msg *x_sendto_msg = xsm.mutable_x_sendto(); x_sendto_msg->set_ddag(dDAG); x_sendto_msg->set_payload((const char*)buf, len); if ((rc = click_data(sockfd, &xsm)) < 0) { LOGF("Error talking to Click: %s", strerror(errno)); return -1; } // because we don't have queueing or seperate control and data sockets, we // can't get status back reliably on a datagram socket as multiple peers // could be talking to it at the same time and the control messages can get // mixed up with the data packets. So just assume that all went well and tell // the caller we sent the data return len; }
static int httpTransact(char* szUrl, char* szResult, int resSize, char* szActionName, ReqType reqtype) { // Parse URL char szHost[256], szPath[256], szRes[16]; int sz = 0, res = 0; unsigned short sPort; bool needClose = false; const char* szPostHdr = soap_post_hdr; char* szData = (char*)mir_alloc(4096); char* szReq = NULL; parseURL(szUrl, szHost, &sPort, szPath); if (sPort != sConnPort || _stricmp(szHost, szConnHost)) closeRouterConnection(); else validateSocket(); while (true) { retryCount = 0; switch (reqtype) { case DeviceGetReq: sz = mir_snprintf(szData, 4096, xml_get_hdr, szPath, szHost, sPort); break; case ControlAction: { char szData1[1024]; szReq = mir_strdup(szResult); sz = mir_snprintf(szData1, _countof(szData1), soap_action, szActionName, szDev, szReq, szActionName); sz = mir_snprintf(szData, 4096, szPostHdr, szPath, szHost, sPort, sz, szDev, szActionName, szData1); } break; case ControlQuery: { char szData1[1024]; sz = mir_snprintf(szData1, _countof(szData1), soap_query, szActionName); sz = mir_snprintf(szData, 4096, szPostHdr, szPath, szHost, sPort, sz, "urn:schemas-upnp-org:control-1-0", "QueryStateVariable", szData1); } break; } szResult[0] = 0; { static const TIMEVAL tv = { 6, 0 }; static unsigned ttl = 4; static u_long mode = 1; fd_set rfd, wfd, efd; SOCKADDR_IN enetaddr; retrycon: if (sock == INVALID_SOCKET) { sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); enetaddr.sin_family = AF_INET; enetaddr.sin_port = htons(sPort); enetaddr.sin_addr.s_addr = inet_addr(szHost); // Resolve host name if needed if (enetaddr.sin_addr.s_addr == INADDR_NONE) { PHOSTENT he = gethostbyname(szHost); if (he) enetaddr.sin_addr.s_addr = *(unsigned*)he->h_addr_list[0]; } NetlibLogf(NULL, "UPnP HTTP connection Host: %s Port: %u", szHost, sPort); FD_ZERO(&rfd); FD_ZERO(&wfd); FD_ZERO(&efd); FD_SET(sock, &rfd); FD_SET(sock, &wfd); FD_SET(sock, &efd); // Limit the scope of the connection (does not work for setsockopt(sock, IPPROTO_IP, IP_TTL, (char *)&ttl, sizeof(unsigned)); // Put socket into non-blocking mode for timeout on connect ioctlsocket(sock, FIONBIO, &mode); // Connect to the remote host if (connect(sock, (SOCKADDR*)&enetaddr, sizeof(enetaddr)) == SOCKET_ERROR) { int err = WSAGetLastError(); // Socket connection failed if (err != WSAEWOULDBLOCK) { closeRouterConnection(); NetlibLogf(NULL, "UPnP connect failed %d", err); break; } // Wait for socket to connect else if (select(1, &rfd, &wfd, &efd, &tv) != 1) { closeRouterConnection(); NetlibLogf(NULL, "UPnP connect timeout"); break; } else if (!FD_ISSET(sock, &wfd)) { closeRouterConnection(); NetlibLogf(NULL, "UPnP connect failed"); break; } } strncpy_s(szConnHost, szHost, _TRUNCATE); sConnPort = sPort; } if (send(sock, szData, sz, 0) != SOCKET_ERROR) { char *hdrend = NULL; int acksz = 0, pktsz = 0; if (szActionName == NULL) { int len = sizeof(locIP); getsockname(sock, (SOCKADDR*)&locIP, &len); if (locIP.sin_addr.S_un.S_addr == 0x0100007f) { struct hostent *he; gethostname(szPath, sizeof(szPath)); he = gethostbyname(szPath); if (he != NULL) locIP.sin_addr.S_un.S_addr = *(PDWORD)he->h_addr_list[0]; } } LongLog(szData); sz = 0; while (true) { int bytesRecv; FD_ZERO(&rfd); FD_SET(sock, &rfd); // Wait for the next packet if (select(1, &rfd, NULL, NULL, &tv) != 1) { closeRouterConnection(); NetlibLogf(NULL, "UPnP recieve timeout"); break; } // bytesRecv = recv(sock, &szResult[sz], resSize - sz, 0); // Connection closed or aborted, all data received if (bytesRecv == 0 || bytesRecv == SOCKET_ERROR) { closeRouterConnection(); if ((bytesRecv == SOCKET_ERROR || sz == 0) && retryCount < 2) { ++retryCount; goto retrycon; } break; } sz += bytesRecv; // Insert null terminator to use string functions if (sz >= (resSize - 1)) { szResult[resSize - 1] = 0; break; } else szResult[sz] = 0; // HTTP header found? if (hdrend == NULL) { // Find HTTP header end hdrend = strstr(szResult, "\r\n\r\n"); if (hdrend == NULL) { hdrend = strstr(szResult, "\n\n"); if (hdrend) hdrend += 2; } else hdrend += 4; if (hdrend != NULL) { // Get packet size if provided if (txtParseParam(szResult, NULL, "Content-Length:", "\n", szRes, sizeof(szRes)) || txtParseParam(szResult, NULL, "CONTENT-LENGTH:", "\n", szRes, sizeof(szRes))) { // Add size of HTTP header to the packet size to compute full transmission size pktsz = atol(ltrimp(szRes)) + (hdrend - szResult); } // Get encoding type if provided else if (txtParseParam(szResult, NULL, "Transfer-Encoding:", "\n", szRes, sizeof(szRes))) { if (_stricmp(lrtrimp(szRes), "Chunked") == 0) acksz = hdrend - szResult; } if (txtParseParam(szResult, NULL, "Connection:", "\n", szRes, sizeof(szRes))) { needClose = (_stricmp(lrtrimp(szRes), "close") == 0); } } } // Content-Length bytes reached, all data received if (sz >= pktsz && pktsz != 0) { szResult[pktsz] = 0; break; } // Chunked encoding processing if (sz > acksz && acksz != 0) { retry: // Parse out chunk size char* data = szResult + acksz; char* peol1 = data == hdrend ? data - 1 : strchr(data, '\n'); if (peol1 != NULL) { char *peol2 = strchr(++peol1, '\n'); if (peol2 != NULL) { // Get chunk size int chunkBytes = strtol(peol1, NULL, 16); acksz += chunkBytes; peol2++; memmove(data, peol2, mir_strlen(peol2) + 1); sz -= peol2 - data; // Last chunk, all data received if (chunkBytes == 0) break; if (sz > acksz) goto retry; } } } } LongLog(szResult); } else { if (retryCount < 2) { closeRouterConnection(); ++retryCount; goto retrycon; } else NetlibLogf(NULL, "UPnP send failed %d", WSAGetLastError()); } } txtParseParam(szResult, "HTTP", " ", " ", szRes, sizeof(szRes)); res = atol(szRes); if (szActionName != NULL && res == 405 && szPostHdr == soap_post_hdr) szPostHdr = soap_post_hdr_m; else break; } if (needClose) closeRouterConnection(); mir_free(szData); mir_free(szReq); return res; }
/*! ** @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 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; }