Esempio n. 1
0
static int32_t
server_process_request(server_p srv, int32_t fd)
{
	uint8_t		ctl[128];
	sdp_pdu_p	pdu = (sdp_pdu_p) srv->req;
	struct msghdr	msg;
	struct iovec	iov;
	int32_t		len, error;
	struct cmsghdr	*cmsg;

	assert(srv->imtu > 0);
	assert(srv->req != NULL);
	assert(FD_ISSET(fd, &srv->fdset));
	assert(srv->fdidx[fd].valid);
	assert(!srv->fdidx[fd].server);
	assert(srv->fdidx[fd].rsp != NULL);
	assert(srv->fdidx[fd].omtu >= L2CAP_MTU_MINIMUM);

	iov.iov_base = srv->req;
	iov.iov_len = srv->imtu;

	msg.msg_name = NULL;
	msg.msg_namelen = 0;
	msg.msg_iov = &iov;
	msg.msg_iovlen = 1;
	msg.msg_control = ctl;
	msg.msg_controllen = sizeof(ctl);
	msg.msg_flags = 0;

	do {
		len = recvmsg(fd, &msg, 0);
	} while (len < 0 && errno == EINTR);

	if (len < 0) {
		log_err("Could not receive SDP request from %s socket. %s (%d)",
			srv->fdidx[fd].control? "control" : "L2CAP",
			strerror(errno), errno);
		return (-1);
	}
	if (len == 0) {
		log_info("Client on %s socket has disconnected",
			srv->fdidx[fd].control? "control" : "L2CAP");
		return (-1);
	}

#if XXX
	if ((cmsg = CMSG_FIRSTHDR(&msg)) != NULL
	    && cmsg->cmsg_level == SOL_SOCKET
	    && cmsg->cmsg_type == SCM_CREDS
#if 0
	    && cmsg->cmsg_len >= CMSG_LEN(SOCKCREDSIZE(0))
#endif
)
	    	srv->fdidx[fd].priv = 
		    server_auth_check(srv, (struct cmsgcred *)CMSG_DATA(cmsg));
#if 0
		    server_auth_check(srv, (struct sockcred *)CMSG_DATA(cmsg));
#endif
#else
srv->fdidx[fd].priv = 1;
#endif

	if (len >= sizeof(*pdu)
	    && (sizeof(*pdu) + (pdu->len = ntohs(pdu->len))) == len) {
		switch (pdu->pid) {
		case SDP_PDU_SERVICE_SEARCH_REQUEST:
			error = server_prepare_service_search_response(srv, fd);
			break;

		case SDP_PDU_SERVICE_ATTRIBUTE_REQUEST:
			error = server_prepare_service_attribute_response(srv, fd);
			break;

		case SDP_PDU_SERVICE_SEARCH_ATTRIBUTE_REQUEST:
			error = server_prepare_service_search_attribute_response(srv, fd);
			break;

		case SDP_PDU_SERVICE_REGISTER_REQUEST:
			error = server_prepare_service_register_response(srv, fd);
			break;

		case SDP_PDU_SERVICE_UNREGISTER_REQUEST:
			error = server_prepare_service_unregister_response(srv, fd);
			break;

		case SDP_PDU_SERVICE_CHANGE_REQUEST:
			error = server_prepare_service_change_response(srv, fd);
			break;

		default:
			error = SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX;
			break;
		}
	} else
		error = SDP_ERROR_CODE_INVALID_PDU_SIZE;

	if (error == 0) {
		switch (pdu->pid) {
		case SDP_PDU_SERVICE_SEARCH_REQUEST:
			error = server_send_service_search_response(srv, fd);
			break;

		case SDP_PDU_SERVICE_ATTRIBUTE_REQUEST:
			error = server_send_service_attribute_response(srv, fd);
			break;

		case SDP_PDU_SERVICE_SEARCH_ATTRIBUTE_REQUEST:
			error = server_send_service_search_attribute_response(srv, fd);
			break;

		case SDP_PDU_SERVICE_REGISTER_REQUEST:
			error = server_send_service_register_response(srv, fd);
			break;

		case SDP_PDU_SERVICE_UNREGISTER_REQUEST:
			error = server_send_service_unregister_response(srv, fd);
			break;

		case SDP_PDU_SERVICE_CHANGE_REQUEST:
			error = server_send_service_change_response(srv, fd);
			break;

		default:
			error = SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX;
			break;
		}

		if (error != 0)
			log_err("Could not send SDP response to %s socket, " \
				"pdu->pid=%d, pdu->tid=%d, error=%d",
				srv->fdidx[fd].control? "control" : "L2CAP",
				pdu->pid, ntohs(pdu->tid), error);
	} else {
		log_err("Could not process SDP request from %s socket, " \
			"pdu->pid=%d, pdu->tid=%d, pdu->len=%d, len=%d, " \
			"error=%d",
			srv->fdidx[fd].control? "control" : "L2CAP",
			pdu->pid, ntohs(pdu->tid), pdu->len, len, error);

		error = server_send_error_response(srv, fd, error);
		if (error != 0)
			log_err("Could not send SDP error response to %s " \
				"socket, pdu->pid=%d, pdu->tid=%d, error=%d",
				srv->fdidx[fd].control? "control" : "L2CAP",
				pdu->pid, ntohs(pdu->tid), error);
	}

	/* On error forget response (if any) */
	if (error != 0) {
		srv->fdidx[fd].rsp_cs = 0;
		srv->fdidx[fd].rsp_size = 0;
		srv->fdidx[fd].rsp_limit = 0;
	}

	return (error);
}
Esempio n. 2
0
/*
 * Process request from the client
 */
static bool
server_process_request(server_t *srv, int fd)
{
	struct msghdr	msg;
	struct iovec	iov[2];
	struct cmsghdr	*cmsg;
	ssize_t		len;
	uint16_t	error;

	assert(FD_ISSET(fd, &srv->fdset));
	assert(srv->fdidx[fd].valid);
	assert(!srv->fdidx[fd].server);

	iov[0].iov_base = &srv->pdu;
	iov[0].iov_len = sizeof(srv->pdu);
	iov[1].iov_base = srv->ibuf;
	iov[1].iov_len = srv->imtu;

	msg.msg_name = NULL;
	msg.msg_namelen = 0;
	msg.msg_iov = iov;
	msg.msg_iovlen = __arraycount(iov);
	msg.msg_control = srv->ctlbuf;
	msg.msg_controllen = srv->ctllen;
	msg.msg_flags = 0;

	do {
		len = recvmsg(fd, &msg, 0);
	} while (len == -1 && errno == EINTR);

	if (len == -1) {
		log_err("Could not receive SDP request on %s socket. %s (%d)",
		    srv->fdidx[fd].control ? "control" : "L2CAP",
		    strerror(errno), errno);

		return false;
	}

	if (len == 0) {
		log_info("Client on %s socket has disconnected",
		    srv->fdidx[fd].control ? "control" : "L2CAP");

		return false;
	}

	if (msg.msg_flags & MSG_TRUNC)
		log_info("Truncated message on %s socket",
		    srv->fdidx[fd].control ? "control" : "L2CAP");

	if ((cmsg = CMSG_FIRSTHDR(&msg)) != NULL
	    && cmsg->cmsg_level == SOL_SOCKET
	    && cmsg->cmsg_type == SCM_CREDS
	    && cmsg->cmsg_len >= CMSG_LEN(SOCKCREDSIZE(0)))
		srv->fdidx[fd].priv = server_auth_check(srv, CMSG_DATA(cmsg));

	srv->pdu.len = be16toh(srv->pdu.len);

	if ((uint32_t)len < sizeof(srv->pdu)
	    || (uint32_t)len != sizeof(srv->pdu) + srv->pdu.len) {
		error = SDP_ERROR_CODE_INVALID_PDU_SIZE;
	} else {
		switch (srv->pdu.pid) {
		case SDP_PDU_SERVICE_SEARCH_REQUEST:
			error = service_search_request(srv, fd);
			break;

		case SDP_PDU_SERVICE_ATTRIBUTE_REQUEST:
			error = service_attribute_request(srv, fd);
			break;

		case SDP_PDU_SERVICE_SEARCH_ATTRIBUTE_REQUEST:
			error = service_search_attribute_request(srv, fd);
			break;

#ifdef SDP_COMPAT
		case SDP_PDU_SERVICE_REGISTER_REQUEST:
			error = compat_register_request(srv, fd);
			break;

		case SDP_PDU_SERVICE_CHANGE_REQUEST:
			error = compat_change_request(srv, fd);
			break;
#endif

		case SDP_PDU_RECORD_INSERT_REQUEST:
			error = record_insert_request(srv, fd);
			break;

		case SDP_PDU_RECORD_UPDATE_REQUEST:
			error = record_update_request(srv, fd);
			break;

		case SDP_PDU_RECORD_REMOVE_REQUEST:
			error = record_remove_request(srv, fd);
			break;

		default:
			error = SDP_ERROR_CODE_INVALID_REQUEST_SYNTAX;
			break;
		}
	}

	if (error != 0) {
		srv->fdidx[fd].offset = 0;
		db_unselect(srv, fd);
		srv->pdu.pid = SDP_PDU_ERROR_RESPONSE;
		srv->pdu.len = sizeof(error);
		be16enc(srv->obuf, error);
		log_debug("sending ErrorResponse (error=0x%04x)", error);
	}

	iov[0].iov_base = &srv->pdu;
	iov[0].iov_len = sizeof(srv->pdu);
	iov[1].iov_base = srv->obuf;
	iov[1].iov_len = srv->pdu.len;

	srv->pdu.len = htobe16(srv->pdu.len);

	msg.msg_name = NULL;
	msg.msg_namelen = 0;
	msg.msg_iov = iov;
	msg.msg_iovlen = __arraycount(iov);
	msg.msg_control = NULL;
	msg.msg_controllen = 0;
	msg.msg_flags = 0;

	do {
		len = sendmsg(fd, &msg, 0);
	} while (len == -1 && errno == EINTR);

	if (len == -1) {
		log_err("Could not send SDP response on %s socket. %s (%d)",
		    srv->fdidx[fd].control ? "control" : "L2CAP",
		    strerror(errno), errno);

		return false;
	}

	return true;
}