static void socket_write (JNIEnv *env, jobject object, jint b, jobject fileDescriptor) { int fd; int err; if (fileDescriptor == NULL) { jniThrowNullPointerException(env, NULL); return; } fd = jniGetFDFromFileDescriptor(env, fileDescriptor); if (env->ExceptionCheck()) { return; } err = socket_write_all(env, object, fd, &b, 1); UNUSED(err); // A return of -1 above means an exception is pending }
static void socket_write (JNIEnv *env, jobject object, jint b, jobject fileDescriptor) { int fd; int err; if (fileDescriptor == NULL) { jniThrowException(env, "java/lang/NullPointerException", NULL); return; } fd = jniGetFDFromFileDescriptor(env, fileDescriptor); if (env->ExceptionOccurred() != NULL) { return; } err = socket_write_all(env, object, fd, &b, 1); // A return of -1 above means an exception is pending }
static void socket_writeba (JNIEnv *env, jobject object, jbyteArray buffer, jint off, jint len, jobject fileDescriptor) { int fd; int err; jbyte* byteBuffer; if (fileDescriptor == NULL || buffer == NULL) { jniThrowNullPointerException(env, NULL); return; } if (off < 0 || len < 0 || (off + len) > env->GetArrayLength(buffer)) { jniThrowException(env, "java/lang/ArrayIndexOutOfBoundsException", NULL); return; } fd = jniGetFDFromFileDescriptor(env, fileDescriptor); if (env->ExceptionCheck()) { return; } byteBuffer = env->GetByteArrayElements(buffer,NULL); if (NULL == byteBuffer) { // an exception will have been thrown return; } err = socket_write_all(env, object, fd, byteBuffer + off, len); UNUSED(err); // A return of -1 above means an exception is pending env->ReleaseByteArrayElements(buffer, byteBuffer, JNI_ABORT); }
int psync_p2p_check_download(psync_fileid_t fileid, const unsigned char *filehashhex, uint64_t fsize, const char *filename){ struct sockaddr_in6 addr; fd_set rfds; packet_check pct1; packet_get pct2; packet_check_resp resp; struct timeval tv; psync_interface_list_t *il; psync_socket_t *sockets; size_t i, tlen; psync_socket_t sock, msock; packet_resp_t bresp; unsigned char hashsource[PSYNC_HASH_BLOCK_SIZE], hashbin[PSYNC_HASH_DIGEST_LEN], hashhex[PSYNC_HASH_DIGEST_HEXLEN]; unsigned char *token; socklen_t slen; int sret; if (!psync_setting_get_bool(_PS(p2psync))) return PSYNC_NET_PERMFAIL; debug(D_NOTICE, "sending P2P_CHECK for file with hash %."NTO_STR(PSYNC_HASH_DIGEST_HEXLEN)"s", filehashhex); pct1.type=P2P_CHECK; memcpy(pct1.hashstart, filehashhex, PSYNC_P2P_HEXHASH_BYTES); pct1.filesize=fsize; psync_ssl_rand_weak(pct1.rand, sizeof(pct1.rand)); memcpy(hashsource, filehashhex, PSYNC_HASH_DIGEST_HEXLEN); memcpy(hashsource+PSYNC_HASH_DIGEST_HEXLEN, pct1.rand, sizeof(pct1.rand)); psync_hash(hashsource, PSYNC_HASH_BLOCK_SIZE, hashbin); psync_binhex(pct1.genhash, hashbin, PSYNC_HASH_DIGEST_LEN); memcpy(pct1.computername, computername, PSYNC_HASH_DIGEST_HEXLEN); il=psync_list_ip_adapters(); sockets=psync_new_cnt(psync_socket_t, il->interfacecnt); FD_ZERO(&rfds); msock=0; for (i=0; i<il->interfacecnt; i++){ sockets[i]=INVALID_SOCKET; sock=psync_create_socket(il->interfaces[i].address.ss_family, SOCK_DGRAM, IPPROTO_UDP); if (unlikely(sock==INVALID_SOCKET)){ debug(D_NOTICE, "could not create a socket for address family %u", (unsigned)il->interfaces[i].address.ss_family); continue; } setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char *)&on, sizeof(on)); setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (const char *)&on, sizeof(on)); if (unlikely_log(bind(sock, (struct sockaddr *)&il->interfaces[i].address, il->interfaces[i].addrsize)==SOCKET_ERROR)){ psync_close_socket(sock); continue; } if (il->interfaces[i].broadcast.ss_family==AF_INET) ((struct sockaddr_in *)(&il->interfaces[i].broadcast))->sin_port=htons(PSYNC_P2P_PORT); else if (il->interfaces[i].broadcast.ss_family==AF_INET6) ((struct sockaddr_in6 *)(&il->interfaces[i].broadcast))->sin6_port=htons(PSYNC_P2P_PORT); if (sendto(sock, (const char *)&pct1, sizeof(pct1), 0, (struct sockaddr *)&il->interfaces[i].broadcast, il->interfaces[i].addrsize)!=SOCKET_ERROR){ sockets[i]=sock; FD_SET(sock, &rfds); if (sock>=msock) msock=sock+1; } else psync_close_socket(sock); } if (unlikely_log(!msock)) goto err_perm; tv.tv_sec=PSYNC_P2P_INITIAL_TIMEOUT/1000; tv.tv_usec=(PSYNC_P2P_INITIAL_TIMEOUT%1000)*1000; sret=select(msock, &rfds, NULL, NULL, &tv); if (sret==0 || unlikely_log(sret==SOCKET_ERROR)) goto err_perm; bresp=P2P_RESP_NOPE; for (i=0; i<il->interfacecnt; i++) if (sockets[i]!=INVALID_SOCKET && FD_ISSET(sockets[i], &rfds)){ slen=sizeof(addr); sret=recvfrom(sockets[i], (char *)&resp, sizeof(resp), 0, (struct sockaddr *)&addr, &slen); if (unlikely_log(sret==SOCKET_ERROR) || unlikely_log(sret<sizeof(resp))) continue; if (!memcmp(pct1.rand, resp.rand, sizeof(resp.rand))){ debug(D_WARNING, "clients are supposed to generate random data, not to reuse mine"); continue; } memcpy(hashsource, filehashhex, PSYNC_HASH_DIGEST_HEXLEN); memcpy(hashsource+PSYNC_HASH_DIGEST_HEXLEN, resp.rand, sizeof(resp.rand)); psync_hash(hashsource, PSYNC_HASH_BLOCK_SIZE, hashbin); psync_binhex(hashhex, hashbin, PSYNC_HASH_DIGEST_LEN); if (unlikely_log(memcmp(hashhex, resp.genhash, PSYNC_HASH_DIGEST_HEXLEN))) continue; if (resp.type==P2P_RESP_HAVEIT){ debug(D_NOTICE, "got P2P_RESP_HAVEIT"); bresp=P2P_RESP_HAVEIT; break; } else if (resp.type==P2P_RESP_WAIT && bresp==P2P_RESP_NOPE) bresp=P2P_RESP_WAIT; } for (i=0; i<il->interfacecnt; i++) if (sockets[i]!=INVALID_SOCKET) psync_close_socket(sockets[i]); psync_free(il); psync_free(sockets); if (bresp==P2P_RESP_NOPE) goto err_perm2; else if (bresp==P2P_RESP_WAIT){ psync_milisleep(PSYNC_P2P_SLEEP_WAIT_DOWNLOAD); goto err_temp2; } if (psync_p2p_check_rsa()) goto err_perm2; sret=psync_p2p_get_download_token(fileid, filehashhex, fsize, &token, &tlen); debug(D_NOTICE, "got token"); if (unlikely_log(sret!=PSYNC_NET_OK)){ if (sret==PSYNC_NET_TEMPFAIL) goto err_temp2; else goto err_perm2; } if (addr.sin6_family==AF_INET6){ sock=psync_create_socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); addr.sin6_port=htons(resp.port); } else if (addr.sin6_family==AF_INET){ sock=psync_create_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); ((struct sockaddr_in *)&addr)->sin_port=htons(resp.port); } else{ debug(D_ERROR, "unknown address family %u", (unsigned)addr.sin6_family); goto err_perm2; } if (unlikely_log(sock==INVALID_SOCKET)) goto err_perm3; if (unlikely(connect(sock, (struct sockaddr *)&addr, slen)==SOCKET_ERROR)){ debug(D_WARNING, "could not connect to %s port %u", p2p_get_address(&addr), (unsigned)resp.port); goto err_perm3; } debug(D_NOTICE, "connected to peer"); pct2.type=P2P_GET; memcpy(pct2.hashstart, filehashhex, PSYNC_P2P_HEXHASH_BYTES); pct2.filesize=fsize; pct2.keylen=psync_rsa_public_bin->datalen; pct2.tokenlen=tlen; memcpy(pct2.rand, pct1.rand, sizeof(pct1.rand)); memcpy(pct2.genhash, pct1.genhash, sizeof(pct1.genhash)); memcpy(pct2.computername, computername, PSYNC_HASH_DIGEST_HEXLEN); if (socket_write_all(sock, &pct2, sizeof(pct2)) || socket_write_all(sock, psync_rsa_public_bin->data, psync_rsa_public_bin->datalen) || socket_write_all(sock, token, tlen)){ debug(D_WARNING, "writing to socket failed"); goto err_temp3; } psync_free(token); sret=psync_p2p_download(sock, fileid, filehashhex, fsize, filename); psync_close_socket(sock); return sret; err_perm3: psync_free(token); goto err_perm2; err_perm: for (i=0; i<il->interfacecnt; i++) if (sockets[i]!=INVALID_SOCKET) psync_close_socket(sockets[i]); psync_free(il); psync_free(sockets); err_perm2: return PSYNC_NET_PERMFAIL; err_temp3: psync_close_socket(sock); psync_free(token); err_temp2: return PSYNC_NET_TEMPFAIL; }
static void psync_p2p_tcphandler(void *ptr){ packet_get packet; psync_fileid_t localfileid; psync_binary_rsa_key_t binpubrsa; psync_rsa_publickey_t pubrsa; psync_symmetric_key_t aeskey; psync_encrypted_symmetric_key_t encaeskey; psync_crypto_aes256_ctr_encoder_decoder_t encoder; char *token, *localpath; uint64_t off; size_t rd; psync_socket_t sock; psync_file_t fd; uint32_t keylen, enctype; unsigned char hashhex[PSYNC_HASH_DIGEST_HEXLEN], buff[4096]; sock=*((psync_socket_t *)ptr); psync_free(ptr); debug(D_NOTICE, "got tcp connection"); if (unlikely_log(socket_read_all(sock, &packet, sizeof(packet)))) goto err0; if (unlikely_log(packet.keylen>PSYNC_P2P_RSA_SIZE) || unlikely_log(packet.tokenlen>512)) /* lets allow 8 times larger keys than we use */ goto err0; localfileid=psync_p2p_has_file(packet.hashstart, packet.genhash, packet.rand, packet.filesize, hashhex); if (!localfileid){ debug(D_WARNING, "got request for file that we do not have"); goto err0; } binpubrsa=psync_ssl_alloc_binary_rsa(packet.keylen); if (unlikely_log(socket_read_all(sock, binpubrsa->data, binpubrsa->datalen))){ psync_free(binpubrsa); goto err0; } token=psync_new_cnt(char, packet.tokenlen); if (unlikely_log(socket_read_all(sock, token, packet.tokenlen)) || unlikely_log(!check_token(token, packet.tokenlen, binpubrsa->data, packet.keylen, hashhex))){ psync_free(binpubrsa); psync_free(token); goto err0; } psync_free(token); pubrsa=psync_ssl_rsa_binary_to_public(binpubrsa); psync_free(binpubrsa); if (unlikely_log(pubrsa==PSYNC_INVALID_RSA)) goto err0; localpath=psync_local_path_for_local_file(localfileid, NULL); if (unlikely_log(!localpath)) goto err0; fd=psync_file_open(localpath, P_O_RDONLY, 0); debug(D_NOTICE, "sending file %s to peer", localpath); psync_free(localpath); if (fd==INVALID_HANDLE_VALUE){ debug(D_WARNING, "could not open local file %lu", (unsigned long)localfileid); goto err0; } aeskey=psync_crypto_aes256_ctr_gen_key(); encaeskey=psync_ssl_rsa_encrypt_symmetric_key(pubrsa, aeskey); encoder=psync_crypto_aes256_ctr_encoder_decoder_create(aeskey); psync_ssl_free_symmetric_key(aeskey); keylen=encaeskey->datalen; enctype=P2P_ENCTYPE_RSA_AES; if (unlikely_log(encaeskey==PSYNC_INVALID_ENC_SYM_KEY) || unlikely_log(encoder==PSYNC_CRYPTO_INVALID_ENCODER) || unlikely_log(socket_write_all(sock, &keylen, sizeof(keylen)) || socket_write_all(sock, &enctype, sizeof(enctype)) || socket_write_all(sock, encaeskey->data, encaeskey->datalen))){ if (encaeskey!=PSYNC_INVALID_ENC_SYM_KEY) psync_free(encaeskey); if (encoder!=PSYNC_CRYPTO_INVALID_ENCODER) psync_crypto_aes256_ctr_encoder_decoder_free(encoder); psync_file_close(fd); goto err0; } psync_free(encaeskey); off=0; while (off<packet.filesize){ if (packet.filesize-off<sizeof(buff)) rd=packet.filesize-off; else rd=sizeof(buff); if (unlikely_log(psync_file_read(fd, buff, rd)!=rd)) break; psync_crypto_aes256_ctr_encode_decode_inplace(encoder, buff, rd, off); if (unlikely_log(socket_write_all(sock, buff, rd))) break; off+=rd; } psync_crypto_aes256_ctr_encoder_decoder_free(encoder); psync_file_close(fd); debug(D_NOTICE, "file sent successfuly"); err0: psync_close_socket(sock); }
/* * Maneja los requests que hacen los clientes. */ int connection_client_handler(events_t *ev, event_t *event) { client_t *client = client_get(event->fd); char *data = "ICY 200 OK\r\n" "icy-notice1: NOTICE 1\r\n" "icy-notice2: NOTICE 2\r\n" "icy-name: STATION NAME\r\n" "icy-genre: GENRE\r\n" "icy-url: http://localhost\r\n" "content-type: audio/mpeg\r\n" "icy-pub: 1\r\n" "icy-metaint: 0\r\n" "icy-br: 128\r\n" "\r\n"; // TODO a buffer moverlo de aca, no tiene sentido alocarlo en la stack cada ves // que llamamos al event handler char buffer[512]; if(event->event_mask & EVENT_READ) { // Evento de lectura, puede ser que se cerro el cliente // o que es el inicio de la conexion y estamos por // intercambiar headers. // Otra cosa es error, no esperada. // Esta funcion es llamada cada ves que hay un evento de lectura // es decir cuando uno de nuestros clientes nos envia algo. // Esto solo sucede al inicio de la conexion cuando el servidor y // el cliente intercambian headers con informacion sobre la proxima // conexion. // // Vamos a aceptar los clientes nuevos aca, a nivel ICECAST no nivel socket // es decir que vamos a crear las estructuras necesarias para // mantener la informacion sobre los clientes. // Tambien vamos a manejar las desconexiones. Estas las vamos a detectar // por que el socket al leer nos va a devolver 0 bytes. // Si el cliente estaba en estado WAITING lo proximo que tendria // que enviar son headers de ICECAST para establecer conexion. if(client->state == CLIENT_WAITING) { #ifdef DEBUG printf("[cliente=%d] connection_client_handler(EVENT_READ):CLIENT_WAITING\n", event->fd); #endif if(socket_read_string(event->fd, buffer, sizeof(buffer)) == -1) { perror("connection_client_handler():"); return -1; } // Por ahora la verificacion es simple if(strcasestr(buffer, "icy-metadata: 1") == NULL) { #ifdef DEBUG fprintf(stderr, "[cliente=%d] Headers invalidos, desconectando\n", event->fd); #endif event_del(ev, event->fd); socket_close(event->fd); client_destroy(client); server.clients--; return 0; } // Si esta todo bien seteamos como empezando la conexion client->state = CLIENT_STARTING; return 0; } else { // Manejar desconecciones if(socket_read_string(event->fd, buffer, sizeof(buffer)) == 0) { #ifdef DEBUG fprintf(stderr, "[cliente=%d] Desconectando cliente\n", event->fd); #endif event_del(ev, event->fd); socket_close(event->fd); client_destroy(client); server.clients--; return 0; } #ifdef DEBUG fprintf(stderr, "[cliente=%d] Invalid read\n%s\n", event->fd, buffer); #endif } } else if(event->event_mask & EVENT_WRITE) { char *buffer; int ret; switch(client->state) { case CLIENT_STARTING: #ifdef DEBUG printf("[cliente=%d] connection_client_handler(EVENT_WRITE):CLIENT_STARTING\n", event->fd); #endif if(socket_write_all(event->fd, data, strlen(data)) == -1) { perror("connection_client_handler():"); return -1; } client->state = CLIENT_ACTIVE; break; case CLIENT_ACTIVE: // Servir con contenido al cliente. #ifdef DEBUG fprintf(stderr, "[cliente=%d] connection_client_handler(EVENT_WRITE):CLIENT_ACTIVE\n", event->fd); #endif ret = stream_read(server.stream, client->offset, server.buffer_size, &buffer); if(ret == -1) { perror("connection_client_handler():"); return -1; } #ifdef BANDWIDTH_THROTTLING #include <sys/time.h> struct timeval now; if(gettimeofday(&now, NULL) == -1) { perror("connection_client_handler():"); return -1; } static inline int difftime(struct timeval *t1, struct timeval *t2, useconds_t interval) { // Si hay diferencia de segundos devolver que si paso el // intervalo ya que este es medido en usecs. if(t2->tv_sec - t1->tv_sec) return 1; // si la diff entre usecs es mayor o igual que interval // podemos enviar return ((t2->tv_usec - t1->tv_usec) >= interval) ? 1 : 0; } if(!difftime(&client->last_write_ts, &now, interval)) { // El intervalo no paso, hacemos que se sirva otro socket return 0; } #endif // Podriamos haber usado socket_write_all pero no me convence, por que // si fallo, es por algo y de ultima eso lo manejamos con el offset del cliente // y los datos se los reenviamos. ret = socket_write(event->fd, buffer, server.buffer_size); if(ret == -1) { perror("connection_client_handler():"); return -1; } #ifdef BANDWIDTH_THROTTLING if(gettimeofday(&client->last_write_ts, NULL) == -1) { perror("connection_client_handler():"); return -1; } #endif client->offset += ret; // Por ahora reiniciamos el streaming. if(client->offset == server.stream->size) { #ifdef DEBUG fprintf(stderr, "[cliente=%d] connection_client_handler(CLIENT_ACTIVE):EVENT_WRITE: Se llego al final del stream, reiniciando.\n" , event->fd); #endif client->offset = 0; } break; default: break; } }