示例#1
0
static int cryptopacket_handle(void *object, IP_Port source, uint8_t *packet, uint32_t length)
{
    DHT *dht = object;

    if (packet[0] == NET_PACKET_CRYPTO) {
        if (length <= crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES + 1 + ENCRYPTION_PADDING ||
                length > MAX_DATA_SIZE + ENCRYPTION_PADDING)
            return 1;

        if (memcmp(packet + 1, dht->c->self_public_key, crypto_box_PUBLICKEYBYTES) == 0) { // Check if request is for us.
            uint8_t public_key[crypto_box_PUBLICKEYBYTES];
            uint8_t data[MAX_DATA_SIZE];
            uint8_t number;
            int len = handle_request(dht->c->self_public_key, dht->c->self_secret_key, public_key, data, &number, packet, length);

            if (len == -1 || len == 0)
                return 1;

            if (!dht->c->cryptopackethandlers[number].function) return 1;

            dht->c->cryptopackethandlers[number].function(dht->c->cryptopackethandlers[number].object, source, public_key, data,
                    len);

        } else { /* If request is not for us, try routing it. */
            int retval = route_packet(dht, packet + 1, packet, length);

            if ((unsigned int)retval == length)
                return 0;
        }
    }

    return 1;
}
示例#2
0
static int friendreq_handlepacket(IP_Port source, uint8_t * packet, uint32_t length)
{
    if (packet[0] == 32) {
        if (length <= crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES + 1 + ENCRYPTION_PADDING ||
            length > MAX_DATA_SIZE + ENCRYPTION_PADDING)
            return 1;
        if (memcmp(packet + 1, self_public_key, crypto_box_PUBLICKEYBYTES) == 0) {// check if request is for us.
            if (handle_friendrequest_isset == 0)
                return 1;

            uint8_t public_key[crypto_box_PUBLICKEYBYTES];
            uint8_t data[MAX_DATA_SIZE];
            int len = handle_request(public_key, data, packet, length);

            if (len == -1)
                return 1;
            if (request_received(public_key))
                return 1;

            addto_receivedlist(public_key);
            (*handle_friendrequest)(public_key, data, len);
        } else { /* if request is not for us, try routing it. */
            if(route_packet(packet + 1, packet, length) == length)
                return 0;
        }
    }
    return 1;
}
示例#3
0
文件: router.c 项目: dburger/archive
/*=============================================================================
Function listen_iface

Purpose:  used as a listening thread for an interface.  When a packet is
          received slip decoding is performed as it is paced in the buffer, the
          packet is then passed to the route_packet routine
          
Parameters:
    *i (IN) - a pointer to the interface to listen on
        
Returns:  nothing
=============================================================================*/
void *listen_iface(void *i) {
  struct interface *iface = (struct interface *)i;

  int sd, addlen, c, totbytes = 0;
  char buf[1];
  char slipBuf[MAX_PACKET];
  struct sockaddr_in sin;
  struct protoent *ptrp;
  /* set up the sockaddr */
  memset((char *)&sin,0,sizeof(sin));
  sin.sin_family = AF_INET;
  sin.sin_addr.s_addr = INADDR_ANY;
  sin.sin_port = htons(iface->lport);

  if (((int)(ptrp = getprotobyname("udp"))) == 0)
    error("getprotobyname");

  if ((sd = socket(AF_INET, SOCK_DGRAM,ptrp->p_proto)) < 0)
    error("socket");

  if (bind(sd,(struct sockaddr *)&sin,sizeof(sin)) < 0)
    error("bind");
  
  while(1) {
    recvfrom(sd,buf,1,0,(struct sockaddr *)&sin,&addlen);
    c = 0xff & buf[0];
    switch (c) {
      case END:
        if (totbytes) {
          route_packet(slipBuf,totbytes); /* handle the packet */
          totbytes = 0; /* reset for next packet */
        }
        break;
      case ESC:
        recvfrom(sd,buf,1,0,(struct sockaddr *)&sin,&addlen);
        c = 0xff & buf[0];
        switch (c) {
          case ESC_END:
            c = END;
            break;
          case ESC_ESC:
            c = ESC;
            break;
        }
        /* falling through here */
      default:
        if (totbytes<MAX_PACKET)
          slipBuf[totbytes++] = c;
    }
  }

}
示例#4
0
static int cryptopacket_handle(IP_Port source, uint8_t * packet, uint32_t length)
{
    if (packet[0] == 32) {
        if (length <= crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES + 1 + ENCRYPTION_PADDING ||
            length > MAX_DATA_SIZE + ENCRYPTION_PADDING)
            return 1;
        if (memcmp(packet + 1, self_public_key, crypto_box_PUBLICKEYBYTES) == 0) {// check if request is for us.
            uint8_t public_key[crypto_box_PUBLICKEYBYTES];
            uint8_t data[MAX_DATA_SIZE];
            uint8_t number;
            int len = handle_request(public_key, data, &number, packet, length);
            if (len == -1 || len == 0)
                return 1;
            if (!cryptopackethandlers[number]) return 1;
            cryptopackethandlers[number](source, public_key, data, len);
            
        } else { /* if request is not for us, try routing it. */
            if(route_packet(packet + 1, packet, length) == length)
                return 0;
        }
    }
    return 1;
}
示例#5
0
void nl_rx_task()
{
	uint8_t len; 				   // to hold the size of the received packet, always = sizeof(NW_Packet) 
	int8_t rssi;  			   	// to hold rssi of received packet
	uint8_t *local_rx_buf;	   // pointer to receive buffer of link layer
	int8_t val;						// status variable to hold the return type of function calls
	int8_t flag;
	
	nrk_time_t start, end, elapsed;		// needed by nl_rx_task()
										// to decide when to send own NGB_LIST
	if(DEBUG_NL >= 1)
	{
		nrk_kprintf(PSTR("NL_RX_TASK PID = "));
		printf("%d\r\n",nrk_get_pid());
	}
	
	// initialise the timer
	nrk_time_get(&start);
	end.secs = start.secs;
	end.nano_secs = start.nano_secs;

	// initialise the link layer	
	val = bmac_init(25);
	if(val == NRK_ERROR)
	{
		nrk_int_disable();
		nrk_led_set(RED_LED);
		while(1)
			nrk_kprintf(PSTR("NL: Error returned by bmac_init()\r\n"));
	}	
		
	// give the link layer a rx buffer 	
	val = bmac_rx_pkt_set_buffer(rx_buf, RF_BUFFER_SIZE);
	if(val == NRK_ERROR)
	{
		nrk_int_disable();
		nrk_led_set(RED_LED);
		while(1)
			nrk_kprintf(PSTR("NL: Error returned by bmac_rx_pkt_set_buffer()\r\n"));
	}
		
	// start processing forever 
	while(1)
	{
		// decide whether it is time to send your own Ngb_List message
		if(CONNECTED_TO_GATEWAY == TRUE)
		{
			nrk_time_get(&end);
			val = nrk_time_sub(&elapsed, end, start);
			nrk_time_compact_nanos(&elapsed);
			if(elapsed.secs >= NGB_LIST_PERIOD)
			{
				ntg_pkt.type = SERIAL_NGB_LIST;
				ntg_pkt.length = SIZE_MSG_NGB_LIST;
				enter_cr(nl_sem, 34);
				pack_Msg_NgbList(ntg_pkt.data, &nl);
				leave_cr(nl_sem, 34);
				pack_NodeToGatewaySerial_Packet_header(to_gw_buf, &ntg_pkt);
				memcpy(to_gw_buf + SIZE_NODETOGATEWAYSERIAL_PACKET_HEADER, ntg_pkt.data, MAX_SERIAL_PAYLOAD);
				if(DEBUG_NL == 2)
				{
					nrk_kprintf(PSTR("Sending own NGB_LIST message to gateway\r\n"));
				}
				sendToSerial(to_gw_buf, SIZE_NODETOGATEWAYSERIAL_PACKET);
				
				// reset the timer
				start.secs = end.secs;
				start.nano_secs = end.nano_secs;
			} // end if
		} // end if
				
		if(DEBUG_NL >= 1)
		{
			nrk_kprintf(PSTR("Waiting for next pkt from link layer\r\n"));
		}
		
		flag = 0;
		// wait for the next packet 		
		while(bmac_rx_pkt_ready() == 0)
		{
			val = bmac_wait_until_rx_pkt();
			if(DEBUG_NL == 2)
			{
				nrk_kprintf(PSTR("NL: bmac_wait_until_rx_packet() returned "));
				printf("%d\n", val);
			}
		}
		
		// Get the packet 
	   	do
	   	{
	   		local_rx_buf = bmac_rx_pkt_get(&len,&rssi);
	   		if(local_rx_buf == NULL)
	   		{
	   			nrk_kprintf(PSTR("NL: NULL returned by bmac_rx_pkt_get()\r\n"));
	   		}
	   		
	   	} while(local_rx_buf == NULL);
	   	
	   	// sanity check for debugging 
	   	if(len != SIZE_NW_PACKET)	// this should not happen 
	   	{
	   		/* 
	   		nrk_int_disable();
	   		nrk_led_set(RED_LED);
	   		while(1)
	   		{
	   			nrk_kprintf(PSTR("NL: Wrong length of packet received: "));
	   			printf("%d\r\n", len);
	   		}
	   		*/
	   		if(DEBUG_NL >= 1)
	   		{
	   			nrk_kprintf(PSTR("NL: nl_rx_task(): Wrong length of packet received: "));
	   			printf("%d\r\n", len);
	   		}
	   		flag = 1;
	   	}
	   	
	   	nrk_led_set(GREEN_LED);
	   	
	   	if(DEBUG_NL == 2)// || flag == 1)
	   	{
				int8_t i; 
				nrk_kprintf(PSTR("NL: Contents of received packet are\r\n"));
				printf("[");
				for(i = 0; i < len; i++)
					printf("%d ", local_rx_buf[i]);
				printf("]\r\n");
		}  	
		if(flag == 1)
		{
			bmac_rx_pkt_release();	// drop the packet and go receive another
			nrk_led_clr(GREEN_LED);
			continue;
		}
			   	
			// unpack the packet header from the received buffer 
			unpack_NW_Packet_header(&pkt_rx, local_rx_buf);
			// copy the packet payload to the data field of the local packet
			memcpy(pkt_rx.data, local_rx_buf + SIZE_NW_PACKET_HEADER, MAX_NETWORK_PAYLOAD);
			// Release the RX buffer quickly so future packets can arrive
			bmac_rx_pkt_release();	
			
			// begin processing this packet
			if(pkt_type(&pkt_rx) == APPLICATION)	// its an application layer packet 
			{
				// case 1: Destination is NODE_ADDR or BCAST_ADDR
				if(pkt_rx.dest == NODE_ADDR || pkt_rx.dest == BCAST_ADDR)
					process_app_pkt(&pkt_rx, rssi);
					
				// case 2: I am enroute to the destination
				else if(pkt_rx.nextHop == NODE_ADDR)
					 {
					 	if(pkt_rx.src == NODE_ADDR)		// routing table corrupted
						{
							nrk_int_disable();
							nrk_led_set(RED_LED);
							while(1)
							{
								nrk_kprintf(PSTR("Routing table corrupted at "));
								printf("%d\r\n", NODE_ADDR);
							} // end while 
						} // end if 
						else
							route_packet(&pkt_rx);
					 } // end if 		
					 // case 3: Routing tables still not made
					 else if(pkt_rx.nextHop == BCAST_ADDR)	
					 			route_packet(&pkt_rx);
					 	  else
					 	  	;		 // drop all other packets								
			} // end if(type == APPLICATION)
			else 
			{
				if(pkt_type(&pkt_rx) == NW_CONTROL)	// its a network control packet 
				{
				  	// case 1: Destination is NODE_ADDR or BCAST_ADDR
				  	if(pkt_rx.dest == NODE_ADDR || pkt_rx.dest == BCAST_ADDR)
				  		process_nw_ctrl_pkt(&pkt_rx, rssi);
				  	
				  	// case 2: I am enroute to a destination
				  	else if(pkt_rx.nextHop == NODE_ADDR)
				  		 {
				  		 	if(pkt_rx.src == NODE_ADDR)		// routing table corrupted
				  		 	{
				  		 		nrk_int_disable();
								nrk_led_set(RED_LED);
								while(1)
								{
									nrk_kprintf(PSTR("Routing table corrupted at "));
									printf("%d\r\n", NODE_ADDR);
								} // end while 
							} // end if
							else
				  		 		route_packet(&pkt_rx);
				  		 } // end if
				  		// case 3: Routing tables still not made 
				  		 else if(pkt_rx.nextHop == BCAST_ADDR)
				  		 		route_packet(&pkt_rx);
				  		 	  else
				  		 		;	// drop all other packets
				  } // end if(type == NW_CONTROL)
				  else	// unknown packet type 
				  {
				  		nrk_kprintf(PSTR("NL: Unknown pkt type received = "));
				  		printf("%d\r\n", pkt_type(&pkt_rx));
				  }
			}
				
			nrk_led_clr(GREEN_LED);			
	 } // end while(1)
	
	return;
}	// end nl_rx_task
示例#6
0
void process_nw_ctrl_pkt(NW_Packet *pkt, int8_t rssi)
{
	int8_t ret;	// to hold the return value of various function calls  
	int8_t i;
	
	if(DEBUG_NL >= 1)
		nrk_kprintf(PSTR("NL: Entered process_nw_ctrl_pkt()\n"));
		
	switch( nw_ctrl_type(pkt -> type) )
	{
		case HELLO:		// HELLO msg
			
			// unpack the Msg_Hello from the packet payload 
			unpack_Msg_Hello(&mh, pkt -> data);
			mh.n.rssi = rssi;
			ret = add_neighbor(mh.n);	
			if(ret == NRK_ERROR)
			{
				record_max_ngb_limit_reached(pkt);	// record this fact
			} 
			if(DEBUG_NL >= 1)
			{
				nrk_kprintf(PSTR("Received HELLO msg from: "));
				printf("%d ", mh.n.addr);
				nrk_kprintf(PSTR("with RSSI = "));
				printf("%d\r\n",mh.n.rssi);
			}
			
			break;

		case NGB_LIST:		// NGB_LIST msg
			// if the node gets it's own NgbList message back, drop it
			if(pkt -> src == NODE_ADDR)	
				break;
						
			// unpack the Msg_NgbList from the packet payload						
			unpack_Msg_NgbList(&mnlist, pkt -> data);
			nlist = mnlist.nl;
			
			if(DEBUG_NL >= 1)
			{
				int8_t i;	// loop index 
				printf("NL: Received NGB_LIST msg from %d with count = %d\n", nlist.my_addr, nlist.count);
				for(i = 0; i < MAX_NGBS; i++)		
				{
					if(nlist.ngbs[i].addr != BCAST_ADDR)	// valid entry
						printf("%u, ", nlist.ngbs[i].addr);
				}
				printf("\r\n");
			}
			
			//multihop(pkt);		// multihop this NGB_LIST message.
			route_packet(pkt); 
								
			if(CONNECTED_TO_GATEWAY == TRUE)	// this node is connected to the gateway 				
			{					
				// construct a packet to be sent to the gateway over the serial connection 
				ntg_pkt.type = SERIAL_NGB_LIST;
				ntg_pkt.length = SIZE_MSG_NGB_LIST;
				// pack the message in the data field of the NodeToGatewaySerial_Packet 
				pack_Msg_NgbList(ntg_pkt.data, &mnlist);
				
				// pack the NodeToGatewaySerial_Packet header into the serial transmit buffer 
				pack_NodeToGatewaySerial_Packet_header(to_gw_buf, &ntg_pkt);
				// append the payload into the serial transmit buffer 
				memcpy(to_gw_buf + SIZE_NODETOGATEWAYSERIAL_PACKET_HEADER, ntg_pkt.data, MAX_SERIAL_PAYLOAD); // CHECK 
				
				//send the packet to gateway
				if(DEBUG_NL >= 1)
				{
					nrk_kprintf(PSTR("Sending packet to gateway\r\n"));
				}
				sendToSerial(to_gw_buf, SIZE_NODETOGATEWAYSERIAL_PACKET);
				//printBuffer(to_gw_buf, SIZE_NODETOGATEWAYSERIAL_PACKET);
			} 
			break;
			
		case ROUTE_CONFIG:
			
			unpack_Msg_RoutingTable(&mrt, pkt -> data);
			enter_cr(nl_sem, 34);
			DEFAULT_GATEWAY = mrt.dg;	// get the value of DEFAULT_GATEWAY in any case
			leave_cr(nl_sem, 34);
			
			if(DEBUG_NL == 0)
			{
				nrk_kprintf(PSTR("Received a ROUTE_CONFIG message\r\n"));
				for(i = 0; i < MAX_NODES; i++)
				{
					printf("%d -> %d [%d, %d]\r\n", mrt.node, mrt.rt[i].dest, mrt.rt[i].nextHop, mrt.rt[i].cost);
				}
			}
			
			if(mrt.node == NODE_ADDR)	// this is my routing table
			{
				/*enter_cr(nl_sem, 34);
				initialise_routing_table();	// invalidate all entries
				for(i = 0; i < MAX_NODES; i++)
				{
					rt[i] = mrt.rt[i];
				}
				leave_cr(nl_sem, 34);
				*/
				set_RoutingTable(&mrt);
			}
			else						// some other node's routing table. Route it
			{
				route_packet(pkt);
			}
				
			break;
			
		default: 
			nrk_kprintf(PSTR("NL: process_nw_ctrl_pkt(): Unsupported network control message received = "));
			printf("%u\n", pkt -> type);
			break;			
			
	} // end switch
	
	return;
}
示例#7
0
/*  up_to_network() IS CALLED FROM THE DATA LINK LAYER (BELOW) TO ACCEPT
 A PACKET FOR THIS NODE, OR TO RE-ROUTE IT TO THE INTENDED DESTINATION.
 */
int up_to_network(char *packet, size_t length, int arrived_on_link) {
	//printf("up to network at hop %d\n", nodeinfo.address);
	NL_PACKET *p = (NL_PACKET *) packet;
	if (p->src == nodeinfo.address) {
		printf("drop a packet at %d, src = %d, des = %d, seqno = %d\n\n",
				nodeinfo.address, p->src, p->dest, p->seqno);
		return 0;
	}
	
	//printf("up to network at %d (from %d to %d)\n", nodeinfo.address, p->src, p->dest);
	++p->hopcount; /* took 1 hop to get here */
	mtu = linkinfo[arrived_on_link].mtu;
	p->trans_time += ((CnetTime) 8000 * 1000 * mtu
			/ linkinfo[arrived_on_link].bandwidth
			+ linkinfo[arrived_on_link].propagationdelay) * 100 / mtu;
	
	/*  IS THIS PACKET IS FOR ME? */
	if (p->dest == nodeinfo.address) {
		switch (p->kind) {
		case NL_DATA:
			if (p->seqno == NL_packetexpected(p->src)) {
				//length = p->length;
				//memcpy(rb[p->src], (char *) p->msg, length);
				//rb[p->src] = rb[p->src] + length;
				//packet_length[p->src] += length;
				RB_save_msg_link(p, arrived_on_link);
				
				if (p->pieceEnd) {
					RB_copy_whole_msg_link(p, arrived_on_link);
					up_to_application(p, arrived_on_link);
					return 0;
				}
			}
			break;

		case NL_ACK:
			if (p->seqno == NL_ackexpected(p->src)) {
				////("ACK come!\n");
				inc_NL_ackexpected(p->src);
				NL_savehopcount(p->src, p->trans_time, arrived_on_link);
				NL_set_has_resent(p->src, 0);
				CHECK(CNET_enable_application(p->src));
			}
			break;
		case NL_ERR_ACK:
			printf("NL_ERR_ACK!\n");
			if (p->seqno == NL_ackexpected(p->src)) {
				if (NL_get_has_resent(p->src) == 0) {
					NL_savehopcount(p->src, p->trans_time, arrived_on_link);
					NL_PACKET * packettoresend = get_last_packet(p->src);
					printf(
							"src = %d, des = %d, seqno = %d, send_length = %d, checksum = %d\n",
							packettoresend->src, packettoresend->dest,
							packettoresend->seqno, packettoresend->length,
							packettoresend->checksum);
					printf("resend it\n");
					int len = PACKET_HEADER_SIZE + packettoresend->length;
					packettoresend->is_resent = 1;
					NL_set_has_resent(p->src, 1);
					//NL_inc_resent_times(p->src); // for debug
					flood((char *) packettoresend, len, 0, 0);

				} else {
					printf(
							"this packet has already been resent, dont resent it again\n");
				}
			} else {
				printf(
						"this packet has already been correct received, dont resent it again\n");
			}
			printf("\n");
			break;
			
		case NL_ERR_ACK_RESENT:
			printf("NL_ERR_ACK_RESENT!\n");
			if (p->seqno == NL_ackexpected(p->src)) {
				NL_savehopcount(p->src, p->trans_time, arrived_on_link);
				NL_PACKET * packettoresend = get_last_packet(p->src);
				printf(
						"resend a resent packet, src = %d, des = %d, seqno = %d, send_length = %d, checksum = %d\n",
						packettoresend->src, packettoresend->dest,
						packettoresend->seqno, packettoresend->length,
						packettoresend->checksum);
				//printf("this packet has been resent %d times before this time\n", NL_get_resent_times(p->src)); //for debug
				//NL_inc_resent_times(p->src); // for debug
				int len = PACKET_HEADER_SIZE + packettoresend->length;
				packettoresend->is_resent = 1;
				flood((char *) packettoresend, len, 0, 0);

			} else {
				printf(
						"this packet has already been correct received, dont resent it again\n");
			}
			printf("\n");
			break;
		default:
			//("it's nothing!====================\n");
			break;
		}
	}
	/* THIS PACKET IS FOR SOMEONE ELSE */
	else {
		if (p->hopcount < MAXHOPS) { /* if not too many hops... */
			//length = p->length;
			//memcpy(rb[p->src], (char *) p->msg, length);
			//rb[p->src] = rb[p->src] + length;
			if(p->kind != NL_DATA){
			  route_packet(p, arrived_on_link);
			} else{
			  RB_save_msg_link(p, arrived_on_link);
			  printf("finish new rb save msg\n");
			  if (p->pieceEnd){

				RB_copy_whole_msg_link(p, arrived_on_link);
				printf("finish copy whole msg\n");
				printf("p->length after copy = %d\n", p->length);
				route_packet(p, arrived_on_link);

			  }
			}
		} else {/* silently drop */;
		
		}
	}
	return 0;
}
示例#8
0
int main(int argc, char **argv)
{

    TYPE_FD_SET actread;
    char buf[1024];
    int addrlen;
    int arg;
    int ch;
    int errflag = 0;
    int fail = 0;
    int flisten;
    int i;
    int n;
    struct connection *p;
    struct sockaddr *addr;

    while ((ch = getopt(argc, argv, "af:")) != EOF)
        switch (ch) {
        case 'a':
            all = 1;
            break;
        case 'f':
            fail = atoi(optarg);
            if (fail < 0 || fail > 100)
                errflag = 1;
            break;
        case '?':
            errflag = 1;
            break;
        }

    if (errflag || optind < argc) {
        fprintf(stderr, "Usage: %s [-a] [-f failures]\n", *argv);
        exit(1);
    }

    for (n = 0; n < FD_SETSIZE; n++)
        close(n);
    chdir("/");
    setsid();
    signal(SIGPIPE, SIG_IGN);

    addr = build_sockaddr("*:4713", &addrlen);
    if (!addr)
        exit(1);
    flisten = socket(addr->sa_family, SOCK_STREAM, 0);
    if (flisten < 0)
        exit(1);
    arg = 1;
    setsockopt(flisten, SOL_SOCKET, SO_REUSEADDR, (char *) &arg, sizeof(arg));
    if (bind(flisten, addr, addrlen))
        exit(1);
    if (listen(flisten, SOMAXCONN))
        exit(1);
    FD_SET(flisten, &chkread);
    if (maxfd < flisten)
        maxfd = flisten;

    for (;;) {
        actread = chkread;
        if (select(maxfd + 1, &actread, 0, 0, 0) <= 0)
            continue;
        if (FD_ISSET(flisten, &actread))
            create_connection(flisten);
        for (p = connections; p; p = p->next)
            if (FD_ISSET(p->fd, &actread)) {
                n = read(p->fd, buf, sizeof(buf));
                if (n <= 0) {
                    close_connection(p);
                    break;
                }
                for (i = 0; i < n; i++)
                    if (((p->buf[p->cnt++] = buf[i]) & 0xff) == FR_END) {
                        if (p->cnt > 1 && (fail == 0 || rand() % 100 >= fail))
                            route_packet(p);
                        p->cnt = 0;
                    }
            }
    }
}