Exemple #1
0
int peisk_bluetoothReceiveIncomming(struct PeisConnection *connection,struct PeisPackage *package) {
  int status;
  double t0, t1;

  static float lastReceive=0.0; /* For debugging only */

  errno=0;
  t0 = peisk_gettimef();
  status=recv(connection->connection.bluetooth.socket,(void*)package,sizeof(PeisPackage),MSG_NOSIGNAL);
  t1 = peisk_gettimef();
  if(t1 - t0 > 0.1) {
    printf("Receive took %.3fs\n",t1-t0);
  }
  if(errno == EAGAIN || status == 0) return 0;       /* Nothing received, come back later */

  if(status > 0) {
    peisk_logTimeStamp(stdout);
    printf("BT receive: %d bytes, sock: %d ",status,connection->connection.bluetooth.socket);
    /*peisk_hexDump(package,status);*/
    peisk_printNetPackageInfo(package);
    lastReceive = peisk_timeNow;
  }

  if(errno == EPIPE || status == -1) {          /* Error - close socket */
    if(1 || peisk_printLevel & PEISK_PRINT_CONNECTIONS) {
      peisk_logTimeStamp(stdout);
      printf("peisk: warning - error EPIPE in BT receive, closing socket status: %d\n",status);
      perror("");
      printf("Time since last read: %.1fs\n",peisk_timeNow - lastReceive);
    }
    peisk_closeConnection(connection->id);
    return 0;
  }
  if(status < sizeof(package->header)) {
    /* For L2CAP it is an error to not receive the full data in each
       recv operation. */
    fprintf(stderr,"Warning, only got partial data on BT connection\n");
    peisk_closeConnection(connection->id);
    return 0;
  }
  if(ntohs(package->header.datalen) > PEISK_MAX_PACKAGE_SIZE) { /* Check for bad package length */
    if(1 || peisk_printLevel & PEISK_PRINT_CONNECTIONS)
      fprintf(stdout,"peisk: error, too large (%d) package received on BT connection %d\n",package->header.datalen,connection->id);
    /*peisk_syncflush(connection);*/
    peisk_closeConnection(connection->id);
    return 0;
  }
  return 1;
}
Exemple #2
0
int peisk_recvAtomic(int fd,void *buf,size_t len,int flags) {
  int i, new_bytes;
  char *data=(char*)buf;
  errno=0;
  new_bytes=recv(fd,data,len,flags|MSG_NOSIGNAL);

  /*printf("ATOMIC>"); fflush(stdout);*/
  if(new_bytes <= 0) { /*printf("<\n"); fflush(stdout);*/ return 0; }/* Nothing received */
  /*printf("new_bytes=%d\n",new_bytes);*/
  len -= new_bytes;
  data+=new_bytes;

  while(len>0) {
    errno=0;
    new_bytes=recv(fd,data,len,flags|MSG_NOSIGNAL);
	printf("new_bytes=%d\n",new_bytes);
    if(errno == EPIPE || new_bytes == 0) {
      /* Broken pipe - close socket and return */
      for(i=0;i<PEISK_MAX_CONNECTIONS;i++) {
	printf("Connection %d socket=%d\n",i,peiskernel.connections[i].connection.tcp.socket);
	if(peiskernel.connections[i].id != -1 && peiskernel.connections[i].connection.tcp.socket == fd)
	  peisk_closeConnection(peiskernel.connections[i].id);
      }
      /*printf("<\n"); fflush(stdout);*/
      return 0;
    }
    if(new_bytes == -1) peisk_waitForRead(fd,0.01); /* was: usleep(100) */
    else {
      len -= new_bytes;
      data+=new_bytes;
    }
  }
  /*printf("<\n"); fflush(stdout);*/
  return 1;
}
Exemple #3
0
int peisk_recvBlocking(int fd,void *buf,size_t len,int flags,double timeout) {
  int i, new_bytes;
  char *data=(char*)buf;
  double t0 = peisk_gettimef();

  while(len>0) {
    errno=0;
    new_bytes=recv(fd,data,len,flags|MSG_NOSIGNAL);
    if(errno == EPIPE || new_bytes == 0) {
      /* Broken pipe - close socket and return */
      for(i=0;i<PEISK_MAX_CONNECTIONS;i++) {
	if(peisk_printLevel & PEISK_PRINT_CONNECTIONS)
	  printf("Connection %d socket=%d\n",i,peiskernel.connections[i].connection.tcp.socket);
	if(peiskernel.connections[i].id != -1 && peiskernel.connections[i].connection.tcp.socket == fd)
	  peisk_closeConnection(peiskernel.connections[i].id);
      }
      /*printf("<\n"); fflush(stdout); */
      return 0;
    }
    if(new_bytes == -1) peisk_waitForRead(fd,0.01); /* was: usleep 0 */
    else {
      if(new_bytes == 0) if(peisk_printLevel & PEISK_PRINT_CONNECTIONS)  printf("peisk: error - not getting any bytes, broken connection?\n");
      len -= new_bytes;
      data+=new_bytes;
    }
    if(peisk_gettimef() > t0 + timeout) { /*printf("< (TIME)\n"); fflush(stdout);*/ return 0; } /* Timeout reached */
  }
  return 1;
}
Exemple #4
0
void peisk_shutdown() {
    int i;

    if(!peisk_int_isRunning)
        /* Don't attempt multiple shutdown's at once */
        return;
    peiskernel.doShutdown=2;

    peisk_sendExitNotification();

    printf("peiskernel shutting down\n");
    peisk_wait(2000000);
    peisk_int_isRunning=0;


    for(i=0;i<PEISK_MAX_CONNECTIONS;i++) {
        if(peiskernel.connections[i].id == -1) continue;
        peisk_closeConnection(peiskernel.connections[i].id);
    }

    if(peiskernel.tcp_isListening) { peiskernel.tcp_isListening=0; close(peiskernel.tcp_serverSocket); }

    if(peiskernel.tcp_broadcast_receiver != -1) { close(peiskernel.tcp_broadcast_receiver); peiskernel.tcp_broadcast_receiver=-1; }

    peisk_closeBluetooth();
}
Exemple #5
0
int peisk_tcpSendAtomic(PeisConnection *connection,PeisPackage *package,int len) {
  int status, timeout, value;
  void *data = (void*) package;
  PeisPackageHeader *header;

  /* First check if this data would fit into buffer. Might have
     portability issues to other platforms but a reasonable fallback
     is to not do these tests. The other code below should handle the
     remaining cases somewhat worse. */

  value=0;
  /* CYGWIN does not have these...  --AS 060816 */
#ifndef __CYGWIN__
  /* MACOS X does not have these...  --MB 061120 */
#ifndef __MACH__
  status=ioctl(connection->connection.tcp.socket, SIOCOUTQ, &value);
  /* todo - use SIOCINQ on input from tcp sockets... */
  if(status) perror("peisk_connection_sendAtomic::ioctl(SIOCOUTQ)");
  /* todo - use getsockopt(SO_RCVBUFFER) to know the buffer size */
  if(value > 20000) return -1; /* Too much data in buffer, come back later */
#endif
#endif

  header=&package->header;
  header->linkCnt = htonl(connection->outgoingIdCnt++);

  status=send(connection->connection.tcp.socket,(void*) data,len,MSG_DONTWAIT|MSG_NOSIGNAL);
  if(status != -1 && status < len) {
    if(peisk_printLevel & PEISK_PRINT_PACKAGE_ERR)
      printf("Warning! Package sent only partially errno=%d, Status=%d\n",errno,status);
    timeout=0;
    while(1) {
      if(status != -1) { data += status; len -= status; if(!len) break; }
      if(++timeout > 100*2) { printf("Warning - forced to break package! (2s timeout)\n"); errno=EPIPE; break; }
      peisk_waitForWrite(connection->connection.tcp.socket,0.01);
      errno=0;
      status=send(connection->connection.tcp.socket,(void*) data,len,MSG_DONTWAIT|MSG_NOSIGNAL);
      if(errno == EPIPE) break;
      if(status == -1 && errno != EAGAIN) {
	/* todo - make this printout dependent on debug level? */
	printf("error sending package - errno=%d '%s'\n",errno,strerror(errno));
	break;
      }
    }
  }
  if(errno == EPIPE || errno == EBADF || errno == EINVAL) {
    if(peisk_printLevel & PEISK_PRINT_CONNECTIONS)
      fprintf(stdout,"peisk: tcp connection %d broken pipe (header)\n",connection->id);
    peisk_closeConnection(connection->id);
    return -1;
  } else if(errno == EAGAIN) {
    if(status > 0) { if(peisk_printLevel & PEISK_PRINT_PACKAGE_ERR) printf("send - EAGAIN, status=%d\n",status); }
    /* Package was not sent - don't remove it from queue and don't attempt any more packages for now */
    /* Also, decrease outgoingIdCnt so we do not count this package
       multiple times */
    connection->outgoingIdCnt--;
    return -1;
  }
  return 0;
}
Exemple #6
0
int peisk_tcpReceiveIncomming(struct PeisConnection *connection,struct PeisPackage *package) {
  int status;
  
  errno=0;
  status=recv(connection->connection.tcp.socket,(void*)package,sizeof(PeisPackage),MSG_PEEK|MSG_NOSIGNAL);
  if(errno == EAGAIN) return 0;                 /* Nothing received, come back later */
  if(errno == EPIPE || status == -1) {          /* Error - close socket */
    if(peisk_printLevel & PEISK_PRINT_CONNECTIONS)
      printf("peisk: warning - error (1) in receive, closing socket\n");
    peisk_closeConnection(connection->id);
    return 0;
  }
  if(status < sizeof(package->header)) return 0; /* We have not yet received the full header, come back later */

  if(ntohs(package->header.datalen) > PEISK_MAX_PACKAGE_SIZE) { /* Check for bad package length */
    if(peisk_printLevel & PEISK_PRINT_CONNECTIONS)
      fprintf(stdout,"peisk: error, too large (%d) package received on connection %d\n",package->header.datalen,connection->id);
    /*peisk_syncflush(connection);*/
    peisk_closeConnection(connection->id);
    return 0;
  }

  if(status < sizeof(package->header) + ntohs(package->header.datalen))
    /* We have not yet received the full data, come back later */
    return 0;

  /* Ok, we have all the data we wanted, read it once again without MSG_PEEK to get rid of it */
  errno=0;
  status=recv(connection->connection.tcp.socket,
	      (void*)package,sizeof(package->header) + ntohs(package->header.datalen),MSG_NOSIGNAL);
  if(errno == EAGAIN || errno == EPIPE || status == -1 ||
     status < sizeof(package->header) + ntohs(package->header.datalen)) {
    if(peisk_printLevel & PEISK_PRINT_CONNECTIONS)
      printf("peisk: warning - error (2) in receive, closing socket. status=%d\n",status);
    peisk_closeConnection(connection->id);
    return 0;
  }
  return 1;
}
Exemple #7
0
/** Call when a connection seem to be out of sync, flushes packages until we are back on track again. */
void peisk_syncflush(PeisConnection *connection) {
  int status;
  long int mysync;

  if(peisk_printLevel & PEISK_PRINT_CONNECTIONS)
    fprintf(stdout,"peisk: connection %d lost sync\n",connection->id);
  switch(connection->type) {
  case eTCPConnection:
	  while(1) {
	    /* For TCP connections we just attempt to read and throw away chars until we have found a sync long int
	       until we have found a new sync character. */
	    errno=0;
	    status=recv(connection->connection.tcp.socket,(void*)&mysync,sizeof(mysync),MSG_PEEK|MSG_NOSIGNAL);
	    if(errno == EAGAIN) return;
	    if(errno == EPIPE || status == -1) {          /* Error - close socket */
	      if(peisk_printLevel & PEISK_PRINT_CONNECTIONS)
		printf("peisk: warning - error (3) in receive, closing socket\n");
	      peisk_closeConnection(connection->id);
	      return;
	    }
	    if(status == sizeof(mysync) && mysync == PEISK_SYNC)
	      /* We have found the sync, continue as before */
	      { peisk_connection_processIncomming(connection); return; }
	    /* read again but without peek so that the data is realy consumed */
	    errno=0;
	    //status=recv(connection->connection.tcp.socket,(void*)&mysync,sizeof(mysync),MSG_NOSIGNAL);
	    status=recv(connection->connection.tcp.socket,(void*)&mysync,1,MSG_NOSIGNAL);
	  }
	  break;
  case eUDPConnection:
    /* UDP connections cannot become out of sync since udp preserves record boundaries */
    return;
  case eBluetoothConnection:
    /* Bluetooth connections cannot become out of sync since L2CAP preserves record boundaries */
    return;
  default: peisk_closeConnection(connection->id);
  }
}
Exemple #8
0
int peisk_verifyConnectMessage(PeisConnection *connection,PeisConnectMessage *message) {
  static int hasWarned=0;
  int index, nConnections;

  message->version = ntohl(message->version);
  message->flags = ntohl(message->flags);
  message->id = ntohl(message->id);

  if(message->id == peiskernel.id) 
    /* We do not trust anyone that claims to be us... */
    return -1;

  if(message->version > peisk_protocollVersion && !hasWarned) {
    hasWarned=1;
    fprintf(stderr,"peisk::WARNING - A newer version of the PEIS kernel might be available\n");
    fprintf(stderr,"Consider updating your peiskernel or running on a private network!\n");
  }
  if(message->version != peisk_protocollVersion) {
    fprintf(stderr,"incomming connection with incorrect protocoll version %d\n",message->version);
    return -1;
  }
  
  if(strncmp(message->networkString,peisk_networkString,sizeof(message->networkString)) != 0){
    printf("network '%s' is wrong\n",message->networkString);
    return -1;
  }

  /* Count how many connections we currently have open */
  nConnections=0;
  for(index=0;index<PEISK_MAX_CONNECTIONS;index++)
    if(peiskernel.connections[index].id != -1) nConnections++;

  if(nConnections+1 > PEISK_MAX_AUTO_CONNECTIONS && 
     !(message->flags & (PEISK_CONNECT_FLAG_FORCED_BW|PEISK_CONNECT_FLAG_FORCED_CL))) {
    /* We have too many connections... and he's not desperate. Just close this one */
    if(1 || peisk_printLevel & PEISK_PRINT_CONNECTIONS)
      printf("Refusing incomming connection from %d (flags: %d)\n",message->id,message->flags);
    return -1;
  }

  if(nConnections+1 > PEISK_MAX_FORCED_AUTO_CONNECTIONS &&
     !(message->flags & PEISK_CONNECT_FLAG_FORCED_CL)) {
    /* He want to connect us to optimize bandwidth. See if the 
       worst connection we have is better than this guy. */
    /* Find the connection with the worst value, also count number of
       valid connections we have*/
    int i,value,worst;
    worst=-1;
    for(i=0,value=10000;i<=peiskernel.highestConnection;i++) {
      if(peiskernel.connections[i].id != -1 && 
	 peiskernel.connections[i].value < value) { value=peiskernel.connections[i].value; worst=i; }
    }
    
    if(worst == -1) {
      /* No non-forced connection found, reject this incoming one */
      if(peisk_printLevel & PEISK_PRINT_CONNECTIONS)
	printf("Refusing incomming connection from %d, no freeable connection found\n",message->id);
      return -1;
    } else {
      peisk_closeConnection(peiskernel.connections[worst].id);
      if(peisk_printLevel & PEISK_PRINT_CONNECTIONS)
	printf("Closing connection #%d to %d in favour for %d\n",
	       peiskernel.connections[worst].id,
	       peiskernel.connections[worst].neighbour.id,
	       message->id);
    }
  }

  return 0;
}
Exemple #9
0
/** \todo remove the pending connection stuff from
    peisk_connection_receiveIncomming and put into periodic functions
    instead. */
int peisk_connection_receiveIncomming(PeisConnection *connection,PeisPackage *package) {
  if(connection->isPending) return 0;

#ifdef OLD
  /* Handle pending UDP connection specially, just check for the ACK message so it can be promoted
     to a eUDPConnected status */
  if(connection->type == eUDPConnection && connection->connection.udp.status == eUDPPending) {
    /* Check for a response... */
    /* Update our sin_port according to response */
    errno=0;
    len=sizeof(addr);
    size=recvfrom(connection->connection.udp.socket,buf,sizeof(buf),MSG_DONTWAIT,&addr,&len);
    if(size <= 0) return 0;

    /* TODO: Test that we realy got the package "ack" back */

    in_addr=(struct sockaddr_in*) &connection->connection.udp.addr; 
    memcpy(&connection->connection.udp.addr,&addr,len);
    connection->connection.udp.len = len;
    printf("UDP connection acknowledged. Socket: %d Len: %d Port: %d\n",connection->connection.udp.socket,len,ntohs(in_addr->sin_port));
    printf("New sin_addr: %d %d %d %d\n",((unsigned char*)&in_addr->sin_addr)[0],((unsigned char*)&in_addr->sin_addr)[1],((unsigned char*)&in_addr->sin_addr)[2],((unsigned char*)&in_addr->sin_addr)[3]);

    /* Force an update of routing tables by directly calling the periodic routing function */
    /* peisk_do_routing(1); */
    if(peisk_printLevel & PEISK_PRINT_CONNECTIONS)
      fprintf(stdout,"peisk: new outbound udp/ip connection #%d established\n",connection->id);

    connection->connection.udp.status=eUDPConnected;
    return 0;
  }
#endif

  int success=0;
  switch(connection->type) {
  case eTCPConnection:
    success = peisk_tcpReceiveIncomming(connection,package);
    break;
  case eUDPConnection:
    /*success = peisk_udpReceiveIncomming(connection,package);*/
    break;
  case eBluetoothConnection:
    success = peisk_bluetoothReceiveIncomming(connection,package);
    break;
  default: return 0; /* TODO - handle other connection types here */
  }

  if(!success) return 0;

  /* Update congestion control information */
  if(ntohl(package->header.linkCnt)+1 > connection->incomingIdHi)
    connection->incomingIdHi = ntohl(package->header.linkCnt)+1;
  connection->incomingIdSuccess++;

  connection->totalIncomming += sizeof(package->header) + ntohs(package->header.datalen);
  peiskernel.incomingTraffic+= sizeof(package->header) + ntohs(package->header.datalen);

  /* Update timestamp on connection so it is kept alive */
  connection->timestamp = peisk_timeNow;

  /* Print debug info if requested */
  if(peisk_debugPackages) /* || ntohs(package->header.port) == PEISK_PORT_SET_REMOTE_TUPLE)*/
    fprintf(stdout,"peisk: IN conn=%d id=%x port=%d hops=%d len=%d type=%d src=%d dest=%d\n",
	    connection->id,ntohl(package->header.id),ntohs(package->header.port),package->header.hops,
	    ntohs(package->header.datalen),package->header.type,
	    ntohl(package->header.source),
	    ntohl(package->header.destination));
  connection->incommingTraffic += sizeof(package->header) + ntohs(package->header.datalen);
  peisk_in_packages[ntohs(package->header.port)]++;

  /* Verify that the sync character where correct, otherwise close connection. */
  if(package->header.sync != PEISK_SYNC) {
    printf("peisk: warning - bad sync. Closing connection %d\n",connection->id);
    peisk_closeConnection(connection->id);
    return 0;
  }

  /* Make sure ID is a valid network byte representation of a natural integer (>= 0) */
  if(ntohl(package->header.id) < 0  || ntohl(package->header.ackID) < 0) {
    fprintf(stdout,"peisk: bad package on connection %d, id=%d\n",connection->id,ntohl(package->header.id));
    peisk_closeConnection(connection->id);
    return 0;
  }

  return 1;
}
Exemple #10
0
int peisk_bluetoothSendAtomic(PeisConnection *connection,PeisPackage *package,int len) {
  int status;
  void *data = (void*) package;
  PeisPackageHeader *header;

  PEISK_ASSERT(connection->connection.bluetooth.adaptor >= &peisk_bluetoothAdaptors[0] &&
	       connection->connection.bluetooth.adaptor <= &peisk_bluetoothAdaptors[peisk_nBluetoothAdaptors],
	       ("ERROR: Invalid adaptor pointer in bluetooth connection #%d towards %d\n",
		connection->id,connection->neighbour.id));

  /* Refuse to send if we already have sent too many packages this period */
  if(connection->connection.bluetooth.adaptor->bsCount > PEISK_BT_MAX_BPS)
    return -1;
  /* Make a random chance to refuse packages if we have an average speed that is too high.
     This lets the allowed bandwidth be evenly distributed between all connections on this interface, and also
     to be shared "over time" (ie. do not send everything at the begining of each period) */
  if(connection->connection.bluetooth.adaptor->bsAvgBps > PEISK_BT_RED_BPS) {
    if(rand() % (PEISK_BT_MAX_BPS-PEISK_BT_RED_BPS) <
       connection->connection.bluetooth.adaptor->bsAvgBps-PEISK_BT_RED_BPS)
      return -1;
  }

  header=&package->header;
  header->linkCnt = htonl(connection->outgoingIdCnt++);

  /** \todo Let the linklayer send operations send partial messages
      and queue the leftovers. */
  errno=0;
  status=send(connection->connection.bluetooth.socket,(void*) data,len,MSG_DONTWAIT|MSG_NOSIGNAL);
  if(status != -1 && status < len) {
    fprintf(stderr,"ERROR - only %d of %d bytes sent over L2CAP bluetooth connection\n",status,len);
    peisk_closeConnection(connection->id);
    return -1;
  }
  if(status > 0) {
    peisk_logTimeStamp(stdout);
    printf("BT send: %d bytes TO: %d ",status,connection->neighbour.id);
    /*peisk_hexDump(package,status);*/
    peisk_printNetPackageInfo(package);
    /* Increment bytes/second counter */
    connection->connection.bluetooth.adaptor->bsCount += status;
  }


  if(errno == EPIPE || errno == EBADF || errno == EINVAL) {
    if(1 || peisk_printLevel & PEISK_PRINT_CONNECTIONS) {
      fprintf(stdout,"peisk: bluetooth connection %d broken pipe (sendAtomic %d bytes)\n",connection->id,len);
      perror(":");
    }
    peisk_closeConnection(connection->id);
    return -1;
  } else if(errno == EAGAIN) {
    if(status > 0) { if(peisk_printLevel & PEISK_PRINT_PACKAGE_ERR) printf("send - EAGAIN, status=%d\n",status); }
    /* Package was not sent - don't remove it from queue and don't attempt any more packages for now */
    /* Also, decrease outgoingIdCnt so we do not count this package
       multiple times */
    connection->outgoingIdCnt--;
    return -1;
  }
  return 0;
}