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