Пример #1
0
/*
 * Queue a packet for reliable transmission.
 */
void
queue_packet_reliable(PACKET *p, int priority) 
{
	assert(p->len < 510);

	THREAD_DATA::net_t *n = get_thread_data()->net;

	if (priority == SP_DEFERRED) {
		n->queues->d_prio->push_back(p);
	} else if (priority == SP_HIGH || priority == SP_NORMAL) {
		uint32_t ack_id;
		PACKET *p2;

		/* packet with space for reliable header */
		p2 = allocate_packet(p->len + 6);

		ack_id = n->rel_o->next_ack_id++;

		/* add reliable header and free old (headerless) packet */
		build_packet(p2->data, "AACZ", 0x00, 0x03, ack_id, p->data, p->len);
		free_packet(p);

		/* store a copy for retransmission until its ack is received */
		RPACKET *rp = allocate_rpacket(p2->len, get_ticks_ms(), ack_id);
		memcpy(rp->data, p2->data, p2->len);
		n->rel_o->queue->push_back(rp);

		/* send p2 */
		queue_packet(p2, priority);
	} else {
		assert(0);
	}
}
Пример #2
0
void
queue_packet_large(PACKET *p, int priority)
{
	// chunk packets need to be sent in succession
	if (priority == SP_DEFERRED) priority = SP_NORMAL;

	// break the packet down into chunks
	int offset = 0;
	while (offset < p->len) {
		// also must fit into a cluster packet
		int chunk_size = MIN(p->len - offset, 240); // min size must be < guard clauses in queue_packet and queue_packet_reliable
		PACKET *q = allocate_packet(chunk_size + 2);
		build_packet(q->data, "AAZ",
			0x00,
			(offset + chunk_size < p->len) ? 0x08 : 0x09,
			&p->data[offset],
			chunk_size
			);

		queue_packet_reliable(q, priority);

		offset += chunk_size;
	}

	free_packet(p);
}
Пример #3
0
void
CreateBootCmds(void)
{
  struct packet_header_T *ph;

  if (db4) printf("***> CreateBootCmds\n");

  last_packet = allocate_packet(last_packet);

  boot_cmds_packet = last_packet;

  last_packet->boot_file = allocate_boot_file(NULL);
  last_packet->boot_file->fileName =  BOOT_CMDS_FILE;
  last_packet->baud_rate =  9600;

  last_packet->size = netBoot ? SIZE_OF_BOOT_CMDS + sizeof(struct packet_header_T)
    : SIZE_OF_BOOT_CMDS;

  last_packet->data = (char *) malloc(last_packet->size);
  last_packet->seq = seq_nr;

  if (netBoot) {
    /* Create packet header. */
    ph = (struct packet_header_T *) last_packet->data;
    memcpy(ph->dest, dst_addr_of_device, 6);
    memcpy(ph->src, eth_addr_local, 6);
    ph->length = htons(last_packet->size);
    ph->snap1 = htonl(SNAP1);
    ph->snap2 = htonl(SNAP2);
    ph->tag = htonl(SERVER_TAG);
    ph->seq = htonl(seq_nr);
    seq_nr++;
    ph->type = htonl(BOOT_CMDS);
    ph->id = htonl(0);
  }

  if (db3) DecodeSvintoBoot(last_packet->data);
  if (db4) printf("<*** CreateBootCmds\n");
}
Пример #4
0
static
void
mainloop(THREAD_DATA *td)
{
	THREAD_DATA::net_t *n = td->net;

	ticks_ms_t acc, ticks, lticks;	/* accumulator, current ticks, last iteration ticks */

	int	pktl;			/* packet length */
	uint8_t pkt[MAX_PACKET];	/* buffer space for a packet */

	if (connect_to_server(td) != 0) {
		free_thread_data(td);
		LogFmt(OP_MOD, "Error performing initial connect");
		return;
	}

	acc = 0;
	ticks = get_ticks_ms();
	lticks = ticks;
	ticks_ms_t last_botman_checkin = ticks;
	ticks_ms_t last_botman_stopcheck = ticks;
	ticks_ms_t last_config_mtime_check = ticks;
	while (td->running >= 0) {
		ticks = get_ticks_ms();
		acc += ticks - lticks;
		lticks = ticks;

		/* check in with the bot manager */
		if (ticks - last_botman_checkin >= BOTMAN_CHECKIN_INTERVAL) {
			botman_bot_checkin(td->botman_handle);
			last_botman_checkin = ticks;
		}
		if (ticks - last_botman_stopcheck >= BOTMAN_STOPCHECK_INTERVAL) {
			if (botman_bot_shouldstop(td->botman_handle)) {
				td->running = -1;
			}
			last_botman_stopcheck = ticks;
		}

		/* flush out tick events to bots */
		if (acc >= STEP_INTERVAL) { 
			libman_expire_timers(td);
			while(acc >= STEP_INTERVAL) {
				/* event_tick */
				libman_export_event(td, EVENT_TICK, NULL);
				acc -= STEP_INTERVAL;
			}
		}

		/* if the bot is disconnected, see if it is time to reconnect */
		if (n->state == NS_DISCONNECTED) {
			if (ticks - n->ticks->disconnected > 60000) {
				free_thread_data(td);
				init_thread_data(td);
				connect_to_server(td);
			} else {
				usleep(50000);	/* 50ms */
				continue;
			}
		}

		/* see if the config file has been modified and if so send a reread event */
		if (ticks - last_config_mtime_check >= CONFIG_MTIME_POLL_INTERVAL) {
			struct stat attr;
			memset(&attr, 0, sizeof(struct stat));
			if (stat(td->config->filename, &attr) == 0) {
				if (td->config->last_modified_time != attr.st_mtime) {
					libman_export_event(td, EVENT_CONFIG_CHANGE, NULL);
					td->config->last_modified_time = attr.st_mtime;
				}
			}
			last_config_mtime_check = ticks;
		}

		/* use up to STEP_INTERVAL ms for the db thread */
		ticks_ms_t ticks_taken = get_ticks_ms() - ticks;
		ticks_ms_t db_ticks = ticks_taken > STEP_INTERVAL ? STEP_INTERVAL : STEP_INTERVAL - ticks_taken;
		db_instance_export_events(db_ticks);

		/* read a packet or wait for a timeout */
		ticks_taken = get_ticks_ms() - ticks;
		ticks_ms_t timeout = ticks_taken > STEP_INTERVAL ? 0 : STEP_INTERVAL - ticks_taken;
		while (poll(n->pfd, 1, (int)timeout) > 0) {
			/* process incoming packet, data is waiting */
			pktl = (int)read(n->fd, pkt, MAX_PACKET);
			if (pktl >= 0) {
				++n->stats->packets_read;
				n->ticks->last_pkt_received = get_ticks_ms();

				if (n->encrypt->use_encryption) {
					if (pkt[0] == 0x00) {
						if (pktl >= 2) {
							decrypt_buffer(td, &pkt[2], pktl-2);
						}
					} else {
						decrypt_buffer(td, &pkt[1], pktl-1);
					}
				}

				if (td->debug->spew_packets) {
					spew_packet(pkt, pktl, DIR_INCOMING);
				}

				process_incoming_packet(td, pkt, pktl);
			}

			ticks_taken = get_ticks_ms() - ticks;
			timeout = timeout > ticks_taken ? timeout - ticks_taken : 0;
		}

		/* update the tick count after potential sleeping in poll() */
		ticks = get_ticks_ms();

		/* network state specfic actions */
		if (n->state == NS_CONNECTING) {
			/* retransmit connection request if it was lost */
			if (ticks - n->ticks->last_connection_request > 15000) {
				pkt_send_client_key(n->encrypt->client_key);
				n->ticks->last_connection_request = ticks;
			}
		} else if (ticks - n->ticks->last_pkt_received > 30*1000) {
			/* disconnect if no packets have been received for 30 seconds */
			Log(OP_MOD, "No data received for 30 seconds, reconnecting...");
			disconnect_from_server(td);
			continue;
		}

		/* transmit player position update if necessary */
		if (n->state == NS_CONNECTED && td->in_arena) {
			if ((ticks - n->ticks->last_pos_update_sent > 100
			    && td->bot_ship != SHIP_SPECTATOR)
			    || (ticks - n->ticks->last_pos_update_sent > 1000
			    && td->bot_ship == SHIP_SPECTATOR)) {
				pkt_send_position_update(td->bot_pos->x, td->bot_pos->y,
				    td->bot_vel->x, td->bot_vel->y);
				n->ticks->last_pos_update_sent = ticks;
			}
		}

		/* send periodic info/einfo */
		if (n->state == NS_CONNECTED) {
			// subtract 10000 to offset this by 10 seconds from *einfo to avoid filling buffers with commands/responses
			if (td->periodic->info && ticks - (td->periodic->last_info - 10000U) >= td->periodic->info) {
				int nhere = player_get_phere(td);
				PLAYER *parray = player_get_parray(td);
				for (int i = 0; i < nhere; ++i) {
					if (parray[i].here && td->enter->send_info) {
						PrivMessage(&parray[i], "*info");
					}
				}

				td->periodic->last_info = ticks;
			}

			if (td->periodic->einfo && ticks - td->periodic->last_einfo >= td->periodic->einfo) {
				int nhere = player_get_phere(td);
				PLAYER *parray = player_get_parray(td);
				for (int i = 0; i < nhere; ++i) {
					if (parray[i].here && td->enter->send_einfo) {
						PrivMessage(&parray[i], "*einfo");
					}
				}

				td->periodic->last_einfo = ticks;
			}
		}

		/* retransmit reliable packets that have not been acked */
		rpacket_list_t *l = n->rel_o->queue;
		rpacket_list_t::iterator iter = l->begin();
		while (iter != l->end()) {
			RPACKET *rp = *iter;
			if (ticks - rp->ticks > RELIABLE_RETRANSMIT_INTERVAL) {
				PACKET *p = allocate_packet(rp->len);
				memcpy(p->data, rp->data, rp->len);

				/* update packets retransmit tick */
				rp->ticks = ticks;

				queue_packet(p, SP_HIGH);
			}
			
			++iter;
		}

		/* free absent players if its time */
		ticks_ms_t flush_check_interval = 60 * 60 * 1000;
		if (ticks - td->arena->ticks->last_player_flush > flush_check_interval) {
			player_free_absent_players(td, flush_check_interval, true);
			td->arena->ticks->last_player_flush = ticks;
		}

		/* write packets generated during loop iteration */
		send_outgoing_packets(td);
	} /* while td->running != 0 */
}
Пример #5
0
void
do_send_file(THREAD_DATA *td)
{
	THREAD_DATA::net_t::send_file_data_t *sfd = td->net->send_file_data;
	char *filename = sfd->cur_filename;
	const char *initiator = (strlen(sfd->cur_initiator) > 0) ? sfd->cur_initiator : NULL;

	char full_filename[64];

	snprintf(full_filename, 64, "files/%s", filename);

	initiator = initiator ? initiator : "";

	FILE *f = fopen(full_filename, "rb");
	if (f == NULL) {
		LogFmt(OP_SMOD, "Couldn't open file for sending: %s", filename);
		if (initiator) {
			RmtMessageFmt(initiator, "Couldn't open file for sending: %s", filename);
		}
		sfd->in_use = 0;
		return;
	}

	struct stat s;
	memset(&s, 0, sizeof(s));
	fstat(fileno(f), &s);
	int bufl = s.st_size + 17;
	uint8_t *buf = (uint8_t*)xmalloc(bufl);
	if (fread(&buf[17], bufl - 17, 1, f) != 1) {
		LogFmt(OP_SMOD, "Couldn't read file for sending: %s", filename);
		if (initiator) {
			RmtMessageFmt(initiator, "Couldn't read file for sending: %s", filename);
		}
		fclose(f);
		free(buf);
		sfd->in_use = 0;
		return;
	}

	/* add file transfer header */
	buf[0] = 0x16;
	strlcpy((char*)&buf[1], filename, 16);

	int bytes_left = bufl;

	/* send initial stream start */
	while (bytes_left > 0) {
		int nout = MIN(bytes_left, 220); // must fit into a cluster header
		PACKET *p = allocate_packet(6 + nout);
		build_packet(p->data, "AACZ",
		    0x00,
		    0x0A,
		    bufl,
		    &buf[bufl - bytes_left], nout);
		bytes_left -= nout;

		queue_packet_reliable(p, SP_DEFERRED);
	}

	free(buf);
}
Пример #6
0
struct packet_buf*
CreateNewBootPacket(void)
{
  static char buf[DATA_SIZE];
  struct packet_header_T *ph;
  int packet_size;
  int header_size;
  int i;
  udword sum;
  int size = 0;
  int padding = 0;

  static struct boot_files_T *bf = NULL;

  if (db3) printf("> CreateNewBootPacket\n");

  bf = bf ? bf : first_boot_file;

  while (bf) {
    if (!bf->fd) {
      if (strcmp(bf->fileName, "-") == 0) {
        bf->fd = stdin;
      }
      else {
        bf->fd = fopen(bf->fileName, "r");
      }

      if (bf->fd == NULL) {
        printf("Cannot open boot file %s. Exiting\n", bf->fileName);
        exit(EXIT_FAILURE);
      }
      if (db3) printf("Opening boot file %s\n", bf->fileName);
    }

    if (!padding) {
      size = fread(buf, 1, DATA_SIZE, bf->fd);
      if (size == 0) {
        if (db3) printf("Nothing more to read. Read: %d/%d\n",
                        bf->size_sent, bf->size);
        padding = 1;
      }
    }

    if (padding) {
      if (bf->size_sent < bf->size) {
        if (db3) printf("padding...\n");
        size = (bf->size - bf->size_sent > DATA_SIZE) ?
          DATA_SIZE : bf->size - bf->size_sent;
        memset(buf, 0, size);
      }
      else {
        if (db3) printf("All written\n");
        padding = 0;
        size = 0;
      }
    }

    if (size != 0) {
      if (db3) printf("size: %d %d/%d\n", size, bf->size_sent, bf->size);
      bf->size_sent += size;
      last_packet = allocate_packet(last_packet);

      /* Calculate checksum. */
      sum = 0;
      for (i = 0; i != size; i++) {
        sum += ((byte*)buf)[i];
      }
      if (db2) printf("Checksum 0x%x, bytes %d\n", sum, i);

      /* Figure out size of packet. */
      if (netBoot) {
        header_size = seq_nr == 0 ?
          SIZE_OF_FIRST_HEADER : sizeof(struct packet_header_T);

        packet_size = ((size) < DATA_SIZE ? size : DATA_SIZE) + header_size;
      }
      else {
        header_size = 0;
        packet_size = size;
      }

      if (packet_size < 60) { /* CRC adds 4 bytes to 64 */
        printf(
          "Last packet from file '%s', is smaller than 64 bytes. \n"
          "This is not allowed in the Ethernet standard. Will pad with %d "
          "bytes.\n", bf->fileName, 60-packet_size);

        *(bf->size_p) += 60-packet_size;
        packet_size = 60;
      }

      last_packet->size = packet_size;
      last_packet->data = (char*)malloc(packet_size);
      last_packet->boot_file = bf;
      last_packet->baud_rate = set_baudrate;

      /*      printf("size %8.8x\n", last_packet->size);*/
      /*      printf("data %8.8x\n",last_packet->data);*/

      if (netBoot) {
        /* Initialize ethernet header. */
        ph = (struct packet_header_T*) last_packet->data;
        memcpy(ph->dest, dst_addr_of_device, 6);
        memcpy(ph->src,  eth_addr_local,     6);
        /*      printf("packet_size %d\n", packet_size);*/
        ph->length = htons(packet_size);
        ph->snap1  = htonl(SNAP1);
        ph->snap2  = htonl(SNAP2);
        ph->tag    = htonl(SERVER_TAG);
        ph->seq    = htonl(seq_nr);
        last_packet->seq = seq_nr;
        if (seq_nr != 0) {
          ph->type = htonl(BOOT_PACKET);
          ph->id   = htonl(0); /* id doesn't matter, we send to a unicast address */
        }
      }

      /* Copy data in place. */
      memcpy(&last_packet->data[header_size], buf, packet_size - header_size);
      if (db2) DecodeSvintoBoot(last_packet->data);
      /*      PrintPacket(last_packet->data, last_packet->size, HEX);*/
      seq_nr++;

      if (db3) printf("< CreateNewBootPacket\n");
      return(last_packet);
    }
    else {                   /* Nothing read from fd. */
      fclose(bf->fd);
      bf = bf->next;
    }
  }

  if (db3) printf("< CreateNewBootPacket\n");
  return(NULL);
}
Пример #7
0
void
CreateBootLoader(void)
{
  struct stat st;
  char *buf = NULL;
  //  int size_pos = 0x18;
  //  int addr_pos = 0x28;
  struct packet_header_T *ph;
  int packet_size;
  int header_size;
  int buf_cnt = 0;
  int i;
  udword sum = 0;

  if (create_boot_loader) {
    int image_nbr = 0;
    int found = 0;
    const struct boot_image_info_type *info;

    if (db4) printf("> CreateBootLoader\n");

    info = &boot_image_info[image_nbr];

    /* Use internal boot loader? */
    while (!found && info->name != NULL) {
      if (strcmp(boot_loader_file, info->name) == 0) {
        st.st_size = info->len;
        buf = (char*) malloc(st.st_size);
        memcpy(buf, info->ptr, st.st_size); /* unnecessary? */
        found = TRUE;
        printf("Using internal boot loader: %s - %s.\n",
               info->name, info->info);
      }
      else {
        image_nbr++;
        info = &boot_image_info[image_nbr];
      }
    }

    /* No internal? Load it from file instead. */
    if (!found) {
      FILE *fd;

      /* We didn't find an internal match, load the boot file from disk. */
      if ((fd = Fopen(boot_loader_file, "r")) == NULL) {
        printf("Cannot open bootloader '%s'. %s.\n",
               boot_loader_file, strerror(errno));
        exit(EXIT_FAILURE);
      }

      if (fstat(fileno(fd), &st) == -1) {
        printf("Cannot get filestatus of bootloader '%s'. %s.\n",
               boot_loader_file, strerror(errno));
        exit(EXIT_FAILURE);
      }

      buf = (char*) malloc(st.st_size);
      //      printf("CreateBootLoader: buf = (char*) malloc(st.st_size); 2\n");
      if (read(fileno(fd), buf, st.st_size) != st.st_size) {
        printf("Read fewer bytes than there should be in %s.\n",
               boot_loader_file);
        exit(EXIT_FAILURE);
      }

      fclose(fd);
    }

    /* Alright, got loader in buf[] and size in st. */
    if (netBoot) {
      /* The etrax code for all boot methods are linked to adress
         380000f0 but since network boot starts execution at 380000f4
         we have two nops in the beginning of the code which we do not
         transmit to etrax in the network case. The link adress
         doesn't change though. */
      buf += 4;
      st.st_size -= 4;
      packet_size = DATA_SIZE;
    }
    else {
      packet_size = st.st_size;
    }

    /* Hack binary, insert size and address. */

    /* Giovanni Varasano (24/06/2005) : bug
     * It is not a good habit to make code endian dependent on the host
     * processor where cross compilation happens. Intel is little endian and
     * PowerPC is big endian, but the target (ETRAX) is always little endian.
     * The use of swap_endian() solves the problem.
     */

#define SIZE_PATTERN 0x12345678
#define ADDR_PATTERN 0x87654321
#define SIZE_POS (netBoot ? 0x0c : 0x10)
#define ADDR_POS (netBoot ? 0x10 : 0x14)

    if (swap_endian(*(udword*)&buf[SIZE_POS]) != SIZE_PATTERN) {
      printf("Bootloader corrupt. Should contain ret/nop (0x%8.8x) at 0x%x, but contains %x\n",
             SIZE_PATTERN, SIZE_POS, *(udword*)&buf[SIZE_POS]);
      exit(EXIT_FAILURE);
    }

    /* How much data to load except data in first packet. */

    if (netBoot) {
      *(udword*)(&buf[SIZE_POS]) = swap_endian(st.st_size - DATA_SIZE);
    }
    else {
      *(udword*)(&buf[SIZE_POS]) = swap_endian(st.st_size - 784);
    }

    if (db3) printf("Inserting boot size 0x%x at 0x%x.\n",
                    (unsigned int) *(udword*)(&buf[SIZE_POS]),
                    (unsigned int)&buf[SIZE_POS]);

    if (swap_endian(*(udword*)&buf[ADDR_POS]) != ADDR_PATTERN) {
      printf("Bootloader corrupt. Should contain ret/nop (0x%8.8x) at 0x%x, but contains %x\n",
             ADDR_PATTERN, ADDR_POS, *(udword*)&buf[ADDR_POS]);
      exit(EXIT_FAILURE);
    }

    if (netBoot) {
      *(udword*)(&buf[ADDR_POS]) = swap_endian(BOOT_ADDRESS + DATA_SIZE);
    }
    else {
      *(udword*)(&buf[ADDR_POS]) = swap_endian(BOOT_ADDRESS-4 + 784);
    }

    if (db3) printf("Inserting boot address 0x%x at 0x%x.\n",
                    (unsigned int)*(udword*)(&buf[ADDR_POS]),
                    (unsigned int)&buf[ADDR_POS]);


    for (i = 0; i != st.st_size; i++) {
      sum += ((byte*)buf)[i];
    }
    if (db1) printf("Checksum 0x%x, bytes %d\n", sum, i);

    if (db4) {
      int i;

      for(i=0; i<st.st_size; i+=8) {
        int j;

        printf("0x%8.8x[%4.4x]: ", BOOT_ADDRESS+i, i);
        for(j=0; i+j<st.st_size && j<8; j++) {
          printf("%2.2x ", (unsigned char) buf[i+j]);
        }
        printf("\n");
      }
    }
    /* Now create list of packets. */
    while (buf_cnt <= st.st_size) {

      header_size = seq_nr == 0 ?
        SIZE_OF_FIRST_HEADER : sizeof(struct packet_header_T);

      if (netBoot) {
        packet_size = ((st.st_size - buf_cnt) < DATA_SIZE ?
                       st.st_size - buf_cnt : DATA_SIZE) + header_size;
      }
      else {
        packet_size = st.st_size;
        header_size = 0;
      }

      if (db4) printf("seq_nr %d, header_size %d, packet_size %d\n",
                      seq_nr, header_size, packet_size);

      last_packet = allocate_packet(last_packet);

      first_packet = first_packet ? first_packet : last_packet;

      last_packet->size = packet_size;
      last_packet->data = (char*)malloc(packet_size);
      last_packet->seq = seq_nr;
      last_packet->baud_rate = 9600;

      last_packet->boot_file = allocate_boot_file(NULL);
      last_packet->boot_file->fileName = boot_loader_file;

      //      printf("last_packet->size %8.8x\n", last_packet->size);
      //      printf("last_packet->data %8.8x\n",last_packet->data);

      if (netBoot) {
        ph = (struct packet_header_T*) last_packet->data;
        memcpy(ph->dest, dst_addr_of_device, 6);
        memcpy(ph->src,  eth_addr_local,     6);
        ph->length = htons(packet_size);
        ph->snap1  = htonl(SNAP1);
        ph->snap2  = htonl(SNAP2);
        ph->tag    = htonl(SERVER_TAG);
        ph->seq    = htonl(seq_nr);
        if (seq_nr != 0) {
          ph->type   = htonl(BOOT_PACKET);
          ph->id     = htonl(0);
        }
      }

      memcpy(&last_packet->data[header_size], &buf[buf_cnt],
             packet_size - header_size);
      if (db3) DecodeSvintoBoot(last_packet->data);

      if (netBoot) {
        buf_cnt += DATA_SIZE;
      }
      else {
        buf_cnt += packet_size +1;
      }

      seq_nr++;
    }
  }

  if (db4) printf("< CreateBootLoader\n");
}