/* * Copyright (c) 2016 Cisco and/or its affiliates. * 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 _GNU_SOURCE /* for strcasestr(3) */ #include #define vl_api_version(n,v) static u32 vpe_api_version = (v); #include #undef vl_api_version #include #include #include "org_openvpp_jvpp_VppJNIConnection.h" #include "org_openvpp_jvpp_JVppRegistryImpl.h" #include #define vl_typedefs /* define message structures */ #include #undef vl_typedefs #define vl_endianfun #include #undef vl_endianfun /* instantiate all the print functions we know about */ #define vl_print(handle, ...) #define vl_printfun #include #undef vl_printfun /* * The Java runtime isn't compile w/ -fstack-protector, * so we have to supply missing external references for the * regular vpp libraries. */ void __stack_chk_guard(void) __attribute__((weak)); void __stack_chk_guard(void) { } typedef struct { /* UThread attachment */ volatile u32 control_ping_result_ready; volatile i32 control_ping_retval; /* Control poing callback */ jobject registryObject; jclass registryClass; jclass controlPingReplyClass; jclass callbackExceptionClass; /* Thread cleanup */ pthread_key_t cleanup_rx_thread_key; /* Connected indication */ volatile u8 is_connected; } jvpp_registry_main_t; jvpp_registry_main_t jvpp_registry_main __attribute__((aligned (64))); void vl_client_add_api_signatures(vl_api_memclnt_create_t *mp) { /* * Send the main API signature in slot 0. This bit of code must * match the checks in ../vpe/api/api.c: vl_msg_api_version_check(). */ mp->api_versions[0] = clib_host_to_net_u32(vpe_api_version); } /* cleanup handler for RX thread */ static_always_inline void cleanup_rx_thread(void *arg) { jvpp_main_t * jm = &jvpp_main; jvpp_registry_main_t * rm = &jvpp_registry_main; vppjni_lock(jm, 99); int getEnvStat = (*jm->jvm)->GetEnv(jm->jvm, (void **) &(jm->jenv), JNI_VERSION_1_8); if (getEnvStat == JNI_EVERSION) { clib_warning("Unsupported JNI version\n"); rm->control_ping_retval = VNET_API_ERROR_UNSUPPORTED_JNI_VERSION; goto out; } else if (getEnvStat != JNI_EDETACHED) { (*jm->jvm)->DetachCurrentThread(jm->jvm); } out: vppjni_unlock(jm); } static void vl_api_control_ping_reply_t_handler( vl_api_control_ping_reply_t * mp) { jvpp_main_t * jm = &jvpp_main; jvpp_registry_main_t * rm = &jvpp_registry_main; char was_thread_connected = 0; // attach to java thread if not attached int getEnvStat = (*jm->jvm)->GetEnv(jm->jvm, (void **) &(jm->jenv), JNI_VERSION_1_8); if (getEnvStat == JNI_EDETACHED) { if ((*jm->jvm)->AttachCurrentThread(jm->jvm, (void **) &(jm->jenv), NULL) != 0) { clib_warning("Failed to attach thread\n"); rm->control_ping_retval = VNET_API_ERROR_FAILED_TO_ATTACH_TO_JAVA_THREAD; goto out; } // workaround as we can't use pthread_cleanup_push pthread_key_create(&rm->cleanup_rx_thread_key, cleanup_rx_thread); // destructor is only called if the value of key is non null pthread_setspecific(rm->cleanup_rx_thread_key, (void *) 1); was_thread_connected = 1; } else if (getEnvStat == JNI_EVERSION) { clib_warning("Unsupported JNI version\n"); rm->control_ping_retval = VNET_API_ERROR_UNSUPPORTED_JNI_VERSION; goto out; } if (was_thread_connected == 0) { JNIEnv *env = jm->jenv; if (mp->retval < 0) { call_on_error("controlPing", mp->context, mp->retval, rm->registryClass, rm->registryObject, rm->callbackExceptionClass); } else { jmethodID constructor = (*env)->GetMethodID(env, rm->controlPingReplyClass, "", "()V"); jmethodID callbackMethod = (*env)->GetMethodID(env, rm->registryClass, "onControlPingReply", "(Lorg/openvpp/jvpp/dto/ControlPingReply;)V"); jobject dto = (*env)->NewObject(env, rm->controlPingReplyClass, constructor); jfieldID contextFieldId = (*env)->GetFieldID(env, rm->controlPingReplyClass, "context", "I"); (*env)->SetIntField(env, dto, contextFieldId, clib_net_to_host_u32(mp->context)); jfieldID clientIndexFieldId = (*env)->GetFieldID(env, rm->controlPingReplyClass, "clientIndex", "I");