// Handles an incoming message (from the message queue). UtlBoolean SipClientWriteBuffer::handleMessage(OsMsg& eventMessage) { UtlBoolean messageProcessed = FALSE; int msgType = eventMessage.getMsgType(); int msgSubType = eventMessage.getMsgSubType(); if (msgType == OsMsg::OS_SHUTDOWN) { // When shutting down, have to return all queued outgoing messages // with transport errors. emptyBuffer(TRUE); // Continue with shutdown processing. messageProcessed = FALSE; } else if (msgType == OsMsg::OS_EVENT && (msgSubType == SipClientSendMsg::SIP_CLIENT_SEND || msgSubType == SipClientSendMsg::SIP_CLIENT_SEND_KEEP_ALIVE)) { // Queued SIP message to send - normal path. if (msgSubType == SipClientSendMsg::SIP_CLIENT_SEND) { // Insert the SIP message into the queue, detaching it from // the incoming eventMessage. SipClientSendMsg* sendMsg = dynamic_cast <SipClientSendMsg*> (&eventMessage); if (sendMsg) { insertMessage(sendMsg->detachMessage()); messageProcessed = TRUE; } else { Os::Logger::instance().log(FAC_SIP, PRI_CRIT, "SipClientWriteBuffer[%s]::handleMessage " "message is not a SipClientSendMsg", mName.data()); } } else // send Keep Alive { Os::Logger::instance().log(FAC_SIP, PRI_DEBUG, "SipClientWriteBuffer[%s]::handleMessage send TCP keep-alive CR-LF response", mName.data()); UtlString* pKeepAlive; pKeepAlive = new UtlString("\r\n"); insertMessage(pKeepAlive); messageProcessed = TRUE; } // Write what we can. writeMore(); // sendMsg will be deleted by ::run(), as usual. // Its destructor will free any storage owned by it. } return (messageProcessed); }
bool LocalClient::write(const String& data) { if (pthread_equal(pthread_self(), EventLoop::instance()->thread())) { if (mBuffers.empty()) EventLoop::instance()->addFileDescriptor(mFd, EventLoop::Read | EventLoop::Write, dataCallback, this); mBuffers.push_back(data); return writeMore(); } else { EventLoop::instance()->postEvent(this, new DelayedWriteEvent(data)); return true; } }
bool SocketClient::write(const String& data) { if (pthread_equal(pthread_self(), EventLoop::instance()->thread())) { if (mBuffers.empty()) EventLoop::instance()->addFileDescriptor(mFd, EventLoop::Read | EventLoop::Write, dataCallback, this); sockaddr_in addr; memset(&addr, 0, sizeof(sockaddr_in)); mBuffers.push_back(std::make_pair(addr, data)); return writeMore(); } else { EventLoop::instance()->postEvent(this, new DelayedWriteEvent(data)); return true; } }
void SocketClient::event(const Event* event) { switch (event->type()) { case DelayedWriteEvent::Type: { const DelayedWriteEvent *ev = static_cast<const DelayedWriteEvent*>(event); assert(pthread_equal(pthread_self(), EventLoop::instance()->thread())); if (mBuffers.empty()) EventLoop::instance()->addFileDescriptor(mFd, EventLoop::Read | EventLoop::Write, dataCallback, this); mBuffers.push_back(std::make_pair(ev->addr, ev->data)); writeMore(); break; } default: EventReceiver::event(event); } }
bool SocketClient::writeTo(const String& host, uint16_t port, const String& data) { sockaddr_in addr; if (!lookupHost(host, port, addr)) return false; if (mFd == -1) { if (!setupUdp(mFd)) return false; mMode = Udp; } if (pthread_equal(pthread_self(), EventLoop::instance()->thread())) { if (mBuffers.empty()) EventLoop::instance()->addFileDescriptor(mFd, EventLoop::Read | EventLoop::Write, dataCallback, this); mBuffers.push_back(std::make_pair(addr, data)); return writeMore(); } else { EventLoop::instance()->postEvent(this, new DelayedWriteEvent(addr, data)); return true; } }
AudioTest::AudioTest() { QWidget *window = new QWidget; QVBoxLayout* layout = new QVBoxLayout; deviceBox = new QComboBox(this); foreach (const QAudioDeviceInfo &deviceInfo, QAudioDeviceInfo::availableDevices(QAudio::AudioOutput)) deviceBox->addItem(deviceInfo.deviceName(), qVariantFromValue(deviceInfo)); connect(deviceBox,SIGNAL(activated(int)),SLOT(deviceChanged(int))); layout->addWidget(deviceBox); button = new QPushButton(this); button->setText(tr("Click for Push Mode")); connect(button,SIGNAL(clicked()),SLOT(toggle())); layout->addWidget(button); button2 = new QPushButton(this); button2->setText(tr("Click To Suspend")); connect(button2,SIGNAL(clicked()),SLOT(togglePlay())); layout->addWidget(button2); window->setLayout(layout); setCentralWidget(window); window->show(); buffer = new char[BUFFER_SIZE]; gen = new Generator(this); pullMode = true; timer = new QTimer(this); connect(timer,SIGNAL(timeout()),SLOT(writeMore())); gen->start(); settings.setFrequency(SYSTEM_FREQ); settings.setChannels(1); settings.setSampleSize(16); settings.setCodec("audio/pcm"); settings.setByteOrder(QAudioFormat::LittleEndian); settings.setSampleType(QAudioFormat::SignedInt); QAudioDeviceInfo info(QAudioDeviceInfo::defaultOutputDevice()); if (!info.isFormatSupported(settings)) { qWarning()<<"default format not supported try to use nearest"; settings = info.nearestFormat(settings); } if(settings.sampleSize() != 16) { qWarning()<<"audio device doesn't support 16 bit samples, example cannot run"; button->setDisabled(true); button2->setDisabled(true); audioOutput = 0; return; } audioOutput = new QAudioOutput(settings,this); connect(audioOutput,SIGNAL(notify()),SLOT(status())); connect(audioOutput,SIGNAL(stateChanged(QAudio::State)),SLOT(state(QAudio::State))); audioOutput->start(gen); }
// Thread execution code. int SipClient::run(void* runArg) { OsMsg* pMsg = NULL; OsStatus res; // Buffer to hold data read from the socket but not yet parsed // into incoming SIP messages. UtlString readBuffer; bool waitingToReportErr = FALSE; // controls whether to read-select on socket bool tcpOnErrWaitForSend = TRUE; int repeatedEOFs = 0; Os::Logger::instance().log(FAC_SIP, PRI_DEBUG, "SipClient[%s]::run start " "tcpOnErrWaitForSend-%d waitingToReportErr-%d mbTcpOnErrWaitForSend-%d repeatedEOFs-%d", mName.data(), tcpOnErrWaitForSend, waitingToReportErr, mbTcpOnErrWaitForSend, repeatedEOFs); // Wait structure: struct pollfd fds[2]; // Incoming message on the message queue (to be sent on the socket). fds[0].fd = mPipeReadingFd; // Socket ready to write (to continue sending message). // Socket ready to read (message to be received). do { assert(repeatedEOFs < 20); // The file descriptor for the socket may changemsg->getSendAddress(&fromIpAddress, &fromPort);, as OsSocket's // can be re-opened. fds[1].fd = mClientSocket->getSocketDescriptor(); // Initialize the revents members. // This may not be necessary (the man page is not clear), but // Valgrind flags 'fds[*].revents' as undefined if they aren't // initialized. fds[0].revents = 0; fds[1].revents = 0; fds[0].events = POLLIN; // only read-select on pipe // For non-blocking connect failures, don't read-select on socket if // the initial read showed an error but we have to wait to report it. if (!waitingToReportErr) { // This is the normal path. // Read the socket only if the socket is not shared. // If it is shared, the ancestral SipClient will read it. // If multiple threads attempt to read the socket, poll() may // succeed but another may read the data, leaving us to block on // read. fds[1].events = mbSharedSocket ? 0 : POLLIN; // Set wait for writing the socket if there is queued messages to // send. if (mWriteQueued) { // Wait for output on the socket to not block. fds[1].events |= POLLOUT; } } else { // just waiting to report error, ignore the socket fds[1].fd =-1; fds[1].events = 0; } // If there is residual data in the read buffer, // pretend the socket is ready to read. if (!readBuffer.isNull()) { fds[1].revents = POLLIN; } else { // Otherwise, call poll() to wait. int resPoll = poll(&fds[0], sizeof (fds) / sizeof (fds[0]), POLL_TIMEOUT); assert(resPoll >= 0 || (resPoll == -1 && errno == EINTR)); if (resPoll != 0) { Os::Logger::instance().log(FAC_SIP, PRI_DEBUG, "SipClient[%s]::run " "resPoll= %d revents: fd[0]= %x fd[1]= %x", mName.data(), resPoll, fds[0].revents, fds[1].revents ); } } if ((fds[1].revents & (POLLERR | POLLHUP)) != 0) { Os::Logger::instance().log(FAC_SIP, PRI_DEBUG, "SipClient[%s]::run " "SipMessage::poll error(%d) ", mName.data(), errno); if (OsSocket::isFramed(mClientSocket->getIpProtocol())) { Os::Logger::instance().log(FAC_SIP, PRI_ERR, "SipClient[%s]::run " "SipMessage::poll error(%d) got POLLERR | POLLHUP on UDP socket", mName.data(), errno); } else // eg. tcp socket // This client's socket is a connection-oriented protocol and the // connection has been terminated (probably by the remote end). // We must terminate the SipClient. // We drop the queued messages, but we do not report them to // SipUserAgent as failed sends. This will cause SipUserAgent to // retry the send using the same transport (rather than continuing // to the next transport), which should cause a new connection to // be made to the remote end. { // On non-blocking connect failures, we need to get the first send message // in order to successfully trigger the protocol fallback mechanism if (!tcpOnErrWaitForSend) { // Return all buffered messages with a transport error indication. emptyBuffer(TRUE); clientStopSelf(); } else { fds[1].revents &= ~(POLLERR | POLLHUP); // clear error bit if waiting waitingToReportErr = TRUE; } } } // Check for message queue messages (fds[0]) before checking the socket(fds[1]), // to make sure that we process shutdown messages promptly, even // if we would be spinning trying to service the socket. else if ((fds[0].revents & POLLIN) != 0) { // Poll finished because the pipe is ready to read. // (One byte in pipe means message available in queue.) // Only a SipClient with a derived SipClientWriteBuffer // uses the pipe in the Sip message send process // Check to see how many messages are in the queue. int numberMsgs = (getMessageQueue())->numMsgs(); Os::Logger::instance().log(FAC_SIP, PRI_DEBUG, "SipClient[%s]::run got pipe-select " "Number of Messages waiting: %d", mName.data(), numberMsgs); int i; char buffer[1]; for (i = 0; i < numberMsgs; i++) { // Receive the messages. res = receiveMessage((OsMsg*&) pMsg, OsTime::NO_WAIT); assert(res == OS_SUCCESS); // Normally, this is a SIP message for the write buffer. Once we have gotten // here, we are able to report any initial non-blocking connect error. mbTcpOnErrWaitForSend = FALSE; tcpOnErrWaitForSend = FALSE; Os::Logger::instance().log(FAC_SIP, PRI_DEBUG, "SipClient[%s]::run got pipe-select " "mbTcpOnErrWaitForSend-%d waitingToReportErr-%d mbTcpOnErrWaitForSend-%d repeatedEOFs-%d", mName.data(), mbTcpOnErrWaitForSend, waitingToReportErr, mbTcpOnErrWaitForSend, repeatedEOFs); // Read 1 byte from the pipe to clear it for this message. One byte is // inserted into the pipe for each message. assert(read(mPipeReadingFd, &buffer, 1) == 1); if (!handleMessage(*pMsg)) // process the message (from queue) { OsServerTask::handleMessage(*pMsg); } if (!pMsg->getSentFromISR()) { pMsg->releaseMsg(); // free the message } // In order to report an unframed(eg TCP) socket error to SipUserAgent dispatcher, // the error must be carried in a sip message from the client's message queue. // The message holds all the identifying information. if (waitingToReportErr) { // Return all buffered messages with a transport error indication. emptyBuffer(TRUE); clientStopSelf(); } } } // end reading msg-available-for-output-queue pipe else if ((fds[1].revents & POLLOUT) != 0) { // Poll finished because socket is ready to write. // Call method to continue writing data. writeMore(); } else if ((fds[1].revents & POLLIN) != 0) { // Poll finished because socket is ready to read. // Read message. // Must allocate a new message because SipUserAgent::dispatch will // take ownership of it. SipMessage* msg = new SipMessage; int res = msg->read(mClientSocket, HTTP_DEFAULT_SOCKET_BUFFER_SIZE, &readBuffer); if (res >= 65536) { // // This is more than the allowable size of a SIP message. Discard! // UtlString remoteHostAddress; int remoteHostPort; msg->getSendAddress(&remoteHostAddress, &remoteHostPort); OS_LOG_WARNING(FAC_SIP, "Received a SIP Message (" << res << " bytes) beyond the maximum allowable size from host " << remoteHostAddress.data() << ":" << remoteHostPort); delete msg; readBuffer.remove(0); continue; } // Use readBuffer to hold any unparsed data after the message // we read. // Note that if a message was successfully parsed, readBuffer // still contains as its prefix the characters of that message. // We save them for logging purposes below and will delete them later. UtlString remoteHostAddress; int remoteHostPort; msg->getSendAddress(&remoteHostAddress, &remoteHostPort); if (!mClientSocket->isSameHost(remoteHostAddress.data(), mLocalHostAddress.data())) { try { if (!remoteHostAddress.isNull()) { boost::asio::ip::address remoteIp = boost::asio::ip::address::from_string(remoteHostAddress.data()); if (rateLimit().isBannedAddress(remoteIp)) { delete msg; readBuffer.remove(0); continue; } rateLimit().logPacket(remoteIp, 0); } } catch(const std::exception& e) { Os::Logger::instance().log(FAC_SIP_INCOMING, PRI_CRIT, "SipClient[%s]::run rate limit exception: %s", mName.data(), e.what()); } } // Note that input was processed at this time. touch(); // // Count the CR/LF to see if this is a keep-alive // int crlfCount = 0; for (int i = 0; i < res; i++) { if (readBuffer(i) == '\r' || readBuffer(i) == '\n') { crlfCount++; } else { break; } } if (res == crlfCount) { repeatedEOFs = 0; // The 'message' was a keepalive (CR-LF or CR-LF-CR-LF). UtlString fromIpAddress; int fromPort; UtlString buffer; int bufferLen; // send one CRLF set in the reply buffer.append("\r\n"); bufferLen = buffer.length(); // Get the send address for response. msg->getSendAddress(&fromIpAddress, &fromPort); if ( !portIsValid(fromPort)) { fromPort = defaultPort(); } // Log the message at DEBUG level. // Only bother processing if the logs are enabled if ( mpSipUserAgent->isMessageLoggingEnabled() || Os::Logger::instance().willLog(FAC_SIP_INCOMING, PRI_DEBUG) ) { UtlString logMessage; logMessage.append("Read keepalive message:\n"); logMessage.append("----Local Host:"); logMessage.append(mLocalHostAddress); logMessage.append("---- Port: "); logMessage.appendNumber( portIsValid(mLocalHostPort) ? mLocalHostPort : defaultPort()); logMessage.append("----\n"); logMessage.append("----Remote Host:"); logMessage.append(fromIpAddress); logMessage.append("---- Port: "); logMessage.appendNumber( portIsValid(fromPort) ? fromPort : defaultPort()); logMessage.append("----\n"); logMessage.append(readBuffer.data(), res); UtlString messageString; logMessage.append(messageString); logMessage.append("====================END====================\n"); // Don't bother to send the message to the SipUserAgent for its internal log. // Write the message to the syslog. Os::Logger::instance().log(FAC_SIP_INCOMING, PRI_DEBUG, "%s", logMessage.data()); } // send the CR-LF response message switch (mSocketType) { case OsSocket::TCP: { Os::Logger::instance().log(FAC_SIP, PRI_DEBUG, "SipClient[%s]::run send TCP keep-alive CR-LF response, ", mName.data()); SipClientSendMsg sendMsg(OsMsg::OS_EVENT, SipClientSendMsg::SIP_CLIENT_SEND_KEEP_ALIVE, fromIpAddress, fromPort); handleMessage(sendMsg); // add newly created keep-alive to write buffer } break; case OsSocket::UDP: { Os::Logger::instance().log(FAC_SIP, PRI_DEBUG, "SipClient[%s]::run send UDP keep-alive CR-LF response, ", mName.data()); (dynamic_cast <OsDatagramSocket*> (mClientSocket))->write(buffer.data(), bufferLen, fromIpAddress, fromPort); } break; default: break; } // Delete the SipMessage allocated above, which is no longer needed. delete msg; // Now that logging is done, remove the parsed bytes and // remember any unparsed input for later use. readBuffer.remove(0, res); } // end keep-alive msg else if (res > 0) // got message, but not keep-alive { // Message successfully read. repeatedEOFs = 0; // Do preliminary processing of message to log it, // clean up its data, and extract any needed source address. preprocessMessage(*msg, readBuffer, res); // Dispatch the message. // dispatch() takes ownership of *msg. mpSipUserAgent->dispatch(msg); // Now that logging is done, remove the parsed bytes and // remember any unparsed input for later use. readBuffer.remove(0, res); } // end process read of >0 bytes else { // Something went wrong while reading the message. // (Possibly EOF on a connection-oriented socket.) repeatedEOFs++; // Delete the SipMessage allocated above, which is no longer needed. delete msg; Os::Logger::instance().log(FAC_SIP, PRI_DEBUG, "SipClient[%s]::run SipMessage::read returns %d (error(%d) or EOF), " "readBuffer = '%.1000s'", mName.data(), res, errno, readBuffer.data()); Os::Logger::instance().log(FAC_SIP, PRI_DEBUG, "SipClient[%s]::run error wait status " "tcpOnErrWaitForSend-%d waitingToReportErr-%d " "mbTcpOnErrWaitForSend-%d repeatedEOFs-%d " "protocol %d framed %d", mName.data(), tcpOnErrWaitForSend, waitingToReportErr, mbTcpOnErrWaitForSend, repeatedEOFs, mClientSocket->getIpProtocol(), OsSocket::isFramed(mClientSocket->getIpProtocol())); // If the socket is not framed (is connection-oriented), // we need to abort the connection and post a message // :TODO: This doesn't work right for framed connection-oriented // protocols (like SCTP), but OsSocket doesn't have an EOF-query // method -- we need to close all connection-oriented // sockets as well in case it was an EOF. // Define a virtual function that returns the correct bit. if (!OsSocket::isFramed(mClientSocket->getIpProtocol())) { // On non-blocking connect failures, we need to get the first send message // in order to successfully trigger the protocol fallback mechanism if (!tcpOnErrWaitForSend) { // Return all buffered messages with a transport error indication. emptyBuffer(TRUE); clientStopSelf(); } else { fds[1].revents &= ~(POLLERR | POLLHUP); // clear error bit if waiting waitingToReportErr = TRUE; } } // Delete the data read so far, which will not have been // deleted by HttpMessage::read. readBuffer.remove(0); } } // end POLLIN reading socket } while (isStarted()); return 0; // and then exit }