Home | History | Annotate | Download | only in wifi-display
      1 /*
      2  * Copyright 2012, The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *     http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 //#define LOG_NEBUG 0
     18 #define LOG_TAG "udptest"
     19 #include <utils/Log.h>
     20 
     21 #include "ANetworkSession.h"
     22 
     23 #include <binder/ProcessState.h>
     24 #include <media/stagefright/foundation/ABuffer.h>
     25 #include <media/stagefright/foundation/ADebug.h>
     26 #include <media/stagefright/foundation/AHandler.h>
     27 #include <media/stagefright/foundation/ALooper.h>
     28 #include <media/stagefright/foundation/AMessage.h>
     29 #include <media/stagefright/Utils.h>
     30 
     31 namespace android {
     32 
     33 struct TestHandler : public AHandler {
     34     TestHandler(const sp<ANetworkSession> &netSession);
     35 
     36     void startServer(unsigned localPort);
     37     void startClient(const char *remoteHost, unsigned remotePort);
     38 
     39 protected:
     40     virtual ~TestHandler();
     41 
     42     virtual void onMessageReceived(const sp<AMessage> &msg);
     43 
     44 private:
     45     enum {
     46         kWhatStartServer,
     47         kWhatStartClient,
     48         kWhatUDPNotify,
     49         kWhatSendPacket,
     50     };
     51 
     52     sp<ANetworkSession> mNetSession;
     53 
     54     bool mIsServer;
     55     bool mConnected;
     56     int32_t mUDPSession;
     57     uint32_t mSeqNo;
     58     double mTotalTimeUs;
     59     int32_t mCount;
     60 
     61     void postSendPacket(int64_t delayUs = 0ll);
     62 
     63     DISALLOW_EVIL_CONSTRUCTORS(TestHandler);
     64 };
     65 
     66 TestHandler::TestHandler(const sp<ANetworkSession> &netSession)
     67     : mNetSession(netSession),
     68       mIsServer(false),
     69       mConnected(false),
     70       mUDPSession(0),
     71       mSeqNo(0),
     72       mTotalTimeUs(0.0),
     73       mCount(0) {
     74 }
     75 
     76 TestHandler::~TestHandler() {
     77 }
     78 
     79 void TestHandler::startServer(unsigned localPort) {
     80     sp<AMessage> msg = new AMessage(kWhatStartServer, id());
     81     msg->setInt32("localPort", localPort);
     82     msg->post();
     83 }
     84 
     85 void TestHandler::startClient(const char *remoteHost, unsigned remotePort) {
     86     sp<AMessage> msg = new AMessage(kWhatStartClient, id());
     87     msg->setString("remoteHost", remoteHost);
     88     msg->setInt32("remotePort", remotePort);
     89     msg->post();
     90 }
     91 
     92 void TestHandler::onMessageReceived(const sp<AMessage> &msg) {
     93     switch (msg->what()) {
     94         case kWhatStartClient:
     95         {
     96             AString remoteHost;
     97             CHECK(msg->findString("remoteHost", &remoteHost));
     98 
     99             int32_t remotePort;
    100             CHECK(msg->findInt32("remotePort", &remotePort));
    101 
    102             sp<AMessage> notify = new AMessage(kWhatUDPNotify, id());
    103 
    104             CHECK_EQ((status_t)OK,
    105                      mNetSession->createUDPSession(
    106                          0 /* localPort */,
    107                          remoteHost.c_str(),
    108                          remotePort,
    109                          notify,
    110                          &mUDPSession));
    111 
    112             postSendPacket();
    113             break;
    114         }
    115 
    116         case kWhatStartServer:
    117         {
    118             mIsServer = true;
    119 
    120             int32_t localPort;
    121             CHECK(msg->findInt32("localPort", &localPort));
    122 
    123             sp<AMessage> notify = new AMessage(kWhatUDPNotify, id());
    124 
    125             CHECK_EQ((status_t)OK,
    126                      mNetSession->createUDPSession(
    127                          localPort, notify, &mUDPSession));
    128 
    129             break;
    130         }
    131 
    132         case kWhatSendPacket:
    133         {
    134             char buffer[12];
    135             memset(buffer, 0, sizeof(buffer));
    136 
    137             buffer[0] = mSeqNo >> 24;
    138             buffer[1] = (mSeqNo >> 16) & 0xff;
    139             buffer[2] = (mSeqNo >> 8) & 0xff;
    140             buffer[3] = mSeqNo & 0xff;
    141             ++mSeqNo;
    142 
    143             int64_t nowUs = ALooper::GetNowUs();
    144             buffer[4] = nowUs >> 56;
    145             buffer[5] = (nowUs >> 48) & 0xff;
    146             buffer[6] = (nowUs >> 40) & 0xff;
    147             buffer[7] = (nowUs >> 32) & 0xff;
    148             buffer[8] = (nowUs >> 24) & 0xff;
    149             buffer[9] = (nowUs >> 16) & 0xff;
    150             buffer[10] = (nowUs >> 8) & 0xff;
    151             buffer[11] = nowUs & 0xff;
    152 
    153             CHECK_EQ((status_t)OK,
    154                      mNetSession->sendRequest(
    155                          mUDPSession, buffer, sizeof(buffer)));
    156 
    157             postSendPacket(20000ll);
    158             break;
    159         }
    160 
    161         case kWhatUDPNotify:
    162         {
    163             int32_t reason;
    164             CHECK(msg->findInt32("reason", &reason));
    165 
    166             switch (reason) {
    167                 case ANetworkSession::kWhatError:
    168                 {
    169                     int32_t sessionID;
    170                     CHECK(msg->findInt32("sessionID", &sessionID));
    171 
    172                     int32_t err;
    173                     CHECK(msg->findInt32("err", &err));
    174 
    175                     AString detail;
    176                     CHECK(msg->findString("detail", &detail));
    177 
    178                     ALOGE("An error occurred in session %d (%d, '%s/%s').",
    179                           sessionID,
    180                           err,
    181                           detail.c_str(),
    182                           strerror(-err));
    183 
    184                     mNetSession->destroySession(sessionID);
    185                     break;
    186                 }
    187 
    188                 case ANetworkSession::kWhatDatagram:
    189                 {
    190                     int32_t sessionID;
    191                     CHECK(msg->findInt32("sessionID", &sessionID));
    192 
    193                     sp<ABuffer> data;
    194                     CHECK(msg->findBuffer("data", &data));
    195 
    196                     if (mIsServer) {
    197                         if (!mConnected) {
    198                             AString fromAddr;
    199                             CHECK(msg->findString("fromAddr", &fromAddr));
    200 
    201                             int32_t fromPort;
    202                             CHECK(msg->findInt32("fromPort", &fromPort));
    203 
    204                             CHECK_EQ((status_t)OK,
    205                                      mNetSession->connectUDPSession(
    206                                          mUDPSession, fromAddr.c_str(), fromPort));
    207 
    208                             mConnected = true;
    209                         }
    210 
    211                         int64_t nowUs = ALooper::GetNowUs();
    212 
    213                         sp<ABuffer> buffer = new ABuffer(data->size() + 8);
    214                         memcpy(buffer->data(), data->data(), data->size());
    215 
    216                         uint8_t *ptr = buffer->data() + data->size();
    217 
    218                         *ptr++ = nowUs >> 56;
    219                         *ptr++ = (nowUs >> 48) & 0xff;
    220                         *ptr++ = (nowUs >> 40) & 0xff;
    221                         *ptr++ = (nowUs >> 32) & 0xff;
    222                         *ptr++ = (nowUs >> 24) & 0xff;
    223                         *ptr++ = (nowUs >> 16) & 0xff;
    224                         *ptr++ = (nowUs >> 8) & 0xff;
    225                         *ptr++ = nowUs & 0xff;
    226 
    227                         CHECK_EQ((status_t)OK,
    228                                  mNetSession->sendRequest(
    229                                      mUDPSession, buffer->data(), buffer->size()));
    230                     } else {
    231                         CHECK_EQ(data->size(), 20u);
    232 
    233                         uint32_t seqNo = U32_AT(data->data());
    234                         int64_t t1 = U64_AT(data->data() + 4);
    235                         int64_t t2 = U64_AT(data->data() + 12);
    236 
    237                         int64_t t3;
    238                         CHECK(data->meta()->findInt64("arrivalTimeUs", &t3));
    239 
    240 #if 0
    241                         printf("roundtrip seqNo %u, time = %lld us\n",
    242                                seqNo, t3 - t1);
    243 #else
    244                         mTotalTimeUs += t3 - t1;
    245                         ++mCount;
    246                         printf("avg. roundtrip time %.2f us\n", mTotalTimeUs / mCount);
    247 #endif
    248                     }
    249                     break;
    250                 }
    251 
    252                 default:
    253                     TRESPASS();
    254             }
    255 
    256             break;
    257         }
    258 
    259         default:
    260             TRESPASS();
    261     }
    262 }
    263 
    264 void TestHandler::postSendPacket(int64_t delayUs) {
    265     (new AMessage(kWhatSendPacket, id()))->post(delayUs);
    266 }
    267 
    268 }  // namespace android
    269 
    270 static void usage(const char *me) {
    271     fprintf(stderr,
    272             "usage: %s -c host[:port]\tconnect to test server\n"
    273             "           -l            \tcreate a test server\n",
    274             me);
    275 }
    276 
    277 int main(int argc, char **argv) {
    278     using namespace android;
    279 
    280     ProcessState::self()->startThreadPool();
    281 
    282     int32_t localPort = -1;
    283     int32_t connectToPort = -1;
    284     AString connectToHost;
    285 
    286     int res;
    287     while ((res = getopt(argc, argv, "hc:l:")) >= 0) {
    288         switch (res) {
    289             case 'c':
    290             {
    291                 const char *colonPos = strrchr(optarg, ':');
    292 
    293                 if (colonPos == NULL) {
    294                     connectToHost = optarg;
    295                     connectToPort = 49152;
    296                 } else {
    297                     connectToHost.setTo(optarg, colonPos - optarg);
    298 
    299                     char *end;
    300                     connectToPort = strtol(colonPos + 1, &end, 10);
    301 
    302                     if (*end != '\0' || end == colonPos + 1
    303                             || connectToPort < 1 || connectToPort > 65535) {
    304                         fprintf(stderr, "Illegal port specified.\n");
    305                         exit(1);
    306                     }
    307                 }
    308                 break;
    309             }
    310 
    311             case 'l':
    312             {
    313                 char *end;
    314                 localPort = strtol(optarg, &end, 10);
    315 
    316                 if (*end != '\0' || end == optarg
    317                         || localPort < 1 || localPort > 65535) {
    318                     fprintf(stderr, "Illegal port specified.\n");
    319                     exit(1);
    320                 }
    321                 break;
    322             }
    323 
    324             case '?':
    325             case 'h':
    326                 usage(argv[0]);
    327                 exit(1);
    328         }
    329     }
    330 
    331     if (localPort < 0 && connectToPort < 0) {
    332         fprintf(stderr,
    333                 "You need to select either client or server mode.\n");
    334         exit(1);
    335     }
    336 
    337     sp<ANetworkSession> netSession = new ANetworkSession;
    338     netSession->start();
    339 
    340     sp<ALooper> looper = new ALooper;
    341 
    342     sp<TestHandler> handler = new TestHandler(netSession);
    343     looper->registerHandler(handler);
    344 
    345     if (localPort >= 0) {
    346         handler->startServer(localPort);
    347     } else {
    348         handler->startClient(connectToHost.c_str(), connectToPort);
    349     }
    350 
    351     looper->start(true /* runOnCallingThread */);
    352 
    353     return 0;
    354 }
    355 
    356