/**@ingroup tsk_uuid_group */ int tsk_uuidgenerate(tsk_uuidstring_t *result) { /* From wikipedia * Version 5 UUIDs use a scheme with SHA-1 hashing, otherwise it is the same idea as in version 3. * RFC 4122 states that version 5 is preferred over version 3 name based UUIDs. * Note that the 160 bit SHA-1 hash is truncated to 128 bits to make the length work out. */ tsk_sha1string_t sha1result; tsk_istr_t epoch; unsigned i, k; static char HEX[] = "0123456789abcdef"; tsk_itoa(tsk_time_epoch(), &epoch); tsk_sha1compute(epoch, sizeof(epoch), &sha1result); /* XOR the SHA-1 result with random numbers. */ for(i=0; i<(TSK_UUID_DIGEST_SIZE*2); i+=4){ #if 0 *((uint32_t*)&sha1result[i]) ^= rand(); #else k = rand(); sha1result[i] ^= k, sha1result[i + 1] ^= k, sha1result[i + 2] ^= k, sha1result[i + 3] ^= k; #endif for(k=0; k<sizeof(uint32_t); k++){ sha1result[i+k] = HEX[sha1result[i+k] & 0x0F]; /* To hexa. */ } } /* f47ac10b-58cc-4372-a567-0e02b2c3d479 */ memcpy(&(*result)[0], &sha1result[0], 8); (*result)[8] = '-'; memcpy(&(*result)[9], &sha1result[8], 4); (*result)[13] = '-'; memcpy(&(*result)[14], &sha1result[12], 4); (*result)[18] = '-'; memcpy(&(*result)[19], &sha1result[16], 4); (*result)[23] = '-'; memcpy(&(*result)[24], &sha1result[20], 12); (*result)[36] = '\0'; return 0; }
//================================================================================================= // SOCKET object definition // static tsk_object_t* tnet_socket_ctor(tsk_object_t * self, va_list * app) { tnet_socket_t *sock = self; if(sock){ int status; tsk_bool_t nonblocking; tsk_bool_t bindsocket; tsk_istr_t port; struct addrinfo *result = 0; struct addrinfo *ptr = 0; struct addrinfo hints; tnet_host_t local_hostname; const char *host = va_arg(*app, const char*); #if defined(__GNUC__) sock->port = (tnet_port_t)va_arg(*app, unsigned); #else sock->port = va_arg(*app, tnet_port_t); #endif tsk_itoa(sock->port, &port); sock->type = va_arg(*app, tnet_socket_type_t); nonblocking = va_arg(*app, tsk_bool_t); bindsocket = va_arg(*app, tsk_bool_t); memset(local_hostname, 0, sizeof(local_hostname)); /* Get the local host name */ if(host != TNET_SOCKET_HOST_ANY && !tsk_strempty(host)){ memcpy(local_hostname, host, tsk_strlen(host)>sizeof(local_hostname)-1 ? sizeof(local_hostname)-1 : tsk_strlen(host)); } else{ if(TNET_SOCKET_TYPE_IS_IPV6(sock->type)){ memcpy(local_hostname, "::", 2); } else{ memcpy(local_hostname, "0.0.0.0", 7); } //if((status = tnet_gethostname(&local_hostname))) //{ // TNET_PRINT_LAST_ERROR("gethostname have failed."); // goto bail; //} } /* hints address info structure */ memset(&hints, 0, sizeof(hints)); hints.ai_family = TNET_SOCKET_TYPE_IS_IPV46(sock->type) ? AF_UNSPEC : (TNET_SOCKET_TYPE_IS_IPV6(sock->type) ? AF_INET6 : AF_INET); hints.ai_socktype = TNET_SOCKET_TYPE_IS_STREAM(sock->type) ? SOCK_STREAM : SOCK_DGRAM; hints.ai_protocol = TNET_SOCKET_TYPE_IS_STREAM(sock->type) ? IPPROTO_TCP : IPPROTO_UDP; hints.ai_flags = AI_PASSIVE #if !TNET_UNDER_WINDOWS || _WIN32_WINNT>=0x600 | AI_ADDRCONFIG #endif ; /* Performs getaddrinfo */ if((status = tnet_getaddrinfo(local_hostname, port, &hints, &result))){ TNET_PRINT_LAST_ERROR("tnet_getaddrinfo(family=%d, hostname=%s and port=%s) failed: [%s]", hints.ai_family, local_hostname, port, tnet_gai_strerror(status)); goto bail; } /* Find our address. */ for(ptr = result; ptr; ptr = ptr->ai_next){ sock->fd = tnet_soccket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol); if(ptr->ai_family != AF_INET6 && ptr->ai_family != AF_INET){ continue; } if(bindsocket){ /* Bind the socket */ if((status = bind(sock->fd, ptr->ai_addr, ptr->ai_addrlen))){ TNET_PRINT_LAST_ERROR("bind have failed."); tnet_socket_close(sock); continue; } /* Get local IP string. */ if(status = tnet_get_ip_n_port(sock->fd , &sock->ip, &sock->port)) /* % */ //if((status = tnet_getnameinfo(ptr->ai_addr, ptr->ai_addrlen, sock->ip, sizeof(sock->ip), 0, 0, NI_NUMERICHOST))) { TNET_PRINT_LAST_ERROR("Failed to get local IP and port."); tnet_socket_close(sock); continue; } // else{ //#if TNET_UNDER_WINDOWS // int index; // if((index = tsk_strindexOf(sock->ip, tsk_strlen(sock->ip), "%")) > 0){ // *(sock->ip + index) = '\0'; // } //#endif // } } /* sets the real socket type (if ipv46) */ if(ptr->ai_family == AF_INET6) { TNET_SOCKET_TYPE_SET_IPV6Only(sock->type); } else{ TNET_SOCKET_TYPE_SET_IPV4Only(sock->type); } break; } /* Check socket validity. */ if(!TNET_SOCKET_IS_VALID(sock)) { TNET_PRINT_LAST_ERROR("Invalid socket."); goto bail; } /* To avoid "Address already in use" error */ { #if defined(SOLARIS) char yes = '1'; #else int yes = 1; #endif if(setsockopt(sock->fd, SOL_SOCKET, SO_REUSEADDR, (char*)&yes, sizeof(int))){ TNET_PRINT_LAST_ERROR("setsockopt(SO_REUSEADDR) have failed."); } } /* Sets the socket to nonblocking mode */ if(nonblocking){ if((status = tnet_sockfd_set_nonblocking(sock->fd))){ goto bail; } } bail: /* Free addrinfo */ tnet_freeaddrinfo(result); /* Close socket if failed. */ if(status && TNET_SOCKET_IS_VALID(sock)){ tnet_socket_close(sock); } } return self; }
/**@ingroup tsk_string_group * Generates a random string. * * @param result A pointer to the result. **/ void tsk_strrandom(tsk_istr_t *result) { static uint64_t __counter = 1; tsk_itoa((tsk_time_now() ^ (rand())) ^ ++__counter, result); }
int execute(const cmd_t* cmd) { int ret = 0; tsip_ssession_id_t sid; tsk_istr_t istr; if(!cmd){ TSK_DEBUG_ERROR("Invalid parameter"); return -1; } tsk_safeobj_lock(ctx); switch(cmd->type){ case cmd_audio: case cmd_audiovideo: { TSK_DEBUG_INFO("command=audio/video"); if((sid = invite_handle_cmd(cmd->type, cmd->opts)) != TSIP_SSESSION_INVALID_ID){ if(cmd->sidparam){ tsk_itoa(sid, &istr); update_param(cmd->sidparam, istr); } } break; } case cmd_config_session: { TSK_DEBUG_INFO("command=config-session"); break; } case cmd_config_stack: { TSK_DEBUG_INFO("command=config-satck"); ret = stack_config(cmd->opts); break; } case cmd_dtmf: { const opt_t* opt; TSK_DEBUG_INFO("command=dtmf"); if(!(opt = opt_get_by_type(cmd->opts, opt_sid)) || tsk_strnullORempty(opt->value)){ /* --sid option */ TSK_DEBUG_ERROR("++dtmf command need --sid option"); break; } if(!(opt = opt_get_by_type(cmd->opts, opt_event)) || tsk_strnullORempty(opt->value)){ /* --event option */ TSK_DEBUG_ERROR("++dtmf command need --event option"); break; } invite_handle_cmd(cmd->type, cmd->opts); break; } case cmd_dump: { TSK_DEBUG_INFO("command=dump"); ret = stack_dump(); break; } case cmd_ect: { const opt_t* opt; TSK_DEBUG_INFO("command=ect"); if((opt = opt_get_by_type(cmd->opts, opt_sid)) && !tsk_strnullORempty(opt->value)){ TSK_DEBUG_ERROR("++ect command need --sid option"); ret = -1; break; } if((opt = opt_get_by_type(cmd->opts, opt_to)) && !tsk_strnullORempty(opt->value)){ TSK_DEBUG_ERROR("++ect command need --to option"); ret = -1; break; } invite_handle_cmd(cmd->type, cmd->opts); break; } case cmd_exit: { TSK_DEBUG_INFO("command=exit"); goto bail; break; } case cmd_file: { const opt_t* opt; TSK_DEBUG_INFO("command=file"); if(!(opt = opt_get_by_type(cmd->opts, opt_path)) || tsk_strnullORempty(opt->value)){ TSK_DEBUG_ERROR("++file command need --path option"); break; } if((sid = invite_handle_cmd(cmd->type, cmd->opts)) != TSIP_SSESSION_INVALID_ID){ if(cmd->sidparam){ tsk_itoa(sid, &istr); update_param(cmd->sidparam, istr); } } break; } case cmd_hangup: { const opt_t* opt; TSK_DEBUG_INFO("command=hangup"); if((opt = opt_get_by_type(cmd->opts, opt_sid)) && !tsk_strnullORempty(opt->value)){ /* --sid option */ ret = session_hangup(tsk_atoll(opt->value)); } else{ TSK_DEBUG_ERROR("++hangup command need --sid option"); ret = -1; } break; } case cmd_help: { TSK_DEBUG_INFO("command=help"); cmd_print_help(); break; } case cmd_hold: { const opt_t* opt; TSK_DEBUG_INFO("command=hold"); if((opt = opt_get_by_type(cmd->opts, opt_sid)) && !tsk_strnullORempty(opt->value)){ /* --sid option */ invite_handle_cmd(cmd->type, cmd->opts); } else{ TSK_DEBUG_ERROR("++hold command need --sid option"); ret = -1; } break; } case cmd_message: { TSK_DEBUG_INFO("command=message"); if((sid = message_handle_cmd(cmd->type, cmd->opts)) != TSIP_SSESSION_INVALID_ID){ if(cmd->sidparam){ tsk_itoa(sid, &istr); update_param(cmd->sidparam, istr); } } break; } case cmd_options: { TSK_DEBUG_INFO("command=options"); if((sid = options_handle_cmd(cmd->type, cmd->opts)) != TSIP_SSESSION_INVALID_ID){ if(cmd->sidparam){ tsk_itoa(sid, &istr); update_param(cmd->sidparam, istr); } } break; } case cmd_publish: { TSK_DEBUG_INFO("command=publish"); if((sid = publish_handle_cmd(cmd->type, cmd->opts)) != TSIP_SSESSION_INVALID_ID){ if(cmd->sidparam){ tsk_itoa(sid, &istr); update_param(cmd->sidparam, istr); } } break; } case cmd_register: { TSK_DEBUG_INFO("command=register"); if((sid = register_handle_cmd(cmd->type, cmd->opts)) != TSIP_SSESSION_INVALID_ID){ if(cmd->sidparam){ tsk_itoa(sid, &istr); update_param(cmd->sidparam, istr); } } break; } case cmd_resume: { const opt_t* opt; TSK_DEBUG_INFO("command=resume"); if((opt = opt_get_by_type(cmd->opts, opt_sid)) && !tsk_strnullORempty(opt->value)){ /* --sid option */ invite_handle_cmd(cmd->type, cmd->opts); } else{ TSK_DEBUG_ERROR("++resume command need --sid option"); ret = -1; } break; } case cmd_run: { TSK_DEBUG_INFO("command=run"); ret = stack_run(cmd->opts); break; } case cmd_scenario: { TSK_DEBUG_INFO("command=scenario"); break; } case cmd_sleep: { const opt_t* opt; double seconds; tsk_safeobj_unlock(ctx); /* beacuse of callback function */ if((opt = opt_get_by_type(cmd->opts, opt_sec)) && !tsk_strnullORempty(opt->value)){ /* --sec option */ seconds = strtod(opt->value, tsk_null); /* strtod() is better than atof() */ if(seconds<=0){ printf("\n==== Press ENTER to continue...\n"); getchar(); } else{ TSK_DEBUG_INFO("Sleeping %f seconds", seconds); tsk_thread_sleep((uint64_t)(seconds * 1000)); } } else{ TSK_DEBUG_WARN("++sleep need --sec option."); } return 0; /* bail: will unlock again */ } case cmd_sms: { TSK_DEBUG_INFO("command=sms"); if((sid = message_handle_cmd(cmd->type, cmd->opts)) != TSIP_SSESSION_INVALID_ID){ if(cmd->sidparam){ tsk_itoa(sid, &istr); update_param(cmd->sidparam, istr); } } break; } case cmd_stop: { TSK_DEBUG_INFO("command=stop"); tsip_stack_stop(ctx->stack); break; } case cmd_subscribe: { TSK_DEBUG_INFO("command=subscribe"); if((sid = subscribe_handle_cmd(cmd->type, cmd->opts)) != TSIP_SSESSION_INVALID_ID){ if(cmd->sidparam){ tsk_itoa(sid, &istr); update_param(cmd->sidparam, istr); } } break; } case cmd_video: { TSK_DEBUG_INFO("command=video"); break; } default: { TSK_DEBUG_ERROR("%d not a valid command.", cmd); break; } } bail: tsk_safeobj_unlock(ctx); return ret; }
/**@ingroup tnet_socket_group * Creates a new socket. * To check that the returned socket is valid use @ref TNET_SOCKET_IS_VALID function. * @param host FQDN (e.g. www.doubango.org) or IPv4/IPv6 IP string. * @param port The local/remote port used to receive/send data. Set the port value to @ref TNET_SOCKET_PORT_ANY to bind to a random port. * @param type The type of the socket. See @ref tnet_socket_type_t. * @param nonblocking Indicates whether to create non-blocking socket. * @param bindsocket Indicates whether to bind the newly created socket or not. * @retval @ref tnet_socket_t object. * @sa @ref tnet_socket_create. */ tnet_socket_t* tnet_socket_create_2(const char* host, tnet_port_t port_, tnet_socket_type_t type, tsk_bool_t nonblocking, tsk_bool_t bindsocket) { tnet_socket_t *sock; if ((sock = tsk_object_new(tnet_socket_def_t))) { int status; tsk_istr_t port; struct addrinfo *result = tsk_null; struct addrinfo *ptr = tsk_null; struct addrinfo hints; tnet_host_t local_hostname; sock->port = port_; tsk_itoa(sock->port, &port); sock->type = type; memset(local_hostname, 0, sizeof(local_hostname)); /* Get the local host name */ if (host != TNET_SOCKET_HOST_ANY && !tsk_strempty(host)){ memcpy(local_hostname, host, tsk_strlen(host) > sizeof(local_hostname) - 1 ? sizeof(local_hostname) - 1 : tsk_strlen(host)); } else{ if (TNET_SOCKET_TYPE_IS_IPV6(sock->type)){ memcpy(local_hostname, "::", 2); } else { memcpy(local_hostname, "0.0.0.0", 7); } } /* hints address info structure */ memset(&hints, 0, sizeof(hints)); hints.ai_family = TNET_SOCKET_TYPE_IS_IPV46(sock->type) ? AF_UNSPEC : (TNET_SOCKET_TYPE_IS_IPV6(sock->type) ? AF_INET6 : AF_INET); hints.ai_socktype = TNET_SOCKET_TYPE_IS_STREAM(sock->type) ? SOCK_STREAM : SOCK_DGRAM; hints.ai_protocol = TNET_SOCKET_TYPE_IS_STREAM(sock->type) ? IPPROTO_TCP : IPPROTO_UDP; hints.ai_flags = AI_PASSIVE #if !TNET_UNDER_WINDOWS || _WIN32_WINNT>=0x600 | AI_ADDRCONFIG #endif ; /* Performs getaddrinfo */ if ((status = tnet_getaddrinfo(local_hostname, port, &hints, &result))) { TNET_PRINT_LAST_ERROR("tnet_getaddrinfo(family=%d, hostname=%s and port=%s) failed: [%s]", hints.ai_family, local_hostname, port, tnet_gai_strerror(status)); goto bail; } /* Find our address. */ for (ptr = result; ptr; ptr = ptr->ai_next){ sock->fd = (tnet_fd_t)tnet_soccket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol); if (ptr->ai_family != AF_INET6 && ptr->ai_family != AF_INET){ continue; } /* To avoid "Address already in use" error * Check issue 368 (https://code.google.com/p/doubango/issues/detail?id=368) to understand why it's not used for UDP/DTLS. */ // if (TNET_SOCKET_TYPE_IS_STREAM(sock->type)) { if ((status = tnet_sockfd_reuseaddr(sock->fd, 1))) { // do not break...continue } } if (bindsocket){ /* Bind the socket */ if ((status = bind(sock->fd, ptr->ai_addr, (int)ptr->ai_addrlen))){ TNET_PRINT_LAST_ERROR("bind to [%s:%s]have failed", local_hostname, port); tnet_socket_close(sock); continue; } /* Get local IP string. */ if ((status = tnet_get_ip_n_port(sock->fd, tsk_true/*local*/, &sock->ip, &sock->port))) /* % */ //if((status = tnet_getnameinfo(ptr->ai_addr, ptr->ai_addrlen, sock->ip, sizeof(sock->ip), 0, 0, NI_NUMERICHOST))) { TNET_PRINT_LAST_ERROR("Failed to get local IP and port."); tnet_socket_close(sock); continue; } } /* sets the real socket type (if ipv46) */ if (ptr->ai_family == AF_INET6) { TNET_SOCKET_TYPE_SET_IPV6Only(sock->type); } else { TNET_SOCKET_TYPE_SET_IPV4Only(sock->type); } break; } /* Check socket validity. */ if (!TNET_SOCKET_IS_VALID(sock)) { TNET_PRINT_LAST_ERROR("Invalid socket."); goto bail; } #if TNET_UNDER_IPHONE || TNET_UNDER_IPHONE_SIMULATOR /* disable SIGPIPE signal */ { int yes = 1; if (setsockopt(sock->fd, SOL_SOCKET, SO_NOSIGPIPE, (char*)&yes, sizeof(int))){ TNET_PRINT_LAST_ERROR("setsockopt(SO_NOSIGPIPE) have failed."); } } #endif /* TNET_UNDER_IPHONE */ /* Sets the socket to nonblocking mode */ if(nonblocking){ if((status = tnet_sockfd_set_nonblocking(sock->fd))){ goto bail; } } bail: /* Free addrinfo */ tnet_freeaddrinfo(result); /* Close socket if failed. */ if (status){ if (TNET_SOCKET_IS_VALID(sock)){ tnet_socket_close(sock); } return tsk_null; } } return sock; }
// RTP/RTCP callback (From the network to the consumer) static int tdav_session_audio_rtp_cb(const void* callback_data, const struct trtp_rtp_packet_s* packet) { tdav_session_audio_t* audio = (tdav_session_audio_t*)callback_data; tdav_session_av_t* base = (tdav_session_av_t*)callback_data; if(!audio || !packet || !packet->header){ TSK_DEBUG_ERROR("Invalid parameter"); return -1; } if(audio->is_started && base->consumer && base->consumer->is_started){ tsk_size_t out_size = 0; // Find the codec to use to decode the RTP payload if(!audio->decoder.codec || audio->decoder.payload_type != packet->header->payload_type){ tsk_istr_t format; TSK_OBJECT_SAFE_FREE(audio->decoder.codec); tsk_itoa(packet->header->payload_type, &format); if(!(audio->decoder.codec = tmedia_codec_find_by_format(TMEDIA_SESSION(audio)->neg_codecs, format)) || !audio->decoder.codec->plugin || !audio->decoder.codec->plugin->decode){ TSK_DEBUG_ERROR("%s is not a valid payload for this session", format); return -2; } audio->decoder.payload_type = packet->header->payload_type; } // Open codec if not already done if(!TMEDIA_CODEC(audio->decoder.codec)->opened){ int ret; tsk_safeobj_lock(base); if((ret = tmedia_codec_open(audio->decoder.codec))){ tsk_safeobj_unlock(base); TSK_DEBUG_ERROR("Failed to open [%s] codec", audio->decoder.codec->plugin->desc); TSK_OBJECT_SAFE_FREE(audio->decoder.codec); return ret; } tsk_safeobj_unlock(base); } // Decode data out_size = audio->decoder.codec->plugin->decode(audio->decoder.codec, packet->payload.data, packet->payload.size, &audio->decoder.buffer, &audio->decoder.buffer_size, packet->header); if(out_size){ void* buffer = audio->decoder.buffer; tsk_size_t size = out_size; // resample if needed if((base->consumer->audio.out.rate && base->consumer->audio.out.rate != audio->decoder.codec->in.rate) || (base->consumer->audio.out.channels && base->consumer->audio.out.channels != TMEDIA_CODEC_AUDIO(audio->decoder.codec)->in.channels)){ tsk_size_t resampler_result_size = 0; int bytesPerSample = (base->consumer->audio.bits_per_sample >> 3); if(!audio->decoder.resampler.instance){ TSK_DEBUG_INFO("Create audio resampler(%s) for consumer: rate=%d->%d, channels=%d->%d, bytesPerSample=%d", audio->decoder.codec->plugin->desc, audio->decoder.codec->in.rate, base->consumer->audio.out.rate, TMEDIA_CODEC_AUDIO(audio->decoder.codec)->in.channels, base->consumer->audio.out.channels, bytesPerSample); audio->decoder.resampler.instance = _tdav_session_audio_resampler_create( bytesPerSample, audio->decoder.codec->in.rate, base->consumer->audio.out.rate, base->consumer->audio.ptime, TMEDIA_CODEC_AUDIO(audio->decoder.codec)->in.channels, base->consumer->audio.out.channels, TDAV_AUDIO_RESAMPLER_DEFAULT_QUALITY, &audio->decoder.resampler.buffer, &audio->decoder.resampler.buffer_size ); } if(!audio->decoder.resampler.instance){ TSK_DEBUG_ERROR("No resampler to handle data"); return -5; } if(!(resampler_result_size = tmedia_resampler_process(audio->decoder.resampler.instance, buffer, size/bytesPerSample, audio->decoder.resampler.buffer, audio->decoder.resampler.buffer_size/bytesPerSample))){ TSK_DEBUG_ERROR("Failed to process audio resampler input buffer"); return -6; } buffer = audio->decoder.resampler.buffer; size = audio->decoder.resampler.buffer_size; } // adjust the gain if(base->consumer->audio.gain){ _tdav_session_audio_apply_gain(buffer, size, base->consumer->audio.bits_per_sample, base->consumer->audio.gain); } // consume the frame tmedia_consumer_consume(base->consumer, buffer, size, packet->header); }