transceiver.cpp

00001
00002 /***************************************************************************
00003  *  transceiver.h - World Info Transceiver
00004  *
00005  *  Created: Sun Jan 21 14:15:32 2007
00006  *  Copyright  2006-2007  Tim Niemueller [www.niemueller.de]
00007  *
00008  ****************************************************************************/
00009
00010 /*  This program is free software; you can redistribute it and/or modify
00011  *  it under the terms of the GNU General Public License as published by
00012  *  the Free Software Foundation; either version 2 of the License, or
00013  *  (at your option) any later version. A runtime exception applies to
00014  *  this software (see LICENSE.GPL_WRE file mentioned below for details).
00015  *
00016  *  This program is distributed in the hope that it will be useful,
00017  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  *  GNU Library General Public License for more details.
00020  *
00021  *  Read the full text in the LICENSE.GPL_WRE file in the doc directory.
00022  */
00023
00024 #include <core/exceptions/system.h>
00025 #include <core/exceptions/software.h>
00026
00027 #include <netcomm/worldinfo/transceiver.h>
00028 #include <netcomm/worldinfo/messages.h>
00029 #include <netcomm/worldinfo/encrypt.h>
00030 #include <netcomm/worldinfo/decrypt.h>
00031
00032 #include <netcomm/socket/datagram_multicast.h>
00033 #include <netcomm/utils/resolver.h>
00034
00035 #include <utils/logging/liblogger.h>
00036
00037 #include <netinet/in.h>
00038 #include <cstdlib>
00039 #include <cstring>
00040
00041 namespace fawkes {
00042 
00043 /** @class WorldInfoException transceiver.h <netcomm/worldinfo/transceiver.h>
00044  * Thrown on critical errors in world info handling.
00045  * @ingroup NetComm
00046  */
00047 
00048 /** Constructor.
00049  * @param msg message
00050  */
00051 WorldInfoException::WorldInfoException(const char *msg)
00052   : Exception(msg)
00053 {
00054 }
00055
00056 
00057 /** @class WorldInfoTransceiver transceiver.h <netcomm/worldinfo/transceiver.h>
00058  * Class to send and receive world information.
00059  * An important point in a domain of cooperating soccer robots is transmitting
00060  * and receiving a robot's belief of its surrounding. The world info
00061  * transceiver does exactly that. It allows for sending information about the
00062  * robot's pose and velocity and its perception of the ball and other robots
00063  * on the field.
00064  *
00065  * The unit for distances and positions is meter (m), speed is given in
00066  * meter per second (m/s), angles are given in radiant (rad). Angles can be in
00067  * the range 0 to 2 * PI or -PI to PI. Since they can be converted easily
00068  * between these ranges without further information users of such information
00069  * shall be able to process both.
00070  *
00071  * Coordinates are given in a right-handed coordinate system with the origin in
00072  * center of the field, X pointing towards the opponent goal, Y to the right
00073  * and Z downwards.
00074  *
00075  * Information is transmitted with a simple protocol via UDP Multicast packets.
00076  *
00077  * A call to send() will reset all information, thus all opponents are removed
00078  * from the list to be sent, positions of robot and ball are marked invalid.
00079  * You have to call the appropriate set methods before the information is sent.
00080  * You can thus call send() at any time but only changed information
00081  * (information set since last send() call) is transmitted over the network.
00082  *
00083  * @ingroup NetComm
00084  * @author Tim Niemueller
00085  */
00086
00087 
00088 /** Constructor.
00089  * @param addr multicast address to send information to and receive from
00090  * @param port UDP port to send information to and receive from
00091  * @param key encryption key
00092  * @param iv encryption initialisation vector
00093  * @param resolver An initialized network resolver, is NULL is supplied
00094  * an internal resolver will be created without mDNS support.
00095  * @exception OutOfMemoryException thrown if internal buffers cannot be created
00096  */
00097 WorldInfoTransceiver::WorldInfoTransceiver(const char *addr, unsigned short port,
00098                                            const char *key, const char *iv,
00099                                            NetworkNameResolver *resolver) :
00100   pose_changed( false ),
00101   vel_changed( false ),
00102   rel_ball_changed( false ),
00103   rel_ball_vel_changed( false ),
00104   glob_ball_changed( false ),
00105   glob_ball_vel_changed( false ),
00106   gamestate_changed( false )
00107 {
00108   try {
00109     s = new MulticastDatagramSocket(addr, port);
00110     s->bind();
00111   } catch (SocketException &e) {
00112     e.append("WorldInfoTransceiver cannot instantiate socket for %s:%u", addr, port);
00113     throw;
00114   }
00115
00116   in_buffer = malloc(WORLDINFO_MTU);
00117   out_buffer = malloc(WORLDINFO_MTU);
00118   if (! in_buffer || ! out_buffer) {
00119     throw OutOfMemoryException();
00120   }
00121
00122   fatmsg_enabled = false;
00123   fatmsg_bufsize = 0;
00124   fatmsg_buf = NULL;
00125   fatmsg_header = NULL;
00126   fatmsg_msgheader = NULL;
00127   fatmsg = NULL;
00128
00129   __key = strdup(key);
00130   __iv  = strdup(iv);
00131
00132   encryptor = new WorldInfoMessageEncryptor((const unsigned char *)__key, (const unsigned char *)__iv);
00133   decryptor = new WorldInfoMessageDecryptor((const unsigned char *)__key, (const unsigned char *)__iv);
00134
00135   // set maximum size buffer to get valid results from encryptor
00136   encryptor->set_plain_buffer(out_buffer, WORLDINFO_MTU);
00137
00138   crypt_buffer_size  = encryptor->recommended_crypt_buffer_size();
00139   crypted_out_buffer = malloc(crypt_buffer_size);
00140   crypted_in_buffer  = malloc(crypt_buffer_size);
00141
00142   if (! crypted_in_buffer || ! crypted_out_buffer) {
00143     throw OutOfMemoryException();
00144   }
00145
00146   encryptor->set_crypt_buffer(crypted_out_buffer, crypt_buffer_size);
00147
00148   decryptor->set_plain_buffer(in_buffer, WORLDINFO_MTU);
00149
00150   if ( resolver == NULL ) {
00151     this->resolver = new NetworkNameResolver();
00152     resolver_delete = true;
00153   } else {
00154     this->resolver = resolver;
00155     resolver_delete = false;
00156   }
00157
00158   out_seq = 0;
00159 }
00160
00161 
00162 /** Destructor. */
00163 WorldInfoTransceiver::~WorldInfoTransceiver()
00164 {
00165   set_fatmsg_enabled(false);
00166   free(out_buffer);
00167   free(in_buffer);
00168   free(crypted_out_buffer);
00169   free(crypted_in_buffer);
00170   free(__key);
00171   free(__iv);
00172   delete s;
00173   delete encryptor;
00174   delete decryptor;
00175   if ( resolver_delete ) {
00176     delete resolver;
00177   }
00178 }
00179
00180 
00181 /** Set loopback of sent packets.
00182  * This sets whether packets should be looped back to local sockets for multicast
00183  * communication.
00184  * @param loop true to deliver sent packets to local sockets, false prevent delivering
00185  * @see MulticastDatagramSocket::set_loop()
00186  */
00187 void
00188 WorldInfoTransceiver::set_loop(bool loop)
00189 {
00190   s->set_loop( loop );
00191 }
00192
00193 
00194 /** Enable or disable sending of fat message.
00195  * The fat message is considered to be legacy code and therefore disabled by default.
00196  * If you happen to need the fat message you can enable it using this method and then
00197  * it will be send for every call to send().
00198  * @param fatmsg_enabled true to enable sending of fat message, false otherwise
00199  */
00200 void
00201 WorldInfoTransceiver::set_fatmsg_enabled(bool fatmsg_enabled)
00202 {
00203   if ( this->fatmsg_enabled && ! fatmsg_enabled ) {
00204     // fatmsg turned off
00205     free(fatmsg_buf);
00206     fatmsg_buf = NULL;
00207     fatmsg_msgheader = NULL;
00208     fatmsg_header = NULL;
00209     fatmsg = NULL;
00210     fatmsg_bufsize = 0;
00211   } else if (! this->fatmsg_enabled && fatmsg_enabled ) {
00212     // fatmsg turned on
00213     fatmsg_bufsize = sizeof(worldinfo_header_t) + sizeof(worldinfo_message_header_t)
00214                                                 + sizeof(worldinfo_fat_message_t);
00215     fatmsg_buf = calloc(1, fatmsg_bufsize);
00216     fatmsg_header = (worldinfo_header_t *)fatmsg_buf;
00217     fatmsg_msgheader = (worldinfo_message_header_t *)((char *)fatmsg_buf + sizeof(worldinfo_header_t));
00218     fatmsg = (worldinfo_fat_message_t *)((char *)fatmsg_buf + sizeof(worldinfo_header_t)
00219                                                             + sizeof(worldinfo_message_header_t));
00220   } // else unchanged
00221
00222   this->fatmsg_enabled = fatmsg_enabled;
00223 }
00224
00225 
00226 /** Add a handler for world information.
00227  * World information will be dispatched to all registered handlers as soon it
00228  * is received.
00229  * @param h handler to register
00230  */
00231 void
00232 WorldInfoTransceiver::add_handler(WorldInfoHandler *h)
00233 {
00234   handlers.lock();
00235   handlers.push_back(h);
00236   handlers.sort();
00237   handlers.unique();
00238   handlers.unlock();
00239 }
00240
00241 
00242 /** Remove handler for world information.
00243  * The handler is removed from the list of handlers that incoming information
00244  * is dispatched to. No error is thrown if the handler was never registered
00245  * so it is safe to call this for any handler.
00246  * @param h handler to remove from subscriber list
00247  */
00248 void
00249 WorldInfoTransceiver::rem_handler(WorldInfoHandler *h)
00250 {
00251   handlers.remove_locked(h);
00252 }
00253
00254 
00255 /** Flush sequence numbers conditionally.
00256  * This will conditionally flush the sequence numbers stored per sender. The
00257  * sequence numbers are stored per IP. With this method you can flush the
00258  * sequence numbers that have been inactive for a specified time. A recommended
00259  * value is 10 seconds. You may NOT call this concurrently to recv()!
00260  * @param sec number of seconds since that must have passed without a message
00261  * to remove a specific IP from sequence list
00262  */
00263 void
00264 WorldInfoTransceiver::flush_sequence_numbers(unsigned int sec)
00265 {
00266   time_t limit = time(NULL) - sec;
00267
00268   std::map<uint32_t, time_t>::iterator   lrtit2;
00269   lrtit = last_received_time.begin();
00270   while (lrtit != last_received_time.end()) {
00271     if ( (*lrtit).second < limit ) {
00272       sequence_numbers.erase((*lrtit).first);
00273       lrtit2 = lrtit;
00274       ++lrtit;
00275       last_received_time.erase(lrtit2);
00276     } else {
00277       ++lrtit;
00278     }
00279   }
00280 }
00281
00282 
00283 /** Set global pose of robot.
00284  * Global pose of sensing robot (x, y, theta) with the origin in the
00285  * middle of the field, right handed coordinate system (y to opponent goal,
00286  * x to the right, z pointing upwards, same as in simulation league).
00287  * Theta points in y direction (theta = 0 iff robot front points to opponent
00288  * goal).
00289  * The confidence about the robot's pose is transmitted as a 3x3 covariance
00290  * matrix.
00291  * @param x x position of robot
00292  * @param y y position of robot
00293  * @param theta rotation of robot
00294  * @param covariance covariance matrix with 9 entries, ordered as three concatenated
00295  * rows (first row, three floats, second row, three floats, third row, three
00296  * floats). No length check or whatsoever is done. This will crash if c is not
00297  * long enough! c will not be copied but referenced so it has to exist when
00298  * send() is called!
00299  */
00300 void
00301 WorldInfoTransceiver::set_pose(float x, float y, float theta, float *covariance)
00302 {
00303   pose_x          = x;
00304   pose_y          = y;
00305   pose_theta      = theta;
00306   pose_covariance = covariance;
00307   pose_changed    = true;
00308 }
00309
00310 
00311 /** Set velocity of the robot.
00312  * Set the current velocity of the robot.
00313  * @param vel_x velocity in x direction
00314  * @param vel_y velocity in y direction
00315  * @param vel_theta rotational velocity, positive velocity means clockwise
00316  * rotation, negative velocity means counter-clockwise.
00317  * @param covariance covariance matrix with 9 entries, ordered as three concatenated
00318  * rows (first row, three floats, second row, three floats, third row, three
00319  * floats). No length check or whatsoever is done. This will crash if c is not
00320  * long enough! c will not be copied but referenced so it has to exist when
00321  * send() is called!
00322  */
00323 void
00324 WorldInfoTransceiver::set_velocity(float vel_x, float vel_y, float vel_theta, float *covariance)
00325 {
00326   this->vel_x          = vel_x;
00327   this->vel_y          = vel_y;
00328   this->vel_theta      = vel_theta;
00329   this->vel_covariance = covariance;
00330   this->vel_changed    = true;
00331 }
00332
00333 
00334 /** Set ball position.
00335  * Set the ball perception relative to the current robot position.
00336  * Note that the ball position is given in polar coordinates in
00337  * 3D space!
00338  * The confidence about the ball position is transmitted as a 3x3 covariance
00339  * matrix.
00340  * @param dist distance to ball in meters
00341  * @param bearing bearing angle to ball
00342  * @param slope slope angle to ball
00343  * @param covariance covariance matrix with 9 entries, ordered as three concatenated
00344  * rows (first row, three floats, second row, three floats, third row, three
00345  * floats). No length check or whatsoever is done. This will crash if c is not
00346  * long enough! c will not be copied but referenced so it has to exist when
00347  * send() is called!
00348  */
00349 void
00350 WorldInfoTransceiver::set_rel_ball_pos(float dist, float bearing, float slope, float *covariance)
00351 {
00352   rel_ball_dist       = dist;
00353   rel_ball_bearing    = bearing;
00354   rel_ball_slope      = slope;
00355   rel_ball_covariance = covariance;
00356   rel_ball_changed    = true;
00357 }
00358
00359 
00360 /** Set global ball position.
00361  * Note that the ball position is given in polar coordinates in
00362  * 3D space!
00363  * The confidence about the ball position is transmitted as a 3x3 covariance
00364  * matrix.
00365  * @param x the x-coordinate of the global ball position
00366  * @param y the y-coordinate of the global ball position
00367  * @param z the z-coordinate of the global ball position
00368  * @param covariance covariance matrix with 9 entries, ordered as three concatenated
00369  * rows (first row, three floats, second row, three floats, third row, three
00370  * floats). No length check or whatsoever is done. This will crash if c is not
00371  * long enough! c will not be copied but referenced so it has to exist when
00372  * send() is called!
00373  */
00374 void
00375 WorldInfoTransceiver::set_glob_ball_pos(float x, float y, float z, float *covariance)
00376 {
00377   glob_ball_x          = x;
00378   glob_ball_y          = y;
00379   glob_ball_z          = z;
00380   glob_ball_covariance = covariance;
00381   glob_ball_changed    = true;
00382 }
00383
00384 
00385 /** Set ball visibility.
00386  * This method defines if the ball is currently visible or not. Additionally more detailed
00387  * information is provided in the visibility history. The history shall be 0 only if the
00388  * vision has just been initialized. It shall be positive if the ball is visible and shall
00389  * have the number of vision cycles in which the ball was visible in a row. It shall be
00390  * negative if the ball is not visible and shall be the negative value of the number
00391  * of frames where the ball was not visible. A value of 30 for example means that the
00392  * ball has been continuously visible for 30 frames, it was never lost. A value of
00393  * -20 means that the ball was not seen for the last 20 frames.
00394  * @param visible true if the ball is visible, false otherwise
00395  * @param visibility_history visibility history, see above.
00396  */
00397 void
00398 WorldInfoTransceiver::set_rel_ball_visible(bool visible, int visibility_history)
00399 {
00400   rel_ball_visible            = visible;
00401   rel_ball_visibility_history = visibility_history;
00402   rel_ball_changed            = true;
00403 }
00404
00405 
00406 /** Set ball visibility for the global ball.
00407  * Same semantics as set_ball_visible().
00408  * @param visible true if the ball is visible, false otherwise
00409  * @param visibility_history visibility history, see above.
00410  */
00411 void
00412 WorldInfoTransceiver::set_glob_ball_visible(bool visible, int visibility_history)
00413 {
00414   glob_ball_visible            = visible;
00415   glob_ball_visibility_history = visibility_history;
00416   glob_ball_changed            = true;
00417 }
00418
00419 
00420 /** Set ball velocity.
00421  * Set the current velocity of the robot.
00422  * @param vel_x velocity in x direction
00423  * @param vel_y velocity in y direction
00424  * @param vel_z velocity in z direction
00425  * @param covariance covariance matrix with 9 entries, ordered as three concatenated
00426  * rows (first row, three floats, second row, three floats, third row, three
00427  * floats). No length check or whatsoever is done. This will crash if c is not
00428  * long enough! c will not be copied but referenced so it has to exist when
00429  * send() is called!
00430  */
00431 void
00432 WorldInfoTransceiver::set_rel_ball_velocity(float vel_x, float vel_y, float vel_z,
00433                                             float *covariance)
00434 {
00435   rel_ball_vel_x          = vel_x;
00436   rel_ball_vel_y          = vel_y;
00437   rel_ball_vel_z          = vel_z;
00438   rel_ball_vel_covariance = covariance;
00439   rel_ball_vel_changed    = true;
00440 }
00441
00442 
00443 /** Set global ball velocity.
00444  * Set the current, global velocity of the robot.
00445  * @param vel_x velocity in x direction wrt. to the global frame
00446  * @param vel_y velocity in y direction wrt. to the global frame
00447  * @param vel_z velocity in z direction wrt. to the global frame
00448  * @param covariance covariance matrix with 9 entries, ordered as three concatenated
00449  * rows (first row, three floats, second row, three floats, third row, three
00450  * floats). No length check or whatsoever is done. This will crash if c is not
00451  * long enough! c will not be copied but referenced so it has to exist when
00452  * send() is called!
00453  */
00454 void
00455 WorldInfoTransceiver::set_glob_ball_velocity(float vel_x, float vel_y, float vel_z,
00456                                             float *covariance)
00457 {
00458   glob_ball_vel_x          = vel_x;
00459   glob_ball_vel_y          = vel_y;
00460   glob_ball_vel_z          = vel_z;
00461   glob_ball_vel_covariance = covariance;
00462   glob_ball_vel_changed    = true;
00463 }
00464
00465 
00466 /** Set current game state.
00467  * @param gamestate current game state
00468  * @param state_team team referenced by the game state
00469  */
00470 void
00471 WorldInfoTransceiver::set_gamestate(int gamestate,
00472                                     worldinfo_gamestate_team_t state_team)
00473 {
00474   if ((gamestate < 0) || (gamestate >= 16)) {
00475     throw OutOfBoundsException("Illegal gamestate", gamestate, 0, 15);
00476   }
00477   gamestate_msg.game_state = gamestate;
00478   gamestate_msg.state_team = state_team;
00479   gamestate_changed = true;
00480 }
00481
00482 
00483 /** Set score.
00484  * @param score_cyan current score of team cyan
00485  * @param score_magenta current score of team magenta
00486  */
00487 void
00488 WorldInfoTransceiver::set_score(unsigned int score_cyan, unsigned int score_magenta)
00489 {
00490   gamestate_msg.score_cyan    = score_cyan;
00491   gamestate_msg.score_magenta = score_magenta;
00492   gamestate_changed = true;
00493 }
00494
00495 
00496 /** Add penalty message.
00497  * @param player player for which the penalty applies
00498  * @param penalty penalty code
00499  * @param seconds_remaining estimated time in seconds until the penalty is lifted
00500  */
00501 void
00502 WorldInfoTransceiver::add_penalty(unsigned int player, unsigned int penalty,
00503                                   unsigned int seconds_remaining)
00504 {
00505   worldinfo_penalty_message_t pm;
00506   pm.reserved = 0;
00507   pm.player = player;
00508   pm.penalty = penalty;
00509   pm.seconds_remaining = seconds_remaining;
00510   penalties[player] = pm;
00511 }
00512 
00513 /** Set team and goal info.
00514  * @param our_team our team color
00515  * @param goal_color our goal color
00516  */
00517 void
00518 WorldInfoTransceiver::set_team_goal(worldinfo_gamestate_team_t our_team,
00519                                     worldinfo_gamestate_goalcolor_t goal_color)
00520 {
00521   gamestate_msg.our_team       = our_team;
00522   gamestate_msg.our_goal_color = goal_color;
00523   gamestate_changed = true;
00524 }
00525
00526 
00527 /** Set current half of the game time.
00528  * @param half current half
00529  */
00530 void
00531 WorldInfoTransceiver::set_half(worldinfo_gamestate_half_t half)
00532 {
00533   gamestate_msg.half = half;
00534   gamestate_changed = true;
00535 }
00536
00537 
00538 /** Clear opponents list.
00539  * Clear the list of opponents that has to be transmitted. This is done
00540  * implicitly in send().
00541  */
00542 void
00543 WorldInfoTransceiver::clear_opponents()
00544 {
00545   opponents.clear();
00546 }
00547
00548 
00549 /** Add opponent to transmit list.
00550  * Add an opponent to the list of opponents to be transmitted on next send()
00551  * call. Opponents are given in a 2D polar coordinate system (assumption is that
00552  * robots don't fly in the soccer domain).
00553  * @param uid unique ID of this opponent. The caller shall assign the same UID to an
00554  * opponent if and only if the object is the same (for example an opponent that was
00555  * tracked)
00556  * @param distance to opponent
00557  * @param bearing to opponent (angle is zero if opponent is in front of robot,
00558  * positive if right of robot, negative if left of robot).
00559  * @param covariance covariance matrix with 4 entries, ordered as two concatenated
00560  * rows (first row, two floats, second row, two floats. No length check or
00561  * whatsoever is done. This will crash if c is not
00562  * long enough! c will not be copied but referenced so it has to exist when
00563  * send() is called!
00564  */
00565 void
00566 WorldInfoTransceiver::add_opponent(unsigned int uid,
00567                                    float distance, float bearing, float *covariance)
00568 {
00569   opponent_t o = { uid, distance, bearing, covariance };
00570   opponents.push_back(o);
00571 }
00572
00573 
00574 /** Add disappeared opponent.
00575  * Add any opponent that you had added in an earlier cycle (before the last send()) with
00576  * add_opponent() and that is no longer visible. After it has been marked as disappeared
00577  * the unique ID may not be reused. Gibt it another new ID instead.
00578  * @param uid Unique ID of opponent that disappeared
00579  */
00580 void
00581 WorldInfoTransceiver::add_disappeared_opponent(unsigned int uid)
00582 {
00583   disappeared_opponents.push_back(uid);
00584 }
00585 
00586 /** Append packet to outbound buffer.
00587  * @param msg_type message type
00588  * @param msg message buffer
00589  * @param msg_size size of message buffer
00590  * @exception OutOfMemoryException thrown if message is too big or if the
00591  * remaining size in the outbound buffer is not big enough
00592  */
00593 void
00594 WorldInfoTransceiver::append_outbound(uint16_t msg_type,
00595                                       void *msg, uint16_t msg_size)
00596 {
00597   worldinfo_message_header_t mh;
00598
00599   if ( (outbound_bytes + sizeof(mh) + msg_size ) > WORLDINFO_MTU ) {
00600     throw OutOfMemoryException();
00601   }
00602
00603   // per message header
00604   mh.type = htons(msg_type);
00605   mh.size = htons(msg_size);
00606   memcpy(outbound_buffer, &mh, sizeof(mh));
00607
00608   outbound_bytes  += sizeof(mh);
00609   outbound_buffer += sizeof(mh);
00610
00611   // message body
00612   memcpy(outbound_buffer, msg, msg_size);
00613   outbound_bytes  += msg_size;
00614   outbound_buffer += msg_size;
00615   ++outbound_num_msgs;
00616 }
00617
00618 
00619 /** Reset outbound buffer.
00620  */
00621 void
00622 WorldInfoTransceiver::reset_outbound()
00623 {
00624   worldinfo_header_t *header = (worldinfo_header_t *)out_buffer;
00625   header->beef = htons(0xBEEF);
00626   header->version  = WORLDINFO_VERSION;
00627
00628   if ( fatmsg_enabled ) {
00629     memset(fatmsg_buf, 0, fatmsg_bufsize);
00630     fatmsg_header->beef = htons(0xBEEF);
00631     fatmsg_header->version  = WORLDINFO_VERSION;
00632     fatmsg_msgheader->type  = htons(WORLDINFO_MSGTYPE_FAT_WORLDINFO);
00633     fatmsg_msgheader->size  = htons(sizeof(worldinfo_fat_message_t));
00634   }
00635
00636   outbound_buffer   = (unsigned char *)out_buffer + sizeof(worldinfo_header_t);
00637   outbound_bytes    = sizeof(worldinfo_header_t);
00638   outbound_num_msgs = 0;
00639 }
00640
00641 
00642 /** Send information.
00643  * All information that has been set since last call is sent over the network.
00644  * This implicitly resets all information and flushes the opponent list.
00645  */
00646 void
00647 WorldInfoTransceiver::send()
00648 {
00649   worldinfo_header_t *header = (worldinfo_header_t *)out_buffer;
00650
00651   reset_outbound();
00652
00653   if ( pose_changed ) {
00654     worldinfo_pose_message_t pm;
00655     pm.x = pose_x;
00656     pm.y = pose_y;
00657     pm.theta = pose_theta;
00658     memcpy(&(pm.covariance), pose_covariance, sizeof(pm.covariance));
00659     pose_changed = false;
00660
00661     append_outbound(WORLDINFO_MSGTYPE_POSE, &pm, sizeof(pm));
00662
00663     if ( fatmsg_enabled ) {
00664       // fill fat msg
00665       memcpy(&(fatmsg->pose), &pm, sizeof(pm));
00666       fatmsg->valid_pose = 1;
00667     }
00668   } else {
00669     if ( fatmsg_enabled ) {
00670       fatmsg->valid_pose = 0;
00671     }
00672   }
00673
00674   if ( vel_changed ) {
00675     worldinfo_velocity_message_t vm;
00676     vm.vel_x     = vel_x;
00677     vm.vel_y     = vel_y;
00678     vm.vel_theta = vel_theta;
00679     memcpy(&(vm.covariance), vel_covariance, sizeof(vm.covariance));
00680     vel_changed = false;
00681
00682     append_outbound(WORLDINFO_MSGTYPE_VELO, &vm, sizeof(vm));
00683
00684     if ( fatmsg_enabled ) {
00685       // fill fat msg
00686       memcpy(&(fatmsg->velo), &vm, sizeof(vm));
00687       fatmsg->valid_velo = 1;
00688     }
00689   } else {
00690     if ( fatmsg_enabled ) {
00691       fatmsg->valid_velo = 0;
00692     }
00693   }
00694
00695   if ( rel_ball_changed ) {
00696     worldinfo_relballpos_message_t bm;
00697     bm.dist    = rel_ball_dist;
00698     bm.bearing = rel_ball_bearing;
00699     bm.slope   = rel_ball_slope;
00700     bm.history = rel_ball_visibility_history;
00701     bm.visible = rel_ball_visible ? -1 : 0;
00702     memcpy(&(bm.covariance), rel_ball_covariance, sizeof(bm.covariance));
00703
00704     rel_ball_changed = false;
00705
00706     append_outbound(WORLDINFO_MSGTYPE_GLOBBALL, &bm, sizeof(bm));
00707
00708     if ( fatmsg_enabled ) {
00709       // fill fat msg
00710       memcpy(&(fatmsg->relball_pos), &bm, sizeof(bm));
00711       fatmsg->valid_relball_pos = 1;
00712     }
00713   } else {
00714     if ( fatmsg_enabled ) {
00715       fatmsg->valid_relball_pos = 0;
00716     }
00717   }
00718
00719   if ( glob_ball_changed ) {
00720     worldinfo_globballpos_message_t bm;
00721     bm.x       = glob_ball_x;
00722     bm.y       = glob_ball_y;
00723     bm.z       = glob_ball_z;
00724     bm.history = glob_ball_visibility_history;
00725     bm.visible = glob_ball_visible ? -1 : 0;
00726     memcpy(&(bm.covariance), glob_ball_covariance, sizeof(bm.covariance));
00727
00728     glob_ball_changed = false;
00729
00730     append_outbound(WORLDINFO_MSGTYPE_GLOBBALL, &bm, sizeof(bm));
00731   }
00732
00733   if ( gamestate_changed ) {
00734     append_outbound(WORLDINFO_MSGTYPE_GAMESTATE,
00735                     &gamestate_msg, sizeof(worldinfo_gamestate_message_t));
00736     gamestate_changed = false;
00737   }
00738
00739   if ( rel_ball_vel_changed ) {
00740     worldinfo_relballvelo_message_t rbvm;
00741     rbvm.vel_x = rel_ball_vel_x;
00742     rbvm.vel_y = rel_ball_vel_y;
00743     rbvm.vel_z = rel_ball_vel_z;
00744     memcpy(&(rbvm.covariance), rel_ball_vel_covariance, sizeof(rbvm.covariance));
00745     rel_ball_vel_changed = false;
00746
00747     append_outbound(WORLDINFO_MSGTYPE_RELBALLVELO, &rbvm, sizeof(rbvm));
00748
00749     if ( fatmsg_enabled ) {
00750       // fill fat msg
00751       memcpy(&(fatmsg->relball_velo), &rbvm, sizeof(rbvm));
00752       fatmsg->valid_relball_velo = 1;
00753     }
00754   } else {
00755     if ( fatmsg_enabled ) {
00756       fatmsg->valid_relball_velo = 0;
00757     }
00758   }
00759
00760   if ( glob_ball_vel_changed ) {
00761     worldinfo_globballvelo_message_t rbvm;
00762     rbvm.vel_x = glob_ball_vel_x;
00763     rbvm.vel_y = glob_ball_vel_y;
00764     rbvm.vel_z = glob_ball_vel_z;
00765     memcpy(&(rbvm.covariance), glob_ball_vel_covariance, sizeof(rbvm.covariance));
00766     glob_ball_vel_changed = false;
00767
00768     append_outbound(WORLDINFO_MSGTYPE_GLOBBALLVELO, &rbvm, sizeof(rbvm));
00769   }
00770
00771   // Append penalties
00772   for (penit = penalties.begin(); penit != penalties.end(); ++penit) {
00773     append_outbound(WORLDINFO_MSGTYPE_PENALTY,
00774                     &(penit->second), sizeof(worldinfo_penalty_message_t));
00775   }
00776   penalties.clear();
00777
00778   // Append opponents
00779   unsigned int num_opponents = 0;
00780   for ( oppit = opponents.begin(); oppit != opponents.end(); ++oppit) {
00781     worldinfo_opppose_message_t opm;
00782     opm.uid     = (*oppit).uid;
00783     opm.dist    = (*oppit).distance;
00784     opm.bearing = (*oppit).bearing;
00785     memcpy(&(opm.covariance), (*oppit).covariance, sizeof(opm.covariance));
00786
00787     append_outbound(WORLDINFO_MSGTYPE_OPP_POSE, &opm, sizeof(opm));
00788
00789     if ( fatmsg_enabled ) {
00790       if ( num_opponents < WORLDINFO_FATMSG_NUMOPPS ) {
00791         // fill fat msg
00792         memcpy(&(fatmsg->opponents[num_opponents]), &opm, sizeof(opm));
00793         ++num_opponents;
00794         fatmsg->num_opponents = num_opponents;
00795       }
00796     }
00797   }
00798   opponents.clear();
00799
00800   for ( doppit = disappeared_opponents.begin(); doppit != disappeared_opponents.end(); ++doppit) {
00801     worldinfo_oppdisappeared_message_t opdm;
00802     opdm.uid     = *doppit;
00803
00804     append_outbound(WORLDINFO_MSGTYPE_OPP_DISAPP, &opdm, sizeof(opdm));
00805   }
00806   disappeared_opponents.clear();
00807
00808   if ( outbound_num_msgs > 0 ) {
00809     // send slim msgs
00810     header->seq      = htonl(out_seq++);
00811
00812     encryptor->set_plain_buffer(out_buffer, outbound_bytes);
00813     crypted_out_bytes = encryptor->encrypt();
00814
00815     s->send(crypted_out_buffer, crypted_out_bytes);
00816
00817     if ( fatmsg_enabled ) {
00818       // send fat msg
00819       fatmsg_header->seq = htonl(out_seq++);
00820
00821       encryptor->set_plain_buffer(fatmsg_buf, fatmsg_bufsize);
00822       crypted_out_bytes = encryptor->encrypt();
00823
00824       s->send(crypted_out_buffer, crypted_out_bytes);
00825     }
00826   }
00827
00828 }
00829
00830 
00831 /** Receive information.
00832  * This checks if there is information on the network waiting to be received
00833  * and if so receives and processes the information and dispatches it to all
00834  * registered handlers. If you order it to block this method will block until
00835  * information has been received and dispatched (useful if running in a
00836  * thread).
00837  *
00838  * Received packets will be ignored if
00839  * - they do not start with 0xBEEF
00840  * - they are of an incompatible version
00841  * - the sequence number is smaller or equal to an already received packet
00842  * They will only be partially handled if
00843  * - a packet has been truncated (truncated message is ignored)
00844  * - an unknown message type is encountered (message is ignored)
00845  * - a message size does not match the expected size for a given type (message is ignored)
00846  *
00847  * @param block set to true for blocking operation, in this case recv() will
00848  * block until data is available, false for non-blocking operation where recv()
00849  * will immediately return if there is no data available
00850  * @param max_num_msgs maximum number of messages to process in a single
00851  * call to recv(). Set to 0 for an unlimited number of messages per call (this
00852  * can block for an infinite time if messages are coming in fast).
00853  */
00854 void
00855 WorldInfoTransceiver::recv(bool block, unsigned int max_num_msgs)
00856 {
00857   if ( ! block ) {
00858     if ( ! s->available() ) {
00859       return;
00860     }
00861   }
00862
00863   handlers.lock();
00864
00865   unsigned int num_msgs = (max_num_msgs == 0 ? 0 : 1);
00866   do {
00867     struct sockaddr_in from;
00868     socklen_t addr_len = sizeof(from);
00869     size_t bytes = crypt_buffer_size;
00870
00871     if ( max_num_msgs != 0 )  ++num_msgs;
00872
00873     bytes = s->recv(crypted_in_buffer, bytes, (struct sockaddr *)&from, &addr_len);
00874
00875     // decryptor decrypts to in_buffer, see constructor
00876     decryptor->set_crypt_buffer(crypted_in_buffer, bytes);
00877     try {
00878       inbound_bytes = decryptor->decrypt();
00879     } catch (MessageDecryptionException &e) {
00880       LibLogger::log_warn("WorldInfoTransceiver", "Message decryption failed, ignoring");
00881       LibLogger::log_warn("WorldInfoTransceiver", e);
00882       continue;
00883     }
00884
00885     /*
00886     cout << "Plain:";
00887     for (size_t i = 0; i < inbound_bytes; ++i) {
00888       unsigned int u = *((unsigned char *)in_buffer + i);
00889       printf("%02x ", u);
00890     }
00891     cout << endl;
00892     */
00893
00894     // Process
00895     worldinfo_header_t *header = (worldinfo_header_t *)in_buffer;
00896     if ( ntohs(header->beef) != 0xBEEF ) {
00897       // throw WorldInfoException("Incorrect message received, wrong key?");
00898       LibLogger::log_warn("WorldInfoTransceiver", "Invalid message received (no 0xBEEF), ignoring");
00899       continue;
00900     }
00901
00902     if ( header->version != WORLDINFO_VERSION ) {
00903       LibLogger::log_warn("WorldInfoTransceiver", "Unsupported version of world info data received, ignoring");
00904       continue;
00905     }
00906
00907     // Sequence number handling per client, IPv4 only, for IPv6 in the pre-128-bit era
00908     // we would need a custom compare function
00909     unsigned int cseq = ntohl(header->seq);
00910     if ( sequence_numbers.find(from.sin_addr.s_addr) != sequence_numbers.end() ) {
00911       if ( cseq <= sequence_numbers[from.sin_addr.s_addr] ) {
00912         // Already received (loop) or replay attack, just ignore
00913         LibLogger::log_warn("WorldInfoTransceiver", "Received packet twice, ignoring");
00914         continue;
00915       }
00916     }
00917     sequence_numbers[from.sin_addr.s_addr] = cseq;
00918     last_received_time[from.sin_addr.s_addr] = time(NULL);
00919
00920     inbound_bytes -= sizeof(worldinfo_header_t);
00921     inbound_buffer = (unsigned char *)in_buffer + sizeof(worldinfo_header_t);
00922
00923     std::string hostname_s;
00924     if ( ! resolver->resolve_address((struct sockaddr *)&from, sizeof(from), hostname_s) ) {
00925       hostname_s = "unknown";
00926     }
00927     const char *hostname = hostname_s.c_str();
00928
00929     // Go through messages
00930     while ( inbound_bytes > 0 ) {
00931       worldinfo_message_header_t *msgh = (worldinfo_message_header_t *)inbound_buffer;
00932       inbound_bytes  -= sizeof(worldinfo_message_header_t);
00933       inbound_buffer += sizeof(worldinfo_message_header_t);
00934       uint16_t msg_type = ntohs(msgh->type);
00935       uint16_t msg_size = ntohs(msgh->size);
00936       //printf("Message type: %u   size: %u  ntype: %u  nsize: %u\n",
00937       //     msg_type, msg_size, msgh->type, msgh->size);
00938       if ( inbound_bytes < msg_size ) {
00939         LibLogger::log_warn("WorldInfoTransceiver", "Truncated packet received or protocol "
00940                             "error, ignoring rest of packet (got %zu bytes, but expected "
00941                             "%zu bytes)", inbound_bytes, msg_size);
00942         break;
00943       }
00944       switch ( msg_type ) {
00945       case WORLDINFO_MSGTYPE_POSE:
00946         if ( msg_size == sizeof(worldinfo_pose_message_t) ) {
00947           worldinfo_pose_message_t *pose_msg = (worldinfo_pose_message_t *)inbound_buffer;
00948           for ( hit = handlers.begin(); hit != handlers.end(); ++hit ) {
00949             (*hit)->pose_rcvd(hostname,
00950                               pose_msg->x, pose_msg->y, pose_msg->theta,
00951                               pose_msg->covariance);
00952           }
00953         } else {
00954           LibLogger::log_warn("WorldInfoTransceiver", "Invalid pose message received "
00955                               "(got %zu bytes but expected %zu bytes), ignoring",
00956                               msg_size, sizeof(worldinfo_pose_message_t));
00957         }
00958         break;
00959
00960       case WORLDINFO_MSGTYPE_VELO:
00961         if ( msg_size == sizeof(worldinfo_velocity_message_t) ) {
00962           worldinfo_velocity_message_t *velo_msg = (worldinfo_velocity_message_t *)inbound_buffer;
00963           for ( hit = handlers.begin(); hit != handlers.end(); ++hit ) {
00964             (*hit)->velocity_rcvd(hostname,
00965                                   velo_msg->vel_x, velo_msg->vel_y, velo_msg->vel_theta,
00966                                   velo_msg->covariance);
00967           }
00968         } else {
00969           LibLogger::log_warn("WorldInfoTransceiver", "Invalid velocity message received "
00970                               "(got %zu bytes but expected %zu bytes), ignoring",
00971                               msg_size, sizeof(worldinfo_velocity_message_t));
00972         }
00973         break;
00974
00975       case WORLDINFO_MSGTYPE_RELBALL:
00976         if ( msg_size == sizeof(worldinfo_relballpos_message_t) ) {
00977           worldinfo_relballpos_message_t *ball_msg = (worldinfo_relballpos_message_t *)inbound_buffer;
00978           for ( hit = handlers.begin(); hit != handlers.end(); ++hit ) {
00979             (*hit)->ball_pos_rcvd(hostname,
00980                                   (ball_msg->visible == -1), ball_msg->history,
00981                                   ball_msg->dist, ball_msg->bearing, ball_msg->slope,
00982                                   ball_msg->covariance);
00983           }
00984         } else {
00985           LibLogger::log_warn("WorldInfoTransceiver", "Invalid relative ball pos message received "
00986                               "(got %zu bytes but expected %zu bytes), ignoring",
00987                               msg_size, sizeof(worldinfo_relballpos_message_t));
00988         }
00989         break;
00990
00991       case WORLDINFO_MSGTYPE_GLOBBALL:
00992         if ( msg_size == sizeof(worldinfo_globballpos_message_t) ) {
00993           worldinfo_globballpos_message_t *ball_msg = (worldinfo_globballpos_message_t *)inbound_buffer;
00994           for ( hit = handlers.begin(); hit != handlers.end(); ++hit ) {
00995             (*hit)->global_ball_pos_rcvd(hostname,
00996                                          (ball_msg->visible == -1), ball_msg->history,
00997                                          ball_msg->x, ball_msg->y, ball_msg->z,
00998                                          ball_msg->covariance);
00999           }
01000         } else {
01001           LibLogger::log_warn("WorldInfoTransceiver", "Invalid global ball pos message received "
01002                               "(got %zu bytes but expected %zu bytes), ignoring",
01003                               msg_size, sizeof(worldinfo_globballpos_message_t));
01004         }
01005         break;
01006
01007       case WORLDINFO_MSGTYPE_RELBALLVELO:
01008         if ( msg_size == sizeof(worldinfo_relballvelo_message_t) ) {
01009           worldinfo_relballvelo_message_t *bvel_msg = (worldinfo_relballvelo_message_t *)inbound_buffer;
01010           for ( hit = handlers.begin(); hit != handlers.end(); ++hit ) {
01011             (*hit)->ball_velocity_rcvd(hostname,
01012                                        bvel_msg->vel_x, bvel_msg->vel_y, bvel_msg->vel_z,
01013                                        bvel_msg->covariance);
01014           }
01015         } else {
01016           LibLogger::log_warn("WorldInfoTransceiver", "Invalid relative ball velocity message received "
01017                               "(got %zu bytes but expected %zu bytes), ignoring",
01018                               msg_size, sizeof(worldinfo_relballvelo_message_t));
01019         }
01020         break;
01021
01022       case WORLDINFO_MSGTYPE_GLOBBALLVELO:
01023         if ( msg_size == sizeof(worldinfo_globballvelo_message_t) ) {
01024           worldinfo_globballvelo_message_t *bvel_msg = (worldinfo_globballvelo_message_t *)inbound_buffer;
01025           for ( hit = handlers.begin(); hit != handlers.end(); ++hit ) {
01026             (*hit)->global_ball_velocity_rcvd(hostname,
01027                                               bvel_msg->vel_x, bvel_msg->vel_y, bvel_msg->vel_z,
01028                                               bvel_msg->covariance);
01029           }
01030         } else {
01031           LibLogger::log_warn("WorldInfoTransceiver", "Invalid global ball velocity message received "
01032                               "(got %zu bytes but expected %zu bytes), ignoring",
01033                               msg_size, sizeof(worldinfo_globballvelo_message_t));
01034         }
01035         break;
01036
01037       case WORLDINFO_MSGTYPE_OPP_POSE:
01038         if ( msg_size == sizeof(worldinfo_opppose_message_t) ) {
01039           worldinfo_opppose_message_t *oppp_msg = (worldinfo_opppose_message_t *)inbound_buffer;
01040           for ( hit = handlers.begin(); hit != handlers.end(); ++hit ) {
01041             (*hit)->opponent_pose_rcvd(hostname,
01042                                        oppp_msg->uid, oppp_msg->dist, oppp_msg->bearing,
01043                                        oppp_msg->covariance);
01044           }
01045         } else {
01046           LibLogger::log_warn("WorldInfoTransceiver", "Invalid opponent pose message received "
01047                               "(got %zu bytes but expected %zu bytes), ignoring",
01048                               msg_size, sizeof(worldinfo_opppose_message_t));
01049         }
01050         break;
01051
01052       case WORLDINFO_MSGTYPE_OPP_DISAPP:
01053         if ( msg_size == sizeof(worldinfo_oppdisappeared_message_t) ) {
01054           worldinfo_oppdisappeared_message_t *oppd_msg = (worldinfo_oppdisappeared_message_t *)inbound_buffer;
01055           for ( hit = handlers.begin(); hit != handlers.end(); ++hit ) {
01056             (*hit)->opponent_disapp_rcvd(hostname, oppd_msg->uid);
01057           }
01058         } else {
01059           LibLogger::log_warn("WorldInfoTransceiver", "Invalid opponent disappeared message received "
01060                               "(got %zu bytes but expected %zu bytes), ignoring",
01061                               msg_size, sizeof(worldinfo_oppdisappeared_message_t));
01062         }
01063         break;
01064
01065       case WORLDINFO_MSGTYPE_GAMESTATE:
01066         if ( msg_size == sizeof(worldinfo_gamestate_message_t) ) {
01067           worldinfo_gamestate_message_t *gs_msg = (worldinfo_gamestate_message_t *)inbound_buffer;
01068           for ( hit = handlers.begin(); hit != handlers.end(); ++hit ) {
01069             (*hit)->gamestate_rcvd(hostname,
01070                                    gs_msg->game_state,
01071                                    (worldinfo_gamestate_team_t)gs_msg->state_team,
01072                                    gs_msg->score_cyan, gs_msg->score_magenta,
01073                                    (worldinfo_gamestate_team_t)gs_msg->our_team,
01074                                    (worldinfo_gamestate_goalcolor_t)gs_msg->our_goal_color,
01075                                    (worldinfo_gamestate_half_t)gs_msg->half);
01076           }
01077         } else {
01078           LibLogger::log_warn("WorldInfoTransceiver", "Invalid gamestate message received "
01079                               "(got %zu bytes but expected %zu bytes), ignoring",
01080                               msg_size, sizeof(worldinfo_gamestate_message_t));
01081         }
01082         break;
01083
01084       case WORLDINFO_MSGTYPE_PENALTY:
01085         if ( msg_size == sizeof(worldinfo_penalty_message_t) ) {
01086           worldinfo_penalty_message_t *p_msg = (worldinfo_penalty_message_t *)inbound_buffer;
01087           for ( hit = handlers.begin(); hit != handlers.end(); ++hit ) {
01088             (*hit)->penalty_rcvd(hostname,
01089                                  p_msg->player, p_msg->penalty, p_msg->seconds_remaining);
01090           }
01091
01092         } else {
01093           LibLogger::log_warn("WorldInfoTransceiver", "Invalid penalty message received "
01094                               "(got %zu bytes but expected %zu bytes), ignoring",
01095                               msg_size, sizeof(worldinfo_penalty_message_t));
01096         }
01097         break;
01098
01099       case WORLDINFO_MSGTYPE_FAT_WORLDINFO:
01100         if ( msg_size == sizeof(worldinfo_fat_message_t) ) {
01101           worldinfo_fat_message_t *fat_msg = (worldinfo_fat_message_t *)inbound_buffer;
01102           for ( hit = handlers.begin(); hit != handlers.end(); ++hit ) {
01103             if ( fat_msg->valid_pose ) {
01104               (*hit)->pose_rcvd(hostname,
01105                                 fat_msg->pose.x, fat_msg->pose.y, fat_msg->pose.theta,
01106                                 fat_msg->pose.covariance);
01107             }
01108
01109             if ( fat_msg->valid_velo ) {
01110               (*hit)->velocity_rcvd(hostname,
01111                                     fat_msg->velo.vel_x, fat_msg->velo.vel_y,
01112                                     fat_msg->velo.vel_theta, fat_msg->velo.covariance);
01113             }
01114             if ( fat_msg->valid_relball_pos ) {
01115               (*hit)->ball_pos_rcvd(hostname,
01116                                     (fat_msg->relball_pos.visible == -1),
01117                                     fat_msg->relball_pos.history,
01118                                     fat_msg->relball_pos.dist, fat_msg->relball_pos.bearing,
01119                                     fat_msg->relball_pos.slope, fat_msg->relball_pos.covariance);
01120             }
01121             if ( fat_msg->valid_relball_velo ) {
01122               (*hit)->ball_velocity_rcvd(hostname,
01123                                          fat_msg->relball_velo.vel_x,
01124                                          fat_msg->relball_velo.vel_y,
01125                                          fat_msg->relball_velo.vel_z,
01126                                          fat_msg->relball_velo.covariance);
01127             }
01128
01129             if ( fat_msg->num_opponents > WORLDINFO_FATMSG_NUMOPPS ) {
01130               // We can't handle this
01131               LibLogger::log_warn("WorldInfoTransceiver", "Too many opponents marked valid in message "
01132                                   "(got %zu but expected a maximum of %zu), ignoring",
01133                                   fat_msg->num_opponents, WORLDINFO_FATMSG_NUMOPPS);
01134             } else {
01135               for ( unsigned int i = 0; i < fat_msg->num_opponents; ++i ) {
01136                 (*hit)->opponent_pose_rcvd(hostname,
01137                                            fat_msg->opponents[i].uid,
01138                                            fat_msg->opponents[i].dist,
01139                                            fat_msg->opponents[i].bearing,
01140                                            fat_msg->opponents[i].covariance);
01141               }
01142             }
01143           } // end for each handler
01144         } else {
01145           LibLogger::log_warn("WorldInfoTransceiver", "Invalid fat message received "
01146                               "(got %zu bytes but expected %zu bytes), ignoring",
01147                               msg_size, sizeof(worldinfo_fat_message_t));
01148         }
01149         break;
01150
01151
01152       default:
01153           LibLogger::log_warn("WorldInfoTransceiver", "Unknown message type %u received "
01154                               ", ignoring", msg_type);
01155       }
01156       // there is more to process
01157       inbound_bytes  -= msg_size;
01158       inbound_buffer += msg_size;
01159     }
01160
01161   } while ( s->available() && (num_msgs <= max_num_msgs) );
01162
01163   handlers.unlock();
01164 }
01165
01166 
01167 /** Get last sent plain buffer.
01168  * This method is meant to be used for debugging and testing purposes only.
01169  * @return last plain text message buffer
01170  */
01171 void *
01172 WorldInfoTransceiver::last_sent_plain_buffer()
01173 {
01174   return out_buffer;
01175 }
01176
01177 
01178 /** Get last sent plain buffer size.
01179  * This method is meant to be used for debugging and testing purposes only.
01180  * @return last plain text message buffer size
01181  */
01182 size_t
01183 WorldInfoTransceiver::last_sent_plain_buffer_size()
01184 {
01185   return outbound_bytes;
01186 }
01187
01188 
01189 /** Get last sent crypted buffer.
01190  * This method is meant to be used for debugging and testing purposes only.
01191  * @return last crytped message buffer
01192  */
01193 void *
01194 WorldInfoTransceiver::last_sent_crypted_buffer()
01195 {
01196   return crypted_out_buffer;
01197 }
01198
01199 
01200 /** Get last sent crypted buffer size.
01201  * This method is meant to be used for debugging and testing purposes only.
01202  * @return last crypted message buffer size
01203  */
01204 size_t
01205 WorldInfoTransceiver::last_sent_crypted_buffer_size()
01206 {
01207   return crypted_out_bytes;
01208 }
01209
01210 } // end namespace fawkes