aboutsummaryrefslogtreecommitdiff
path: root/src/stream
diff options
context:
space:
mode:
authorSree Harsha Totakura <totakura@in.tum.de>2012-09-04 12:24:15 +0000
committerSree Harsha Totakura <totakura@in.tum.de>2012-09-04 12:24:15 +0000
commit2ece5c39ccabb8bd1450dcf75d145b062f9d02f6 (patch)
tree4631904eed45ea535e036fdce16d029877a52846 /src/stream
parent148498775bb468c6dc586b95c7cfd007ce0c4b54 (diff)
downloadgnunet-2ece5c39ccabb8bd1450dcf75d145b062f9d02f6.tar.gz
gnunet-2ece5c39ccabb8bd1450dcf75d145b062f9d02f6.zip
new stream testcase using testbed
Diffstat (limited to 'src/stream')
-rw-r--r--src/stream/Makefile.am16
-rw-r--r--src/stream/stream_api.c2
-rw-r--r--src/stream/stream_protocol.h6
-rw-r--r--src/stream/test_stream_2peers_new.c622
4 files changed, 636 insertions, 10 deletions
diff --git a/src/stream/Makefile.am b/src/stream/Makefile.am
index 54f2a6fa5..4f8b47f1d 100644
--- a/src/stream/Makefile.am
+++ b/src/stream/Makefile.am
@@ -22,6 +22,7 @@ libgnunetstream_la_LDFLAGS = \
22 22
23check_PROGRAMS = \ 23check_PROGRAMS = \
24 test_stream_2peers \ 24 test_stream_2peers \
25 test_stream_2peers_new \
25 test_stream_2peers_halfclose \ 26 test_stream_2peers_halfclose \
26 test_stream_local \ 27 test_stream_local \
27 test_stream_big \ 28 test_stream_big \
@@ -30,10 +31,12 @@ check_PROGRAMS = \
30EXTRA_DIST = test_stream_local.conf 31EXTRA_DIST = test_stream_local.conf
31 32
32if ENABLE_TEST_RUN 33if ENABLE_TEST_RUN
33TESTS = $(check_PROGRAMS) 34TESTS = \
34# test_stream_2peers \ 35 test_stream_2peers \
35 test_stream_2peers_halfclose \ 36 test_stream_2peers_halfclose \
36 test_stream_local 37 test_stream_local \
38 test_stream_big \
39 test_stream_sequence_wraparound
37endif 40endif
38 41
39test_stream_2peers_SOURCES = \ 42test_stream_2peers_SOURCES = \
@@ -43,6 +46,13 @@ test_stream_2peers_LDADD = \
43 $(top_builddir)/src/util/libgnunetutil.la \ 46 $(top_builddir)/src/util/libgnunetutil.la \
44 $(top_builddir)/src/testing_old/libgnunettesting_old.la 47 $(top_builddir)/src/testing_old/libgnunettesting_old.la
45 48
49test_stream_2peers_new_SOURCES = \
50 test_stream_2peers_new.c
51test_stream_2peers_new_LDADD = \
52 $(top_builddir)/src/stream/libgnunetstream.la \
53 $(top_builddir)/src/util/libgnunetutil.la \
54 $(top_builddir)/src/testbed/libgnunettestbed.la
55
46test_stream_2peers_halfclose_SOURCES = \ 56test_stream_2peers_halfclose_SOURCES = \
47 test_stream_2peers_halfclose.c 57 test_stream_2peers_halfclose.c
48test_stream_2peers_halfclose_LDADD = \ 58test_stream_2peers_halfclose_LDADD = \
diff --git a/src/stream/stream_api.c b/src/stream/stream_api.c
index 4e5401c56..fe7038dd0 100644
--- a/src/stream/stream_api.c
+++ b/src/stream/stream_api.c
@@ -1466,7 +1466,7 @@ control_retransmission_task (void *cls,
1466 socket->control_retransmission_task_id = GNUNET_SCHEDULER_NO_TASK; 1466 socket->control_retransmission_task_id = GNUNET_SCHEDULER_NO_TASK;
1467 LOG_DEBUG ("%s: Retransmitting a control message\n", 1467 LOG_DEBUG ("%s: Retransmitting a control message\n",
1468 GNUNET_i2s (&socket->other_peer)); 1468 GNUNET_i2s (&socket->other_peer));
1469 switch (socket->status) 1469 switch (socket->state)
1470 { 1470 {
1471 case STATE_INIT: 1471 case STATE_INIT:
1472 GNUNET_break (0); 1472 GNUNET_break (0);
diff --git a/src/stream/stream_protocol.h b/src/stream/stream_protocol.h
index d1c43b778..04b1ef1ee 100644
--- a/src/stream/stream_protocol.h
+++ b/src/stream/stream_protocol.h
@@ -50,12 +50,6 @@ struct GNUNET_STREAM_MessageHeader
50 * The GNUNET message header, types are from GNUNET_MESSAGE_TYPE_STREAM_*-range. 50 * The GNUNET message header, types are from GNUNET_MESSAGE_TYPE_STREAM_*-range.
51 */ 51 */
52 struct GNUNET_MessageHeader header; 52 struct GNUNET_MessageHeader header;
53
54 /**
55 * A number which identifies a session between the two peers. FIXME: not needed
56 */
57 uint32_t session_id GNUNET_PACKED;
58
59}; 53};
60 54
61 55
diff --git a/src/stream/test_stream_2peers_new.c b/src/stream/test_stream_2peers_new.c
new file mode 100644
index 000000000..937500d1f
--- /dev/null
+++ b/src/stream/test_stream_2peers_new.c
@@ -0,0 +1,622 @@
1/*
2 This file is part of GNUnet.
3 (C) 2011, 2012 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21/**
22 * @file stream/test_stream_2peers.c
23 * @brief Stream API testing between 2 peers using testing API
24 * @author Sree Harsha Totakura
25 */
26
27#include <string.h>
28
29#include "platform.h"
30#include "gnunet_util_lib.h"
31#include "gnunet_mesh_service.h"
32#include "gnunet_stream_lib.h"
33#include "gnunet_testbed_service.h"
34
35/**
36 * Number of peers; Do NOT change this
37 */
38#define NUM_PEERS 2
39
40/**
41 * Shorthand for Relative time in seconds
42 */
43#define TIME_REL_SECS(sec) \
44 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, sec)
45
46/**
47 * Structure for holding peer's sockets and IO Handles
48 */
49struct PeerData
50{
51 /**
52 * Handle to testbed peer
53 */
54 struct GNUNET_TESTBED_Peer *peer;
55
56 /**
57 * Peer's stream socket
58 */
59 struct GNUNET_STREAM_Socket *socket;
60
61 /**
62 * Peer's io write handle
63 */
64 struct GNUNET_STREAM_IOWriteHandle *io_write_handle;
65
66 /**
67 * Peer's io read handle
68 */
69 struct GNUNET_STREAM_IOReadHandle *io_read_handle;
70
71 /**
72 * Peer's shutdown handle
73 */
74 struct GNUNET_STREAM_ShutdownHandle *shutdown_handle;
75
76 /**
77 * The service connect operation to stream
78 */
79 struct GNUNET_TESTBED_Operation *op;
80
81 /**
82 * Our Peer id
83 */
84 struct GNUNET_PeerIdentity our_id;
85
86 /**
87 * Bytes the peer has written
88 */
89 unsigned int bytes_wrote;
90
91 /**
92 * Byte the peer has read
93 */
94 unsigned int bytes_read;
95};
96
97
98/**
99 * Different states in test setup
100 */
101enum SetupState
102{
103 /**
104 * The initial state
105 */
106 INIT,
107
108 /**
109 * Get the identity of peer 1
110 */
111 PEER1_GET_IDENTITY,
112
113 /**
114 * Get the identity of peer 2
115 */
116 PEER2_GET_IDENTITY,
117
118 /**
119 * Connect to stream service of peer 1
120 */
121 PEER1_STREAM_CONNECT,
122
123 /**
124 * Connect to stream service of peer 2
125 */
126 PEER2_STREAM_CONNECT
127
128};
129
130/**
131 * Various states during test setup
132 */
133static enum SetupState setup_state;
134
135/**
136 * Data context for peer 1
137 */
138static struct PeerData peer1;
139
140/**
141 * Data context for peer 2
142 */
143static struct PeerData peer2;
144
145/**
146 * Testbed operation handle
147 */
148static struct GNUNET_TESTBED_Operation *op;
149
150static GNUNET_SCHEDULER_TaskIdentifier abort_task;
151
152static char *data = "ABCD";
153static int result;
154
155static int writing_success;
156static int reading_success;
157
158
159/**
160 * Input processor
161 *
162 * @param cls the closure from GNUNET_STREAM_write/read
163 * @param status the status of the stream at the time this function is called
164 * @param data traffic from the other side
165 * @param size the number of bytes available in data read
166 * @return number of bytes of processed from 'data' (any data remaining should be
167 * given to the next time the read processor is called).
168 */
169static size_t
170input_processor (void *cls,
171 enum GNUNET_STREAM_Status status,
172 const void *input_data,
173 size_t size);
174
175/**
176 * Task for calling STREAM_read
177 *
178 * @param cls the peer data entity
179 * @param tc the task context
180 */
181static void
182stream_read_task (void *cls,
183 const struct GNUNET_SCHEDULER_TaskContext *tc)
184{
185 struct PeerData *peer = cls;
186
187 peer->io_read_handle = GNUNET_STREAM_read (peer->socket,
188 GNUNET_TIME_relative_multiply
189 (GNUNET_TIME_UNIT_SECONDS, 5),
190 &input_processor,
191 peer);
192 GNUNET_assert (NULL != peer->io_read_handle);
193}
194
195/**
196 * The write completion function; called upon writing some data to stream or
197 * upon error
198 *
199 * @param cls the closure from GNUNET_STREAM_write/read
200 * @param status the status of the stream at the time this function is called
201 * @param size the number of bytes read or written
202 */
203static void
204write_completion (void *cls,
205 enum GNUNET_STREAM_Status status,
206 size_t size);
207
208
209/**
210 * Task for calling STREAM_write
211 *
212 * @param cls the peer data entity
213 * @param tc the task context
214 */
215static void
216stream_write_task (void *cls,
217 const struct GNUNET_SCHEDULER_TaskContext *tc)
218{
219 struct PeerData *peer = cls;
220
221 peer->io_write_handle =
222 GNUNET_STREAM_write (peer->socket,
223 (void *) data,
224 strlen(data) - peer->bytes_wrote,
225 GNUNET_TIME_relative_multiply
226 (GNUNET_TIME_UNIT_SECONDS, 5),
227 &write_completion,
228 peer);
229
230 GNUNET_assert (NULL != peer->io_write_handle);
231 }
232
233
234/**
235 * Close sockets and stop testing deamons nicely
236 */
237static void
238do_close (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
239{
240 if (GNUNET_SCHEDULER_NO_TASK != abort_task)
241 GNUNET_SCHEDULER_cancel (abort_task);
242 if (NULL != peer1.socket)
243 GNUNET_STREAM_close (peer1.socket);
244 GNUNET_TESTBED_operation_done (peer1.op);
245}
246
247
248/**
249 * Completion callback for shutdown
250 *
251 * @param cls the closure from GNUNET_STREAM_shutdown call
252 * @param operation the operation that was shutdown (SHUT_RD, SHUT_WR,
253 * SHUT_RDWR)
254 */
255static void
256shutdown_completion (void *cls,
257 int operation)
258{
259 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "STREAM shutdown successful\n");
260 GNUNET_SCHEDULER_add_now (&do_close, cls);
261}
262
263
264
265/**
266 * Shutdown sockets gracefully
267 */
268static void
269do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
270{
271 result = GNUNET_OK;
272 peer1.shutdown_handle = GNUNET_STREAM_shutdown (peer1.socket, SHUT_RDWR,
273 &shutdown_completion, cls);
274}
275
276
277/**
278 * Something went wrong and timed out. Kill everything and set error flag
279 */
280static void
281do_abort (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
282{
283 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: ABORT\n");
284 result = GNUNET_SYSERR;
285 abort_task = 0;
286 do_close (cls, tc);
287}
288
289
290/**
291 * The write completion function; called upon writing some data to stream or
292 * upon error
293 *
294 * @param cls the closure from GNUNET_STREAM_write/read
295 * @param status the status of the stream at the time this function is called
296 * @param size the number of bytes read or written
297 */
298static void
299write_completion (void *cls,
300 enum GNUNET_STREAM_Status status,
301 size_t size)
302{
303 struct PeerData *peer=cls;
304
305 GNUNET_assert (GNUNET_STREAM_OK == status);
306 GNUNET_assert (size <= strlen (data));
307 peer->bytes_wrote += size;
308
309 if (peer->bytes_wrote < strlen(data)) /* Have more data to send */
310 {
311 GNUNET_SCHEDULER_add_now (&stream_write_task, peer);
312 }
313 else
314 {
315 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
316 "Writing completed\n");
317
318 if (&peer2 == peer) /* Peer1 has finished writing; should read now */
319 {
320 peer->bytes_read = 0;
321 GNUNET_SCHEDULER_add_now (&stream_read_task, peer);
322 }
323 else
324 {
325 writing_success = GNUNET_YES;
326 if (GNUNET_YES == reading_success)
327 GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
328 }
329 }
330}
331
332
333/**
334 * Function executed after stream has been established
335 *
336 * @param cls the closure from GNUNET_STREAM_open
337 * @param socket socket to use to communicate with the other side (read/write)
338 */
339static void
340stream_open_cb (void *cls,
341 struct GNUNET_STREAM_Socket *socket)
342{
343 struct PeerData *peer=cls;
344
345 GNUNET_assert (&peer2 == peer);
346 GNUNET_assert (socket == peer2.socket);
347 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s: Stream established from peer2\n",
348 GNUNET_i2s (&peer1.our_id));
349 peer->bytes_wrote = 0;
350 GNUNET_SCHEDULER_add_now (&stream_write_task, peer);
351}
352
353
354/**
355 * Input processor
356 *
357 * @param cls the closure from GNUNET_STREAM_write/read
358 * @param status the status of the stream at the time this function is called
359 * @param data traffic from the other side
360 * @param size the number of bytes available in data read
361 * @return number of bytes of processed from 'data' (any data remaining should be
362 * given to the next time the read processor is called).
363 */
364static size_t
365input_processor (void *cls,
366 enum GNUNET_STREAM_Status status,
367 const void *input_data,
368 size_t size)
369{
370 struct PeerData *peer;
371
372 peer = (struct PeerData *) cls;
373
374 if (GNUNET_STREAM_TIMEOUT == status)
375 {
376 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
377 "Read operation timedout - reading again!\n");
378 GNUNET_assert (0 == size);
379 GNUNET_SCHEDULER_add_now (&stream_read_task, peer);
380 return 0;
381 }
382
383 GNUNET_assert (GNUNET_STREAM_OK == status);
384 GNUNET_assert (size <= strlen (data));
385 GNUNET_assert (0 == strncmp ((const char *) data + peer->bytes_read,
386 (const char *) input_data,
387 size));
388 peer->bytes_read += size;
389
390 if (peer->bytes_read < strlen (data))
391 {
392 GNUNET_SCHEDULER_add_now (&stream_read_task, peer);
393 }
394 else
395 {
396 if (&peer1 == peer) /* Peer2 has completed reading; should write */
397 {
398 peer->bytes_wrote = 0;
399 GNUNET_SCHEDULER_add_now (&stream_write_task, peer);
400 }
401 else /* Peer1 has completed reading. End of tests */
402 {
403 reading_success = GNUNET_YES;
404 if (GNUNET_YES == writing_success)
405 GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
406 }
407 }
408 return size;
409}
410
411
412/**
413 * Functions of this type are called upon new stream connection from other peers
414 *
415 * @param cls the closure from GNUNET_STREAM_listen
416 * @param socket the socket representing the stream
417 * @param initiator the identity of the peer who wants to establish a stream
418 * with us
419 * @return GNUNET_OK to keep the socket open, GNUNET_SYSERR to close the
420 * stream (the socket will be invalid after the call)
421 */
422static int
423stream_listen_cb (void *cls,
424 struct GNUNET_STREAM_Socket *socket,
425 const struct GNUNET_PeerIdentity *initiator)
426{
427 GNUNET_assert (NULL != socket);
428 GNUNET_assert (NULL != initiator);
429 GNUNET_assert (socket != peer2.socket);
430 GNUNET_assert (0 == memcmp (initiator, &peer2.our_id,
431 sizeof (struct GNUNET_PeerIdentity)));
432 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s: Peer connected: %s\n",
433 GNUNET_i2s (&peer1.our_id), GNUNET_i2s (initiator));
434 peer1.socket = socket;
435 peer1.bytes_read = 0;
436 GNUNET_SCHEDULER_add_now (&stream_read_task, &peer1);
437 return GNUNET_OK;
438}
439
440
441/**
442 * Listen success callback; connects a peer to stream as client
443 */
444static void stream_connect (void);
445
446
447/**
448 * Adapter function called to destroy a connection to
449 * a service.
450 *
451 * @param cls closure
452 * @param op_result service handle returned from the connect adapter
453 */
454static void
455stream_da (void *cls, void *op_result)
456{
457 struct GNUNET_STREAM_ListenSocket *lsocket;
458 struct GNUNET_STREAM_Socket *socket;
459
460 if (&peer1 == cls)
461 {
462 lsocket = op_result;
463 GNUNET_STREAM_listen_close (lsocket);
464 GNUNET_TESTBED_operation_done (peer2.op);
465 return;
466 }
467 if (&peer2 == cls)
468 {
469 socket = op_result;
470 GNUNET_STREAM_close (socket);
471 GNUNET_SCHEDULER_shutdown (); /* Exit point of the test */
472 return;
473 }
474 GNUNET_assert (0);
475}
476
477
478/**
479 * Adapter function called to establish a connection to
480 * a service.
481 *
482 * @param cls closure
483 * @param cfg configuration of the peer to connect to; will be available until
484 * GNUNET_TESTBED_operation_done() is called on the operation returned
485 * from GNUNET_TESTBED_service_connect()
486 * @return service handle to return in 'op_result', NULL on error
487 */
488static void *
489stream_ca (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg)
490{
491 struct GNUNET_STREAM_ListenSocket *lsocket;
492
493 switch (setup_state)
494 {
495 case PEER1_STREAM_CONNECT:
496 lsocket = GNUNET_STREAM_listen (cfg, 10, &stream_listen_cb, NULL,
497 GNUNET_STREAM_OPTION_SIGNAL_LISTEN_SUCCESS,
498 &stream_connect, GNUNET_STREAM_OPTION_END);
499 return lsocket;
500 case PEER2_STREAM_CONNECT:
501 peer2.socket = GNUNET_STREAM_open (cfg, &peer1.our_id, 10, &stream_open_cb,
502 &peer2, GNUNET_STREAM_OPTION_END);
503 return peer2.socket;
504 default:
505 GNUNET_assert (0);
506 }
507}
508
509
510/**
511 * Listen success callback; connects a peer to stream as client
512 */
513static void
514stream_connect (void)
515{
516 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stream listen open successful\n");
517 peer2.op = GNUNET_TESTBED_service_connect (&peer2, peer2.peer, "stream",
518 stream_ca, stream_da, &peer2);
519 setup_state = PEER2_STREAM_CONNECT;
520}
521
522
523/**
524 * Controller event callback
525 *
526 * @param cls NULL
527 * @param event the controller event
528 */
529static void
530controller_event_cb (void *cls,
531 const struct GNUNET_TESTBED_EventInformation *event)
532{
533 switch (event->type)
534 {
535 case GNUNET_TESTBED_ET_CONNECT:
536 GNUNET_assert (INIT == setup_state);
537 GNUNET_TESTBED_operation_done (op);
538 /* Get the peer identity and configuration of peers */
539 op = GNUNET_TESTBED_peer_get_information (peer1.peer,
540 GNUNET_TESTBED_PIT_IDENTITY);
541 setup_state = PEER1_GET_IDENTITY;
542 break;
543 case GNUNET_TESTBED_ET_OPERATION_FINISHED:
544 switch (setup_state)
545 {
546 case PEER1_GET_IDENTITY:
547 memcpy (&peer1.our_id, event->details.operation_finished.op_result.pid,
548 sizeof (struct GNUNET_PeerIdentity));
549 GNUNET_TESTBED_operation_done (op);
550 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer 1 id: %s\n", GNUNET_i2s
551 (&peer1.our_id));
552 op = GNUNET_TESTBED_peer_get_information (peer2.peer,
553 GNUNET_TESTBED_PIT_IDENTITY);
554 setup_state = PEER2_GET_IDENTITY;
555 break;
556 case PEER2_GET_IDENTITY:
557 memcpy (&peer2.our_id, event->details.operation_finished.op_result.pid,
558 sizeof (struct GNUNET_PeerIdentity));
559 GNUNET_TESTBED_operation_done (op);
560 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer 2 id: %s\n", GNUNET_i2s
561 (&peer2.our_id));
562 peer1.op = GNUNET_TESTBED_service_connect (&peer1, peer1.peer, "stream",
563 stream_ca, stream_da, &peer1);
564 setup_state = PEER1_STREAM_CONNECT;
565 break;
566 case PEER1_STREAM_CONNECT:
567 case PEER2_STREAM_CONNECT:
568 GNUNET_assert (NULL == event->details.operation_finished.emsg);
569 break;
570 default:
571 GNUNET_assert (0);
572 }
573 break;
574 default:
575 GNUNET_assert (0);
576 }
577}
578
579
580/**
581 * Signature of a main function for a testcase.
582 *
583 * @param cls closure
584 * @param num_peers number of peers in 'peers'
585 * @param peers handle to peers run in the testbed
586 */
587static void
588test_master (void *cls, unsigned int num_peers,
589 struct GNUNET_TESTBED_Peer **peers)
590{
591 GNUNET_assert (NULL != peers);
592 GNUNET_assert (NULL != peers[0]);
593 GNUNET_assert (NULL != peers[1]);
594 peer1.peer = peers[0];
595 peer2.peer = peers[1];
596 op = GNUNET_TESTBED_overlay_connect (NULL, peer2.peer, peer1.peer);
597 setup_state = INIT;
598 abort_task =
599 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
600 (GNUNET_TIME_UNIT_SECONDS, 40), &do_abort,
601 NULL);
602}
603
604
605/**
606 * Main function
607 */
608int main (int argc, char **argv)
609{
610 uint64_t event_mask;
611
612 result = GNUNET_NO;
613 event_mask = 0;
614 event_mask |= (1LL << GNUNET_TESTBED_ET_CONNECT);
615 event_mask |= (1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED);
616 GNUNET_TESTBED_test_run ("test_stream_2peers", "test_stream_local.conf",
617 NUM_PEERS, event_mask, &controller_event_cb, NULL,
618 &test_master, NULL);
619 if (GNUNET_SYSERR == result)
620 return 1;
621 return 0;
622}