text: /**
  Network Working Group                                          J. Postel
  Request for Comments: 864                                            ISI
  																May 1983
  
  
  
  					  Character Generator Protocol
  
  
  
  
  This RFC specifies a standard for the ARPA Internet community.  Hosts on
  the ARPA Internet that choose to implement a Character Generator
  Protocol are expected to adopt and implement this standard.
  
  A useful debugging and measurement tool is a character generator
  service.  A character generator service simply sends data without regard
  to the input.
  
  TCP Based Character Generator Service
  
     One character generator service is defined as a connection based
     application on TCP.  A server listens for TCP connections on TCP port
     19.  Once a connection is established a stream of data is sent out
     the connection (and any data received is thrown away).  This
     continues until the calling user terminates the connection.
  
     It is fairly likely that users of this service will abruptly decide
     that they have had enough and abort the TCP connection, instead of
     carefully closing it.  The service should be prepared for either the
     carfull close or the rude abort.
  
     The data flow over the connection is limited by the normal TCP flow
     control mechanisms, so there is no concern about the service sending
     data faster than the user can process it.
  
  UDP Based Character Generator Service
  
     Another character generator service is defined as a datagram based
     application on UDP.  A server listens for UDP datagrams on UDP port
     19.  When a datagram is received, an answering datagram is sent
     containing a random number (between 0 and 512) of characters (the
     data in the received datagram is ignored).
  
     There is no history or state information associated with the UDP
     version of this service, so there is no continuity of data from one
     answering datagram to another.
  
     The service only send one datagram in response to each received
     datagram, so there is no concern about the service sending data
     faster than the user can process it.
  
  Data Syntax
  
     The data may be anything.  It is recommended that a recognizable
     pattern be used in tha data.
  
  	  One popular pattern is 72 chraracter lines of the ASCII printing
  	  characters.  There are 95 printing characters in the ASCII
  	  character set.  Sort the characters into an ordered sequence and
  	  number the characters from 0 through 94.  Think of the sequence as
  	  a ring so that character number 0 follows character number 94.  On
  	  the first line (line 0) put the characters numbered 0 through 71.
  	  On the next line (line 1) put the characters numbered 1 through
  	  72.  And so on.  On line N, put characters (0+N mod 95) through
  	  (71+N mod 95).  End each line with carriage return and line feed.
  
  Example
  
  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefgh
  "#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghi
  #$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghij
  $%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijk
  %&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijkl
  &'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklm
  '()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmn
  ()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmno
  )*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnop
  *+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopq
  +,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqr
  ,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrs
  -./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrst
  ./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstu
  /0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuv
  0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvw
  123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwx
  23456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxy
  3456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz
  456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{
  56789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|
  6789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}
  789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
  89:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
  9:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ !
  :;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ !"
  ;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ !"#
  <=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ !"#$
  =>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ !"#$%
  >?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ !"#$%&
  ?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ !"#$%&'
  @ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ !"#$%&'(
  ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ !"#$%&'()
  BCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ !"#$%&'()*
  CDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ !"#$%&'()*+
  DEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ !"#$%&'()*+,
  EFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ !"#$%&'()*+,-
  FGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ !"#$%&'()*+,-.
  GHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ !"#$%&'()*+,-./
  HIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ !"#$%&'()*+,-./0
  IJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ !"#$%&'()*+,-./01
  JKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ !"#$%&'()*+,-./012
  KLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ !"#$%&'()*+,-./0123
  LMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ !"#$%&'()*+,-./01234
  MNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ !"#$%&'()*+,-./012345
  NOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ !"#$%&'()*+,-./0123456
  */
  
  #ifndef _WIN32
  #include <netinet/in.h>
  #include <arpa/inet.h>
  #include <sys/socket.h>
  #else
  # ifndef  _CRT_SECURE_NO_WARNINGS
  #  define  _CRT_SECURE_NO_WARNINGS
  # endif
  #include <WinSock2.h>
  #pragma comment(lib, "ws2_32.lib")
  #endif
  
  #include <stdio.h>
  #include <errno.h>
  #include <string.h>
  #include <stdint.h>
  #include <event2/listener.h>
  #include <event2/buffer.h>
  #include <event2/bufferevent.h>
  #include <chrono>
  
  int64_t bytes_sent = 0;
  std::chrono::steady_clock::time_point last_time_checked = {};
  
  // [33, 126] \r \n
  constexpr int msg_len = (72 + 2) * 95;
  char msg[msg_len];
  
  void init_msg()
  {
  	char two_line[95 * 2];
  	two_line[94] = two_line[95 * 2 - 1] = ' ';
  	for (char c = 0; c < 94; c++) {
  		two_line[c] = two_line[c + 95] = c + 33;
  	}
  	int pos = 0;
  	for (int i = 0; i < 95; i++) {
  		memcpy(msg + pos, two_line + i, 72);
  		pos += 72;
  		msg[pos++] = '\r';
  		msg[pos++] = '\n';
  	}
  }
  
  void writecb(struct bufferevent* bev, void* user_data)
  {
  	auto output = bufferevent_get_output(bev);
  	if (evbuffer_get_length(output) == 0) {
  		//bufferevent_write(bev, msg, msg_len);
  		evbuffer_add(output, msg, msg_len);
  		bytes_sent += msg_len;
  	}
  }
  
  void eventcb(struct bufferevent* bev, short events, void* user_data)
  {
  	printf("eventcb events=%04X\n", events);
  	if (events & BEV_EVENT_EOF) {
  		printf("Connection closed.\n");
  	} else if (events & (BEV_EVENT_WRITING)) {
  		printf("Got an error while writing.\n");
  	} else if (events & (BEV_EVENT_ERROR)) {
  		printf("Got an error on the connection: %s\n",
  			   strerror(errno));/*XXX win32*/
  	}
  	/* None of the other events can happen here, since we haven't enabled
  		* timeouts */
  
  	bufferevent_free(bev);
  }
  
  void timer_cb(evutil_socket_t fd, short what, void* arg)
  {
  	auto now = std::chrono::steady_clock::now();
  	auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(now - last_time_checked).count();
  	printf("%4.3f MiB/s\n",
  		   double(bytes_sent * 1000.0 / ms / 1024 / 1024));
  
  	bytes_sent = 0;
  	last_time_checked = now;
  }
  
  void accept_cb(evconnlistener* listener, evutil_socket_t fd, sockaddr* addr, int socklen, void* context)
  {
  	char str[INET_ADDRSTRLEN] = { 0 };
  	auto sin = (sockaddr_in*)addr;
  	inet_ntop(AF_INET, &sin->sin_addr, str, INET_ADDRSTRLEN);
  	printf("accpet TCP connection from: %s:%d\n", str, sin->sin_port);
  
  	//evutil_make_socket_nonblocking(fd);
  	auto base = evconnlistener_get_base(listener);
  	auto bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
  	if (!bev) {
  		fprintf(stderr, "Error constructing bufferevent!\n");
  		event_base_loopbreak(base);
  		return;
  	}
  
  	bufferevent_setcb(bev, nullptr, writecb, eventcb, nullptr);
  	bufferevent_enable(bev, EV_WRITE);
  	bufferevent_disable(bev, EV_READ);
  	bufferevent_write(bev, msg, msg_len);
  	//evbuffer_add(bufferevent_get_output(bev), msg, msg_len);
  }
  
  void accpet_error_cb(evconnlistener* listener, void* context)
  {
  	auto base = evconnlistener_get_base(listener);
  	int err = EVUTIL_SOCKET_ERROR();
  	fprintf(stderr, "accpet_error_cb:%d:%s\n", err, evutil_socket_error_to_string(err));
  	event_base_loopexit(base, nullptr);
  }
  
  int main(int argc, char** argv)
  {
  	init_msg();
  #ifdef _WIN32
  	WSADATA wsa_data;
  	WSAStartup(0x0201, &wsa_data);
  #endif
  
  	int port = 10019;
  
  	sockaddr_in sin = { 0 };
  	sin.sin_family = AF_INET;
  	sin.sin_addr.s_addr = htonl(INADDR_ANY);
  	sin.sin_port = htons(port);
  
  	auto base = event_base_new();
  	if (!base) {
  		fprintf(stderr, "init libevent failed\n");
  		return -1;
  	}
  
  	auto listener = evconnlistener_new_bind(base,
  											accept_cb,
  											nullptr,
  											LEV_OPT_REUSEABLE | LEV_OPT_CLOSE_ON_FREE,
  											-1, // backlog, -1 for default
  											(sockaddr*)(&sin),
  											sizeof(sin));
  	if (!listener) {
  		fprintf(stderr, "create listener failed\n");
  		return -1;
  	}
  	printf("%s is listening on port %d\n", argv[0], port);
  	evconnlistener_set_error_cb(listener, accpet_error_cb);
  
  	last_time_checked = std::chrono::steady_clock::now();
  	auto timer = event_new(base, -1, EV_PERSIST, timer_cb, nullptr);
  	if (!timer) {
  		fprintf(stderr, "create timer failed\n");
  		return -1;
  	}
  	struct timeval three_sec = { 3, 0 };
  	event_add(timer, &three_sec);
  
  	event_base_dispatch(base);
  
  	return 0;
  }
  