[89174] | 1 | /* $Id: AudioTestService.cpp 90745 2021-08-19 13:32:46Z vboxsync $ */
|
---|
| 2 | /** @file
|
---|
| 3 | * AudioTestService - Audio test execution server.
|
---|
| 4 | */
|
---|
| 5 |
|
---|
| 6 | /*
|
---|
| 7 | * Copyright (C) 2021 Oracle Corporation
|
---|
| 8 | *
|
---|
| 9 | * This file is part of VirtualBox Open Source Edition (OSE), as
|
---|
| 10 | * available from http://www.virtualbox.org. This file is free software;
|
---|
| 11 | * you can redistribute it and/or modify it under the terms of the GNU
|
---|
| 12 | * General Public License (GPL) as published by the Free Software
|
---|
| 13 | * Foundation, in version 2 as it comes in the "COPYING" file of the
|
---|
| 14 | * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
|
---|
| 15 | * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
|
---|
| 16 | */
|
---|
| 17 |
|
---|
| 18 |
|
---|
| 19 | /*********************************************************************************************************************************
|
---|
| 20 | * Header Files *
|
---|
| 21 | *********************************************************************************************************************************/
|
---|
[90048] | 22 | #define LOG_GROUP LOG_GROUP_AUDIO_TEST
|
---|
[89962] | 23 |
|
---|
[89174] | 24 | #include <iprt/alloca.h>
|
---|
| 25 | #include <iprt/asm.h>
|
---|
| 26 | #include <iprt/assert.h>
|
---|
| 27 | #include <iprt/critsect.h>
|
---|
| 28 | #include <iprt/crc.h>
|
---|
| 29 | #include <iprt/ctype.h>
|
---|
| 30 | #include <iprt/dir.h>
|
---|
| 31 | #include <iprt/env.h>
|
---|
| 32 | #include <iprt/err.h>
|
---|
[89962] | 33 | #include <iprt/file.h>
|
---|
[89174] | 34 | #include <iprt/getopt.h>
|
---|
| 35 | #include <iprt/handle.h>
|
---|
| 36 | #include <iprt/initterm.h>
|
---|
| 37 | #include <iprt/json.h>
|
---|
| 38 | #include <iprt/list.h>
|
---|
| 39 | #include <iprt/log.h>
|
---|
| 40 | #include <iprt/mem.h>
|
---|
| 41 | #include <iprt/message.h>
|
---|
| 42 | #include <iprt/param.h>
|
---|
| 43 | #include <iprt/path.h>
|
---|
| 44 | #include <iprt/pipe.h>
|
---|
| 45 | #include <iprt/poll.h>
|
---|
| 46 | #include <iprt/process.h>
|
---|
| 47 | #include <iprt/stream.h>
|
---|
| 48 | #include <iprt/string.h>
|
---|
| 49 | #include <iprt/thread.h>
|
---|
| 50 |
|
---|
[89962] | 51 | #include <VBox/log.h>
|
---|
| 52 |
|
---|
[89174] | 53 | #include "AudioTestService.h"
|
---|
| 54 | #include "AudioTestServiceInternal.h"
|
---|
| 55 |
|
---|
| 56 |
|
---|
| 57 | /*********************************************************************************************************************************
|
---|
| 58 | * Structures and Typedefs *
|
---|
| 59 | *********************************************************************************************************************************/
|
---|
[89962] | 60 | /**
|
---|
| 61 | * A generic ATS reply, used by the client
|
---|
| 62 | * to process the incoming packets.
|
---|
| 63 | */
|
---|
| 64 | typedef struct ATSSRVREPLY
|
---|
| 65 | {
|
---|
| 66 | char szOp[ATSPKT_OPCODE_MAX_LEN];
|
---|
| 67 | void *pvPayload;
|
---|
| 68 | size_t cbPayload;
|
---|
| 69 | } ATSSRVREPLY;
|
---|
| 70 | /** Pointer to a generic ATS reply. */
|
---|
| 71 | typedef struct ATSSRVREPLY *PATSSRVREPLY;
|
---|
[89174] | 72 |
|
---|
| 73 |
|
---|
| 74 | /*********************************************************************************************************************************
|
---|
| 75 | * Global Variables *
|
---|
| 76 | *********************************************************************************************************************************/
|
---|
| 77 | /**
|
---|
| 78 | * Transport layers.
|
---|
| 79 | */
|
---|
[89962] | 80 | const PCATSTRANSPORT g_apTransports[] =
|
---|
[89174] | 81 | {
|
---|
| 82 | &g_TcpTransport
|
---|
| 83 | };
|
---|
[89962] | 84 | /** Number of transport layers in \a g_apTransports. */
|
---|
| 85 | const size_t g_cTransports = RT_ELEMENTS(g_apTransports);
|
---|
[89174] | 86 |
|
---|
| 87 | /**
|
---|
| 88 | * ATS client state.
|
---|
| 89 | */
|
---|
| 90 | typedef enum ATSCLIENTSTATE
|
---|
| 91 | {
|
---|
| 92 | /** Invalid client state. */
|
---|
| 93 | ATSCLIENTSTATE_INVALID = 0,
|
---|
| 94 | /** Client is initialising, only the HOWDY and BYE packets are allowed. */
|
---|
| 95 | ATSCLIENTSTATE_INITIALISING,
|
---|
| 96 | /** Client is in fully cuntional state and ready to process all requests. */
|
---|
| 97 | ATSCLIENTSTATE_READY,
|
---|
| 98 | /** Client is destroying. */
|
---|
| 99 | ATSCLIENTSTATE_DESTROYING,
|
---|
| 100 | /** 32bit hack. */
|
---|
| 101 | ATSCLIENTSTATE_32BIT_HACK = 0x7fffffff
|
---|
| 102 | } ATSCLIENTSTATE;
|
---|
| 103 |
|
---|
| 104 | /**
|
---|
| 105 | * ATS client instance.
|
---|
| 106 | */
|
---|
[89204] | 107 | typedef struct ATSCLIENTINST
|
---|
[89174] | 108 | {
|
---|
| 109 | /** List node for new clients. */
|
---|
| 110 | RTLISTNODE NdLst;
|
---|
| 111 | /** The current client state. */
|
---|
| 112 | ATSCLIENTSTATE enmState;
|
---|
| 113 | /** Transport backend specific data. */
|
---|
| 114 | PATSTRANSPORTCLIENT pTransportClient;
|
---|
| 115 | /** Client hostname. */
|
---|
| 116 | char *pszHostname;
|
---|
[89204] | 117 | } ATSCLIENTINST;
|
---|
[89174] | 118 | /** Pointer to a ATS client instance. */
|
---|
[89962] | 119 | typedef ATSCLIENTINST *PATSSERVERINST;
|
---|
[89174] | 120 |
|
---|
| 121 | /**
|
---|
| 122 | * Returns the string represenation of the given state.
|
---|
| 123 | */
|
---|
| 124 | static const char *atsClientStateStringify(ATSCLIENTSTATE enmState)
|
---|
| 125 | {
|
---|
| 126 | switch (enmState)
|
---|
| 127 | {
|
---|
| 128 | case ATSCLIENTSTATE_INVALID:
|
---|
| 129 | return "INVALID";
|
---|
| 130 | case ATSCLIENTSTATE_INITIALISING:
|
---|
| 131 | return "INITIALISING";
|
---|
| 132 | case ATSCLIENTSTATE_READY:
|
---|
| 133 | return "READY";
|
---|
| 134 | case ATSCLIENTSTATE_DESTROYING:
|
---|
| 135 | return "DESTROYING";
|
---|
| 136 | case ATSCLIENTSTATE_32BIT_HACK:
|
---|
| 137 | default:
|
---|
| 138 | break;
|
---|
| 139 | }
|
---|
| 140 |
|
---|
| 141 | AssertMsgFailed(("Unknown state %#x\n", enmState));
|
---|
| 142 | return "UNKNOWN";
|
---|
| 143 | }
|
---|
| 144 |
|
---|
| 145 | /**
|
---|
| 146 | * Calculates the checksum value, zero any padding space and send the packet.
|
---|
| 147 | *
|
---|
| 148 | * @returns IPRT status code.
|
---|
[89215] | 149 | * @param pThis The ATS instance.
|
---|
[89962] | 150 | * @param pInst The ATS client structure.
|
---|
[89174] | 151 | * @param pPkt The packet to send. Must point to a correctly
|
---|
| 152 | * aligned buffer.
|
---|
| 153 | */
|
---|
[89962] | 154 | static int atsSendPkt(PATSSERVER pThis, PATSSERVERINST pInst, PATSPKTHDR pPkt)
|
---|
[89174] | 155 | {
|
---|
| 156 | Assert(pPkt->cb >= sizeof(*pPkt));
|
---|
| 157 | pPkt->uCrc32 = RTCrc32(pPkt->achOpcode, pPkt->cb - RT_UOFFSETOF(ATSPKTHDR, achOpcode));
|
---|
| 158 | if (pPkt->cb != RT_ALIGN_32(pPkt->cb, ATSPKT_ALIGNMENT))
|
---|
| 159 | memset((uint8_t *)pPkt + pPkt->cb, '\0', RT_ALIGN_32(pPkt->cb, ATSPKT_ALIGNMENT) - pPkt->cb);
|
---|
| 160 |
|
---|
[89614] | 161 | LogFlowFunc(("cb=%RU32 (%#x), payload=%RU32 (%#x), opcode=%.8s\n",
|
---|
[89962] | 162 | pPkt->cb, pPkt->cb, pPkt->cb - sizeof(ATSPKTHDR), pPkt->cb - sizeof(ATSPKTHDR), pPkt->achOpcode));
|
---|
| 163 | int rc = pThis->pTransport->pfnSendPkt(pThis->pTransportInst, pInst->pTransportClient, pPkt);
|
---|
[89215] | 164 | while (RT_UNLIKELY(rc == VERR_INTERRUPTED) && !pThis->fTerminate)
|
---|
[89962] | 165 | rc = pThis->pTransport->pfnSendPkt(pThis->pTransportInst, pInst->pTransportClient, pPkt);
|
---|
[89174] | 166 |
|
---|
| 167 | return rc;
|
---|
| 168 | }
|
---|
| 169 |
|
---|
| 170 | /**
|
---|
| 171 | * Sends a babble reply and disconnects the client (if applicable).
|
---|
| 172 | *
|
---|
[89215] | 173 | * @param pThis The ATS instance.
|
---|
[89962] | 174 | * @param pInst The ATS server instance.
|
---|
[89174] | 175 | * @param pszOpcode The BABBLE opcode.
|
---|
| 176 | */
|
---|
[89962] | 177 | static void atsReplyBabble(PATSSERVER pThis, PATSSERVERINST pInst, const char *pszOpcode)
|
---|
[89174] | 178 | {
|
---|
| 179 | ATSPKTHDR Reply;
|
---|
| 180 | Reply.cb = sizeof(Reply);
|
---|
| 181 | Reply.uCrc32 = 0;
|
---|
| 182 | memcpy(Reply.achOpcode, pszOpcode, sizeof(Reply.achOpcode));
|
---|
| 183 |
|
---|
[89962] | 184 | pThis->pTransport->pfnBabble(pThis->pTransportInst, pInst->pTransportClient, &Reply, 20*1000);
|
---|
[89174] | 185 | }
|
---|
| 186 |
|
---|
| 187 | /**
|
---|
| 188 | * Receive and validate a packet.
|
---|
| 189 | *
|
---|
| 190 | * Will send bable responses to malformed packets that results in a error status
|
---|
| 191 | * code.
|
---|
| 192 | *
|
---|
| 193 | * @returns IPRT status code.
|
---|
[89215] | 194 | * @param pThis The ATS instance.
|
---|
[89962] | 195 | * @param pInst The opaque ATS instance structure.
|
---|
[89174] | 196 | * @param ppPktHdr Where to return the packet on success. Free
|
---|
| 197 | * with RTMemFree.
|
---|
| 198 | * @param fAutoRetryOnFailure Whether to retry on error.
|
---|
| 199 | */
|
---|
[89962] | 200 | static int atsRecvPkt(PATSSERVER pThis, PATSSERVERINST pInst, PPATSPKTHDR ppPktHdr, bool fAutoRetryOnFailure)
|
---|
[89174] | 201 | {
|
---|
| 202 | for (;;)
|
---|
| 203 | {
|
---|
| 204 | PATSPKTHDR pPktHdr;
|
---|
[89962] | 205 | int rc = pThis->pTransport->pfnRecvPkt(pThis->pTransportInst, pInst->pTransportClient, &pPktHdr);
|
---|
[89174] | 206 | if (RT_SUCCESS(rc))
|
---|
| 207 | {
|
---|
| 208 | /* validate the packet. */
|
---|
| 209 | if ( pPktHdr->cb >= sizeof(ATSPKTHDR)
|
---|
| 210 | && pPktHdr->cb < ATSPKT_MAX_SIZE)
|
---|
| 211 | {
|
---|
[89962] | 212 | Log2Func(("pPktHdr=%p cb=%#x crc32=%#x opcode=%.8s\n",
|
---|
| 213 | pPktHdr, pPktHdr->cb, pPktHdr->uCrc32, pPktHdr->achOpcode));
|
---|
[89174] | 214 | uint32_t uCrc32Calc = pPktHdr->uCrc32 != 0
|
---|
| 215 | ? RTCrc32(&pPktHdr->achOpcode[0], pPktHdr->cb - RT_UOFFSETOF(ATSPKTHDR, achOpcode))
|
---|
| 216 | : 0;
|
---|
| 217 | if (pPktHdr->uCrc32 == uCrc32Calc)
|
---|
| 218 | {
|
---|
| 219 | AssertCompileMemberSize(ATSPKTHDR, achOpcode, 8);
|
---|
| 220 | if ( RT_C_IS_UPPER(pPktHdr->achOpcode[0])
|
---|
| 221 | && RT_C_IS_UPPER(pPktHdr->achOpcode[1])
|
---|
| 222 | && (RT_C_IS_UPPER(pPktHdr->achOpcode[2]) || pPktHdr->achOpcode[2] == ' ')
|
---|
| 223 | && (RT_C_IS_PRINT(pPktHdr->achOpcode[3]) || pPktHdr->achOpcode[3] == ' ')
|
---|
| 224 | && (RT_C_IS_PRINT(pPktHdr->achOpcode[4]) || pPktHdr->achOpcode[4] == ' ')
|
---|
| 225 | && (RT_C_IS_PRINT(pPktHdr->achOpcode[5]) || pPktHdr->achOpcode[5] == ' ')
|
---|
| 226 | && (RT_C_IS_PRINT(pPktHdr->achOpcode[6]) || pPktHdr->achOpcode[6] == ' ')
|
---|
| 227 | && (RT_C_IS_PRINT(pPktHdr->achOpcode[7]) || pPktHdr->achOpcode[7] == ' ')
|
---|
| 228 | )
|
---|
| 229 | {
|
---|
[89962] | 230 | Log(("cb=%#x opcode=%.8s\n", pPktHdr->cb, pPktHdr->achOpcode));
|
---|
[89174] | 231 | *ppPktHdr = pPktHdr;
|
---|
| 232 | return rc;
|
---|
| 233 | }
|
---|
| 234 |
|
---|
| 235 | rc = VERR_IO_BAD_COMMAND;
|
---|
| 236 | }
|
---|
| 237 | else
|
---|
| 238 | {
|
---|
[89962] | 239 | Log(("cb=%#x opcode=%.8s crc32=%#x actual=%#x\n",
|
---|
[89174] | 240 | pPktHdr->cb, pPktHdr->achOpcode, pPktHdr->uCrc32, uCrc32Calc));
|
---|
| 241 | rc = VERR_IO_CRC;
|
---|
| 242 | }
|
---|
| 243 | }
|
---|
| 244 | else
|
---|
| 245 | rc = VERR_IO_BAD_LENGTH;
|
---|
| 246 |
|
---|
| 247 | /* Send babble reply and disconnect the client if the transport is
|
---|
| 248 | connection oriented. */
|
---|
| 249 | if (rc == VERR_IO_BAD_LENGTH)
|
---|
[89962] | 250 | atsReplyBabble(pThis, pInst, "BABBLE L");
|
---|
[89174] | 251 | else if (rc == VERR_IO_CRC)
|
---|
[89962] | 252 | atsReplyBabble(pThis, pInst, "BABBLE C");
|
---|
[89174] | 253 | else if (rc == VERR_IO_BAD_COMMAND)
|
---|
[89962] | 254 | atsReplyBabble(pThis, pInst, "BABBLE O");
|
---|
[89174] | 255 | else
|
---|
[89962] | 256 | atsReplyBabble(pThis, pInst, "BABBLE ");
|
---|
[89174] | 257 | RTMemFree(pPktHdr);
|
---|
| 258 | }
|
---|
| 259 |
|
---|
| 260 | /* Try again or return failure? */
|
---|
[89215] | 261 | if ( pThis->fTerminate
|
---|
[89174] | 262 | || rc != VERR_INTERRUPTED
|
---|
| 263 | || !fAutoRetryOnFailure
|
---|
| 264 | )
|
---|
| 265 | {
|
---|
[89962] | 266 | Log(("rc=%Rrc\n", rc));
|
---|
[89174] | 267 | return rc;
|
---|
| 268 | }
|
---|
| 269 | }
|
---|
| 270 | }
|
---|
| 271 |
|
---|
| 272 | /**
|
---|
| 273 | * Make a simple reply, only status opcode.
|
---|
| 274 | *
|
---|
| 275 | * @returns IPRT status code of the send.
|
---|
[89215] | 276 | * @param pThis The ATS instance.
|
---|
[89962] | 277 | * @param pInst The opaque ATS instance structure.
|
---|
[89174] | 278 | * @param pReply The reply packet.
|
---|
| 279 | * @param pszOpcode The status opcode. Exactly 8 chars long, padd
|
---|
| 280 | * with space.
|
---|
| 281 | * @param cbExtra Bytes in addition to the header.
|
---|
| 282 | */
|
---|
[89962] | 283 | static int atsReplyInternal(PATSSERVER pThis, PATSSERVERINST pInst, PATSPKTHDR pReply, const char *pszOpcode, size_t cbExtra)
|
---|
[89174] | 284 | {
|
---|
| 285 | /* copy the opcode, don't be too strict in case of a padding screw up. */
|
---|
| 286 | size_t cchOpcode = strlen(pszOpcode);
|
---|
[89614] | 287 | if (RT_LIKELY(cchOpcode == sizeof(pReply->achOpcode)))
|
---|
| 288 | memcpy(pReply->achOpcode, pszOpcode, sizeof(pReply->achOpcode));
|
---|
[89174] | 289 | else
|
---|
| 290 | {
|
---|
[89614] | 291 | Assert(cchOpcode == sizeof(pReply->achOpcode));
|
---|
[89174] | 292 | while (cchOpcode > 0 && pszOpcode[cchOpcode - 1] == ' ')
|
---|
| 293 | cchOpcode--;
|
---|
[89614] | 294 | AssertMsgReturn(cchOpcode < sizeof(pReply->achOpcode), ("%d/'%.8s'\n", cchOpcode, pszOpcode), VERR_INTERNAL_ERROR_4);
|
---|
| 295 | memcpy(pReply->achOpcode, pszOpcode, cchOpcode);
|
---|
| 296 | memset(&pReply->achOpcode[cchOpcode], ' ', sizeof(pReply->achOpcode) - cchOpcode);
|
---|
[89174] | 297 | }
|
---|
| 298 |
|
---|
[89614] | 299 | pReply->cb = (uint32_t)sizeof(ATSPKTHDR) + (uint32_t)cbExtra;
|
---|
| 300 | pReply->uCrc32 = 0;
|
---|
[89174] | 301 |
|
---|
[89962] | 302 | return atsSendPkt(pThis, pInst, pReply);
|
---|
[89174] | 303 | }
|
---|
| 304 |
|
---|
| 305 | /**
|
---|
| 306 | * Make a simple reply, only status opcode.
|
---|
| 307 | *
|
---|
| 308 | * @returns IPRT status code of the send.
|
---|
[89215] | 309 | * @param pThis The ATS instance.
|
---|
[89962] | 310 | * @param pInst The opaque ATS instance structure.
|
---|
[89174] | 311 | * @param pPktHdr The original packet (for future use).
|
---|
| 312 | * @param pszOpcode The status opcode. Exactly 8 chars long, padd
|
---|
| 313 | * with space.
|
---|
| 314 | */
|
---|
[89962] | 315 | static int atsReplySimple(PATSSERVER pThis, PATSSERVERINST pInst, PATSPKTHDR pPktHdr, const char *pszOpcode)
|
---|
[89174] | 316 | {
|
---|
[89962] | 317 | return atsReplyInternal(pThis, pInst, pPktHdr, pszOpcode, 0);
|
---|
[89174] | 318 | }
|
---|
| 319 |
|
---|
| 320 | /**
|
---|
| 321 | * Acknowledges a packet with success.
|
---|
| 322 | *
|
---|
| 323 | * @returns IPRT status code of the send.
|
---|
[89215] | 324 | * @param pThis The ATS instance.
|
---|
[89962] | 325 | * @param pInst The opaque ATS instance structure.
|
---|
[89174] | 326 | * @param pPktHdr The original packet (for future use).
|
---|
| 327 | */
|
---|
[89962] | 328 | static int atsReplyAck(PATSSERVER pThis, PATSSERVERINST pInst, PATSPKTHDR pPktHdr)
|
---|
[89174] | 329 | {
|
---|
[89962] | 330 | return atsReplySimple(pThis, pInst, pPktHdr, "ACK ");
|
---|
[89174] | 331 | }
|
---|
| 332 |
|
---|
| 333 | /**
|
---|
| 334 | * Replies with a failure.
|
---|
| 335 | *
|
---|
| 336 | * @returns IPRT status code of the send.
|
---|
[89215] | 337 | * @param pThis The ATS instance.
|
---|
[89962] | 338 | * @param pInst The opaque ATS instance structure.
|
---|
[89174] | 339 | * @param pPktHdr The original packet (for future use).
|
---|
| 340 | * @param pszOpcode The status opcode. Exactly 8 chars long, padd
|
---|
| 341 | * with space.
|
---|
| 342 | * @param rcReq The status code of the request.
|
---|
| 343 | * @param pszDetailFmt Longer description of the problem (format string).
|
---|
| 344 | * @param va Format arguments.
|
---|
| 345 | */
|
---|
[89962] | 346 | static int atsReplyFailureV(PATSSERVER pThis, PATSSERVERINST pInst, PATSPKTHDR pPktHdr,
|
---|
[89788] | 347 | const char *pszOpcode, int rcReq, const char *pszDetailFmt, va_list va)
|
---|
[89174] | 348 | {
|
---|
[89215] | 349 | RT_NOREF(pPktHdr);
|
---|
[89174] | 350 | union
|
---|
| 351 | {
|
---|
[89614] | 352 | ATSPKTHDR Hdr;
|
---|
| 353 | int rc;
|
---|
[89174] | 354 | char ach[256];
|
---|
| 355 | } uPkt;
|
---|
[89614] | 356 | RT_ZERO(uPkt);
|
---|
[89174] | 357 |
|
---|
[89614] | 358 | size_t cchDetail = RTStrPrintfV(&uPkt.ach[sizeof(ATSPKTHDR)],
|
---|
| 359 | sizeof(uPkt) - sizeof(ATSPKTHDR),
|
---|
[89174] | 360 | pszDetailFmt, va);
|
---|
[89614] | 361 |
|
---|
| 362 | uPkt.rc = rcReq;
|
---|
| 363 |
|
---|
[89962] | 364 | return atsReplyInternal(pThis, pInst, &uPkt.Hdr, pszOpcode, sizeof(int) + cchDetail + 1);
|
---|
[89174] | 365 | }
|
---|
| 366 |
|
---|
| 367 | /**
|
---|
| 368 | * Replies with a failure.
|
---|
| 369 | *
|
---|
| 370 | * @returns IPRT status code of the send.
|
---|
[89215] | 371 | * @param pThis The ATS instance.
|
---|
[89962] | 372 | * @param pInst The opaque ATS instance structure.
|
---|
[89174] | 373 | * @param pPktHdr The original packet (for future use).
|
---|
| 374 | * @param pszOpcode The status opcode. Exactly 8 chars long, padd
|
---|
| 375 | * with space.
|
---|
| 376 | * @param rcReq Status code.
|
---|
| 377 | * @param pszDetailFmt Longer description of the problem (format string).
|
---|
| 378 | * @param ... Format arguments.
|
---|
| 379 | */
|
---|
[89962] | 380 | static int atsReplyFailure(PATSSERVER pThis, PATSSERVERINST pInst, PATSPKTHDR pPktHdr,
|
---|
[89788] | 381 | const char *pszOpcode, int rcReq, const char *pszDetailFmt, ...)
|
---|
[89174] | 382 | {
|
---|
| 383 | va_list va;
|
---|
| 384 | va_start(va, pszDetailFmt);
|
---|
[89962] | 385 | int rc = atsReplyFailureV(pThis, pInst, pPktHdr, pszOpcode, rcReq, pszDetailFmt, va);
|
---|
[89174] | 386 | va_end(va);
|
---|
| 387 | return rc;
|
---|
| 388 | }
|
---|
| 389 |
|
---|
| 390 | /**
|
---|
| 391 | * Replies according to the return code.
|
---|
| 392 | *
|
---|
| 393 | * @returns IPRT status code of the send.
|
---|
[89215] | 394 | * @param pThis The ATS instance.
|
---|
[89962] | 395 | * @param pInst The opaque ATS instance structure.
|
---|
[89174] | 396 | * @param pPktHdr The packet to reply to.
|
---|
| 397 | * @param rcOperation The status code to report.
|
---|
| 398 | * @param pszOperationFmt The operation that failed. Typically giving the
|
---|
| 399 | * function call with important arguments.
|
---|
| 400 | * @param ... Arguments to the format string.
|
---|
| 401 | */
|
---|
[89215] | 402 | static int atsReplyRC(PATSSERVER pThis,
|
---|
[89962] | 403 | PATSSERVERINST pInst, PATSPKTHDR pPktHdr, int rcOperation, const char *pszOperationFmt, ...)
|
---|
[89174] | 404 | {
|
---|
| 405 | if (RT_SUCCESS(rcOperation))
|
---|
[89962] | 406 | return atsReplyAck(pThis, pInst, pPktHdr);
|
---|
[89174] | 407 |
|
---|
| 408 | char szOperation[128];
|
---|
| 409 | va_list va;
|
---|
| 410 | va_start(va, pszOperationFmt);
|
---|
| 411 | RTStrPrintfV(szOperation, sizeof(szOperation), pszOperationFmt, va);
|
---|
| 412 | va_end(va);
|
---|
| 413 |
|
---|
[89962] | 414 | return atsReplyFailure(pThis, pInst, pPktHdr, "FAILED ", rcOperation, "%s failed with rc=%Rrc (opcode '%.8s')",
|
---|
[89174] | 415 | szOperation, rcOperation, pPktHdr->achOpcode);
|
---|
| 416 | }
|
---|
| 417 |
|
---|
| 418 | /**
|
---|
| 419 | * Signal a bad packet exact size.
|
---|
| 420 | *
|
---|
| 421 | * @returns IPRT status code of the send.
|
---|
[89215] | 422 | * @param pThis The ATS instance.
|
---|
[89962] | 423 | * @param pInst The opaque ATS instance structure.
|
---|
[89174] | 424 | * @param pPktHdr The packet to reply to.
|
---|
| 425 | * @param cb The wanted size.
|
---|
| 426 | */
|
---|
[89962] | 427 | static int atsReplyBadSize(PATSSERVER pThis, PATSSERVERINST pInst, PATSPKTHDR pPktHdr, size_t cb)
|
---|
[89174] | 428 | {
|
---|
[89962] | 429 | return atsReplyFailure(pThis, pInst, pPktHdr, "BAD SIZE", VERR_INVALID_PARAMETER, "Expected at %zu bytes, got %u (opcode '%.8s')",
|
---|
[89174] | 430 | cb, pPktHdr->cb, pPktHdr->achOpcode);
|
---|
| 431 | }
|
---|
| 432 |
|
---|
| 433 | /**
|
---|
| 434 | * Deals with a unknown command.
|
---|
[89215] | 435 | *
|
---|
[89174] | 436 | * @returns IPRT status code of the send.
|
---|
[89215] | 437 | * @param pThis The ATS instance.
|
---|
[89962] | 438 | * @param pInst The opaque ATS instance structure.
|
---|
[89174] | 439 | * @param pPktHdr The packet to reply to.
|
---|
| 440 | */
|
---|
[89962] | 441 | static int atsReplyUnknown(PATSSERVER pThis, PATSSERVERINST pInst, PATSPKTHDR pPktHdr)
|
---|
[89174] | 442 | {
|
---|
[89962] | 443 | return atsReplyFailure(pThis, pInst, pPktHdr, "UNKNOWN ", VERR_NOT_FOUND, "Opcode '%.8s' is not known", pPktHdr->achOpcode);
|
---|
[89174] | 444 | }
|
---|
| 445 |
|
---|
| 446 | /**
|
---|
| 447 | * Deals with a command sent in an invalid client state.
|
---|
| 448 | *
|
---|
| 449 | * @returns IPRT status code of the send.
|
---|
[89215] | 450 | * @param pThis The ATS instance.
|
---|
[89962] | 451 | * @param pInst The opaque ATS instance structure.
|
---|
[89174] | 452 | * @param pPktHdr The packet containing the unterminated string.
|
---|
| 453 | */
|
---|
[89962] | 454 | static int atsReplyInvalidState(PATSSERVER pThis, PATSSERVERINST pInst, PATSPKTHDR pPktHdr)
|
---|
[89174] | 455 | {
|
---|
[89962] | 456 | return atsReplyFailure(pThis, pInst, pPktHdr, "INVSTATE", VERR_INVALID_STATE, "Opcode '%.8s' is not supported at client state '%s",
|
---|
| 457 | pPktHdr->achOpcode, atsClientStateStringify(pInst->enmState));
|
---|
[89174] | 458 | }
|
---|
| 459 |
|
---|
| 460 | /**
|
---|
| 461 | * Verifies and acknowledges a "BYE" request.
|
---|
| 462 | *
|
---|
| 463 | * @returns IPRT status code.
|
---|
[89215] | 464 | * @param pThis The ATS instance.
|
---|
[89962] | 465 | * @param pInst The opaque ATS instance structure.
|
---|
[89614] | 466 | * @param pPktHdr The bye packet.
|
---|
[89174] | 467 | */
|
---|
[89962] | 468 | static int atsDoBye(PATSSERVER pThis, PATSSERVERINST pInst, PATSPKTHDR pPktHdr)
|
---|
[89174] | 469 | {
|
---|
| 470 | int rc;
|
---|
| 471 | if (pPktHdr->cb == sizeof(ATSPKTHDR))
|
---|
[89431] | 472 | {
|
---|
[89962] | 473 | rc = atsReplyAck(pThis, pInst, pPktHdr);
|
---|
[90745] | 474 | if (RT_SUCCESS(rc))
|
---|
| 475 | pThis->pTransport->pfnNotifyBye(pThis->pTransportInst, pInst->pTransportClient);
|
---|
[89431] | 476 | }
|
---|
[89174] | 477 | else
|
---|
[89962] | 478 | rc = atsReplyBadSize(pThis, pInst, pPktHdr, sizeof(ATSPKTHDR));
|
---|
[89174] | 479 | return rc;
|
---|
| 480 | }
|
---|
| 481 |
|
---|
| 482 | /**
|
---|
| 483 | * Verifies and acknowledges a "HOWDY" request.
|
---|
| 484 | *
|
---|
| 485 | * @returns IPRT status code.
|
---|
[89215] | 486 | * @param pThis The ATS instance.
|
---|
[89962] | 487 | * @param pInst The opaque ATS instance structure.
|
---|
[89174] | 488 | * @param pPktHdr The howdy packet.
|
---|
| 489 | */
|
---|
[89962] | 490 | static int atsDoHowdy(PATSSERVER pThis, PATSSERVERINST pInst, PATSPKTHDR pPktHdr)
|
---|
[89174] | 491 | {
|
---|
| 492 | int rc = VINF_SUCCESS;
|
---|
| 493 |
|
---|
| 494 | if (pPktHdr->cb != sizeof(ATSPKTREQHOWDY))
|
---|
[89962] | 495 | return atsReplyBadSize(pThis, pInst, pPktHdr, sizeof(ATSPKTREQHOWDY));
|
---|
[89174] | 496 |
|
---|
[89962] | 497 | if (pInst->enmState != ATSCLIENTSTATE_INITIALISING)
|
---|
| 498 | return atsReplyInvalidState(pThis, pInst, pPktHdr);
|
---|
[89174] | 499 |
|
---|
| 500 | PATSPKTREQHOWDY pReq = (PATSPKTREQHOWDY)pPktHdr;
|
---|
| 501 |
|
---|
| 502 | if (pReq->uVersion != ATS_PROTOCOL_VS)
|
---|
[89962] | 503 | return atsReplyRC(pThis, pInst, pPktHdr, VERR_VERSION_MISMATCH, "The given version %#x is not supported", pReq->uVersion);
|
---|
[89174] | 504 |
|
---|
[89204] | 505 | ATSPKTREPHOWDY Rep;
|
---|
| 506 | RT_ZERO(Rep);
|
---|
| 507 |
|
---|
| 508 | Rep.uVersion = ATS_PROTOCOL_VS;
|
---|
| 509 |
|
---|
[89962] | 510 | rc = atsReplyInternal(pThis, pInst, &Rep.Hdr, "ACK ", sizeof(Rep) - sizeof(ATSPKTHDR));
|
---|
[89204] | 511 | if (RT_SUCCESS(rc))
|
---|
| 512 | {
|
---|
[89962] | 513 | pThis->pTransport->pfnNotifyHowdy(pThis->pTransportInst, pInst->pTransportClient);
|
---|
| 514 | pInst->enmState = ATSCLIENTSTATE_READY;
|
---|
[89204] | 515 | }
|
---|
| 516 |
|
---|
[89174] | 517 | return rc;
|
---|
| 518 | }
|
---|
| 519 |
|
---|
| 520 | /**
|
---|
[89431] | 521 | * Verifies and acknowledges a "TSET BEG" request.
|
---|
| 522 | *
|
---|
| 523 | * @returns IPRT status code.
|
---|
| 524 | * @param pThis The ATS instance.
|
---|
[89962] | 525 | * @param pInst The opaque ATS instance structure.
|
---|
[89431] | 526 | * @param pPktHdr The test set begin packet.
|
---|
| 527 | */
|
---|
[89962] | 528 | static int atsDoTestSetBegin(PATSSERVER pThis, PATSSERVERINST pInst, PATSPKTHDR pPktHdr)
|
---|
[89431] | 529 | {
|
---|
| 530 | if (pPktHdr->cb != sizeof(ATSPKTREQTSETBEG))
|
---|
[89962] | 531 | return atsReplyBadSize(pThis, pInst, pPktHdr, sizeof(ATSPKTREQTSETBEG));
|
---|
[89431] | 532 |
|
---|
| 533 | PATSPKTREQTSETBEG pReq = (PATSPKTREQTSETBEG)pPktHdr;
|
---|
| 534 |
|
---|
| 535 | int rc = VINF_SUCCESS;
|
---|
| 536 |
|
---|
| 537 | if (pThis->Callbacks.pfnTestSetBegin)
|
---|
| 538 | {
|
---|
| 539 | rc = pThis->Callbacks.pfnTestSetBegin(pThis->Callbacks.pvUser, pReq->szTag);
|
---|
| 540 | if (RT_FAILURE(rc))
|
---|
[89962] | 541 | return atsReplyRC(pThis, pInst, pPktHdr, rc, "Beginning test set '%s' failed", pReq->szTag);
|
---|
[89431] | 542 | }
|
---|
| 543 |
|
---|
| 544 | if (RT_SUCCESS(rc))
|
---|
| 545 | {
|
---|
[89962] | 546 | rc = atsReplyAck(pThis, pInst, pPktHdr);
|
---|
[89431] | 547 | }
|
---|
| 548 | else
|
---|
[89962] | 549 | rc = atsReplyRC(pThis, pInst, pPktHdr, rc, "Beginning test set failed");
|
---|
[89431] | 550 |
|
---|
| 551 | return rc;
|
---|
| 552 | }
|
---|
| 553 |
|
---|
| 554 | /**
|
---|
| 555 | * Verifies and acknowledges a "TSET END" request.
|
---|
| 556 | *
|
---|
| 557 | * @returns IPRT status code.
|
---|
| 558 | * @param pThis The ATS instance.
|
---|
[89962] | 559 | * @param pInst The opaque ATS instance structure.
|
---|
[89431] | 560 | * @param pPktHdr The test set end packet.
|
---|
| 561 | */
|
---|
[89962] | 562 | static int atsDoTestSetEnd(PATSSERVER pThis, PATSSERVERINST pInst, PATSPKTHDR pPktHdr)
|
---|
[89431] | 563 | {
|
---|
| 564 | if (pPktHdr->cb != sizeof(ATSPKTREQTSETEND))
|
---|
[89962] | 565 | return atsReplyBadSize(pThis, pInst, pPktHdr, sizeof(ATSPKTREQTSETEND));
|
---|
[89431] | 566 |
|
---|
| 567 | PATSPKTREQTSETEND pReq = (PATSPKTREQTSETEND)pPktHdr;
|
---|
| 568 |
|
---|
| 569 | int rc = VINF_SUCCESS;
|
---|
| 570 |
|
---|
| 571 | if (pThis->Callbacks.pfnTestSetEnd)
|
---|
| 572 | {
|
---|
| 573 | rc = pThis->Callbacks.pfnTestSetEnd(pThis->Callbacks.pvUser, pReq->szTag);
|
---|
| 574 | if (RT_FAILURE(rc))
|
---|
[89962] | 575 | return atsReplyRC(pThis, pInst, pPktHdr, rc, "Ending test set '%s' failed", pReq->szTag);
|
---|
[89431] | 576 | }
|
---|
| 577 | if (RT_SUCCESS(rc))
|
---|
| 578 | {
|
---|
[89962] | 579 | rc = atsReplyAck(pThis, pInst, pPktHdr);
|
---|
[89431] | 580 | }
|
---|
| 581 | else
|
---|
[89962] | 582 | rc = atsReplyRC(pThis, pInst, pPktHdr, rc, "Ending test set failed");
|
---|
[89431] | 583 |
|
---|
| 584 | return rc;
|
---|
| 585 | }
|
---|
| 586 |
|
---|
| 587 | /**
|
---|
[89614] | 588 | * Used by atsDoTestSetSend to wait for a reply ACK from the client.
|
---|
| 589 | *
|
---|
| 590 | * @returns VINF_SUCCESS on ACK, VERR_GENERAL_FAILURE on NACK,
|
---|
| 591 | * VERR_NET_NOT_CONNECTED on unknown response (sending a bable reply),
|
---|
| 592 | * or whatever atsRecvPkt returns.
|
---|
[89616] | 593 | * @param pThis The ATS instance.
|
---|
[89962] | 594 | * @param pInst The opaque ATS instance structure.
|
---|
[89614] | 595 | * @param pPktHdr The original packet (for future use).
|
---|
| 596 | */
|
---|
[89962] | 597 | static int atsWaitForAck(PATSSERVER pThis, PATSSERVERINST pInst, PATSPKTHDR pPktHdr)
|
---|
[89614] | 598 | {
|
---|
| 599 | RT_NOREF(pPktHdr);
|
---|
| 600 | /** @todo timeout? */
|
---|
| 601 | PATSPKTHDR pReply;
|
---|
[89962] | 602 | int rc = atsRecvPkt(pThis, pInst, &pReply, false /*fAutoRetryOnFailure*/);
|
---|
[89614] | 603 | if (RT_SUCCESS(rc))
|
---|
| 604 | {
|
---|
| 605 | if (atsIsSameOpcode(pReply, "ACK"))
|
---|
| 606 | rc = VINF_SUCCESS;
|
---|
| 607 | else if (atsIsSameOpcode(pReply, "NACK"))
|
---|
| 608 | rc = VERR_GENERAL_FAILURE;
|
---|
| 609 | else
|
---|
| 610 | {
|
---|
[89962] | 611 | atsReplyBabble(pThis, pInst, "BABBLE ");
|
---|
[89614] | 612 | rc = VERR_NET_NOT_CONNECTED;
|
---|
| 613 | }
|
---|
| 614 | RTMemFree(pReply);
|
---|
| 615 | }
|
---|
| 616 | return rc;
|
---|
| 617 | }
|
---|
| 618 |
|
---|
| 619 | /**
|
---|
| 620 | * Verifies and acknowledges a "TSET SND" request.
|
---|
| 621 | *
|
---|
| 622 | * @returns IPRT status code.
|
---|
| 623 | * @param pThis The ATS instance.
|
---|
[89962] | 624 | * @param pInst The opaque ATS instance structure.
|
---|
[89614] | 625 | * @param pPktHdr The test set end packet.
|
---|
| 626 | */
|
---|
[89962] | 627 | static int atsDoTestSetSend(PATSSERVER pThis, PATSSERVERINST pInst, PATSPKTHDR pPktHdr)
|
---|
[89614] | 628 | {
|
---|
| 629 | if (pPktHdr->cb != sizeof(ATSPKTREQTSETSND))
|
---|
[89962] | 630 | return atsReplyBadSize(pThis, pInst, pPktHdr, sizeof(ATSPKTREQTSETSND));
|
---|
[89614] | 631 |
|
---|
| 632 | PATSPKTREQTSETSND pReq = (PATSPKTREQTSETSND)pPktHdr;
|
---|
| 633 |
|
---|
| 634 | int rc = VINF_SUCCESS;
|
---|
| 635 |
|
---|
| 636 | if (!pThis->Callbacks.pfnTestSetSendRead)
|
---|
[89962] | 637 | return atsReplyRC(pThis, pInst, pPktHdr, VERR_NOT_SUPPORTED, "Sending test set not implemented");
|
---|
[89614] | 638 |
|
---|
| 639 | if (pThis->Callbacks.pfnTestSetSendBegin)
|
---|
| 640 | {
|
---|
| 641 | rc = pThis->Callbacks.pfnTestSetSendBegin(pThis->Callbacks.pvUser, pReq->szTag);
|
---|
| 642 | if (RT_FAILURE(rc))
|
---|
[89962] | 643 | return atsReplyRC(pThis, pInst, pPktHdr, rc, "Beginning sending test set '%s' failed", pReq->szTag);
|
---|
[89614] | 644 | }
|
---|
| 645 |
|
---|
| 646 | for (;;)
|
---|
| 647 | {
|
---|
[89803] | 648 | uint32_t uMyCrc32 = RTCrc32Start();
|
---|
[89614] | 649 | struct
|
---|
| 650 | {
|
---|
| 651 | ATSPKTHDR Hdr;
|
---|
| 652 | uint32_t uCrc32;
|
---|
[89803] | 653 | char ab[_64K];
|
---|
[89614] | 654 | char abPadding[ATSPKT_ALIGNMENT];
|
---|
| 655 | } Pkt;
|
---|
[89962] | 656 | #ifdef DEBUG
|
---|
| 657 | RT_ZERO(Pkt);
|
---|
| 658 | #endif
|
---|
[89803] | 659 | size_t cbRead = 0;
|
---|
[89614] | 660 | rc = pThis->Callbacks.pfnTestSetSendRead(pThis->Callbacks.pvUser, pReq->szTag, &Pkt.ab, sizeof(Pkt.ab), &cbRead);
|
---|
| 661 | if ( RT_FAILURE(rc)
|
---|
| 662 | || cbRead == 0)
|
---|
| 663 | {
|
---|
| 664 | if ( rc == VERR_EOF
|
---|
| 665 | || (RT_SUCCESS(rc) && cbRead == 0))
|
---|
| 666 | {
|
---|
| 667 | Pkt.uCrc32 = RTCrc32Finish(uMyCrc32);
|
---|
[89962] | 668 | rc = atsReplyInternal(pThis, pInst, &Pkt.Hdr, "DATA EOF", sizeof(uint32_t) /* uCrc32 */);
|
---|
[89614] | 669 | if (RT_SUCCESS(rc))
|
---|
[89962] | 670 | rc = atsWaitForAck(pThis, pInst, &Pkt.Hdr);
|
---|
[89614] | 671 | }
|
---|
| 672 | else
|
---|
[89962] | 673 | rc = atsReplyRC(pThis, pInst, pPktHdr, rc, "Sending data for test set '%s' failed", pReq->szTag);
|
---|
[89614] | 674 | break;
|
---|
| 675 | }
|
---|
| 676 |
|
---|
| 677 | uMyCrc32 = RTCrc32Process(uMyCrc32, &Pkt.ab[0], cbRead);
|
---|
| 678 | Pkt.uCrc32 = RTCrc32Finish(uMyCrc32);
|
---|
| 679 |
|
---|
[89962] | 680 | Log2Func(("cbRead=%zu -> uCrc32=%#x\n", cbRead, Pkt.uCrc32));
|
---|
| 681 |
|
---|
[89614] | 682 | Assert(cbRead <= sizeof(Pkt.ab));
|
---|
| 683 |
|
---|
[89962] | 684 | rc = atsReplyInternal(pThis, pInst, &Pkt.Hdr, "DATA ", sizeof(uint32_t) /* uCrc32 */ + cbRead);
|
---|
[89614] | 685 | if (RT_FAILURE(rc))
|
---|
| 686 | break;
|
---|
| 687 |
|
---|
[89962] | 688 | rc = atsWaitForAck(pThis, pInst, &Pkt.Hdr);
|
---|
[89614] | 689 | if (RT_FAILURE(rc))
|
---|
| 690 | break;
|
---|
| 691 | }
|
---|
| 692 |
|
---|
| 693 | if (pThis->Callbacks.pfnTestSetSendEnd)
|
---|
| 694 | {
|
---|
| 695 | int rc2 = pThis->Callbacks.pfnTestSetSendEnd(pThis->Callbacks.pvUser, pReq->szTag);
|
---|
| 696 | if (RT_FAILURE(rc2))
|
---|
[89962] | 697 | return atsReplyRC(pThis, pInst, pPktHdr, rc2, "Ending sending test set '%s' failed", pReq->szTag);
|
---|
[89614] | 698 | }
|
---|
| 699 |
|
---|
| 700 | return rc;
|
---|
| 701 | }
|
---|
| 702 |
|
---|
| 703 | /**
|
---|
[89456] | 704 | * Verifies and processes a "TN PLY" request.
|
---|
[89174] | 705 | *
|
---|
| 706 | * @returns IPRT status code.
|
---|
[89215] | 707 | * @param pThis The ATS instance.
|
---|
[89962] | 708 | * @param pInst The opaque ATS instance structure.
|
---|
[89174] | 709 | * @param pPktHdr The packet header.
|
---|
| 710 | */
|
---|
[89962] | 711 | static int atsDoTonePlay(PATSSERVER pThis, PATSSERVERINST pInst, PATSPKTHDR pPktHdr)
|
---|
[89174] | 712 | {
|
---|
| 713 | int rc = VINF_SUCCESS;
|
---|
| 714 |
|
---|
| 715 | if (pPktHdr->cb < sizeof(ATSPKTREQTONEPLAY))
|
---|
[89962] | 716 | return atsReplyBadSize(pThis, pInst, pPktHdr, sizeof(ATSPKTREQTONEPLAY));
|
---|
[89174] | 717 |
|
---|
[89962] | 718 | if (pInst->enmState != ATSCLIENTSTATE_READY)
|
---|
| 719 | return atsReplyInvalidState(pThis, pInst, pPktHdr);
|
---|
[89174] | 720 |
|
---|
[89226] | 721 | if (!pThis->Callbacks.pfnTonePlay)
|
---|
[89962] | 722 | return atsReplyRC(pThis, pInst, pPktHdr, VERR_NOT_SUPPORTED, "Playing tones not supported");
|
---|
[89226] | 723 |
|
---|
| 724 | PATSPKTREQTONEPLAY pReq = (PATSPKTREQTONEPLAY)pPktHdr;
|
---|
[89458] | 725 | rc = pThis->Callbacks.pfnTonePlay(pThis->Callbacks.pvUser, &pReq->ToneParms);
|
---|
[89226] | 726 |
|
---|
[89962] | 727 | int rc2 = atsReplyAck(pThis, pInst, pPktHdr);
|
---|
[89226] | 728 | if (RT_SUCCESS(rc))
|
---|
| 729 | rc = rc2;
|
---|
| 730 |
|
---|
[89174] | 731 | return rc;
|
---|
| 732 | }
|
---|
| 733 |
|
---|
| 734 | /**
|
---|
[89456] | 735 | * Verifies and processes a "TN REC" request.
|
---|
| 736 | *
|
---|
| 737 | * @returns IPRT status code.
|
---|
| 738 | * @param pThis The ATS instance.
|
---|
[89962] | 739 | * @param pInst The opaque ATS instance structure.
|
---|
[89456] | 740 | * @param pPktHdr The packet header.
|
---|
| 741 | */
|
---|
[89962] | 742 | static int atsDoToneRecord(PATSSERVER pThis, PATSSERVERINST pInst, PATSPKTHDR pPktHdr)
|
---|
[89456] | 743 | {
|
---|
| 744 | int rc = VINF_SUCCESS;
|
---|
| 745 |
|
---|
| 746 | if (pPktHdr->cb < sizeof(ATSPKTREQTONEREC))
|
---|
[89962] | 747 | return atsReplyBadSize(pThis, pInst, pPktHdr, sizeof(ATSPKTREQTONEREC));
|
---|
[89456] | 748 |
|
---|
[89962] | 749 | if (pInst->enmState != ATSCLIENTSTATE_READY)
|
---|
| 750 | return atsReplyInvalidState(pThis, pInst, pPktHdr);
|
---|
[89456] | 751 |
|
---|
| 752 | if (!pThis->Callbacks.pfnToneRecord)
|
---|
[89962] | 753 | return atsReplyRC(pThis, pInst, pPktHdr, VERR_NOT_SUPPORTED, "Recording tones not supported");
|
---|
[89456] | 754 |
|
---|
| 755 | PATSPKTREQTONEREC pReq = (PATSPKTREQTONEREC)pPktHdr;
|
---|
[89458] | 756 | rc = pThis->Callbacks.pfnToneRecord(pThis->Callbacks.pvUser, &pReq->ToneParms);
|
---|
[89456] | 757 |
|
---|
[89962] | 758 | int rc2 = atsReplyAck(pThis, pInst, pPktHdr);
|
---|
[89456] | 759 | if (RT_SUCCESS(rc))
|
---|
| 760 | rc = rc2;
|
---|
| 761 |
|
---|
| 762 | return rc;
|
---|
| 763 | }
|
---|
| 764 |
|
---|
| 765 | /**
|
---|
[89174] | 766 | * Main request processing routine for each client.
|
---|
| 767 | *
|
---|
| 768 | * @returns IPRT status code.
|
---|
[89215] | 769 | * @param pThis The ATS instance.
|
---|
[89962] | 770 | * @param pInst The ATS client structure sending the request.
|
---|
[89174] | 771 | */
|
---|
[89962] | 772 | static int atsClientReqProcess(PATSSERVER pThis, PATSSERVERINST pInst)
|
---|
[89174] | 773 | {
|
---|
| 774 | /*
|
---|
| 775 | * Read client command packet and process it.
|
---|
| 776 | */
|
---|
| 777 | PATSPKTHDR pPktHdr = NULL;
|
---|
[89962] | 778 | int rc = atsRecvPkt(pThis, pInst, &pPktHdr, true /*fAutoRetryOnFailure*/);
|
---|
[89174] | 779 | if (RT_FAILURE(rc))
|
---|
| 780 | return rc;
|
---|
| 781 |
|
---|
| 782 | /*
|
---|
| 783 | * Do a string switch on the opcode bit.
|
---|
| 784 | */
|
---|
| 785 | /* Connection: */
|
---|
| 786 | if ( atsIsSameOpcode(pPktHdr, ATSPKT_OPCODE_HOWDY))
|
---|
[89962] | 787 | rc = atsDoHowdy(pThis, pInst, pPktHdr);
|
---|
[89174] | 788 | else if (atsIsSameOpcode(pPktHdr, ATSPKT_OPCODE_BYE))
|
---|
[89962] | 789 | rc = atsDoBye(pThis, pInst, pPktHdr);
|
---|
[89431] | 790 | /* Test set handling: */
|
---|
| 791 | else if (atsIsSameOpcode(pPktHdr, ATSPKT_OPCODE_TESTSET_BEGIN))
|
---|
[89962] | 792 | rc = atsDoTestSetBegin(pThis, pInst, pPktHdr);
|
---|
[89431] | 793 | else if (atsIsSameOpcode(pPktHdr, ATSPKT_OPCODE_TESTSET_END))
|
---|
[89962] | 794 | rc = atsDoTestSetEnd(pThis, pInst, pPktHdr);
|
---|
[89614] | 795 | else if (atsIsSameOpcode(pPktHdr, ATSPKT_OPCODE_TESTSET_SEND))
|
---|
[89962] | 796 | rc = atsDoTestSetSend(pThis, pInst, pPktHdr);
|
---|
[89226] | 797 | /* Audio testing: */
|
---|
[89174] | 798 | else if (atsIsSameOpcode(pPktHdr, ATSPKT_OPCODE_TONE_PLAY))
|
---|
[89962] | 799 | rc = atsDoTonePlay(pThis, pInst, pPktHdr);
|
---|
[89456] | 800 | else if (atsIsSameOpcode(pPktHdr, ATSPKT_OPCODE_TONE_RECORD))
|
---|
[89962] | 801 | rc = atsDoToneRecord(pThis, pInst, pPktHdr);
|
---|
[89174] | 802 | /* Misc: */
|
---|
| 803 | else
|
---|
[89962] | 804 | rc = atsReplyUnknown(pThis, pInst, pPktHdr);
|
---|
[89174] | 805 |
|
---|
| 806 | RTMemFree(pPktHdr);
|
---|
| 807 |
|
---|
| 808 | return rc;
|
---|
| 809 | }
|
---|
| 810 |
|
---|
| 811 | /**
|
---|
| 812 | * Destroys a client instance.
|
---|
| 813 | *
|
---|
| 814 | * @returns nothing.
|
---|
[89962] | 815 | * @param pInst The opaque ATS instance structure.
|
---|
[89174] | 816 | */
|
---|
[89962] | 817 | static void atsClientDestroy(PATSSERVERINST pInst)
|
---|
[89174] | 818 | {
|
---|
[89962] | 819 | if (pInst->pszHostname)
|
---|
| 820 | RTStrFree(pInst->pszHostname);
|
---|
| 821 | RTMemFree(pInst);
|
---|
[89174] | 822 | }
|
---|
| 823 |
|
---|
| 824 | /**
|
---|
| 825 | * The main thread worker serving the clients.
|
---|
| 826 | */
|
---|
| 827 | static DECLCALLBACK(int) atsClientWorker(RTTHREAD hThread, void *pvUser)
|
---|
| 828 | {
|
---|
[89215] | 829 | RT_NOREF(hThread);
|
---|
| 830 |
|
---|
| 831 | PATSSERVER pThis = (PATSSERVER)pvUser;
|
---|
| 832 | AssertPtrReturn(pThis, VERR_INVALID_POINTER);
|
---|
| 833 |
|
---|
[89174] | 834 | unsigned cClientsMax = 0;
|
---|
| 835 | unsigned cClientsCur = 0;
|
---|
[89962] | 836 | PATSSERVERINST *papInsts = NULL;
|
---|
[89174] | 837 |
|
---|
| 838 | /* Add the pipe to the poll set. */
|
---|
[89225] | 839 | int rc = RTPollSetAddPipe(pThis->hPollSet, pThis->hPipeR, RTPOLL_EVT_READ | RTPOLL_EVT_ERROR, 0);
|
---|
[89174] | 840 | if (RT_SUCCESS(rc))
|
---|
| 841 | {
|
---|
[89215] | 842 | while (!pThis->fTerminate)
|
---|
[89174] | 843 | {
|
---|
| 844 | uint32_t fEvts;
|
---|
| 845 | uint32_t uId;
|
---|
[89225] | 846 | rc = RTPoll(pThis->hPollSet, RT_INDEFINITE_WAIT, &fEvts, &uId);
|
---|
[89174] | 847 | if (RT_SUCCESS(rc))
|
---|
| 848 | {
|
---|
| 849 | if (uId == 0)
|
---|
| 850 | {
|
---|
| 851 | if (fEvts & RTPOLL_EVT_ERROR)
|
---|
| 852 | break;
|
---|
| 853 |
|
---|
| 854 | /* We got woken up because of a new client. */
|
---|
| 855 | Assert(fEvts & RTPOLL_EVT_READ);
|
---|
| 856 |
|
---|
| 857 | uint8_t bRead;
|
---|
| 858 | size_t cbRead = 0;
|
---|
[89215] | 859 | rc = RTPipeRead(pThis->hPipeR, &bRead, 1, &cbRead);
|
---|
[89174] | 860 | AssertRC(rc);
|
---|
| 861 |
|
---|
[89215] | 862 | RTCritSectEnter(&pThis->CritSectClients);
|
---|
[89174] | 863 | /* Walk the list and add all new clients. */
|
---|
[89962] | 864 | PATSSERVERINST pIt, pItNext;
|
---|
[89215] | 865 | RTListForEachSafe(&pThis->LstClientsNew, pIt, pItNext, ATSCLIENTINST, NdLst)
|
---|
[89174] | 866 | {
|
---|
| 867 | RTListNodeRemove(&pIt->NdLst);
|
---|
| 868 | Assert(cClientsCur <= cClientsMax);
|
---|
| 869 | if (cClientsCur == cClientsMax)
|
---|
| 870 | {
|
---|
| 871 | /* Realloc to accommodate for the new clients. */
|
---|
[89962] | 872 | PATSSERVERINST *papInstsNew = (PATSSERVERINST *)RTMemRealloc(papInsts, (cClientsMax + 10) * sizeof(PATSSERVERINST));
|
---|
| 873 | if (RT_LIKELY(papInstsNew))
|
---|
[89174] | 874 | {
|
---|
| 875 | cClientsMax += 10;
|
---|
[89962] | 876 | papInsts = papInstsNew;
|
---|
[89174] | 877 | }
|
---|
| 878 | }
|
---|
| 879 | if (cClientsCur < cClientsMax)
|
---|
| 880 | {
|
---|
| 881 | /* Find a free slot in the client array. */
|
---|
| 882 | unsigned idxSlt = 0;
|
---|
| 883 | while ( idxSlt < cClientsMax
|
---|
[89962] | 884 | && papInsts[idxSlt] != NULL)
|
---|
[89174] | 885 | idxSlt++;
|
---|
| 886 |
|
---|
[89962] | 887 | rc = pThis->pTransport->pfnPollSetAdd(pThis->pTransportInst, pThis->hPollSet, pIt->pTransportClient, idxSlt + 1);
|
---|
[89174] | 888 | if (RT_SUCCESS(rc))
|
---|
| 889 | {
|
---|
| 890 | cClientsCur++;
|
---|
[89962] | 891 | papInsts[idxSlt] = pIt;
|
---|
[89174] | 892 | }
|
---|
| 893 | else
|
---|
| 894 | {
|
---|
[89962] | 895 | pThis->pTransport->pfnNotifyBye(pThis->pTransportInst, pIt->pTransportClient);
|
---|
[89174] | 896 | atsClientDestroy(pIt);
|
---|
| 897 | }
|
---|
| 898 | }
|
---|
| 899 | else
|
---|
| 900 | {
|
---|
[89962] | 901 | pThis->pTransport->pfnNotifyBye(pThis->pTransportInst, pIt->pTransportClient);
|
---|
[89174] | 902 | atsClientDestroy(pIt);
|
---|
| 903 | }
|
---|
| 904 | }
|
---|
[89215] | 905 | RTCritSectLeave(&pThis->CritSectClients);
|
---|
[89174] | 906 | }
|
---|
| 907 | else
|
---|
| 908 | {
|
---|
| 909 | /* Client sends a request, pick the right client and process it. */
|
---|
[89962] | 910 | PATSSERVERINST pInst = papInsts[uId - 1];
|
---|
| 911 | AssertPtr(pInst);
|
---|
[89174] | 912 | if (fEvts & RTPOLL_EVT_READ)
|
---|
[89962] | 913 | rc = atsClientReqProcess(pThis, pInst);
|
---|
[89174] | 914 |
|
---|
| 915 | if ( (fEvts & RTPOLL_EVT_ERROR)
|
---|
| 916 | || RT_FAILURE(rc))
|
---|
| 917 | {
|
---|
| 918 | /* Close connection and remove client from array. */
|
---|
[89962] | 919 | rc = pThis->pTransport->pfnPollSetRemove(pThis->pTransportInst, pThis->hPollSet, pInst->pTransportClient, uId);
|
---|
[89174] | 920 | AssertRC(rc);
|
---|
| 921 |
|
---|
[89962] | 922 | pThis->pTransport->pfnNotifyBye(pThis->pTransportInst, pInst->pTransportClient);
|
---|
| 923 | papInsts[uId - 1] = NULL;
|
---|
[89174] | 924 | cClientsCur--;
|
---|
[89962] | 925 | atsClientDestroy(pInst);
|
---|
[89174] | 926 | }
|
---|
| 927 | }
|
---|
| 928 | }
|
---|
| 929 | }
|
---|
| 930 | }
|
---|
| 931 |
|
---|
| 932 | return rc;
|
---|
| 933 | }
|
---|
| 934 |
|
---|
| 935 | /**
|
---|
| 936 | * The main thread waiting for new client connections.
|
---|
| 937 | *
|
---|
| 938 | * @returns VBox status code.
|
---|
| 939 | */
|
---|
[90176] | 940 | static DECLCALLBACK(int) atsMainThread(RTTHREAD hThread, void *pvUser)
|
---|
[89174] | 941 | {
|
---|
[89215] | 942 | RT_NOREF(hThread);
|
---|
[89174] | 943 |
|
---|
[89215] | 944 | PATSSERVER pThis = (PATSSERVER)pvUser;
|
---|
| 945 | AssertPtrReturn(pThis, VERR_INVALID_POINTER);
|
---|
| 946 |
|
---|
[89541] | 947 | int rc = RTThreadUserSignal(hThread);
|
---|
| 948 | AssertRCReturn(rc, rc);
|
---|
[89174] | 949 |
|
---|
[89215] | 950 | while (!pThis->fTerminate)
|
---|
[89174] | 951 | {
|
---|
| 952 | /*
|
---|
| 953 | * Wait for new connection and spin off a new thread
|
---|
| 954 | * for every new client.
|
---|
| 955 | */
|
---|
| 956 | PATSTRANSPORTCLIENT pTransportClient;
|
---|
[89962] | 957 | rc = pThis->pTransport->pfnWaitForConnect(pThis->pTransportInst, &pTransportClient);
|
---|
[89174] | 958 | if (RT_FAILURE(rc))
|
---|
| 959 | continue;
|
---|
| 960 |
|
---|
| 961 | /*
|
---|
| 962 | * New connection, create new client structure and spin of
|
---|
| 963 | * the request handling thread.
|
---|
| 964 | */
|
---|
[89962] | 965 | PATSSERVERINST pInst = (PATSSERVERINST)RTMemAllocZ(sizeof(ATSCLIENTINST));
|
---|
| 966 | if (RT_LIKELY(pInst))
|
---|
[89174] | 967 | {
|
---|
[89962] | 968 | pInst->enmState = ATSCLIENTSTATE_INITIALISING;
|
---|
| 969 | pInst->pTransportClient = pTransportClient;
|
---|
| 970 | pInst->pszHostname = NULL;
|
---|
[89174] | 971 |
|
---|
| 972 | /* Add client to the new list and inform the worker thread. */
|
---|
[89215] | 973 | RTCritSectEnter(&pThis->CritSectClients);
|
---|
[89962] | 974 | RTListAppend(&pThis->LstClientsNew, &pInst->NdLst);
|
---|
[89215] | 975 | RTCritSectLeave(&pThis->CritSectClients);
|
---|
[89174] | 976 |
|
---|
| 977 | size_t cbWritten = 0;
|
---|
[89215] | 978 | rc = RTPipeWrite(pThis->hPipeW, "", 1, &cbWritten);
|
---|
[89174] | 979 | if (RT_FAILURE(rc))
|
---|
| 980 | RTMsgError("Failed to inform worker thread of a new client");
|
---|
| 981 | }
|
---|
| 982 | else
|
---|
| 983 | {
|
---|
| 984 | RTMsgError("Creating new client structure failed with out of memory error\n");
|
---|
[89962] | 985 | pThis->pTransport->pfnNotifyBye(pThis->pTransportInst, pTransportClient);
|
---|
[89174] | 986 | }
|
---|
| 987 | }
|
---|
| 988 |
|
---|
| 989 | return rc;
|
---|
| 990 | }
|
---|
| 991 |
|
---|
| 992 | /**
|
---|
[89962] | 993 | * Creates an ATS instance.
|
---|
[89174] | 994 | *
|
---|
| 995 | * @returns VBox status code.
|
---|
[89962] | 996 | * @param pThis The ATS instance to create.
|
---|
| 997 | */
|
---|
| 998 | int AudioTestSvcCreate(PATSSERVER pThis)
|
---|
| 999 | {
|
---|
| 1000 | /*
|
---|
| 1001 | * The default transporter is the first one.
|
---|
| 1002 | */
|
---|
| 1003 | pThis->pTransport = g_apTransports[0]; /** @todo Make this dynamic. */
|
---|
| 1004 |
|
---|
| 1005 | return pThis->pTransport->pfnCreate(&pThis->pTransportInst);
|
---|
| 1006 | }
|
---|
| 1007 |
|
---|
| 1008 | /**
|
---|
| 1009 | * Initializes an ATS instance.
|
---|
| 1010 | *
|
---|
| 1011 | * @returns VBox status code.
|
---|
[89215] | 1012 | * @param pThis The ATS instance.
|
---|
[89228] | 1013 | * @param pCallbacks The callbacks table to use.
|
---|
[89962] | 1014 | */
|
---|
| 1015 | int AudioTestSvcInit(PATSSERVER pThis, PCATSCALLBACKS pCallbacks)
|
---|
[89174] | 1016 | {
|
---|
[89226] | 1017 | memcpy(&pThis->Callbacks, pCallbacks, sizeof(ATSCALLBACKS));
|
---|
| 1018 |
|
---|
[89225] | 1019 | pThis->fStarted = false;
|
---|
[89215] | 1020 | pThis->fTerminate = false;
|
---|
[89567] | 1021 |
|
---|
| 1022 | pThis->hPipeR = NIL_RTPIPE;
|
---|
| 1023 | pThis->hPipeW = NIL_RTPIPE;
|
---|
| 1024 |
|
---|
[89215] | 1025 | RTListInit(&pThis->LstClientsNew);
|
---|
[89174] | 1026 |
|
---|
| 1027 | /*
|
---|
| 1028 | * Initialize the transport layer.
|
---|
| 1029 | */
|
---|
[89962] | 1030 | int rc = RTCritSectInit(&pThis->CritSectClients);
|
---|
[89174] | 1031 | if (RT_SUCCESS(rc))
|
---|
| 1032 | {
|
---|
[89962] | 1033 | rc = RTPollSetCreate(&pThis->hPollSet);
|
---|
[89174] | 1034 | if (RT_SUCCESS(rc))
|
---|
| 1035 | {
|
---|
[89962] | 1036 | rc = RTPipeCreate(&pThis->hPipeR, &pThis->hPipeW, 0);
|
---|
[89174] | 1037 | if (RT_SUCCESS(rc))
|
---|
| 1038 | {
|
---|
[89962] | 1039 | /* Spin off the thread serving connections. */
|
---|
| 1040 | rc = RTThreadCreate(&pThis->hThreadServing, atsClientWorker, pThis, 0, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE,
|
---|
| 1041 | "AUDTSTSRVC");
|
---|
[89174] | 1042 | if (RT_SUCCESS(rc))
|
---|
[89962] | 1043 | return VINF_SUCCESS;
|
---|
[89174] | 1044 | else
|
---|
[89962] | 1045 | RTMsgError("Creating the client worker thread failed with %Rrc\n", rc);
|
---|
[89174] | 1046 |
|
---|
[89962] | 1047 | RTPipeClose(pThis->hPipeR);
|
---|
| 1048 | RTPipeClose(pThis->hPipeW);
|
---|
[89174] | 1049 | }
|
---|
| 1050 | else
|
---|
[89962] | 1051 | RTMsgError("Creating communications pipe failed with %Rrc\n", rc);
|
---|
[89174] | 1052 |
|
---|
[89962] | 1053 | RTPollSetDestroy(pThis->hPollSet);
|
---|
[89174] | 1054 | }
|
---|
| 1055 | else
|
---|
[89962] | 1056 | RTMsgError("Creating pollset failed with %Rrc\n", rc);
|
---|
| 1057 |
|
---|
| 1058 | RTCritSectDelete(&pThis->CritSectClients);
|
---|
[89174] | 1059 | }
|
---|
| 1060 | else
|
---|
[89962] | 1061 | RTMsgError("Creating global critical section failed with %Rrc\n", rc);
|
---|
[89174] | 1062 |
|
---|
| 1063 | return rc;
|
---|
| 1064 | }
|
---|
| 1065 |
|
---|
[89215] | 1066 | /**
|
---|
[89962] | 1067 | * Handles a command line option.
|
---|
| 1068 | *
|
---|
| 1069 | * @returns VBox status code.
|
---|
| 1070 | * @param pThis The ATS instance to handle option for.
|
---|
| 1071 | * @param ch Option (short) to handle.
|
---|
| 1072 | * @param pVal Option union to store the result in on success.
|
---|
| 1073 | */
|
---|
| 1074 | int AudioTestSvcHandleOption(PATSSERVER pThis, int ch, PCRTGETOPTUNION pVal)
|
---|
| 1075 | {
|
---|
| 1076 | AssertPtrReturn(pThis->pTransport, VERR_WRONG_ORDER); /* Must be creatd first. */
|
---|
| 1077 | if (!pThis->pTransport->pfnOption)
|
---|
| 1078 | return VERR_GETOPT_UNKNOWN_OPTION;
|
---|
| 1079 | return pThis->pTransport->pfnOption(pThis->pTransportInst, ch, pVal);
|
---|
| 1080 | }
|
---|
| 1081 |
|
---|
| 1082 | /**
|
---|
[89215] | 1083 | * Starts a formerly initialized ATS instance.
|
---|
| 1084 | *
|
---|
| 1085 | * @returns VBox status code.
|
---|
[89962] | 1086 | * @param pThis The ATS instance to start.
|
---|
[89215] | 1087 | */
|
---|
| 1088 | int AudioTestSvcStart(PATSSERVER pThis)
|
---|
[89174] | 1089 | {
|
---|
[89962] | 1090 | int rc = pThis->pTransport->pfnStart(pThis->pTransportInst);
|
---|
[89225] | 1091 | if (RT_SUCCESS(rc))
|
---|
[89541] | 1092 | {
|
---|
[89962] | 1093 | /* Spin off the connection thread. */
|
---|
[90176] | 1094 | rc = RTThreadCreate(&pThis->hThreadMain, atsMainThread, pThis, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE,
|
---|
[89962] | 1095 | "AUDTSTSRVM");
|
---|
[89541] | 1096 | if (RT_SUCCESS(rc))
|
---|
[89962] | 1097 | {
|
---|
| 1098 | rc = RTThreadUserWait(pThis->hThreadMain, RT_MS_30SEC);
|
---|
| 1099 | if (RT_SUCCESS(rc))
|
---|
| 1100 | pThis->fStarted = true;
|
---|
| 1101 | }
|
---|
[89541] | 1102 | }
|
---|
[89174] | 1103 |
|
---|
| 1104 | return rc;
|
---|
| 1105 | }
|
---|
| 1106 |
|
---|
[89215] | 1107 | /**
|
---|
| 1108 | * Shuts down a formerly started ATS instance.
|
---|
| 1109 | *
|
---|
| 1110 | * @returns VBox status code.
|
---|
| 1111 | * @param pThis The ATS instance.
|
---|
| 1112 | */
|
---|
| 1113 | int AudioTestSvcShutdown(PATSSERVER pThis)
|
---|
| 1114 | {
|
---|
[89225] | 1115 | if (!pThis->fStarted)
|
---|
| 1116 | return VINF_SUCCESS;
|
---|
| 1117 |
|
---|
| 1118 | ASMAtomicXchgBool(&pThis->fTerminate, true);
|
---|
| 1119 |
|
---|
| 1120 | if (pThis->pTransport)
|
---|
[89962] | 1121 | pThis->pTransport->pfnTerm(pThis->pTransportInst);
|
---|
[89225] | 1122 |
|
---|
| 1123 | size_t cbWritten;
|
---|
| 1124 | int rc = RTPipeWrite(pThis->hPipeW, "", 1, &cbWritten);
|
---|
| 1125 | AssertRCReturn(rc, rc);
|
---|
| 1126 |
|
---|
| 1127 | /* First close serving thread. */
|
---|
| 1128 | int rcThread;
|
---|
| 1129 | rc = RTThreadWait(pThis->hThreadServing, RT_MS_30SEC, &rcThread);
|
---|
| 1130 | if (RT_SUCCESS(rc))
|
---|
| 1131 | {
|
---|
| 1132 | rc = rcThread;
|
---|
| 1133 | if (RT_SUCCESS(rc))
|
---|
| 1134 | {
|
---|
| 1135 | /* Close the main thread last. */
|
---|
| 1136 | rc = RTThreadWait(pThis->hThreadMain, RT_MS_30SEC, &rcThread);
|
---|
| 1137 | if (RT_SUCCESS(rc))
|
---|
| 1138 | rc = rcThread;
|
---|
| 1139 |
|
---|
| 1140 | if (rc == VERR_TCP_SERVER_DESTROYED)
|
---|
| 1141 | rc = VINF_SUCCESS;
|
---|
| 1142 | }
|
---|
| 1143 | }
|
---|
| 1144 |
|
---|
| 1145 | if (RT_SUCCESS(rc))
|
---|
| 1146 | pThis->fStarted = false;
|
---|
| 1147 |
|
---|
| 1148 | return rc;
|
---|
[89215] | 1149 | }
|
---|
| 1150 |
|
---|
[89225] | 1151 | /**
|
---|
| 1152 | * Destroys an ATS instance, internal version.
|
---|
| 1153 | *
|
---|
| 1154 | * @returns VBox status code.
|
---|
| 1155 | * @param pThis ATS instance to destroy.
|
---|
| 1156 | */
|
---|
| 1157 | static int audioTestSvcDestroyInternal(PATSSERVER pThis)
|
---|
| 1158 | {
|
---|
| 1159 | int rc = VINF_SUCCESS;
|
---|
| 1160 |
|
---|
| 1161 | if (pThis->hPipeR != NIL_RTPIPE)
|
---|
| 1162 | {
|
---|
| 1163 | rc = RTPipeClose(pThis->hPipeR);
|
---|
| 1164 | AssertRCReturn(rc, rc);
|
---|
| 1165 | pThis->hPipeR = NIL_RTPIPE;
|
---|
| 1166 | }
|
---|
| 1167 |
|
---|
| 1168 | if (pThis->hPipeW != NIL_RTPIPE)
|
---|
| 1169 | {
|
---|
| 1170 | rc = RTPipeClose(pThis->hPipeW);
|
---|
| 1171 | AssertRCReturn(rc, rc);
|
---|
| 1172 | pThis->hPipeW = NIL_RTPIPE;
|
---|
| 1173 | }
|
---|
| 1174 |
|
---|
| 1175 | RTPollSetDestroy(pThis->hPollSet);
|
---|
| 1176 | pThis->hPollSet = NIL_RTPOLLSET;
|
---|
| 1177 |
|
---|
[89962] | 1178 | PATSSERVERINST pIt, pItNext;
|
---|
[89225] | 1179 | RTListForEachSafe(&pThis->LstClientsNew, pIt, pItNext, ATSCLIENTINST, NdLst)
|
---|
| 1180 | {
|
---|
| 1181 | RTListNodeRemove(&pIt->NdLst);
|
---|
| 1182 |
|
---|
| 1183 | RTMemFree(pIt);
|
---|
| 1184 | pIt = NULL;
|
---|
| 1185 | }
|
---|
| 1186 |
|
---|
| 1187 | if (RTCritSectIsInitialized(&pThis->CritSectClients))
|
---|
| 1188 | {
|
---|
| 1189 | rc = RTCritSectDelete(&pThis->CritSectClients);
|
---|
| 1190 | AssertRCReturn(rc, rc);
|
---|
| 1191 | }
|
---|
| 1192 |
|
---|
| 1193 | return rc;
|
---|
| 1194 | }
|
---|
| 1195 |
|
---|
| 1196 | /**
|
---|
| 1197 | * Destroys an ATS instance.
|
---|
| 1198 | *
|
---|
| 1199 | * @returns VBox status code.
|
---|
| 1200 | * @param pThis ATS instance to destroy.
|
---|
| 1201 | */
|
---|
| 1202 | int AudioTestSvcDestroy(PATSSERVER pThis)
|
---|
| 1203 | {
|
---|
[89962] | 1204 | int rc = audioTestSvcDestroyInternal(pThis);
|
---|
| 1205 | if (RT_SUCCESS(rc))
|
---|
| 1206 | {
|
---|
| 1207 | if (pThis->pTransport)
|
---|
| 1208 | {
|
---|
| 1209 | if ( pThis->pTransport->pfnDestroy
|
---|
| 1210 | && pThis->pTransportInst)
|
---|
| 1211 | {
|
---|
| 1212 | pThis->pTransport->pfnDestroy(pThis->pTransportInst);
|
---|
| 1213 | pThis->pTransportInst = NULL;
|
---|
| 1214 | }
|
---|
| 1215 | }
|
---|
| 1216 | }
|
---|
| 1217 |
|
---|
| 1218 | return rc;
|
---|
[89225] | 1219 | }
|
---|