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

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

	if (numChunks == 0)
		return 0;

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

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

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

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

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

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

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

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

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

	return 0;
}