#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <sys/wait.h>
#include <sys/resource.h>

unsigned long long aaa[] = {
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0xc4ffffff00000000ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0xffffffffd5ffffffull,
0x0ull,
0x0ull,
0xfbfffffffeffffffull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
0x0ull,
};
int iii = 0;

int readn(int fd, char *buf, int n) {
  int orig = n;
  while(n > 0){
    int cc = read(fd, buf, n);
    if(cc <= 0) { perror("read"); return -1; }
    n -= cc;
    buf += cc;
  }
  return orig;
}

int
main(){
  struct rlimit r;
  r.rlim_cur = r.rlim_max = 0;
  setrlimit(RLIMIT_CORE, &r);

  int s = socket(AF_INET, SOCK_STREAM, 0);
  struct sockaddr_in sin;
  memset(&sin, 0, sizeof(sin));
  sin.sin_family = AF_INET;
  sin.sin_port = htons(2049);
  if(bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0){
    perror("bind"); exit(1);
  }
  listen(s, 10);
  sync(); sleep(1); sleep(1); sleep(1);

  if(fork() == 0){
    if(system("echo -n mount: ; mount -v -t nfs 127.0.0.1:/tmp /mnt") == 0){
      system("echo -n ls: ; ls -l /mnt/. /mnt/z");
      system("echo -n echo: ; echo hi > /mnt/x");
      system("echo -n umount: ; umount /mnt");
    }
    exit(0);
  }

  if(fork() == 0){
#define NAA 64
    unsigned long long aa[NAA];
    for(int i = 0; i < NAA; i++) aa[i] = aaa[iii++];
    int ii = 0;

    socklen_t sinlen = sizeof(sin);
    int s1 = accept(s, (struct sockaddr *) &sin, &sinlen);
    printf("accept returned %d\n", s1);
    if(s1 < 0) { perror("accept"); exit(1); }
    close(s);
  
    while(1){
      unsigned int ilen;
      if(readn(s1, (char*)&ilen, 4) < 0) break;
      ilen = ntohl(ilen);
      ilen &= 0x7fffffff;
      char ibuf[1024];
      if(readn(s1, (char*)ibuf, ilen) < 0) break;
      int xid = *(int*)(ibuf+0);
      int proc = ntohl(*(int*)(ibuf+20));
      printf("proc %d\n", proc);
      
      char obuf[128];
      int olen = sizeof(obuf);
      int dummy = htonl(olen | 0x80000000);
      write(s1, &dummy, 4);
      memset(obuf, 0xff, sizeof(obuf));
      for(int i = 0; i+8 <= sizeof(obuf) && ii < NAA; i += 8)
        *(unsigned long long *)(obuf + i) ^= aa[ii++];
      *(int*)(obuf+0) = xid;
      *(int*)(obuf+4) = htonl(1); // REPLY
      *(int*)(obuf+8) = htonl(0); // MSG_ACCEPTED
      *(int*)(obuf+12) = htonl(0); // opaque_auth flavor = AUTH_NULL
      *(int*)(obuf+16) = htonl(0); // opaque_auth length
      *(int*)(obuf+20) = htonl(0); // SUCCESS
      if(write(s1, obuf, olen)<=0) perror("write");
    }
    exit(1);
  }
  close(s);
  sleep(7);
}
