/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ //#define LOG_NDEBUG 0 #define LOG_TAG "UDPPusher" #include #include "UDPPusher.h" #include #include #include #include #include namespace android { UDPPusher::UDPPusher(const char *filename, unsigned port) : mFile(fopen(filename, "rb")), mFirstTimeMs(0), mFirstTimeUs(0) { CHECK(mFile != NULL); mSocket = socket(AF_INET, SOCK_DGRAM, 0); struct sockaddr_in addr; memset(addr.sin_zero, 0, sizeof(addr.sin_zero)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = INADDR_ANY; addr.sin_port = 0; CHECK_EQ(0, bind(mSocket, (const struct sockaddr *)&addr, sizeof(addr))); memset(mRemoteAddr.sin_zero, 0, sizeof(mRemoteAddr.sin_zero)); mRemoteAddr.sin_family = AF_INET; mRemoteAddr.sin_addr.s_addr = INADDR_ANY; mRemoteAddr.sin_port = htons(port); } UDPPusher::~UDPPusher() { close(mSocket); mSocket = -1; fclose(mFile); mFile = NULL; } void UDPPusher::start() { uint32_t timeMs; CHECK_EQ(fread(&timeMs, 1, sizeof(timeMs), mFile), sizeof(timeMs)); mFirstTimeMs = fromlel(timeMs); mFirstTimeUs = ALooper::GetNowUs(); (new AMessage(kWhatPush, id()))->post(); } bool UDPPusher::onPush() { uint32_t length; if (fread(&length, 1, sizeof(length), mFile) < sizeof(length)) { ALOGI("No more data to push."); return false; } length = fromlel(length); CHECK_GT(length, 0u); sp buffer = new ABuffer(length); if (fread(buffer->data(), 1, length, mFile) < length) { ALOGE("File truncated?."); return false; } ssize_t n = sendto( mSocket, buffer->data(), buffer->size(), 0, (const struct sockaddr *)&mRemoteAddr, sizeof(mRemoteAddr)); CHECK_EQ(n, (ssize_t)buffer->size()); uint32_t timeMs; if (fread(&timeMs, 1, sizeof(timeMs), mFile) < sizeof(timeMs)) { ALOGI("No more data to push."); return false; } timeMs = fromlel(timeMs); CHECK_GE(timeMs, mFirstTimeMs); timeMs -= mFirstTimeMs; int64_t whenUs = mFirstTimeUs + timeMs * 1000ll; int64_t nowUs = ALooper::GetNowUs(); (new AMessage(kWhatPush, id()))->post(whenUs - nowUs); return true; } void UDPPusher::onMessageReceived(const sp &msg) { switch (msg->what()) { case kWhatPush: { if (!onPush() && !(ntohs(mRemoteAddr.sin_port) & 1)) { ALOGI("emulating BYE packet"); sp buffer = new ABuffer(8); uint8_t *data = buffer->data(); *data++ = (2 << 6) | 1; *data++ = 203; *data++ = 0; *data++ = 1; *data++ = 0x8f; *data++ = 0x49; *data++ = 0xc0; *data++ = 0xd0; buffer->setRange(0, 8); struct sockaddr_in tmp = mRemoteAddr; tmp.sin_port = htons(ntohs(mRemoteAddr.sin_port) | 1); ssize_t n = sendto( mSocket, buffer->data(), buffer->size(), 0, (const struct sockaddr *)&tmp, sizeof(tmp)); CHECK_EQ(n, (ssize_t)buffer->size()); } break; } default: TRESPASS(); break; } } } // namespace android