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);
}
Exemple #4
0
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;
}
Exemple #5
0
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;
		}
	}