meta data for this page
  •  

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
courses:ct30a5000:assignment4notes [2012/11/06 20:41]
julaakko
courses:ct30a5000:assignment4notes [2012/11/06 21:16] (current)
julaakko
Line 3: Line 3:
 This page contains notes about assignment 4 as well as some corrections to common problems. This page contains notes about assignment 4 as well as some corrections to common problems.
  
 +===== Comments =====
  
 +^ Student number ^ Comment ^
 +| 0312399 | No need to separately set multicast interface, the struct ip_mreq should contain it and all can be set with one socket option when joining to multicast group. Queries (WHOIS) and replies (HOSTINFO) are sent from different ports (query using multicast port, reply using game port). The clients reply to queries but the advertisement of games does not work →  the games cannot be shown on clients (your or others). The game packet checks do not seem to be working well.  Game somewhat works with other clients. |
 +| 0316023 | Sometimes the first placement message goes to wrong peer – that accepts it but hasn't started the game and the mark stays in the grid. The marks show as reverse, if first player puts '​o'​ then peer sees it as '​x'​. The game starting detection does not seem to be always working. Client does not remove itself from multicast. The indexes are handled in opposite direction (x → y & y → x) | 
 +| 0342246 | Client does not drop multicast membership. Only a stub implementation. Otherwise multicast part works ok. |
 +| 0342327 | No game implementation but the multicast part seems to be working and some data can be sent to opened sockets. |
 +| 0358454 | You cannot use strlen() to get a message length that has no characters, the WHOIS message contains only the 0 (NULL) and strlen() would return 0. No game implementation and the multicast somewhat works. |
 +| 0377037 | Automatic game selection makes this a bit confusing and hard to test, user should select it. There are lots of code here, most of it is not used, why you commit all of these? The client replies to WHOIS if playing a game. Game can be started but functionality seems to stop there. Game ends with core dump when calling quit. |
 +| 0378227 | Some warnings indicating that it will crash at some point. Invalid binary name. Invalid parameters. Does not follow the specification ​ at all. |
 +| 0404450 | The player who connects should have the first turn but otherwise everything works as it should. |
 +| 0404489 | Works ok, except the game can be crashes with too short placement packages. |
  
 +===== Multicast =====
 +
 +Here is a way to use ''​getaddrinfo()''​ and ''​getnameinfo()''​ with multicast addresses.
 +
 +<code c>
 +
 +// Sockets
 +int multicastsocket = -1, peersocket = -1;
 +
 +int in_addr_length = sizeof(struct in_addr);
 +
 +// For storing addresses and ports
 +char hostbuffer[NI_MAXHOST] = {0}; // Set the multicast address here
 +char portbuffer[NI_MAXSERV] = {0}; // Set the port here
 +char peerportbuffer[NI_MAXSERV] = {0}; // Set the port for incoming connections here
 +
 +char buffer[MESSAGELENGTH] = {0};
 +
 +// For getaddrinfo()
 +struct addrinfo *result = NULL, *iter = NULL;
 +struct addrinfo hints = { .ai_flags = AI_NUMERICHOST,​
 +                          .ai_family = AF_INET,
 +                          .ai_socktype = SOCK_DGRAM,
 +                          .ai_protocol = IPPROTO_UDP};​
 +
 +// The multicast address is stored here
 +struct sockaddr mc_sending_addr:​
 +memset(&​mc_sending_addr,​0,​sizeof(mc_sending_addr));​
 +
 +// Who sent us data
 +struct sockaddr receiving_addr;​
 +memset(&​receiving_addr,​0,​sizeof(receiving_addr));​
 +
 +// Multicast structure
 +struct ip_mreq multicast;
 +memset(&​multicast,​0,​sizeof(multicast));​
 +
 +// First fill multicast & sending address
 +if(getaddrinfo(hostbuffer,​portbuffer,&​hints,&​result)) perror("​Cannot resolve multicast address"​);​
 +
 +for(iter = result; iter != NULL; iter = iter->​ai_next) {
 +   ​
 +  // Set the multicast address (since we need the struct in_addr this is not so portable...)
 +  memcpy(&​multicast.imr_multiaddr,​ &​((struct sockaddr_in*)iter->​ai_addr)->​sin_addr,​in_addr_length);​
 +   ​
 +  // Send address - the multicast address
 +  memcpy(&​mc_sending_addr,​iter->​ai_addr,​iter->​ai_addrlen);​
 +}
 +freeaddrinfo(result);​
 +
 +// Then get the listening address (any), using the port defined for multicast
 +hints.ai_flags = AI_PASSIVE;
 +if(getaddrinfo(NULL,​portbuffer,&​hints,&​result)) perror("​Cannot get listening address"​);​
 +
 +for(iter = result; iter != NULL; iter = iter->​ai_next) {
 +   ​
 +  // Create socket and bind it
 +  if((multicastsocket = socket(iter->​ai_family,​iter->​ai_socktype,​iter->​ai_protocol)) < 0) perror("​Cannot create socket"​);​
 +  if(bind(multicastsocket,​iter->​ai_addr,​iter->​ai_addrlen)) perror("​Cannot bind to address"​);​
 +   ​
 +  // Set the any-address as interface for multicast
 +  memcpy(&​multicast.imr_interface,&​((struct sockaddr_in*)iter->​ai_addr)->​sin_addr,​sin_length);​
 +}
 +freeaddrinfo(result);​
 +
 +// And with same approach get the peer listening address, using the peer port (and previously set hints with AI_PASSIVE)
 +if(getaddrinfo(NULL,​peerportbuffer,&​hints,&​result)) perror("​Cannot get peer listening address"​);​
 +
 +for(iter = result; iter != NULL; iter = iter->​ai_next) {
 +  // Create socket and bind it
 +  if((peersocket = socket(iter->​ai_family,​iter->​ai_socktype,​iter->​ai_protocol)) < 0) perror("​Cannot create socket"​);​
 +  if(bind(peersocket,​iter->​ai_addr,​iter->​ai_addrlen)) perror("​Cannot bind to address"​);​
 +}
 +freeaddrinfo(result);​
 +
 +// Finally we can join (add membership) to multicast group
 +if(setsockopt(multicastsocket,​IPPROTO_IP,​IP_ADD_MEMBERSHIP,&​multicast,​sizeof(multicast)) < 0)
 +  perror("​Error joining multicastgroup"​);​
 +  ​
 +...
 +
 +// when we receive something from multicast
 +n = recvfrom(multicastsocket,​buffer,​MESSAGELENGTH,​0,&​receiving_addr,&​length);​
 +
 +// Get the address
 +if((getnameinfo((struct sockaddr*)&​recv_addr,​length,​hostbuffer,​NI_MAXHOST,​portbuffer,​NI_MAXSERV,​NI_NUMERICSERV)) != 0) perror("​Cannot get IP");
 +
 +// 1. Get the port from message
 +// 2. Replace the port in portbuffer with the one in the message
 +// 3. Use getaddrinfo to fill in struct
 +hints.ai_flags = 0;
 +if(getaddrinfo(NULL,​portbuffer,&​hints,&​result)) perror("​Cannot fill peer address"​);​
 +
 +// 4. Use the struct sockaddr in the result to send data to new port on that host
 +
 +...
 +
 +// And drop the membership before quitting
 +if(setsockopt(multicastsocket,​IPPROTO_IP,​IP_DROP_MEMBERSHIP,&​multicast,​sizeof(multicast)) < 0)
 +  perror("​Error leaving multicastgroup"​);​
 +</​code>​