]> code.citadel.org Git - citadel.git/blob - libcitadel/tests/stringbuf_IO_test.c
* start out a unit test for our buffered I/O; copy bind/accept/select stuff from...
[citadel.git] / libcitadel / tests / stringbuf_IO_test.c
1
2 /*
3  *  CUnit - A Unit testing framework library for C.
4  *  Copyright (C) 2001  Anil Kumar
5  *  
6  *  This library is free software; you can redistribute it and/or
7  *  modify it under the terms of the GNU Library General Public
8  *  License as published by the Free Software Foundation; either
9  *  version 2 of the License, or (at your option) any later version.
10  *
11  *  This library is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  *  Library General Public License for more details.
15  *
16  *  You should have received a copy of the GNU Library General Public
17  *  License along with this library; if not, write to the Free Software
18  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include <stdio.h>
22 #include <stdlib.h>
23
24 #include <sys/select.h>
25
26 #include <ctype.h>
27 #include <unistd.h>
28 #include <fcntl.h>
29 #include <signal.h>
30 #include <sys/types.h>
31 #include <sys/wait.h>
32 #include <sys/socket.h>
33 #include <sys/time.h>
34 #include <sys/stat.h>
35 #include <limits.h>
36 #include <netinet/in.h>
37 #include <arpa/inet.h>
38 #include <sys/un.h>
39 #include <netdb.h>
40 #include <sys/poll.h>
41 #include <string.h>
42 #include <pwd.h>
43 #include <errno.h>
44 #include <stdarg.h>
45 #include <pthread.h>
46 #include <signal.h>
47 #include <sys/utsname.h>
48
49
50 typedef void testfunc(int Sock);
51
52 #define LISTEN_QUEUE_LENGTH 100
53 #include <string.h>
54
55 #include "stringbuf_test.h"
56 #include "../lib/libcitadel.h"
57
58 int msock;                      /* master listening socket */
59 int BindPort;
60 int time_to_die=0;
61 int listen_port=6666;
62 int n_Lines_to_read = 0;
63 int blobsize = 0;
64 int timeout = 5;
65 int selres = 1;
66 char ip_addr[256]="0.0.0.0";
67
68
69 static void TestRevalidateStrBuf(StrBuf *Buf)
70 {
71         CU_ASSERT(strlen(ChrPtr(Buf)) == StrLength(Buf));
72 }
73
74 /* 
75  * This is a generic function to set up a master socket for listening on
76  * a TCP port.  The server shuts down if the bind fails.
77  *
78  * ip_addr      IP address to bind
79  * port_number  port number to bind
80  * queue_len    number of incoming connections to allow in the queue
81  */
82 static int ig_tcp_server(char *ip_addr, int port_number, int queue_len)
83 {
84         struct protoent *p;
85         struct sockaddr_in sin;
86         int s, i;
87
88         memset(&sin, 0, sizeof(sin));
89         sin.sin_family = AF_INET;
90         if (ip_addr == NULL) {
91                 sin.sin_addr.s_addr = INADDR_ANY;
92         } else {
93                 sin.sin_addr.s_addr = inet_addr(ip_addr);
94         }
95
96         if (sin.sin_addr.s_addr == INADDR_NONE) {
97                 sin.sin_addr.s_addr = INADDR_ANY;
98         }
99
100         if (port_number == 0) {
101                 printf("Cannot start: no port number specified.\n");
102                 return (-1);
103         }
104         sin.sin_port = htons((u_short) port_number);
105
106         p = getprotobyname("tcp");
107
108         s = socket(PF_INET, SOCK_STREAM, (p->p_proto));
109         if (s < 0) {
110                 printf("Can't create a socket: %s\n", strerror(errno));
111                 return (-2);
112         }
113         /* Set some socket options that make sense. */
114         i = 1;
115         setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i));
116
117         #ifndef __APPLE__
118         fcntl(s, F_SETFL, O_NONBLOCK); /* maide: this statement is incorrect
119                                           there should be a preceding F_GETFL
120                                           and a bitwise OR with the previous
121                                           fd flags */
122         #endif
123         
124         if (bind(s, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
125                 printf("Can't bind: %s\n", strerror(errno));
126                 return (-3);
127         }
128         if (listen(s, queue_len) < 0) {
129                 printf("Can't listen: %s\n", strerror(errno));
130                 return (-4);
131         }
132         return (s);
133 }
134
135
136
137 /*
138  * Entry point for worker threads
139  */
140 static void worker_entry(testfunc F)
141 {
142         int ssock;
143         int i = 0;
144         int fail_this_transaction = 0;
145         int ret;
146         struct timeval tv;
147         fd_set readset, tempset;
148
149         
150         tv.tv_sec = 0;
151         tv.tv_usec = 10000;
152         FD_ZERO(&readset);
153         FD_SET(msock, &readset);
154
155         do {
156                 /* Only one thread can accept at a time */
157                 fail_this_transaction = 0;
158                 ssock = -1; 
159                 errno = EAGAIN;
160                 do {
161                         ret = -1; /* just one at once should select... */
162                         
163                         FD_ZERO(&tempset);
164                         if (msock > 0) FD_SET(msock, &tempset);
165                         tv.tv_sec = 0;
166                         tv.tv_usec = 10000;
167                         if (msock > 0)  
168                                 ret = select(msock+1, &tempset, NULL, NULL,  &tv);
169                         if ((ret < 0) && (errno != EINTR) && (errno != EAGAIN))
170                         {/* EINTR and EAGAIN are thrown but not of interest. */
171                                 printf("accept() failed:%d %s\n",
172                                         errno, strerror(errno));
173                         }
174                         else if ((ret > 0) && (msock > 0) && FD_ISSET(msock, &tempset))
175                         {/* Successfully selected, and still not shutting down? Accept! */
176                                 ssock = accept(msock, NULL, 0);
177                         }
178                         
179                 } while ((msock > 0) && (ssock < 0)  && (time_to_die == 0));
180
181                 if ((msock == -1)||(time_to_die))
182                 {/* ok, we're going down. */
183                         exit(0);
184                 }
185                 if (ssock < 0 ) continue;
186
187                 if (msock < 0) {
188                         if (ssock > 0) close (ssock);
189                         printf( "inbetween.");
190                         return;
191                 } else { /* Got it? do some real work! */
192                         /* Set the SO_REUSEADDR socket option */
193                         int fdflags; 
194                         i = 1;
195                         setsockopt(ssock, SOL_SOCKET, SO_REUSEADDR,
196                                    &i, sizeof(i));
197
198                         fdflags = fcntl(ssock, F_GETFL);
199                         if (fdflags < 0)
200                                 printf("unable to get server socket flags! %s \n",
201                                         strerror(errno));
202                         fdflags = fdflags | O_NONBLOCK;
203                         if (fcntl(ssock, F_SETFL, fdflags) < 0)
204                                 printf("unable to set server socket nonblocking flags! %s \n",
205                                         strerror(errno));
206
207
208                         F(ssock);
209                 }
210
211         } while (!time_to_die);
212         printf ("bye\n");
213 }
214
215
216 static void SimpleLineBufTestFunc(int sock)
217 {
218         StrBuf *ReadBuffer;
219         StrBuf *Line;
220         const char *Pos = NULL;
221         const char *err;
222         int i;
223
224         ReadBuffer = NewStrBuf();
225         Line = NewStrBuf();
226
227         for (i = 0; i < n_Lines_to_read; i++) {
228                 StrBufTCP_read_buffered_line_fast(Line, 
229                                                   ReadBuffer, 
230                                                   &Pos,
231                                                   &sock,
232                                                   timeout,
233                                                   selres,
234                                                   &err);
235                 if (err != NULL)
236                         printf("%s", err);
237                 CU_ASSERT_PTR_NOT_NULL(err);
238                 CU_ASSERT_NOT_EQUAL(sock, -1);
239                 if (sock == -1)
240                         break;
241                 printf("LINE: >%s<\n", ChrPtr(Line));
242         }
243         FreeStrBuf(&ReadBuffer);
244         FreeStrBuf(&Line);
245         time_to_die = 1;
246 }
247
248
249 static void SimpleLinebufferTest(void)
250 {
251         msock = ig_tcp_server(ip_addr, listen_port, LISTEN_QUEUE_LENGTH);
252
253         worker_entry(SimpleLineBufTestFunc);
254 }
255
256 /*
257 Some samples from the original...
258         CU_ASSERT_EQUAL(10, 10);
259         CU_ASSERT_EQUAL(0, -0);
260         CU_ASSERT_EQUAL(-12, -12);
261         CU_ASSERT_NOT_EQUAL(10, 11);
262         CU_ASSERT_NOT_EQUAL(0, -1);
263         CU_ASSERT_NOT_EQUAL(-12, -11);
264         CU_ASSERT_PTR_EQUAL((void*)0x100, (void*)0x100);
265         CU_ASSERT_PTR_NOT_EQUAL((void*)0x100, (void*)0x101);
266         CU_ASSERT_PTR_NULL(NULL);
267         CU_ASSERT_PTR_NULL(0x0);
268         CU_ASSERT_PTR_NOT_NULL((void*)0x23);
269         CU_ASSERT_STRING_EQUAL(str1, str2);
270         CU_ASSERT_STRING_NOT_EQUAL(str1, str2);
271         CU_ASSERT_NSTRING_EQUAL(str1, str2, strlen(str1));
272         CU_ASSERT_NSTRING_EQUAL(str1, str1, strlen(str1));
273         CU_ASSERT_NSTRING_EQUAL(str1, str1, strlen(str1) + 1);
274         CU_ASSERT_NSTRING_NOT_EQUAL(str1, str2, 3);
275         CU_ASSERT_NSTRING_NOT_EQUAL(str1, str3, strlen(str1) + 1);
276         CU_ASSERT_DOUBLE_EQUAL(10, 10.0001, 0.0001);
277         CU_ASSERT_DOUBLE_EQUAL(10, 10.0001, -0.0001);
278         CU_ASSERT_DOUBLE_EQUAL(-10, -10.0001, 0.0001);
279         CU_ASSERT_DOUBLE_EQUAL(-10, -10.0001, -0.0001);
280         CU_ASSERT_DOUBLE_NOT_EQUAL(10, 10.001, 0.0001);
281         CU_ASSERT_DOUBLE_NOT_EQUAL(10, 10.001, -0.0001);
282         CU_ASSERT_DOUBLE_NOT_EQUAL(-10, -10.001, 0.0001);
283         CU_ASSERT_DOUBLE_NOT_EQUAL(-10, -10.001, -0.0001);
284 */
285
286
287
288
289
290 static void AddStrBufSimlpeTests(void)
291 {
292         CU_pSuite pGroup = NULL;
293         CU_pTest pTest = NULL;
294
295         pGroup = CU_add_suite("TestStringBufSimpleAppenders", NULL, NULL);
296         pTest = CU_add_test(pGroup, "testSimpleLinebufferTest", SimpleLinebufferTest);
297
298
299 }
300
301
302 int main(int argc, char* argv[])
303 {
304         char a;
305         setvbuf(stdout, NULL, _IONBF, 0);
306
307
308         while ((a = getopt(argc, argv, "p:i:n:b:t:s")) != EOF)
309         {
310                 switch (a) {
311
312                 case 'p':
313                         listen_port = atoi(optarg);
314                         break;
315                 case 'i':
316                         safestrncpy(ip_addr, optarg, sizeof ip_addr);
317                         break;
318                 case 'n':
319                         n_Lines_to_read = atoi(optarg);
320                         break;
321                 case 'b':
322                         blobsize = atoi(optarg);
323                         break;
324                 case 't':
325                         timeout = atoi(optarg);
326                         break;
327                 case 's':
328                         selres = atoi(optarg);
329                         break;
330                 }
331         }
332
333
334         StartLibCitadel(8);
335         CU_BOOL Run = CU_FALSE ;
336         
337         CU_set_output_filename("TestAutomated");
338         if (CU_initialize_registry()) {
339                 printf("\nInitialize of test Registry failed.");
340         }
341         
342         Run = CU_TRUE ;
343         AddStrBufSimlpeTests();
344         
345         if (CU_TRUE == Run) {
346                 //CU_console_run_tests();
347     printf("\nTests completed with return value %d.\n", CU_basic_run_tests());
348     
349     ///CU_automated_run_tests();
350         }
351         
352         CU_cleanup_registry();
353
354         return 0;
355 }