CComUDPLayer.cpp 12.4 KB
Newer Older
1
#include "include/CComUDPLayer.h"
2
#ifndef WIN32
3 4
#include <sys/ioctl.h>
#include <net/if.h>
5 6 7 8 9 10 11 12 13 14 15 16 17 18
#else
#include <winsock.h>
#include <winsock2.h>
#include "include/inet_pton.h"
#include <windows.h>
#define socklen_t int
#endif
#include <string>
#include <string.h>
#include <iostream>
#include <fstream>
#ifndef WIN32
#include <ifaddrs.h>
#endif
19

20
using namespace std;
21 22 23 24

pthread_mutex_t server_mutex = PTHREAD_MUTEX_INITIALIZER;
/* UDP SERVER*/
CComUDPServer::~CComUDPServer() {
25
  pthread_cancel(thread);
26
#ifndef WIN32
27
  close(this->ServerSocket);
28
#else
29 30
  closesocket(this->ServerSocket);
  WSACleanup();
31
#endif
32 33 34
};

void * CComUDPServer::UDP_server_thread(void *parm) {
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
  UDP_server_thread_parm_t *p = (UDP_server_thread_parm_t*)parm;
  struct sockaddr_in cliaddr; /* Client address */
  socklen_t len = sizeof(cliaddr);
  char buffer[MAXINDSIZE];
  int recvMsgSize;

  for(;;) {/*forever loop*/
    /*receive UDP datagrams from client*/
    if ((recvMsgSize = recvfrom(p->Socket,buffer,MAXINDSIZE,0,(struct sockaddr *)&cliaddr,&len)) < 0) {
      printf("\nError recvfrom()\n");
    }
    else{
      if(p->debug) {
        buffer[recvMsgSize] = 0;
        printf("\nData entry[%i]\n",*p->nb_data);
        printf("Received the following:\n");
        printf("%s\n",buffer);
        printf("%d\n",(int)strlen(buffer));
      }
      printf("    Received individual from %s:%d\n", inet_ntoa(cliaddr.sin_addr), ntohs(cliaddr.sin_port));
      pthread_mutex_lock(&server_mutex);
      /*process received data */
57
      RECV_DATA buffer_copy;
58
      memmove(buffer_copy.data,buffer,sizeof(char)*MAXINDSIZE);
59
      //  printf("address %p\n",(p->data));
60 61
      p->data.push_back(buffer_copy);
      (*p->nb_data)++;
62
      //  printf("address %p\n",(p->data));
63 64 65 66 67 68
      pthread_mutex_unlock(&server_mutex);
      /*reset receiving buffer*/
      memset(buffer,0,MAXINDSIZE);
    }
  }
  return 0;
69 70
};

71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
CComUDPServer::CComUDPServer(unsigned short port,int dg) {
  struct sockaddr_in ServAddr; /* Local address */
  debug = dg;
  this->nb_data = 0;
#ifdef WIN32
  WSADATA wsadata;
  if (WSAStartup(MAKEWORD(1,1), &wsadata) == SOCKET_ERROR) {
    printf("Error creating socket.");
    exit(1);
  }
#endif

  /* Create socket for incoming connections */
  if ((this->ServerSocket =  socket(AF_INET,SOCK_DGRAM,0)) < 0) {
    printf("%d\n",socket(AF_INET,SOCK_DGRAM,0));
    printf("Socket create problem.\n"); exit(1);
  }
88

89
  /*int bufsize = 50000;
90 91 92 93
    socklen_t optlen = sizeof(bufsize);
    setsockopt(this->ServerSocket, SOL_SOCKET, SO_RCVBUF, &bufsize, sizeof(int));
    getsockopt(this->ServerSocket, SOL_SOCKET, SO_RCVBUF, &bufsize, &optlen);
    printf("buf size %d\n",bufsize);*/
94

95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
  /* Construct local address structure */
  memset(&ServAddr, 0, sizeof(ServAddr));   /* Zero out structure */
  ServAddr.sin_family = AF_INET;                /* Internet address family */
  ServAddr.sin_addr.s_addr = htonl(INADDR_ANY); /* Any incoming interface */
  ServAddr.sin_port = htons(port);              /* Local port */

  /* Bind to the local address */
  if (bind(ServerSocket, (struct sockaddr *) &ServAddr, sizeof(ServAddr)) < 0) {
    printf("Can't bind to given port number. Try a different one.\n"); exit(1);
  }

  //UDP_server_thread_parm_t   *parm;
  this->parm = (UDP_server_thread_parm_t*)malloc(sizeof(UDP_server_thread_parm_t));
  this->parm->Socket = ServerSocket;
  this->parm->ServAddr = ServAddr;
  this->parm->nb_data = &this->nb_data;
  this->parm->data = this->data;
  this->parm->debug = this->debug;

  if(pthread_create(&thread, NULL, &CComUDPServer::UDP_server_thread, (void *)this->parm) != 0) {
    printf("pthread create failed. exiting\n"); exit(1);
  }
117 118 119
};

void CComUDPServer::read_data_lock() {
120
  pthread_mutex_lock(&server_mutex);
121 122 123
};

void CComUDPServer::read_data_unlock() {
124
  pthread_mutex_unlock(&server_mutex);
125
};
126

127 128 129 130 131 132
/*UDP SERVER*/

/*UDP CLIENT*/
CComUDPClient::~CComUDPClient() {};

CComUDPClient::CComUDPClient(unsigned short port, const char *ip,int dg){
133 134 135 136 137 138
  this->debug = dg;
  /* Construct local address structure */
  memset(&ServAddr, 0, sizeof(ServAddr));   /* Zero out structure */
  ServAddr.sin_family = AF_INET;            /* Internet address family */
  ServAddr.sin_addr.s_addr = inet_addr(ip);     /* Any incoming interface */
  ServAddr.sin_port = htons(port);          /* Local port */
139 140
};

141
CComUDPClient::CComUDPClient(struct sockaddr_in* addr, int dg){
142 143
  this->debug = dg;
  memcpy(&ServAddr, addr, sizeof(ServAddr));
144 145
}

146
void CComUDPClient::CComUDP_client_send(char *individual) {
147 148 149 150 151 152 153 154 155 156
#ifdef WIN32
  WSADATA wsadata;
  if (WSAStartup(MAKEWORD(1,1), &wsadata) == SOCKET_ERROR) {
    printf("Error creating socket.");
    exit(1);
  }
#endif
  if ((this->Socket = socket(AF_INET,SOCK_DGRAM,0)) < 0) {
    printf("Socket create problem."); exit(1);
  }
157

158
  int sendbuff=35000;
159
#ifdef WIN32
160
  setsockopt(this->Socket, SOL_SOCKET, SO_SNDBUF, (char*)&sendbuff, sizeof(sendbuff));
161
#else
162
  setsockopt(this->Socket, SOL_SOCKET, SO_SNDBUF, &sendbuff, sizeof(sendbuff));
163 164
#endif

165 166 167 168 169 170 171 172 173
  if(strlen(individual) < (unsigned)sendbuff ) { 
    int n_sent = sendto(this->Socket,individual,strlen(individual),0,(struct sockaddr *)&this->ServAddr,sizeof(this->ServAddr));
    //int n_sent = sendto(this->Socket,t,strlen(individual),0,(struct sockaddr *)&this->ServAddr,sizeof(this->ServAddr));
    if( n_sent < 0){
      printf("Size of the individual %d\n", (int)strlen(individual));
      perror("! Error while sending the message !");
    }
  }
  else {fprintf(stderr,"Not sending individual with strlen(): %i, MAX msg size %i\n",(int)strlen(individual), sendbuff);}
174
#ifndef WIN32
175
  close(this->Socket);
176
#else
177 178
  closesocket(this->Socket);
  WSACleanup();
179
#endif
180 181 182
};

std::string CComUDPClient::getIP(){
183
  return inet_ntoa(this->ServAddr.sin_addr);
184
}
185 186

int CComUDPClient::getPort(){
187
  return ntohs(this->ServAddr.sin_port);
188 189
}

190
/*UDP CLIENT*/
191 192
#ifndef WIN32
bool isLocalMachine(const char*  address, int clientPort, int serverPort){
193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
  struct ifaddrs * ifAddrStruct=NULL; 
  struct ifaddrs * ifa=NULL;
  void * tmpAddrPtr=NULL;

  getifaddrs(&ifAddrStruct);
  for (ifa = ifAddrStruct; ifa != NULL; ifa = ifa->ifa_next) {
    if (ifa ->ifa_addr->sa_family==AF_INET) { // check it is IP4
      // is a valid IP4 Address
      tmpAddrPtr=&((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
      char addressBuffer[INET_ADDRSTRLEN];
      inet_ntop(AF_INET, tmpAddrPtr, addressBuffer, INET_ADDRSTRLEN);
      //printf("%s IP Address %s\n", ifa->ifa_name, addressBuffer); 

      if((strcmp(address,addressBuffer)==0)
          && serverPort==clientPort)
        return true;
    }    
  }

  if(ifAddrStruct!=NULL) freeifaddrs(ifAddrStruct);

  return false;
215 216 217 218
}
#endif

/*bool isLocalMachine(const char*  address, int clientPort, int serverPort){
219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234
  char hostname[128];
  struct in_addr ipv4addr;
  struct hostent *he;
  struct ifaddrs * ifAddrStruct=NULL; 
  struct ifaddrs * ifa=NULL;
  void * tmpAddrPtr=NULL;
//int size;

//retrieve local host name
gethostname(hostname, sizeof(hostname));
///printf("Local host name %s\n",hostname);

//retrieve ip's host name

//inet_pton(AF_INET, address, &ipv4addr);
inet_aton(address, &ipv4addr);
235
#ifdef WIN32
236 237 238 239 240 241 242 243
unsigned long ip = inet_addr(address);
//printf("IP : %d\n",ip);
//printf("Adresse : %s\n",address);
he = gethostbyaddr((const char*)&ip, 4, 0);
if(he == NULL){
printf("*** WARNING ***\nCouldn't find host, are you sure the host at %s exists or the local machine is connected to a network ?\n", address);
return false;
}
244
#else
245 246 247 248 249 250 251
//he = gethostbyaddr((const char*)address, sizeof address, AF_INET);
he = gethostbyaddr((void *)&ipv4addr, sizeof ipv4addr, AF_INET);
if(he == NULL){
// herror("PROB\n");
//printf("**** WARNING ***\nCouldn't find host, are you sure the host at %s exists or the local machine is connected to a network ?\n", address);
return false;
}
252
#endif
253 254 255 256 257 258 259 260 261 262
//printf("Host name:%s\n",he->h_name);
//printf("Client Port:%d\n",clientPort);
//printf("Server Port:%d\n",serverPort);

if((strcmp(hostname,he->h_name)==0
|| strcmp(he->h_name,"localhost")==0)
&& serverPort==clientPort)
return true;
else
return false;
263 264 265 266 267 268 269 270 271 272 273
}*/

/**
 * Check the validity of an IP line. This line should have the form like : 1.2.3.4:5 (ip:port).
 *
 * @ARG line : the line containing the ip and port description.
 * @ @RETURN : boolean containing the result of the regex match.
 *
 */
//www.dreamincode.net/forums/topic/168930-valid-or-not-for-a-ip-address/
bool checkValidLine(string line){
274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296
  const char* ligne = line.c_str();
  char* holder = (char*)malloc(strlen(ligne)+1);
  strcpy(holder,ligne);
  char* address = strtok(holder, ":");
  char* port = strtok(NULL,":");

  //printf("IP %s\n",address);
  //printf("port %s\n",port);

  //Check if there is an IP and a port
  if(address==NULL || port==NULL){
    cout << "*** WARNING ***\nThere is a problem with the following IP: " << line << "\t===> IGNORING IT\n";
    return false;
  }

  //Check if it is a valid ip
  char* byte = strtok(address,".");
  int nibble = 0, octets = 0, flag = 0;
  while(byte != NULL){
    octets++;
    if(octets>4){
      cout << "*** WARNING ***\nThere is a problem with the following IP: " << line << "\t===> IGNORING IT\n";
      return false;
297
    }
298 299 300 301
    nibble = atoi(byte);
    if((nibble<0)||(nibble>255)){
      cout << "*** WARNING ***\nThere is a problem with the following IP: " << line << "\t===> IGNORING IT\n";
      return false;
302
    }
303 304 305
    string s = byte;
    for(unsigned int i=0; i<s.length(); i++){
      if(!isdigit(s[i])){
306 307
        cout << "*** WARNING ***\nThere is a problem with the following IP: " << line << "\t===> IGNORING IT\n";
        return false;
308
      }
309
    }
310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327
    byte = strtok(NULL,".");
  }
  if(flag || octets<4){
    cout << "*** WARNING ***\nThere is a problem with the following IP: " << line << "\t===> IGNORING IT\n";
    return false;
  }

  //Check if it is a valid port
  nibble = atoi(port);
  if(nibble<0){
    cout << "*** WARNING ***\nThere is a problem with the following IP: " << line << "\t===> IGNORING IT\n";
    return false;
  }
  string s = port;
  for(unsigned int i=0; i<s.length(); i++){
    if(!isdigit(s[i])){
      cout << "*** WARNING ***\nThere is a problem with the following IP: " << line << "\t===> IGNORING IT\n";
      return false;
328
    }
329
  }
330

331 332
  free(holder);
  return true;
333 334 335 336 337 338 339 340 341 342 343 344
}

/**
 * Parse an IP line. This line should have the form like : 1.2.3.4:5 (ip:port).
 *
 * @ARG line : the line containing the ip and port description.
 * @ @RETURN : a sockaddr_in structure, containing the corresponding ip.
 *
 * @TODO : This function should support the use of naming service instead of just ip adress.
 *         Is was the case in older version of EASEA.
 */
struct sockaddr_in parse_addr_string(const char* line){
345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362
  char tmp_line[512];
  char* res_field_ptr;
  strncpy(tmp_line,line,512);
  struct sockaddr_in addr;
  unsigned short port;

  res_field_ptr = strtok(tmp_line,":");
  //printf("addr : %s\n",res_field_ptr);
  addr.sin_family = AF_INET;            /* Internet address family */
  addr.sin_addr.s_addr = inet_addr(res_field_ptr);     /* Any incoming interface */

  char* endptr;
  res_field_ptr = strtok(NULL,":");
  port = strtol(res_field_ptr,&endptr,10);
  addr.sin_port = htons(port);          /* Local port */
  //printf("addr : %s\n",res_field_ptr);

  return addr;
363 364 365 366 367 368 369 370 371 372 373 374 375
}

/**
 * Load an "ip" file and create a sockaddr_in per line.
 *
 * @ARG file : a char* containing a patch to the ip file.
 * @ARG no_client : the number of ip loaded from the ip file.
 *
 * @RETURN : an array of *(p_no_client) CComUDPClient related to each ip file line.
 *
 * @TODO : ip file line shouldn't do more than 512 char. no line shouldn't be more than 128.
 */
CComUDPClient** parse_file(const char* file_name, unsigned* p_no_client, int portServer){
376 377 378 379 380 381 382 383 384 385 386 387
  //char* tmp_line = new char[512];
  string tmp_line;
  //FILE* ip_file = fopen(file_name,"r");
  ifstream ip_file(file_name);
  //size_t n = 512;
  unsigned no_client = 0;
  struct sockaddr_in* client_addr = new struct sockaddr_in[128];

  //while(getline(&tmp_line,&n,ip_file)>0){
  while(getline(ip_file, tmp_line)){
    if(checkValidLine(tmp_line)){
      struct sockaddr_in tmpClient = parse_addr_string(tmp_line.c_str());
388
#ifndef WIN32
389 390 391
      if(!isLocalMachine(inet_ntoa(tmpClient.sin_addr), ntohs(tmpClient.sin_port), portServer)){
        client_addr[no_client++] = tmpClient;
      }
392
#else
393
      client_addr[no_client++] = tmpClient;
394 395
#endif
    }
396 397 398 399 400 401 402 403 404 405 406 407
  }

  // copy the client_addr array in a fitted array. 
  CComUDPClient** clients = new CComUDPClient*[no_client];
  for( unsigned i=0 ; i<no_client ; i++ ){
    clients[i] = new CComUDPClient(&client_addr[i],0);
  }

  (*p_no_client) = no_client;
  //delete[] tmp_line;
  delete[] client_addr;
  return clients;
408
}