/**************************************************************************** Send all waiting data. Return TRUE on success. ****************************************************************************/ static bool conn_compression_flush(struct connection *pconn) { int compression_level = get_compression_level(); uLongf compressed_size = 12 + 1.001 * pconn->compression.queue.size; int error; Bytef compressed[compressed_size]; error = compress2(compressed, &compressed_size, pconn->compression.queue.p, pconn->compression.queue.size, compression_level); fc_assert_ret_val(error == Z_OK, FALSE); if (compressed_size + 2 < pconn->compression.queue.size) { struct data_out dout; log_compress("COMPRESS: compressed %lu bytes to %ld (level %d)", (unsigned long) pconn->compression.queue.size, compressed_size, compression_level); stat_size_uncompressed += pconn->compression.queue.size; stat_size_compressed += compressed_size; if (compressed_size <= JUMBO_BORDER) { unsigned char header[2]; log_compress("COMPRESS: sending %ld as normal", compressed_size); dio_output_init(&dout, header, sizeof(header)); dio_put_uint16(&dout, 2 + compressed_size + COMPRESSION_BORDER); connection_send_data(pconn, header, sizeof(header)); connection_send_data(pconn, compressed, compressed_size); } else { unsigned char header[6]; log_compress("COMPRESS: sending %ld as jumbo", compressed_size); dio_output_init(&dout, header, sizeof(header)); dio_put_uint16(&dout, JUMBO_SIZE); dio_put_uint32(&dout, 6 + compressed_size); connection_send_data(pconn, header, sizeof(header)); connection_send_data(pconn, compressed, compressed_size); } } else { log_compress("COMPRESS: would enlarging %lu bytes to %ld; " "sending uncompressed", (unsigned long) pconn->compression.queue.size, compressed_size); connection_send_data(pconn, pconn->compression.queue.p, pconn->compression.queue.size); stat_size_no_compression += pconn->compression.queue.size; } return pconn->used; }
static int send_request(MHANDLE con, MBTCPHDR *mb) { static unsigned short tid = 1; static unsigned short count = 1; unsigned char data[8]; unsigned char mbtcp_buf[260]; unsigned short addr, d; int len; mb->trans_identifier = tid; if (tid == 65535) tid = 1; else tid++; /* compose request PDU */ data[0] = 10; /* slave ID */ data[1] = 0x03; /* function code */ addr = 100; d = BSWAP16(addr); memcpy(&data[2], &d, 2); d = BSWAP16(count); memcpy(&data[4], &d, 2); if (count == 10) count = 1; else count++; len = mbtcp_packet_format(mb, data, 6, mbtcp_buf); connection_send_data(con, (char *)mbtcp_buf, len); return 0; }
/* this user-defined function is called after the user program receives a data packet. It reverses the content of the packet and then send the result back to the client */ static int udp_server_dispatch_client (MHANDLE conp, void *private_data, DATAPKT *dpkt) { char buffer[1024]; (void) private_data; dpkt->packet_consumed = dpkt->packet_size; memcpy(buffer, dpkt->packet_data, dpkt->packet_size); buffer[dpkt->packet_size] = 0; printf("RECV: %s\n", buffer); /* reverse the received data */ reverse_bytes(buffer, dpkt->packet_size); buffer[dpkt->packet_size] = 0; printf("SEND: %s\n", buffer); /* send data back to the client */ connection_send_data(conp, buffer, dpkt->packet_size); return 0; }
/* This user-defined function is called after the user program receives a data packet. It processes the content of the packet and then send the simulated result back to the master */ static int mbasc_slave_dispatch (MHANDLE conp, void *private_data, DATAPKT *dpkt) { unsigned char *buf = (unsigned char *) private_data; unsigned int plen = dpkt->packet_size; int consumed; unsigned char mbasc_buf[256]; int len; unsigned short slave_id; unsigned short Modbus_id = 10; len = mbasc_packet_digest(dpkt->packet_data, &plen, mbasc_buf); if (len <= 0) { /* MODBUS ADU packet not complete */ slave_id = mbasc_buf[0]; if (slave_id == Modbus_id) /* wait */ consumed = 0; else /* discard */ consumed = plen; } else { consumed = plen; slave_id = mbasc_buf[0]; if (slave_id == Modbus_id) { /* process MODBUS ASCII request packet and get response PDU */ len = mbasc_parser(mbasc_buf, len, buf, sizeof(buf)); /* format response ADU */ len = mbasc_packet_format(buf, len, mbasc_buf); /* send MODBUS ASCII response */ if (len > 0) connection_send_data(conp, mbasc_buf, len); } } dpkt->packet_consumed = consumed; return consumed; }
/************************************************************************** It returns the request id of the outgoing packet (or 0 if is_server()). **************************************************************************/ int send_packet_data(struct connection *pc, unsigned char *data, int len) { /* default for the server */ int result = 0; log_packet("sending packet type=%s(%d) len=%d to %s", packet_name(data[2]), data[2], len, is_server() ? pc->username : "******"); if (!is_server()) { pc->client.last_request_id_used = get_next_request_id(pc->client.last_request_id_used); result = pc->client.last_request_id_used; log_packet("sending request %d", result); } if (pc->outgoing_packet_notify) { pc->outgoing_packet_notify(pc, data[2], len, result); } #ifdef USE_COMPRESSION if (TRUE) { int packet_type; int size = len; packet_type = data[2]; if (conn_compression_frozen(pc)) { size_t old_size = pc->compression.queue.size; byte_vector_reserve(&pc->compression.queue, old_size + len); memcpy(pc->compression.queue.p + old_size, data, len); log_compress2("COMPRESS: putting %s into the queue", packet_name(packet_type)); if (MAX_LEN_BUFFER < byte_vector_size(&pc->compression.queue)) { log_compress2("COMPRESS: huge queue, forcing to flush (%lu/%lu)", (long unsigned) byte_vector_size(&pc->compression.queue), (long unsigned) MAX_LEN_BUFFER); if (!conn_compression_flush(pc)) { return -1; } byte_vector_reserve(&pc->compression.queue, 0); } } else { stat_size_alone += size; log_compress("COMPRESS: sending %s alone (%d bytes total)", packet_name(packet_type), stat_size_alone); connection_send_data(pc, data, len); } log_compress2("COMPRESS: STATS: alone=%d compression-expand=%d " "compression (before/after) = %d/%d", stat_size_alone, stat_size_no_compression, stat_size_uncompressed, stat_size_compressed); } #else connection_send_data(pc, data, len); #endif #if PACKET_SIZE_STATISTICS { static struct { int counter; int size; } packets_stats[PACKET_LAST]; static int packet_counter = 0; static int last_start_turn_seen = -1; static bool start_turn_seen = FALSE; int packet_type = data[2]; int size = len; bool print = FALSE; bool clear = FALSE; if (!packet_counter) { int i; for (i = 0; i < PACKET_LAST; i++) { packets_stats[i].counter = 0; packets_stats[i].size = 0; } } packets_stats[packet_type].counter++; packets_stats[packet_type].size += size; packet_counter++; if (packet_type == PACKET_START_TURN && last_start_turn_seen != game.turn) { start_turn_seen=TRUE; last_start_turn_seen = game.turn; } if ((packet_type == PACKET_PROCESSING_FINISHED || packet_type == PACKET_THAW_HINT) && start_turn_seen) { start_turn_seen = FALSE; print = TRUE; clear = TRUE; } if(print) { int i, sum = 0; #define log_ll log_debug #if PACKET_SIZE_STATISTICS == 2 delta_stats_report(); #endif log_ll("Transmitted packets:"); log_ll("%8s %8s %8s %s", "Packets", "Bytes", "Byt/Pac", "Name"); for (i = 0; i < PACKET_LAST; i++) { if (packets_stats[i].counter == 0) { continue; } sum += packets_stats[i].size; log_ll("%8d %8d %8d %s(%i)", packets_stats[i].counter, packets_stats[i].size, packets_stats[i].size / packets_stats[i].counter, packet_name(i),i); } log_test("turn=%d; transmitted %d bytes in %d packets;average size " "per packet %d bytes", game.turn, sum, packet_counter, sum / packet_counter); log_test("turn=%d; transmitted %d bytes", game.turn, pc->statistics.bytes_send); } if (clear) { int i; for (i = 0; i < PACKET_LAST; i++) { packets_stats[i].counter = 0; packets_stats[i].size = 0; } packet_counter = 0; pc->statistics.bytes_send = 0; delta_stats_reset(); } } #undef log_ll #endif /* PACKET_SIZE_STATISTICS */ return result; }
/************************************************************************** It returns the request id of the outgoing packet (or 0 if is_server()). **************************************************************************/ int send_packet_data(struct connection *pc, unsigned char *data, int len, enum packet_type packet_type) { /* default for the server */ int result = 0; log_packet("sending packet type=%s(%d) len=%d to %s", packet_name(packet_type), packet_type, len, is_server() ? pc->username : "******"); if (!is_server()) { pc->client.last_request_id_used = get_next_request_id(pc->client.last_request_id_used); result = pc->client.last_request_id_used; log_packet("sending request %d", result); } if (pc->outgoing_packet_notify) { pc->outgoing_packet_notify(pc, packet_type, len, result); } #ifdef USE_COMPRESSION if (TRUE) { int size = len; if (conn_compression_frozen(pc)) { size_t old_size; /* Keep this a decent amount less than MAX_LEN_BUFFER to avoid the * (remote) possibility of trying to dump MAX_LEN_BUFFER to the * network in one go */ #define MAX_LEN_COMPRESS_QUEUE (MAX_LEN_BUFFER/2) FC_STATIC_ASSERT(MAX_LEN_COMPRESS_QUEUE < MAX_LEN_BUFFER, compress_queue_maxlen_too_big); /* If this packet would cause us to overfill the queue, flush * everything that's in there already before queuing this one */ if (MAX_LEN_COMPRESS_QUEUE < byte_vector_size(&pc->compression.queue) + len) { log_compress2("COMPRESS: huge queue, forcing to flush (%lu/%lu)", (long unsigned) byte_vector_size(&pc->compression.queue), (long unsigned) MAX_LEN_COMPRESS_QUEUE); if (!conn_compression_flush(pc)) { return -1; } byte_vector_reserve(&pc->compression.queue, 0); } old_size = byte_vector_size(&pc->compression.queue); byte_vector_reserve(&pc->compression.queue, old_size + len); memcpy(pc->compression.queue.p + old_size, data, len); log_compress2("COMPRESS: putting %s into the queue", packet_name(packet_type)); } else { stat_size_alone += size; log_compress("COMPRESS: sending %s alone (%d bytes total)", packet_name(packet_type), stat_size_alone); connection_send_data(pc, data, len); } log_compress2("COMPRESS: STATS: alone=%d compression-expand=%d " "compression (before/after) = %d/%d", stat_size_alone, stat_size_no_compression, stat_size_uncompressed, stat_size_compressed); } #else /* USE_COMPRESSION */ connection_send_data(pc, data, len); #endif /* USE_COMPRESSION */ #if PACKET_SIZE_STATISTICS { static struct { int counter; int size; } packets_stats[PACKET_LAST]; static int packet_counter = 0; static int last_start_turn_seen = -1; static bool start_turn_seen = FALSE; int size = len; bool print = FALSE; bool clear = FALSE; if (!packet_counter) { int i; for (i = 0; i < PACKET_LAST; i++) { packets_stats[i].counter = 0; packets_stats[i].size = 0; } } packets_stats[packet_type].counter++; packets_stats[packet_type].size += size; packet_counter++; if (packet_type == PACKET_START_TURN && last_start_turn_seen != game.turn) { start_turn_seen=TRUE; last_start_turn_seen = game.turn; } if ((packet_type == PACKET_PROCESSING_FINISHED || packet_type == PACKET_THAW_HINT) && start_turn_seen) { start_turn_seen = FALSE; print = TRUE; clear = TRUE; } if(print) { int i, sum = 0; #define log_ll log_debug #if PACKET_SIZE_STATISTICS == 2 delta_stats_report(); #endif log_ll("Transmitted packets:"); log_ll("%8s %8s %8s %s", "Packets", "Bytes", "Byt/Pac", "Name"); for (i = 0; i < PACKET_LAST; i++) { if (packets_stats[i].counter == 0) { continue; } sum += packets_stats[i].size; log_ll("%8d %8d %8d %s(%i)", packets_stats[i].counter, packets_stats[i].size, packets_stats[i].size / packets_stats[i].counter, packet_name(i),i); } log_test("turn=%d; transmitted %d bytes in %d packets;average size " "per packet %d bytes", game.turn, sum, packet_counter, sum / packet_counter); log_test("turn=%d; transmitted %d bytes", game.turn, pc->statistics.bytes_send); } if (clear) { int i; for (i = 0; i < PACKET_LAST; i++) { packets_stats[i].counter = 0; packets_stats[i].size = 0; } packet_counter = 0; pc->statistics.bytes_send = 0; delta_stats_reset(); } } #undef log_ll #endif /* PACKET_SIZE_STATISTICS */ return result; }
/**************************************************************************** Send all waiting data. Return TRUE on success. ****************************************************************************/ static bool conn_compression_flush(struct connection *pconn) { int compression_level = get_compression_level(); uLongf compressed_size = 12 + 1.001 * pconn->compression.queue.size; int error; Bytef compressed[compressed_size]; bool jumbo; unsigned long compressed_packet_len; error = compress2(compressed, &compressed_size, pconn->compression.queue.p, pconn->compression.queue.size, compression_level); fc_assert_ret_val(error == Z_OK, FALSE); /* Compression signalling currently assumes a 2-byte packet length; if that * changes, the protocol should probably be changed */ fc_assert_ret_val(data_type_size(pconn->packet_header.length) == 2, FALSE); /* Include normal length field in decision */ jumbo = (compressed_size+2 >= JUMBO_BORDER); compressed_packet_len = compressed_size + (jumbo ? 6 : 2); if (compressed_packet_len < pconn->compression.queue.size) { struct data_out dout; log_compress("COMPRESS: compressed %lu bytes to %ld (level %d)", (unsigned long) pconn->compression.queue.size, compressed_size, compression_level); stat_size_uncompressed += pconn->compression.queue.size; stat_size_compressed += compressed_size; if (!jumbo) { unsigned char header[2]; FC_STATIC_ASSERT(COMPRESSION_BORDER > MAX_LEN_PACKET, uncompressed_compressed_packet_len_overlap); log_compress("COMPRESS: sending %ld as normal", compressed_size); dio_output_init(&dout, header, sizeof(header)); dio_put_uint16(&dout, 2 + compressed_size + COMPRESSION_BORDER); connection_send_data(pconn, header, sizeof(header)); connection_send_data(pconn, compressed, compressed_size); } else { unsigned char header[6]; FC_STATIC_ASSERT(JUMBO_SIZE >= JUMBO_BORDER+COMPRESSION_BORDER, compressed_normal_jumbo_packet_len_overlap); log_compress("COMPRESS: sending %ld as jumbo", compressed_size); dio_output_init(&dout, header, sizeof(header)); dio_put_uint16(&dout, JUMBO_SIZE); dio_put_uint32(&dout, 6 + compressed_size); connection_send_data(pconn, header, sizeof(header)); connection_send_data(pconn, compressed, compressed_size); } } else { log_compress("COMPRESS: would enlarge %lu bytes to %ld; " "sending uncompressed", (unsigned long) pconn->compression.queue.size, compressed_packet_len); connection_send_data(pconn, pconn->compression.queue.p, pconn->compression.queue.size); stat_size_no_compression += pconn->compression.queue.size; } return pconn->used; }