{\scriptsize \begin{lstlisting}
     1	/**
     2	   @file
     3	
     4	   This program tests the low-level block transfer and authentication
     5	   functions.
     6	
     7	*/
     8	
     9	/*
    10	  Copyright (c) Andreas Hofmeier
    11	  (www.an-h.de, www.an-h.de.vu, www.lgut.uni-bremen.de/an-h/)
    12	  
    13	  This program is free software; you can redistribute it and/or modify
    14	  it under the terms of the GNU General Public License as published by
    15	  the Free Software Foundation; either version 2 of the License, or
    16	  (at your option) any later version.
    17	
    18	  This program is distributed in the hope that it will be useful, but
    19	  WITHOUT ANY WARRANTY; without even the implied warranty of
    20	  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    21	  General Public License for more details.
    22	
    23	  You should have received a copy of the GNU General Public License
    24	  along with this program; if not, write to the Free Software
    25	  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
    26	*/
    27	
    28	
    29	#include <stdio.h>
    30	#include <arpa/inet.h>
    31	#include <sys/types.h>
    32	#include <signal.h>
    33	#include "libcomm.h"
    34	#include <unistd.h>
    35	
    36	
    37	/** Port on which the server is listening and the client trys to
    38	    connect. */
    39	#define PORT 1235
    40	/** How much random bytes should be transfered? */
    41	#define bufsize 8192
    42	/** The ID which identifies the thread of the block_call()
    43	    function. This value can be coosen arbitrary and is passwd to all
    44	    called functions. */
    45	#define threadid 1234
    46	//#define bufsize 8
    47	
    48	/** test0001sockts: see test0001sockts.c.
    49	*/
    50	
    51	main(int argc, char *argv[]) {
    52	  // PID of the child process
    53	  int fpid;
    54	  int iport = PORT;
    55	
    56	  printf("running %s...\n", argv[0]);
    57	
    58	  printf("  trying blocked read mode... ");
    59	  fflush(stdout);
    60	  if (!(fpid = fork())) {
    61	    server_test_program(iport, 0);
    62	  }
    63	
    64	  client_test_program("localhost", iport++, 0);
    65	
    66	  // kill server terst programm
    67	  kill(fpid, 9);
    68	
    69	
    70	  printf("  trying non-blocked read mode... ");
    71	  fflush(stdout);
    72	  if (!(fpid = fork())) {
    73	    server_test_program(iport, 1);
    74	  }
    75	  client_test_program("localhost", iport++, 0);
    76	
    77	  // kill server terst programm
    78	  kill(fpid, 9);
    79	
    80	  printf("  trying function-call read mode... ");
    81	  fflush(stdout);
    82	  if (!(fpid = fork())) {
    83	    server_test_program(iport, 2);
    84	  }
    85	  client_test_program("localhost", iport++, 0);
    86	
    87	  // kill server terst programm
    88	  kill(fpid, 9);
    89	
    90	  printf("  trying accept-call and function-call read mode... ");
    91	  fflush(stdout);
    92	  server_test_program(iport, 3);
    93	  sleep(2);
    94	  client_test_program("localhost", iport++, 0);
    95	
    96	  printf("  testing authentification... ");
    97	  fflush(stdout);
    98	  if (!(fpid = fork())) {
    99	    server_test_program(iport, 4);
   100	  }
   101	
   102	  client_test_program("localhost", iport++, 1);
   103	
   104	  // kill server terst programm
   105	  kill(fpid, 9);
   106	
   107	
   108	  exit(0);
   109	}
   110	
   111	
   112	/** test0001sockts: see test0001sockts.c, Client Test Programm.
   113	
   114	   The client test program generates a block of n*(bufsize) random
   115	   bytes, sents theses bytes to the server, receive a block from
   116	   server, invert it and compare it with generated block.
   117	
   118	   BUGS: Receives only one block. If not all data ready and function
   119	   resv() do noct block, data get lost. Test fails.
   120	
   121	   @param server (char *) contains the server name
   122	
   123	   @param port (int) specifies the port on the server
   124	
   125	   @param auth (int) 0: normale test; 1: do authentification before
   126	   run test.
   127	
   128	*/
   129	client_test_program(char *server, int port, int auth) {
   130	  // **************************************************************
   131	  // *** Client Test Programm
   132	
   133	  int i;
   134	
   135	  // FD of socket
   136	  int sock;
   137	
   138	  char buf[bufsize], buf2[bufsize];
   139	  int type, type2, rsize;
   140	
   141	  // wait one second, give the fork enough time to bind and listen
   142	  // the socket
   143	  sleep(1);
   144	
   145	  if (block_random(buf, bufsize) == NULL) {
   146	    fail("cannot generate random numbers", 1);
   147	  }
   148	  if (block_random((char *) &type, 2) == NULL) {
   149	    fail("cannot generate random numbers", 1);
   150	  }
   151	  
   152	  // Connect to server
   153	  if ((sock = socket_connect(server, port)) < 0) {
   154	    fail("Cannot connect.", 1);    
   155	  }
   156	
   157	  sleep(3);
   158	
   159	  if (auth) {
   160	    struct AUTHINFO *local, *remote;
   161	
   162	    char a[] = "remote";
   163	    char b[] = "loginname54321";
   164	
   165	    //    if (socket_md5auth(sock, NULL, &b, &local, &remote) < 0) {
   166	    if (socket_md5auth(sock, (char *) &a, NULL, &local, &remote) < 0) {
   167	      fail("authentifications failed!", 1);    
   168	    } else {
   169	      printf("(client OK [%s:%s]) ", local -> name, local -> passwd);
   170	      fflush(stdout);
   171	    }
   172	  }
   173	
   174	  // send datablock to server
   175	  block_send(sock, type, buf, bufsize);
   176	
   177	  // receive datablock from server
   178	  block_receive(sock, &type2, buf2, &rsize, bufsize, false);
   179	  if (rsize != bufsize) {
   180	    fprintf(stderr, "WARNING: received less data from server than was" \
   181		    " send.\n(%d:%d)\n", rsize, bufsize);
   182	  }
   183	
   184	  close(sock);
   185	
   186	  // invert the bits of the local datablock and
   187	  // compare it with the result from the server
   188	  // should be the same.
   189	  for (i = 0; i < bufsize; i++) {
   190	    if (~buf2[i] != buf[i]) {
   191	      fail("some errors occure during the data transfer...", 1);
   192	    }
   193	  }
   194	  printf("OK.\n");
   195	  fflush(stdout);
   196	  sleep(1);
   197	}
   198	
   199	
   200	/**
   201	   testfunction which ist called from block_call() if a
   202	   message/datablock has received.
   203	*/
   204	block_call_do_test(int fd, int id, unsigned int type, char *buf,
   205			   unsigned int size, int term) {
   206	  int i;
   207	
   208	  if (id != threadid) {
   209	    fprintf(stderr, "** WARNING: Thread-ID was not stored correctly!");
   210	  }
   211	
   212	  // invert the bits of the whole datablock
   213	  for (i = 0; i < size; i++) {
   214	    buf[i] = ~buf[i];
   215	  }
   216	
   217	  //  printf("block_call_do_test()");
   218	  fflush(stdout);
   219	
   220	  // send inverted datablock to client
   221	  block_send(fd, type, buf, size);
   222	  close(fd);
   223	}
   224	
   225	
   226	/**
   227	   testfunction which ist called from block_call() if a
   228	   the connection terminates.
   229	*/
   230	block_call_term_test(int fd, int id) {
   231	  int i;
   232	
   233	  if (id != threadid) {
   234	    fprintf(stderr, "** WARNING: Thread-ID was not stored correctly!");
   235	  }
   236	
   237	  printf("(server: connection terminated.)\n");
   238	  fflush(stdout);
   239	}
   240	
   241	
   242	/**
   243	   testfunction which ist called from socket_accept() if someone has
   244	   connected.
   245	*/
   246	socket_accept_do_test(int fd, int id, char *pip,
   247			      struct sockaddr_in their_addr, int term) {
   248	  block_call(fd, id, false, 
   249		     (void *) block_call_do_test,
   250		     (void *) block_call_term_test);
   251	}
   252	
   253	
   254	/** test0001sockts: see test0001sockts.c, Server Test Programm.
   255	
   256	   The server test program binds a port and waits for connections. If
   257	   someone connects it reads n*(bufsize) bytes, invert all bits of
   258	   these bytes and send all back.
   259	
   260	   BUGS: Receives only one block. If not all data ready and function
   261	   resv() do noct block, data get lost. Test fails.
   262	
   263	   @param port (int) specify the port to bind.
   264	
   265	   @param mode (int) select the mode of receiving a message/datablock:
   266	   0: blocked mode, use block_receive(); 1: poll mode, poll with
   267	   block_receive_poll(); 2: call function block_call_do_test() if a
   268	   block is received, use block_call(); 3: call
   269	   socket_accept_do_test() if someone has connected. This function
   270	   calls block_call() which does the same like in 2, use
   271	   socket_accept(); 4: testing authenication by using
   272	   socket_md5auth(). After this do the same as in 0.
   273	*/
   274	server_test_program(int port, int mode) {
   275	  // **************************************************************
   276	  // *** Server Test Program
   277	
   278	  // buffer for storing data.
   279	  char *buf;
   280	
   281	  // FD of socket which is bounded to the port
   282	  int sockport;
   283	  // FD of socket
   284	  int sock;
   285	
   286	  /* connector's address information */
   287	  struct sockaddr_in their_addr;
   288	  int sin_size;
   289	
   290	    
   291	  // Bind port
   292	  if ((sockport = socket_bind(port, 10)) < 0) {
   293	    fail("Cannot bind port.", 1);
   294	  }
   295	
   296	  if (mode == 3) {
   297	    socket_accept(sockport, threadid, (void *) socket_accept_do_test);
   298	    return;
   299	  }
   300	
   301	  // accept connection
   302	  sin_size = sizeof(struct sockaddr_in);
   303	  if ((sock = accept(sockport, (struct sockaddr *) &their_addr,
   304			     &sin_size)) != -1) {
   305	    int i, size, type;
   306	    char *pard = inet_ntoa(their_addr.sin_addr);
   307	    //    fprintf(stdout, "  got connection from %s\n", pard);
   308	    
   309	    
   310	    // receive datablock from client
   311	    switch (mode) {
   312	    case 0:
   313	      // blocking function
   314	      buf = block_receive(sock, &type, NULL, &size, 0, false);
   315	      if (buf == NULL) {
   316		fprintf(stderr, "Can't receive block from client...\n");
   317		exit(1);
   318	      }
   319	      break;
   320	    case 1:
   321	      // polling function
   322	      i = 0;
   323	      do {
   324		usleep(2L);
   325		i++;
   326		buf = block_receive_poll(sock, &type, NULL, &size, 0, false);
   327	      } while (buf == (char *) 1L);
   328	      if (buf == NULL) {
   329		fprintf(stderr, "Error during receivion occured...\n");
   330		exit(1);
   331	      }
   332	      printf("(%d polls) ", i);
   333	      fflush(stdout);
   334	      break;
   335	    case 2:
   336	      // function call
   337	      block_call(sock, threadid, false, (void *) block_call_do_test,
   338			 (void *) block_call_term_test);
   339	      sleep(500); // simulate the running of the "normal" program...
   340	      return;
   341	      break;
   342	    case 4:
   343	      // authentification with blocking function
   344	      {
   345		struct AUTHINFO *local, *remote;
   346		char a[] = "loginname12345";
   347	
   348		if (socket_md5auth(sock, NULL, (char *) &a, &local, &remote) == 0) {
   349		  printf("(server OK [%s:%s]) ", local -> name, local -> passwd);
   350		  fflush(stdout);
   351		}
   352		buf = block_receive(sock, &type, NULL, &size, 0, false);
   353		if (buf == NULL) {
   354		  fprintf(stderr, "Can't receive block from client...\n");
   355		  exit(1);
   356		}
   357	      }
   358	      break;
   359	    }
   360	
   361	    // invert the bits of the whole datablock
   362	    for (i = 0; i < size; i++) {
   363	      buf[i] = ~buf[i];
   364	    }
   365	
   366	    // send inverted datablock to client
   367	    block_send(sock, type, buf, size);
   368	    close(sock);
   369	  }
   370	  close(sockport);
   371	  exit(0);
   372	}  
   373	
   374	
\end{lstlisting}}
