/* returns index of new client on the list */
int handle_incoming_conn(Arraylist list, char *servername, int listenfd){
  /* Incoming Connection */
  struct sockaddr_storage remoteaddr;
  socklen_t addrlen = sizeof(remoteaddr);
  int newfd = accept(listenfd, (struct sockaddr *)&remoteaddr, &addrlen);

  if (newfd == -1) {
    DEBUG_PERROR("accept");
    return -1;
  }

  DPRINTF(DEBUG_SOCKETS,"handle_incoming_conn: new connection on socket %d\n",newfd);

  return addClientToList(list, servername, newfd, &remoteaddr);
}
Exemple #2
0
int send_packet(int peer_id, int type, int seq, int ack, char* body, int body_len) {
  DPRINTF(DEBUG_SOCKETS, "send packet to peer:%d type:%d seq:%d ack:%d body_len:%d\n",
          peer_id, type, seq, ack, body_len);

  struct io_peer *peer = NULL;
  HASH_FIND(hh_id, peers_id, &peer_id, sizeof(int), peer);
  if (peer == NULL) {
    fprintf(stderr, "Unknown peer id %d\n", peer_id);
    return -1;
  }

  char data[sizeof(struct packet_header) + body_len];
  struct packet_header *header = (struct packet_header *) data;
  header->magic = PACKET_MAGIC;
  header->version = PACKET_VERSION;
  header->header_len = sizeof(struct packet_header);
  header->total_len = (uint16_t) (header->header_len + body_len);
  header->type = (unsigned int) type;
  header->seq = (unsigned int) seq;
  header->ack = (unsigned int) ack;
  if (header->type == PACKET_ACK) {
    --header->ack;
  }
  packet_hton(header);

  if (body && body_len) {
    memcpy(data + sizeof(struct packet_header), body, (size_t) body_len);
  }

  int ret = spiffy_sendto(peer_sockfd, data, sizeof(data), MSG_NOSIGNAL, (const struct sockaddr *) &peer->addr, sizeof(struct sockaddr_in));
  if (ret == -1) {
    DEBUG_PERROR("Cannot send packet\n");
  }

  return ret;
}
Exemple #3
0
enum ach_status
ach_create( const char *channel_name,
            size_t frame_cnt, size_t frame_size,
            ach_create_attr_t *attr) {
    ach_header_t *shm;
    int fd;
    size_t len;
    /* fixme: truncate */
    /* open shm */
    {
        len = sizeof( ach_header_t) +
            frame_cnt*sizeof( ach_index_t ) +
            frame_cnt*frame_size +
            3*sizeof(uint64_t);

        if( attr && attr->map_anon ) {
            /* anonymous (heap) */
            shm = (ach_header_t *) malloc( len );
            fd = -1;
        }else {
            int oflag = O_EXCL | O_CREAT;
            /* shm */
            if( ! channel_name_ok( channel_name ) )
                return ACH_INVALID_NAME;
            if( attr ) {
                if( attr->truncate ) oflag &= ~O_EXCL;
            }
            if( (fd = fd_for_channel_name( channel_name, oflag )) < 0 ) {
                return check_errno();;
            }

            { /* make file proper size */
                /* FreeBSD needs ftruncate before mmap, Linux can do either order */
                int r;
                int i = 0;
                do {
                    r = ftruncate( fd, (off_t) len );
                }while(-1 == r && EINTR == errno && i++ < ACH_INTR_RETRY);
                if( -1 == r ) {
                    DEBUG_PERROR( "ftruncate");
                    return ACH_FAILED_SYSCALL;
                }
            }

            /* mmap */
            if( (shm = (ach_header_t *)mmap( NULL, len, PROT_READ|PROT_WRITE,
                                             MAP_SHARED, fd, 0) )
                == MAP_FAILED ) {
                DEBUG_PERROR("mmap");
                DEBUGF("mmap failed %s, len: %"PRIuPTR", fd: %d\n", strerror(errno), len, fd);
                return ACH_FAILED_SYSCALL;
            }

        }

        memset( shm, 0, len );
        shm->len = len;
    }

    { /* initialize synchronization */
        { /* initialize condition variables */
            int r;
            pthread_condattr_t cond_attr;
            if( (r = pthread_condattr_init(&cond_attr)) ) {
                DEBUG_PERROR("pthread_condattr_init");
                return ACH_FAILED_SYSCALL;
            }
            /* Process Shared */
            if( ! (attr && attr->map_anon) ) {
                /* Set shared if not anonymous mapping
                   Default will be private. */
                if( (r = pthread_condattr_setpshared(&cond_attr, PTHREAD_PROCESS_SHARED)) ) {
                    DEBUG_PERROR("pthread_condattr_setpshared");
                    return ACH_FAILED_SYSCALL;
                }
            }
            /* Clock */
            if( attr && attr->set_clock ) {
                if( (r = pthread_condattr_setclock(&cond_attr, attr->clock)) ) {
                    DEBUG_PERROR("pthread_condattr_setclock");
                    return ACH_FAILED_SYSCALL;
                }
            } else {
                if( (r = pthread_condattr_setclock(&cond_attr, ACH_DEFAULT_CLOCK)) ) {
                    DEBUG_PERROR("pthread_condattr_setclock");
                    return ACH_FAILED_SYSCALL;
                }
            }

            if( (r = pthread_cond_init(&shm->sync.cond, &cond_attr)) ) {
                DEBUG_PERROR("pthread_cond_init");
                return ACH_FAILED_SYSCALL;
            }

            if( (r = pthread_condattr_destroy(&cond_attr)) ) {
                DEBUG_PERROR("pthread_condattr_destroy");
                return ACH_FAILED_SYSCALL;
            }
        }
        { /* initialize mutex */
            int r;
            pthread_mutexattr_t mutex_attr;
            if( (r = pthread_mutexattr_init(&mutex_attr)) ) {
                DEBUG_PERROR("pthread_mutexattr_init");
                return ACH_FAILED_SYSCALL;
            }
            if( (r = pthread_mutexattr_setpshared(&mutex_attr,
                                                  PTHREAD_PROCESS_SHARED)) ) {
                DEBUG_PERROR("pthread_mutexattr_setpshared");
                return ACH_FAILED_SYSCALL;
            }
            /* Error Checking Mutex */
#ifdef PTHREAD_MUTEX_ERRORCHECK_NP
            if( (r = pthread_mutexattr_settype(&mutex_attr,
                                               PTHREAD_MUTEX_ERRORCHECK_NP)) ) {
                DEBUG_PERROR("pthread_mutexattr_settype");
                return ACH_FAILED_SYSCALL;
            }
#endif
            /* Priority Inheritance Mutex */
#ifdef PTHREAD_PRIO_INHERIT
            if( (r = pthread_mutexattr_setprotocol(&mutex_attr,
                                                   PTHREAD_PRIO_INHERIT)) ) {
                DEBUG_PERROR("pthread_mutexattr_setprotocol");
                return ACH_FAILED_SYSCALL;
            }
#endif

            if( (r = pthread_mutex_init(&shm->sync.mutex, &mutex_attr)) ) {
                DEBUG_PERROR("pthread_mutexattr_init");
                return ACH_FAILED_SYSCALL;
            }

            if( (r = pthread_mutexattr_destroy(&mutex_attr)) ) {
                DEBUG_PERROR("pthread_mutexattr_destroy");
                return ACH_FAILED_SYSCALL;
            }
        }
    }
    /* initialize name */
    strncpy( shm->name, channel_name, ACH_CHAN_NAME_MAX );
    /* initialize counts */
    shm->index_cnt = frame_cnt;
    shm->index_head = 0;
    shm->index_free = frame_cnt;
    shm->data_head = 0;
    shm->data_free = frame_cnt * frame_size;
    shm->data_size = frame_cnt * frame_size;
    assert( sizeof( ach_header_t ) +
            shm->index_free * sizeof( ach_index_t ) +
            shm->data_free + 3*sizeof(uint64_t) ==  len );

    *ACH_SHM_GUARD_HEADER(shm) = ACH_SHM_GUARD_HEADER_NUM;
    *ACH_SHM_GUARD_INDEX(shm) = ACH_SHM_GUARD_INDEX_NUM;
    *ACH_SHM_GUARD_DATA(shm) = ACH_SHM_GUARD_DATA_NUM;
    shm->magic = ACH_SHM_MAGIC_NUM;

    if( attr && attr->map_anon ) {
        attr->shm = shm;
    } else {
        int r;
        /* remove mapping */
        r = munmap(shm, len);
        if( 0 != r ){
            DEBUG_PERROR("munmap");
            return ACH_FAILED_SYSCALL;
        }
        /* close file */
        int i = 0;
        do {
            IFDEBUG( i ? DEBUGF("Retrying close()\n"):0 );
            r = close(fd);
        }while( -1 == r && EINTR == errno && i++ < ACH_INTR_RETRY );
        if( -1 == r ){
            DEBUG_PERROR("close");
            return ACH_FAILED_SYSCALL;
        }
    }
    return ACH_OK;
}
int main( int argc, char *argv[] )
{
  /* for parsing args */
  extern char *optarg;
  extern int optind;
  int ch;

  /* vars */
  int i,j;
  int listenfd;

  /* select vars */
  fd_set read_set;
  int fdmax;

  /* client arr */
  Arraylist clientList;
  /* channel arr */
  Arraylist channelList;

  /* servername */
  char servername[MAX_SERVERNAME+1];

  while ((ch = getopt(argc, argv, "hD:")) != -1)
  switch (ch) {
  case 'D':
    if (set_debug(optarg)) {
      exit(0);
    }
    break;
  case 'h':
  default: /* FALLTHROUGH */
    usage();
  }
  argc -= optind;
  argv += optind;

  if (argc < 2) {
    usage();
  }
  signal(SIGPIPE, SIG_IGN);
  init_node(argv[0], argv[1]);

  printf( "I am node %lu and I listen on port %d for new users\n", curr_nodeID, curr_node_config_entry->irc_port );

  /* Start your engines here! */
  if (gethostname(servername,MAX_SERVERNAME) < 0){
    perror("gethostname");
    return EXIT_FAILURE;
  }
  servername[MAX_SERVERNAME] = '\0';

  /* delegate all function calling to setupListenSocket.
        It should print out relevant err messages. */
  listenfd = setupListenSocket(curr_node_config_entry->irc_port);
  if (listenfd < 0){
    return EXIT_FAILURE;
  }

  /* initialize client array */
  clientList = arraylist_create();

  /* initialize channel array */
  channelList = arraylist_create();

  /* prepare for select */
  fdmax = listenfd;
  FD_ZERO(&master_set);
  FD_ZERO(&write_set);
  FD_SET(listenfd,&master_set);

  /* FD_ZERO(&write_set);  initially no data to write */

  /* main loop!! */
  for (;;){
    int retval;
    read_set = master_set;

    /* wait until any sockets become available */
    retval = select(fdmax+1,&read_set,&write_set,NULL,NULL);

    if (retval <= 0){
      if (retval < 0)
      DEBUG_PERROR("select");
      continue; /* handle errors gracefully and wait again if timed out (it shouldn't)*/
    }
    /* at least one socket ready*/
    for (i = 0; i <= fdmax; i++){
      if (FD_ISSET(i, &write_set)) {
        int listIndex = findClientIndexBySockFD(clientList,i);
        client_t *thisClient = (client_t *) CLIENT_GET(clientList,listIndex);
        /*client data ready to be written */
        int nbytes;
        /* iterate through item to be sent, until it will block */
        Arraylist outbuf = thisClient->outbuf;

        while (!arraylist_is_empty(outbuf))
        {
          /* write */
          char *dataToSend = (char *) (arraylist_get(outbuf,0)) + thisClient->outbuf_offset;
          size_t sizeToSend = strlen(dataToSend);
          nbytes = send(thisClient->sock, dataToSend, sizeToSend, 0);
          if (nbytes <0){
            /* error */
            if (errno == EPIPE || errno == ECONNRESET){
              /* connection lost or closed by the peer */

              DPRINTF(DEBUG_SOCKETS,"send: client %d hungup\n",i);
              remove_client(clientList,listIndex);
              continue;
            }
          }
          else if (nbytes == sizeToSend){
            /* current line completely sent */
            char *toRemove = (char *) (arraylist_get(outbuf,0));
            arraylist_removeIndex(outbuf,0);
            free(toRemove);
          }
          else{
            /* partial send */
            thisClient->outbuf_offset += nbytes;
            break;
          }
        }
        if (arraylist_is_empty(outbuf))
          FD_CLR(i, &write_set);
      }
      if (FD_ISSET(i, &read_set)) {
        if (i == listenfd){
          /* incoming connection */
          int newindex = handle_incoming_conn(clientList,servername,listenfd);
          if (newindex < 0){
            continue;
          }
          client_t *newClient = CLIENT_GET(clientList,newindex);
          int newfd = newClient->sock;
          FD_SET(newfd,&master_set);
          if (newfd > fdmax){
            fdmax = newfd;
          }
        }
        else{
          /* client data ready */
          char *tempPtr;
          int listIndex = findClientIndexBySockFD(clientList,i);

          /* for split function */
          char** tokenArr;
          int numToken;
          int lastTokenTerminated;

          if (listIndex < 0){
            close(i);
            FD_CLR(i,&master_set);
            continue;
          }

          int nbytes = recv(i, CLIENT_GET(clientList,listIndex)->inbuf + CLIENT_GET(clientList,listIndex)->inbuf_size,
          MAX_MSG_LEN - CLIENT_GET(clientList,listIndex)->inbuf_size, 0);

          /* recv failed. Either client left or error */
          if (nbytes <= 0){
            if (nbytes == 0){
              DPRINTF(DEBUG_SOCKETS,"recv: client %d hungup\n",i);
              remove_client(clientList, listIndex);

            }
            else if (errno == ECONNRESET || errno == EPIPE){
              DPRINTF(DEBUG_SOCKETS,"recv: client %d connection reset \n",i);
              remove_client(clientList, listIndex);

            }
            else{
              perror("recv");
            }
            continue;
          }

          /* NULL terminate to use strpbrk */
          CLIENT_GET(clientList,listIndex)->inbuf_size += nbytes;
          CLIENT_GET(clientList,listIndex)->inbuf[CLIENT_GET(clientList,listIndex)->inbuf_size] = '\0';
          tempPtr = strpbrk(CLIENT_GET(clientList,listIndex)->inbuf,"\r\n");
          if (!tempPtr){
            if (CLIENT_GET(clientList,listIndex)->inbuf_size == MAX_MSG_LEN){
              /* Message too long. Dump the content */
              DPRINTF(DEBUG_INPUT,"recv: message longer than MAX_MESSAGE detected. The message will be discarded\n");
              CLIENT_GET(clientList,listIndex)->inbuf_size = 0;
            }
            continue;
          }

          tokenArr = splitByDelimStr(CLIENT_GET(clientList,listIndex)->inbuf,"\r\n",&numToken,&lastTokenTerminated);
          /* since we have checked if there's delimeter beforehand, there should be at least one terminated token available*/
          if (!tokenArr){
            DPRINTF(DEBUG_INPUT,"splitByDelimStr: failed to split inputToken\n");
            CLIENT_GET(clientList,listIndex)->inbuf_size = 0;
            continue;
          }
          if (!lastTokenTerminated){
            CLIENT_GET(clientList,listIndex)->inbuf_size = strlen(tokenArr[numToken-1]);
            memcpy(CLIENT_GET(clientList,listIndex)->inbuf,tokenArr[numToken-1],CLIENT_GET(clientList,listIndex)->inbuf_size);
            numToken--;
          }

          for (j=0;j<numToken;j++){
            handle_line(clientList,listIndex,channelList,servername,tokenArr[j]);
          }

          for (j = 0; j < arraylist_size(clientList); j++){
            client_t *client = CLIENT_GET(clientList,j);
            if (arraylist_size(client->outbuf)){
                FD_SET(client->sock,&write_set);
            }
          }
          freeTokens(&tokenArr,numToken);
        }
      }
    }
  }

  return 0;
}