0

I want to build a chat application without server (I don't know what is called maybe it's peer-to-peer chat) using Winsock.

I just learned from this two source code :

//==================================================== file = udpServer.c =====
//=  A message "server" program to demonstrate sockets programming            =
//=============================================================================
//=  Notes:                                                                   =
//=    1) This program conditionally compiles for Winsock and BSD sockets.    =
//=       Set the initial #define to WIN or BSD as appropriate.               =
//=    2) This program serves a message to program udpClient running on       =
//=       another host.                                                       =
//=    3) The steps #'s correspond to lecture topics.                         =
//=---------------------------------------------------------------------------=
//=  Example execution: (udpServer and udpClient running on host 127.0.0.1)   =
//=    Waiting for recvfrom() to complete...                                  =
//=    IP address of client = 127.0.0.1  port = 55476)                        =
//=    Received from client: Test message from CLIENT to SERVER               =
//=---------------------------------------------------------------------------=
//=  Build: bcc32 udpServer.c or cl udpServer.c wsock32.lib for Winsock       =
//=         gcc udpServer.c -lsocket -lnsl for BSD                            =
//=---------------------------------------------------------------------------=
//=  Execute: udpServer                                                       =
//=---------------------------------------------------------------------------=
//=  Author: Ken Christensen                                                  =
//=          University of South Florida                                      =
//=          WWW: http://www.csee.usf.edu/~christen                           =
//=          Email: christen@csee.usf.edu                                     =
//=---------------------------------------------------------------------------=
//=  History:  KJC (08/02/08) - Genesis (from server1.c)                      =
//=            KJC (09/07/09) - Minor clean-up                                =
//=            KJC (09/22/13) - Minor clean-up to fix warnings                =
//=============================================================================
#define  WIN                // WIN for Winsock and BSD for BSD sockets

//----- Include files --------------------------------------------------------
#include <stdio.h>          // Needed for printf()
#include <string.h>         // Needed for memcpy() and strcpy()
#include <stdlib.h>         // Needed for exit()
#ifdef WIN
  #include <windows.h>      // Needed for all Winsock stuff
#endif
#ifdef BSD
  #include <sys/types.h>    // Needed for sockets stuff
  #include <netinet/in.h>   // Needed for sockets stuff
  #include <sys/socket.h>   // Needed for sockets stuff
  #include <arpa/inet.h>    // Needed for sockets stuff
  #include <fcntl.h>        // Needed for sockets stuff
  #include <netdb.h>        // Needed for sockets stuff
#endif

//----- Defines --------------------------------------------------------------
#define  PORT_NUM   1050    // Arbitrary port number for the server

//===== Main program =========================================================
int main()
{
#ifdef WIN
  WORD wVersionRequested = MAKEWORD(1,1);       // Stuff for WSA functions
  WSADATA wsaData;                              // Stuff for WSA functions
#endif
  int                  server_s;        // Server socket descriptor
  struct sockaddr_in   server_addr;     // Server Internet address
  struct sockaddr_in   client_addr;     // Client Internet address
  struct in_addr       client_ip_addr;  // Client IP address
  int                  addr_len;        // Internet address length
  char                 out_buf[4096];   // Output buffer for data
  char                 in_buf[4096];    // Input buffer for data
  int                  retcode;         // Return code

#ifdef WIN
  // This stuff initializes winsock
  WSAStartup(wVersionRequested, &wsaData);
#endif

  // >>> Step #1 <<<
  // Create a socket
  //   - AF_INET is Address Family Internet and SOCK_DGRAM is datagram
  server_s = socket(AF_INET, SOCK_DGRAM, 0);
  if (server_s < 0)
  {
    printf("*** ERROR - socket() failed \n");
    exit(-1);
  }

  // >>> Step #2 <<<
  // Fill-in my socket's address information
  server_addr.sin_family = AF_INET;                 // Address family to use
  server_addr.sin_port = htons(PORT_NUM);           // Port number to use
  server_addr.sin_addr.s_addr = htonl(INADDR_ANY);  // Listen on any IP address
  retcode = bind(server_s, (struct sockaddr *)&server_addr,
    sizeof(server_addr));
  if (retcode < 0)
  {
    printf("*** ERROR - bind() failed \n");
    exit(-1);
  }

  // >>> Step #3 <<<
  // Wait to receive a message from client
  printf("Waiting for recvfrom() to complete... \n");
  addr_len = sizeof(client_addr);
  retcode = recvfrom(server_s, in_buf, sizeof(in_buf), 0,
    (struct sockaddr *)&client_addr, &addr_len);
  if (retcode < 0)
  {
    printf("*** ERROR - recvfrom() failed \n");
    exit(-1);
  }

  // Copy the four-byte client IP address into an IP address structure
  memcpy(&client_ip_addr, &client_addr.sin_addr.s_addr, 4);

  // Print an informational message of IP address and port of the client
  printf("IP address of client = %s  port = %d) \n", inet_ntoa(client_ip_addr),
    ntohs(client_addr.sin_port));

  // Output the received message
  printf("Received from client: %s \n", in_buf);

  // >>> Step #4 <<<
  // Send to the client using the server socket
  strcpy(out_buf, "This is a reply message from SERVER to CLIENT");
  retcode = sendto(server_s, out_buf, (strlen(out_buf) + 1), 0,
    (struct sockaddr *)&client_addr, sizeof(client_addr));
  if (retcode < 0)
  {
    printf("*** ERROR - sendto() failed \n");
    exit(-1);
  }

  // >>> Step #5 <<<
  // Close all open sockets
#ifdef WIN
  retcode = closesocket(server_s);
  if (retcode < 0)
  {
    printf("*** ERROR - closesocket() failed \n");
    exit(-1);
  }
#endif
#ifdef BSD
  retcode = close(server_s);
  if (retcode < 0)
  {
    printf("*** ERROR - close() failed \n");
    exit(-1);
  }
#endif

#ifdef WIN
  // This stuff cleans-up winsock
  WSACleanup();
#endif

  // Return zero and terminate
  return(0);
}

and

//=========================================== file = udpClientBroadcast.c =====
//=  A message "client" program to demonstrate sockets programming            =
//=   - This is udpClient.c modified to use broadcast                         =
//=============================================================================
//=  Notes:                                                                   =
//=    1) This program conditionally compiles for Winsock and BSD sockets.    =
//=       Set the initial #define to WIN or BSD as appropriate.               =
//=    2) This program needs udpServer to be running on another host.         =
//=       Program udpServer must be started first.                            =
//=---------------------------------------------------------------------------=
//=  Example execution: (udpServer and udpClientBroadcast on host 127.0.0.1)  =
//=    Received from server: This is a reply message from SERVER to CLIENT    =
//=---------------------------------------------------------------------------=
//=  Build: Windows: Borland: bcc32 udpClientBroadcast.c                      =
//=                  Visual C cmd line: cl udpClientBroadcast.c wsock32.lib   =
//=                  MinGW: gcc udpClientBroadcast.c -lws2_32                 =
//=         Unix: gcc udpClientBroadcast.c -lnsl -o udpClientBroadcast        =
//=---------------------------------------------------------------------------=
//=  Execute: udpClientBroadcast                                              =
//=---------------------------------------------------------------------------=
//=  Author: Ken Christensen                                                  =
//=          University of South Florida                                      =
//=          WWW: http://www.csee.usf.edu/~christen                           =
//=          Email: christen@csee.usf.edu                                     =
//=---------------------------------------------------------------------------=
//=  History:  KJC (04/10/10) - Genesis (from udpClient.c)                    =
//=============================================================================
#define  WIN                // WIN for Winsock and BSD for BSD sockets

//----- Include files ---------------------------------------------------------
#include <stdio.h>          // Needed for printf()
#include <string.h>         // Needed for memcpy() and strcpy()
#ifdef WIN
  #include <windows.h>      // Needed for all Winsock stuff
#endif
#ifdef BSD
  #include <sys/types.h>    // Needed for sockets stuff
  #include <netinet/in.h>   // Needed for sockets stuff
  #include <sys/socket.h>   // Needed for sockets stuff
  #include <arpa/inet.h>    // Needed for sockets stuff
  #include <fcntl.h>        // Needed for sockets stuff
  #include <netdb.h>        // Needed for sockets stuff
#endif

//----- Defines ---------------------------------------------------------------
#define  PORT_NUM           1050  // Port number used

//===== Main program ==========================================================
void main(void)
{
#ifdef WIN
  WORD wVersionRequested = MAKEWORD(1,1);       // Stuff for WSA functions
  WSADATA wsaData;                              // Stuff for WSA functions
#endif
  int                  client_s;        // Client socket descriptor
  struct sockaddr_in   server_addr;     // Server Internet address
  int                  addr_len;        // Internet address length
  char                 out_buf[4096];   // Output buffer for data
  char                 in_buf[4096];    // Input buffer for data
  int                  retcode;         // Return code
  int                  iOptVal;         // Socket option value
  int                  iOptLen;         // Socket option length

#ifdef WIN
  // This stuff initializes winsock
  WSAStartup(wVersionRequested, &wsaData);
#endif

  // Create a socket
  client_s = socket(AF_INET, SOCK_DGRAM, 0);
  if (client_s < 0)
  {
    printf("*** ERROR - socket() failed \n");
    exit(-1);
  }

  // Fill-in server socket's address information
  server_addr.sin_family = AF_INET;                 // Address family to use
  server_addr.sin_port = htons(PORT_NUM);           // Port num to use
  server_addr.sin_addr.s_addr = inet_addr(INADDR_ANY); // Need this for Broadcast

  // Set socket to use MAC-level broadcast
  iOptVal = 1;
  iOptLen = sizeof(int);
  setsockopt(client_s, SOL_SOCKET, SO_BROADCAST, (char*)&iOptVal, iOptLen);

  // Assign a message to buffer out_buf
  strcpy(out_buf, "Test message from CLIENT to SERVER");

  // Now send the message to server.
  retcode = sendto(client_s, out_buf, (strlen(out_buf) + 1), 0,
    (struct sockaddr *)&server_addr, sizeof(server_addr));
  if (retcode < 0)
  {
    printf("*** ERROR - sendto() failed \n");
    exit(-1);
  }

  // Wait to receive a message
  addr_len = sizeof(server_addr);
  retcode = recvfrom(client_s, in_buf, sizeof(in_buf), 0,
    (struct sockaddr *)&server_addr, &addr_len);
  if (retcode < 0)
  {
    printf("*** ERROR - recvfrom() failed \n");
    exit(-1);
  }

  // Output the received message
  printf("Received from server: %s \n", in_buf);

  // Close all open sockets
#ifdef WIN
  retcode = closesocket(client_s);
  if (retcode < 0)
  {
    printf("*** ERROR - closesocket() failed \n");
    exit(-1);
  }
#endif
#ifdef BSD
  retcode = close(client_s);
  if (retcode < 0)
  {
    printf("*** ERROR - close() failed \n");
    exit(-1);
  }
#endif

#ifdef WIN
  // This stuff cleans-up winsock
  WSACleanup();
#endif
}

These two codes works fine for me, however these are 2 applications and I just want 1 application that can act as a server and also as a client.

So I combine these two source codes into one using a thread.

Again, the program works, but the listener socket accepts the connection from the broadcasted message.

What I want is the listener to block the incoming connection from the loopback address.

How to do that?

edit :

example I have 2 computers, one is A(192.168.1.100) and the other is B(192.168.1.101), when i run the program computer A receive the message from itself, what I want is A receive only any except A.

EDIT 27/01/2014 :

after a few days of searching i think i wasn't be able to find the solution to my problem.
however, there's an alternate way to make it possible.

first step is to get your local computer IP Address.

second step is to construct your message before it is send for example format is "ipAddress_messageToSend".

third step create function to process incoming message from recvfrom() function that will split the incoming message by "_"
so that you'll have two dimensional arrays, the first row is for IP Address where this message come from and the second is the message itself.

fourth step, you'll have to do comparation between incoming message IP Address and your computer IP Address.
you can use this code below to obtain an IP Address.

char ac[80];
gethostname(ac, sizeof(ac));
struct hostent *phe = gethostbyname(ac);
struct in_addr addr;
memcpy(&addr, phe->h_addr_list[0], sizeof(struct in_addr));
printf("IP Address is : %s\n", inet_ntoa(addr));

fifth step when the IP is compared and they're same do nothing, if not then do what you want to do.

hope this will help you all

Rizky
  • 414
  • 6
  • 20
  • Question: how do you know you are receiving from loopback if? Just to clarify: is it possible what you want is that server not receive messages from itself? – rodolk Jan 23 '14 at 20:39
  • i'm sorry, i have mistaken, it is not loopback but it receive the message broadcasted from itself. yes that is, how to make the server refuse the message from the itself – Rizky Jan 24 '14 at 06:45
  • Please edit that correction into your question and your title, if you want an answer. At present neither makes sense. – user207421 Jan 24 '14 at 11:52
  • @rizkynggakool, I don't agree with the one that downvoted your question. Too extreme. It's an interesting question and the topic you are working on presents many problems of distributed systems. So I upvoted the question. Just please make the corrections so that others can benefit from the question and the answer. – rodolk Jan 25 '14 at 11:55
  • @rodolk thank you, i think i have another solution for my problem check the edit section. i'm not good at english and maybe they're get it the wrong mean, that's why i oftenly get down voted by people. – Rizky Jan 27 '14 at 14:40

2 Answers2

1

Based on your responses to the comments, the problem is that you the server is receiving messages from the client running in the same node. You want the server to filter out those messages sent out by itself.

In order to achieve that the servers needs:

1-Before beginning, server detects its own interfaces and IP addresses. Winsock should have a function like getifaddrs. Here there is a link of a similar question related to Windows: Get the IP Address of local computer You add the list of local addresses in a list or any other data structure.

This is a similar problem for UNIX: Lazarus: How to list all the available network connection on a system?

2-Whenever a message is received, after recvfrom, the server compares client_addr.sin_addr.s_addr with the list of own addresses to detect its own messages. Then filter out those messages.

I don't think it is possible to filter out messages from itself in a different way, in a simple way. In Linux you could filter out messages from itself using iptables and I don't know if Windows has a similar mechanism.

Other recommendations: 1-You should use multicast for your chat application instead of broadcast. Then systems not running the chat application are not affected by the chat messages.

2-You could complement the multicast or broadcast mechanism with a method that assures every peer can read all messages. Broadcast and multicast messages could be lost by a peer. There are various ways to implement it. But that's the next step once you solve this question.

Community
  • 1
  • 1
rodolk
  • 5,606
  • 3
  • 28
  • 34
0

You're getting data from loopback because you're binding to INADDR_ANY.

See this thread for a more complete explanation/example: Using a specific network interface for a socket in windows

Community
  • 1
  • 1
cioffstix
  • 81
  • 2
  • yes, so what value should i use? i'm sorry but i'm confused by the link you gave me. – Rizky Jan 24 '14 at 06:48
  • i want the server to accept all except the loopback address and the ip of the program itself – Rizky Jan 24 '14 at 06:49