173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh/*
273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh * Copyright (C) 2010 The Android Open Source Project
373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh *
473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh * Licensed under the Apache License, Version 2.0 (the "License");
573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh * you may not use this file except in compliance with the License.
673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh * You may obtain a copy of the License at
773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh *
873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh *      http://www.apache.org/licenses/LICENSE-2.0
973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh *
1073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh * Unless required by applicable law or agreed to in writing, software
1173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh * distributed under the License is distributed on an "AS IS" BASIS,
1273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh * See the License for the specific language governing permissions and
1473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh * limitations under the License.
1573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh */
1673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
1773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include <stdio.h>
1873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include <stdint.h>
1973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include <string.h>
2073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include <errno.h>
2173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include <sys/types.h>
2273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include <sys/socket.h>
2373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include <arpa/inet.h>
2473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include <netinet/in.h>
2573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
2673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#define LOG_TAG "RtpStream"
2773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include <utils/Log.h>
2873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
2973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include "jni.h"
3073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh#include "JNIHelp.h"
3173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
3273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehextern int parse(JNIEnv *env, jstring jAddress, int port, sockaddr_storage *ss);
3373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
3473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehnamespace {
3573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
362bf2e642d061e7b48dd71927752e9151a5126fb2Chia-chi YehjfieldID gSocket;
3773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
3873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehjint create(JNIEnv *env, jobject thiz, jstring jAddress)
3973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
402bf2e642d061e7b48dd71927752e9151a5126fb2Chia-chi Yeh    env->SetIntField(thiz, gSocket, -1);
4173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
4273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    sockaddr_storage ss;
4373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (parse(env, jAddress, 0, &ss) < 0) {
4473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        // Exception already thrown.
4573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return -1;
4673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
4773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
4873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    int socket = ::socket(ss.ss_family, SOCK_DGRAM, 0);
4973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    socklen_t len = sizeof(ss);
5073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (socket == -1 || bind(socket, (sockaddr *)&ss, sizeof(ss)) != 0 ||
5173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        getsockname(socket, (sockaddr *)&ss, &len) != 0) {
5273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        jniThrowException(env, "java/net/SocketException", strerror(errno));
5373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        ::close(socket);
5473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return -1;
5573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
5673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
5773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    uint16_t *p = (ss.ss_family == AF_INET) ?
5873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        &((sockaddr_in *)&ss)->sin_port : &((sockaddr_in6 *)&ss)->sin6_port;
5973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    uint16_t port = ntohs(*p);
6073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if ((port & 1) == 0) {
612bf2e642d061e7b48dd71927752e9151a5126fb2Chia-chi Yeh        env->SetIntField(thiz, gSocket, socket);
6273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return port;
6373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
6473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    ::close(socket);
6573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
6673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    socket = ::socket(ss.ss_family, SOCK_DGRAM, 0);
6773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if (socket != -1) {
6873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        uint16_t delta = port << 1;
6973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        ++port;
7073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
7173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        for (int i = 0; i < 1000; ++i) {
7273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            do {
7373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh                port += delta;
7473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            } while (port < 1024);
7573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            *p = htons(port);
7673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
7773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            if (bind(socket, (sockaddr *)&ss, sizeof(ss)) == 0) {
782bf2e642d061e7b48dd71927752e9151a5126fb2Chia-chi Yeh                env->SetIntField(thiz, gSocket, socket);
7973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh                return port;
8073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh            }
8173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        }
8273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
8373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
8473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    jniThrowException(env, "java/net/SocketException", strerror(errno));
8573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    ::close(socket);
8673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    return -1;
8773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh}
8873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
8973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehvoid close(JNIEnv *env, jobject thiz)
9073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
912bf2e642d061e7b48dd71927752e9151a5126fb2Chia-chi Yeh    int socket = env->GetIntField(thiz, gSocket);
9273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    ::close(socket);
932bf2e642d061e7b48dd71927752e9151a5126fb2Chia-chi Yeh    env->SetIntField(thiz, gSocket, -1);
9473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh}
9573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
9673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi YehJNINativeMethod gMethods[] = {
9773f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    {"create", "(Ljava/lang/String;)I", (void *)create},
9873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    {"close", "()V", (void *)close},
9973f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh};
10073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
10173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh} // namespace
10273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh
10373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yehint registerRtpStream(JNIEnv *env)
10473f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh{
10573f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    jclass clazz;
10673f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    if ((clazz = env->FindClass("android/net/rtp/RtpStream")) == NULL ||
1072bf2e642d061e7b48dd71927752e9151a5126fb2Chia-chi Yeh        (gSocket = env->GetFieldID(clazz, "mSocket", "I")) == NULL ||
10873f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        env->RegisterNatives(clazz, gMethods, NELEM(gMethods)) < 0) {
1098913af783fc2cf197ef55449792bb8416a356263Steve Block        ALOGE("JNI registration failed");
11073f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh        return -1;
11173f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    }
11273f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh    return 0;
11373f6df1f0aac12c243e2110e30337ab01aa71598Chia-chi Yeh}
114