Esempio n. 1
0
struct raop_server_settings_t raop_server_get_settings(struct raop_server_t* rs) {
    
    return (struct raop_server_settings_t){
        settings_get_name(rs->settings),
        settings_get_password(rs->settings),
        settings_get_ignore_source_volume(rs->settings)
    };
    
}

void raop_server_set_settings(struct raop_server_t* rs, struct raop_server_settings_t settings) {
    
    const char* old_name = settings_get_name(rs->settings);
    char* old_name_c = (char*)malloc(strlen(old_name) + 1);
    strcpy(old_name_c, old_name);
    
    settings_set_name(rs->settings, settings.name);
    settings_set_password(rs->settings, settings.password);
    settings_set_ignore_source_volume(rs->settings, settings.ignore_source_volume);
    
    const char* new_name = settings_get_name(rs->settings);
    
    if (strcmp(old_name_c, new_name) != 0) {
        zeroconf_raop_ad_destroy(rs->zeroconf_ad);
        rs->zeroconf_ad = zeroconf_raop_ad_create(sockaddr_get_port(web_server_get_local_end_point(rs->server, sockaddr_type_inet_4)), new_name);
    }
    
    free(old_name_c);
    
}

void raop_server_stop(struct raop_server_t* rs) {
    
    mutex_lock(rs->mutex);
    
    if (rs->is_running) {
        
        rs->is_running = false;
        
        while (rs->sessions_count > 0) {
            mutex_unlock(rs->mutex);
            raop_session_destroy(rs->sessions[0]);
            mutex_lock(rs->mutex);
        }
        
        free(rs->sessions);
        
        rs->sessions = NULL;
        rs->sessions_count = 0;
        
        zeroconf_raop_ad_destroy(rs->zeroconf_ad);
        
        web_server_stop(rs->server);
        
    }
    
    mutex_unlock(rs->mutex);
    
}
Esempio n. 2
0
uint16_t rtp_socket_get_local_port(rtp_socket_p rs) {
    
    for (uint32_t i = 0 ; i < rs->sockets_count ; i++)
        if (!rs->sockets[i]->is_data_socket)
            return sockaddr_get_port(socket_get_local_end_point(rs->sockets[i]->socket));
    
    return 0;
    
}
Esempio n. 3
0
/*
 * Send a file. It is implemented as a state machine using a while loop
 * and a switch statement. Function flow is as follow:
 *  - sanity check
 *  - check client's request
 *  - enter state machine
 *
 *     1) send a DATA or OACK
 *     2) wait replay
 *          - if ACK, goto 3
 *          - if ERROR abort
 *          - if TIMEOUT goto previous state
 *     3) send data, goto 2
 */
int tftpd_send_file(struct thread_data *data)
{
     int state = S_BEGIN;
     int timeout_state = state;
     int result;
     int block_number = 0;
     int last_block = -1;
     int data_size;
     struct sockaddr_storage *sa = &data->client_info->client;
     struct sockaddr_storage from;
     char addr_str[SOCKADDR_PRINT_ADDR_LEN];
     int sockfd = data->sockfd;
     struct tftphdr *tftphdr = (struct tftphdr *)data->data_buffer;
     FILE *fp;
     char filename[MAXLEN];
     char string[MAXLEN];
     int timeout = data->timeout;
     int number_of_timeout = 0;
     int mcast_switch = data->mcast_switch_client;
     struct stat file_stat;
     int convert = 0;           /* if true, do netascii conversion */
     struct thread_data *thread = NULL; /* used when looking for a multicast
                                           thread */
     int multicast = 0;         /* set to 1 if multicast */

     struct client_info *client_info = data->client_info;
     struct client_info *client_old = NULL;
     struct tftp_opt options[OPT_NUMBER];

     int prev_block_number = 0; /* needed to support netascii convertion */
     int prev_file_pos = 0;
     int temp = 0;

     /* look for mode option */
     if (strcasecmp(data->tftp_options[OPT_MODE].value, "netascii") == 0)
     {
          convert = 1;
          logger(LOG_DEBUG, "will do netascii convertion");
     }

     /* file name verification */
     Strncpy(filename, data->tftp_options[OPT_FILENAME].value,
             MAXLEN);
     if (tftpd_rules_check(filename) != OK)
     {
          tftp_send_error(sockfd, sa, EACCESS, data->data_buffer, data->data_buffer_size);
          if (data->trace)
               logger(LOG_DEBUG, "sent ERROR <code: %d, msg: %s>", EACCESS,
                      tftp_errmsg[EACCESS]);
          return ERR;
     }

     /* verify that the requested file exist */
     fp = fopen(filename, "r");

#ifdef HAVE_PCRE
     if (fp == NULL)
     {
          /* Verify if this file have a working subsitution */
          if (pcre_top != NULL)
          {
               if (tftpd_pcre_sub(pcre_top, string, MAXLEN,
                                  data->tftp_options[OPT_FILENAME].value) < 0)
               {
                    logger(LOG_DEBUG, "PCRE failed to match");
               }
               else
               {
                    logger(LOG_INFO, "PCRE mapped %s -> %s", 
                           data->tftp_options[OPT_FILENAME].value, string);
                    Strncpy(filename, string, MAXLEN);
                    /* recheck those rules */
                    if (tftpd_rules_check(filename) != OK)
                    {
                         tftp_send_error(sockfd, sa, EACCESS, data->data_buffer,
                                         data->data_buffer_size);
                         if (data->trace)
                              logger(LOG_DEBUG, "sent ERROR <code: %d, msg: %s>", EACCESS,
                                     tftp_errmsg[EACCESS]);
                         return ERR;
                    }
                    /* write back the new file name to the option structure */
                    opt_set_options(data->tftp_options, "filename", filename);
                    /* try to open this new file */
                    fp = fopen(filename, "r");
               }
          }
     }
#endif
     if (fp == NULL)
     {
          tftp_send_error(sockfd, sa, ENOTFOUND, data->data_buffer, data->data_buffer_size);
          logger(LOG_INFO, "File %s not found", filename);
          if (data->trace)
               logger(LOG_DEBUG, "sent ERROR <code: %d, msg: %s>", ENOTFOUND,
                      tftp_errmsg[ENOTFOUND]);
          return ERR;
     }

     /* To return the size of the file with tsize argument */
     fstat(fileno(fp), &file_stat);

     /* tsize option */
     if ((opt_get_tsize(data->tftp_options) > -1) && !convert)
     {
          opt_set_tsize(file_stat.st_size, data->tftp_options);
          logger(LOG_INFO, "tsize option -> %d", file_stat.st_size);
     }

     /* timeout option */
     if ((result = opt_get_timeout(data->tftp_options)) > -1)
     {
          if ((result < 1) || (result > 255))
          {
               tftp_send_error(sockfd, sa, EOPTNEG, data->data_buffer, data->data_buffer_size);
               if (data->trace)
                    logger(LOG_DEBUG, "sent ERROR <code: %d, msg: %s>", EOPTNEG,
                           tftp_errmsg[EOPTNEG]);
               fclose(fp);
               return ERR;
          }
          timeout = result;
          opt_set_timeout(timeout, data->tftp_options);
          logger(LOG_INFO, "timeout option -> %d", timeout);
     }

     /* blksize options */
     if ((result = opt_get_blksize(data->tftp_options)) > -1)
     {
          if ((result < 8) || (result > 65464))
          {
               tftp_send_error(sockfd, sa, EOPTNEG, data->data_buffer, data->data_buffer_size);
               if (data->trace)
                    logger(LOG_DEBUG, "sent ERROR <code: %d, msg: %s>", EOPTNEG,
                           tftp_errmsg[EOPTNEG]);
               fclose(fp);
               return ERR;
          }

          data->data_buffer_size = result + 4;
          data->data_buffer = realloc(data->data_buffer, data->data_buffer_size);

          if (data->data_buffer == NULL)
          {
               logger(LOG_ERR, "memory allocation failure");
               fclose(fp);
               return ERR;
          }
          tftphdr = (struct tftphdr *)data->data_buffer;

          if (data->data_buffer == NULL)
          {
               tftp_send_error(sockfd, sa, ENOSPACE, data->data_buffer, data->data_buffer_size);
               if (data->trace)
                    logger(LOG_DEBUG, "sent ERROR <code: %d, msg: %s>", ENOSPACE,
                           tftp_errmsg[ENOSPACE]);
               fclose(fp);
               return ERR;
          }
          opt_set_blksize(result, data->tftp_options);
          logger(LOG_INFO, "blksize option -> %d", result);
     }

     /* Verify that the file can be sent in 2^16 block of BLKSIZE octets */
     if ((file_stat.st_size / (data->data_buffer_size - 4)) > 65535)
     {
          tftp_send_error(sockfd, sa, EUNDEF, data->data_buffer, data->data_buffer_size);
          logger(LOG_NOTICE, "Requested file to big, increase BLKSIZE");
          if (data->trace)
               logger(LOG_DEBUG, "sent ERROR <code: %d, msg: %s>", EUNDEF,
                      tftp_errmsg[EUNDEF]);
          fclose(fp);
          return ERR;
     }

     /* multicast option */
     if (data->tftp_options[OPT_MULTICAST].specified &&
         data->tftp_options[OPT_MULTICAST].enabled && !convert)
     {
          /*
           * Find a server with the same options to give up the client.
           */
          logger(LOG_DEBUG, "Searching a server thread to give up this client");
          result = tftpd_list_find_multicast_server_and_add(&thread, data, data->client_info);
          if ( result > 0)
          {
               /* add this client to its list of client */
               if (result == 1)
                    logger(LOG_DEBUG, "Added client %p to thread %p", data->client_info,
                           thread);
               else
                    logger(LOG_DEBUG, "Client (%p) is already in list of thread %p",
                           data->client_info, thread);

               /* NULL our own pointer so we don't free memory */
               if (result == 1)
                    data->client_info = NULL;

               /* Look at needed information to oack that client */
               opt_set_multicast(data->tftp_options, thread->mc_addr,
                                 thread->mc_port, 0);
               logger(LOG_INFO, "multicast option -> %s,%d,%d",
                      thread->mc_addr, thread->mc_port, 0);

               /* Send an OACK to that client. There is a possible race condition
                  here where the new server thread OACK this client before us. This should
                  not be a problem: the client thread will receive a second OACK and fall
                  back to non master mode. Then the server will timeout and either resend
                  OACK or continu with the next client */
               opt_options_to_string(data->tftp_options, string, MAXLEN);
               if (data->trace)
                    logger(LOG_DEBUG, "sent OACK <%s>", string);
               tftp_send_oack(thread->sockfd, sa, data->tftp_options,
                              data->data_buffer, data->data_buffer_size);

               /* We are done */
               logger(LOG_INFO, "Client transfered to %p", thread);
               fclose(fp);
               return OK;
          }
          else
          {
               struct addrinfo hints, *result;

               /* configure socket, get an IP address */
               if (tftpd_mcast_get_tid(&data->mc_addr, &data->mc_port) != OK)
               {
                    logger(LOG_ERR, "No multicast address/port available");
                    fclose(fp);
                    return ERR;
               }
               logger(LOG_DEBUG, "mcast_addr: %s, mcast_port: %d",
                      data->mc_addr, data->mc_port);

               /* convert address */
               memset(&hints, 0, sizeof(hints));
               hints.ai_socktype = SOCK_DGRAM;
               hints.ai_flags = AI_NUMERICHOST;
               if (getaddrinfo(data->mc_addr, NULL, &hints, &result) ||
                   sockaddr_set_addrinfo(&data->sa_mcast, result))
               {
                    logger(LOG_ERR, "bad address %s\n",data->mc_addr);
                    fclose(fp);
                    return ERR;
               }
               freeaddrinfo(result);
               sockaddr_set_port(&data->sa_mcast, data->mc_port);

               /* verify address is multicast */
               if (!sockaddr_is_multicast(&data->sa_mcast))
               {
                    logger(LOG_ERR, "bad multicast address %s\n",
                           sockaddr_print_addr(&data->sa_mcast,
                                               addr_str, sizeof(addr_str)));
                    fclose(fp);
                    return ERR;
               }

               /* initialise multicast address structure */
               sockaddr_get_mreq(&data->sa_mcast, &data->mcastaddr);
               if (data->sa_mcast.ss_family == AF_INET)
                    setsockopt(data->sockfd, IPPROTO_IP, IP_MULTICAST_TTL,
                               &data->mcast_ttl, sizeof(data->mcast_ttl));
               else
                    setsockopt(data->sockfd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
                               &data->mcast_ttl, sizeof(data->mcast_ttl));
               
               /* set options data for OACK */
               opt_set_multicast(data->tftp_options, data->mc_addr,
                                 data->mc_port, 1);
               logger(LOG_INFO, "multicast option -> %s,%d,%d", data->mc_addr,
                      data->mc_port, 1);
            
               /* the socket must be unconnected for multicast */
               sa->ss_family = AF_UNSPEC;
               connect(sockfd, (struct sockaddr *)sa, sizeof(*sa));

               /* set multicast flag */
               multicast = 1;
               /* Now ready to receive new clients */
               tftpd_clientlist_ready(data);
          }
     }

     /* copy options to local structure, used when falling back a client to slave */
     memcpy(options, data->tftp_options, sizeof(options));
     opt_set_multicast(options, data->mc_addr, data->mc_port, 0);

     /* That's it, ready to send the file */
     while (1)
     {
          if (tftpd_cancel)
          {
               /* Send error to all client */
               logger(LOG_DEBUG, "thread cancelled");
               do
               {
                    tftpd_clientlist_done(data, client_info, NULL);
                    tftp_send_error(sockfd, &client_info->client,
                                    EUNDEF, data->data_buffer, data->data_buffer_size);
                    if (data->trace)
                    {
                         logger(LOG_DEBUG, "sent ERROR <code: %d, msg: %s> to %s", EUNDEF,
                                tftp_errmsg[EUNDEF],
                                sockaddr_print_addr(&client_info->client,
                                                    addr_str, sizeof(addr_str)));
                    }
               } while (tftpd_clientlist_next(data, &client_info) == 1);
               state = S_ABORT;
          }

          switch (state)
          {
          case S_BEGIN:
               if (opt_support_options(data->tftp_options))
                    state = S_SEND_OACK;
               else
                    state = S_SEND_DATA;
               break;
          case S_SEND_OACK:
               timeout_state = state;
               opt_options_to_string(data->tftp_options, string, MAXLEN);
               if (data->trace)
                    logger(LOG_DEBUG, "sent OACK <%s>", string);
               tftp_send_oack(sockfd, sa, data->tftp_options,
                              data->data_buffer, data->data_buffer_size);
               state = S_WAIT_PACKET;
               break;
          case S_SEND_DATA:
               timeout_state = state;

               data_size = tftp_file_read(fp, tftphdr->th_data, data->data_buffer_size - 4, block_number,
                                          convert, &prev_block_number, &prev_file_pos, &temp);
               data_size += 4;  /* need to consider tftp header */

               /* record the last block number */
               if (feof(fp))
                    last_block = block_number;

               if (multicast)
               {
                    tftp_send_data(sockfd, &data->sa_mcast,
                                   block_number + 1, data_size,
                                   data->data_buffer);
               }
               else
               {
                    tftp_send_data(sockfd, sa, block_number + 1,
                                   data_size, data->data_buffer);
               }
               if (data->trace)
                    logger(LOG_DEBUG, "sent DATA <block: %d, size %d>",
                           block_number + 1, data_size - 4);
               state = S_WAIT_PACKET;
               break;
          case S_WAIT_PACKET:
               data_size = data->data_buffer_size;
               result = tftp_get_packet(sockfd, -1, NULL, sa, &from, NULL,
                                        timeout, &data_size, data->data_buffer);
               switch (result)
               {
               case GET_TIMEOUT:
                    number_of_timeout++;
                    
                    if (number_of_timeout > NB_OF_RETRY)
                    {
                         logger(LOG_INFO, "client (%s) not responding",
                                sockaddr_print_addr(&client_info->client,
                                                    addr_str, sizeof(addr_str)));
                         state = S_END;
                    }
                    else
                    {
                         /* The client failed to ACK our last packet. Send an
                            OACK with mc=0 to it, fetch the next client in the
                            list and continu with this new one */
                         if (multicast && mcast_switch)
                         {
                              client_old = client_info;

                              tftpd_clientlist_next(data, &client_info);

                              if (client_info && (client_info != client_old))
                              {
                                   /* Send an OACK to the old client remove is
                                      master client status */
                                   opt_options_to_string(options,
                                                         string, MAXLEN);
                                   if (data->trace)
                                        logger(LOG_DEBUG, "sent OACK <%s>", string);
                                   tftp_send_oack(sockfd, sa, options,
                                                  data->data_buffer, data->data_buffer_size);

                                   /* Proceed normally with the next client,
                                      going to OACK state */
                                   logger(LOG_INFO,
                                          "Serving next client: %s:%d",
                                          sockaddr_print_addr(
                                               &client_info->client,
                                               addr_str, sizeof(addr_str)),
                                          sockaddr_get_port(
                                               &client_info->client));
                                   sa = &client_info->client;
                                   state = S_SEND_OACK;
                                   break;
                              }
                              else if (client_info == NULL)
                              {
                                   /* we got a big problem if this happend */
                                   logger(LOG_ERR,
                                          "%s: %d: abnormal condition",
                                          __FILE__, __LINE__);
                                   state = S_ABORT;
                                   break;
                              }
                         }
                         logger(LOG_WARNING, "timeout: retrying...");
                         state = timeout_state;
                    }
                    break;
               case GET_ACK:
                    /* handle case where packet come from un unexpected client */
                    if (multicast)
                    {
                         if (!sockaddr_equal(sa, &from))
                         {
                              /* We got an ACK from a client that is not the master client.
                               * If this is an ACK for the last block, mark this client as
                               * done
                               */
                              if ((last_block != -1) && (block_number > last_block))
                              {
                                   if (tftpd_clientlist_done(data, NULL, &from) == 1)
                                        logger(LOG_DEBUG, "client done <%s>",
                                               sockaddr_print_addr(
                                                    &from, addr_str,
                                                    sizeof(addr_str)));
                                   else
                                        logger(LOG_WARNING, "packet discarded <%s:%d>",
                                               sockaddr_print_addr(
                                                    &from, addr_str,
                                                    sizeof(addr_str)),
                                               sockaddr_get_port(&from));
                              }
                              else
                                   /* If not, send and OACK with mc=0 to shut it up. */
                              {
                                   opt_options_to_string(options,
                                                         string, MAXLEN);
                                   if (data->trace)
                                        logger(LOG_DEBUG, "sent OACK <%s>", string);
                                   tftp_send_oack(sockfd, &from, options,
                                                  data->data_buffer, data->data_buffer_size);
                              }
                              break;
                              
                         }
                    }
                    else
                    {
                         /* check that the packet is from the current client */
                         if (sockaddr_get_port(sa) != sockaddr_get_port(&from))
                         {
                              if (data->checkport)
                              {
                                   logger(LOG_WARNING, "packet discarded <%s:%d>",
                                          sockaddr_print_addr(&from, addr_str,
                                                              sizeof(addr_str)),
                                          sockaddr_get_port(&from));
                                   break;
                              }
                              else
                                   logger(LOG_WARNING,
                                          "source port mismatch, check bypassed");
                         }
                    }
                    /* The ACK is from the current client */
                    number_of_timeout = 0;
                    block_number = ntohs(tftphdr->th_block);
                    if (data->trace)
                         logger(LOG_DEBUG, "received ACK <block: %d>",
                                block_number);
                    if ((last_block != -1) && (block_number > last_block))
                    {
                         state = S_END;
                         break;
                    }
                    state = S_SEND_DATA;
                    break;
               case GET_ERROR:
                    /* handle case where packet come from un unexpected client */
                    if (multicast)
                    {
                         /* if packet is not from the current master client */
                         if (!sockaddr_equal(sa, &from))
                         {
                              /* mark this client done */
                              if (tftpd_clientlist_done(data, NULL, &from) == 1)
                              {
                                   if (data->trace)
                                        logger(LOG_DEBUG, "client sent ERROR, mark as done <%s>",
                                               sockaddr_print_addr(
                                                    &from, addr_str,
                                                    sizeof(addr_str)));
                              }
                              else
                                   logger(LOG_WARNING, "packet discarded <%s>",
                                          sockaddr_print_addr(&from, addr_str,
                                                              sizeof(addr_str)));
                              /* current state is unchanged */
                              break;
                         }
                    }
                    else
                    {
                         /* check that the packet is from the current client */
                         if (sockaddr_get_port(sa) != sockaddr_get_port(&from))
                         {
                              if (data->checkport)
                              {
                                   logger(LOG_WARNING, "packet discarded <%s>",
                                          sockaddr_print_addr(&from, addr_str,
                                                              sizeof(addr_str)));
                                   break;
                              }
                              else
                                   logger(LOG_WARNING,
                                          "source port mismatch, check bypassed");
                         }
                    }
                    /* Got an ERROR from the current master client */
                    Strncpy(string, tftphdr->th_msg,
                            (((data_size - 4) > MAXLEN) ? MAXLEN :
                             (data_size - 4)));
                    if (data->trace)
                         logger(LOG_DEBUG, "received ERROR <code: %d, msg: %s>",
                                ntohs(tftphdr->th_code), string);
                    if (multicast)
                    {
                         logger(LOG_DEBUG, "Marking client as done");
                         state = S_END;
                    }
                    else
                         state = S_ABORT;
                    break;
               case GET_DISCARD:
                    /* FIXME: should we increment number_of_timeout */
                    logger(LOG_WARNING, "packet discarded <%s>",
                           sockaddr_print_addr(&from, addr_str,
                                               sizeof(addr_str)));
                    break;
               case ERR:
                    logger(LOG_ERR, "%s: %d: recvfrom: %s",
                           __FILE__, __LINE__, strerror(errno));
                    state = S_ABORT;
                    break;
               default:
                    logger(LOG_ERR, "%s: %d: abnormal return value %d",
                           __FILE__, __LINE__, result);
               }
               break;
          case S_END:
               if (multicast)
               {
                    logger(LOG_DEBUG, "End of multicast transfer");
                    /* mark the current client done */
                    tftpd_clientlist_done(data, client_info, NULL);
                    /* Look if there is another client to serve. We lock list of
                       client to make sure no other thread try to add clients in
                       our back */
                    if (tftpd_clientlist_next(data, &client_info) == 1)
                    {
                         logger(LOG_INFO,
                                "Serving next client: %s:%d",
                                sockaddr_print_addr(&client_info->client,
                                                    addr_str, sizeof(addr_str)),
                                sockaddr_get_port(&client_info->client));
                         /* client is a new client structure */
                         sa =  &client_info->client;
                         /* nedd to send an oack to that client */
                         state = S_SEND_OACK;                
                         fseek(fp, 0, SEEK_SET);
                    }
                    else
                    {
                         logger(LOG_INFO, "No more client, end of tranfers");
                         fclose(fp);
                         return OK;
                    }
               }
               else
               {
                    logger(LOG_DEBUG, "End of transfer");
                    fclose(fp);
                    return OK;
               }
               break;
          case S_ABORT:
               logger(LOG_DEBUG, "Aborting transfer");
               fclose(fp);
               return ERR;
          default:
               fclose(fp);
               logger(LOG_ERR, "%s: %d: abnormal condition",
                      __FILE__, __LINE__);
               return ERR;
          }
     }
}
Esempio n. 4
0
/*
 * Receive a file. It is implemented as a state machine using a while loop
 * and a switch statement. Function flow is as follow:
 *  - sanity check
 *  - check client's request
 *  - enter state machine
 *
 *     1) send a ACK or OACK
 *     2) wait replay
 *          - if DATA packet, read it, send an acknoledge, goto 2
 *          - if ERROR abort
 *          - if TIMEOUT goto previous state
 */
int tftpd_receive_file(struct thread_data *data)
{
     int state = S_BEGIN;
     int timeout_state = state;
     int result;
     int block_number = 0;
     int data_size;
     int sockfd = data->sockfd;
     struct sockaddr_storage *sa = &data->client_info->client;
     struct sockaddr_storage from;
     char addr_str[SOCKADDR_PRINT_ADDR_LEN];
     struct tftphdr *tftphdr = (struct tftphdr *)data->data_buffer;
     FILE *fp;
     char filename[MAXLEN];
     char string[MAXLEN];
     int timeout = data->timeout;
     int number_of_timeout = 0;
     int all_blocks_received = 0; /* temporary kludge */
     int convert = 0;           /* if true, do netascii convertion */

     int prev_block_number = 0; /* needed to support netascii convertion */
     int temp = 0;

     /* look for mode option */
     if (strcasecmp(data->tftp_options[OPT_MODE].value, "netascii") == 0)
     {
          convert = 1;
          logger(LOG_DEBUG, "will do netascii convertion");
     }

     /* file name verification */
     Strncpy(filename, data->tftp_options[OPT_FILENAME].value,
             MAXLEN);
     if (tftpd_rules_check(filename) != OK)
     {
          tftp_send_error(sockfd, sa, EACCESS, data->data_buffer, data->data_buffer_size);
          if (data->trace)
               logger(LOG_DEBUG, "sent ERROR <code: %d, msg: %s>", EACCESS,
                      tftp_errmsg[EACCESS]);
          return ERR;
     }

     /* Open the file for writing. */
     if ((fp = fopen(filename, "w")) == NULL)
     {
          /* Can't create the file. */
          logger(LOG_INFO, "Can't open %s for writing", filename);
          tftp_send_error(sockfd, sa, EACCESS, data->data_buffer, data->data_buffer_size);
          if (data->trace)
               logger(LOG_DEBUG, "sent ERROR <code: %d, msg: %s>", EACCESS,
                      tftp_errmsg[EACCESS]);
          return ERR;
     }

     /* tsize option */
     if (((result = opt_get_tsize(data->tftp_options)) > -1) && !convert)
     {
          opt_set_tsize(result, data->tftp_options);
          logger(LOG_DEBUG, "tsize option -> %d", result);
     }

     /* timeout option */
     if ((result = opt_get_timeout(data->tftp_options)) > -1)
     {
          if ((result < 1) || (result > 255))
          {
               tftp_send_error(sockfd, sa, EOPTNEG, data->data_buffer, data->data_buffer_size);
               if (data->trace)
                    logger(LOG_DEBUG, "sent ERROR <code: %d, msg: %s>", EOPTNEG,
                           tftp_errmsg[EOPTNEG]);
               fclose(fp);
               return ERR;
          }
          timeout = result;
          opt_set_timeout(timeout, data->tftp_options);
          logger(LOG_DEBUG, "timeout option -> %d", timeout);
     }

     /* blksize options */
     if ((result = opt_get_blksize(data->tftp_options)) > -1)
     {
          if ((result < 8) || (result > 65464))
          {
               tftp_send_error(sockfd, sa, EOPTNEG, data->data_buffer, data->data_buffer_size);
               if (data->trace)
                    logger(LOG_DEBUG, "sent ERROR <code: %d, msg: %s>", EOPTNEG,
                           tftp_errmsg[EOPTNEG]);
               fclose(fp);
               return ERR;
          }

          data->data_buffer_size = result + 4;
          data->data_buffer = realloc(data->data_buffer, data->data_buffer_size);

          if (data->data_buffer == NULL)
          {
               logger(LOG_ERR, "memory allocation failure");
               fclose(fp);
               return ERR;
          }
          tftphdr = (struct tftphdr *)data->data_buffer;

          if (data->data_buffer == NULL)
          {
               tftp_send_error(sockfd, sa, ENOSPACE, data->data_buffer, data->data_buffer_size);
               if (data->trace)
                    logger(LOG_DEBUG, "sent ERROR <code: %d, msg: %s>", ENOSPACE,
                           tftp_errmsg[ENOSPACE]);
               fclose(fp);
               return ERR;
          }
          opt_set_blksize(result, data->tftp_options);
          logger(LOG_DEBUG, "blksize option -> %d", result);
     }

     /* that's it, we start receiving the file */
     while (1)
     {
          if (tftpd_cancel)
          {
               logger(LOG_DEBUG, "thread cancelled");
               tftp_send_error(sockfd, sa, EUNDEF, data->data_buffer, data->data_buffer_size);
               if (data->trace)
                    logger(LOG_DEBUG, "sent ERROR <code: %d, msg: %s>", EUNDEF,
                           tftp_errmsg[EUNDEF]);
               state = S_ABORT;
          }

          switch (state)
          {
          case S_BEGIN:
               /* Did the client request RFC1350 options ?*/
               if (opt_support_options(data->tftp_options))
                    state = S_SEND_OACK;
               else
                    state = S_SEND_ACK;
               break;
          case S_SEND_ACK:
               timeout_state = state;
               tftp_send_ack(sockfd, sa, block_number);
               if (data->trace)
                    logger(LOG_DEBUG, "sent ACK <block: %d>", block_number);
               if (all_blocks_received)
                    state = S_END;
               else
                    state = S_WAIT_PACKET;
               break;
          case S_SEND_OACK:
               timeout_state = state;
               tftp_send_oack(sockfd, sa, data->tftp_options,
                              data->data_buffer, data->data_buffer_size);
               opt_options_to_string(data->tftp_options, string, MAXLEN);
               if (data->trace)
                    logger(LOG_DEBUG, "sent OACK <%s>", string);
               state = S_WAIT_PACKET;
               break;
          case S_WAIT_PACKET:
               data_size = data->data_buffer_size;
               result = tftp_get_packet(sockfd, -1, NULL, sa, &from, NULL,
                                        timeout, &data_size, data->data_buffer);
               
               switch (result)
               {
               case GET_TIMEOUT:
                    number_of_timeout++;
                    if (number_of_timeout > NB_OF_RETRY)
                    {
                         logger(LOG_INFO, "client (%s) not responding",
                                sockaddr_print_addr(&data->client_info->client,
                                                    addr_str, sizeof(addr_str)));
                         state = S_END;
                    }
                    else
                    {
                         logger(LOG_WARNING, "timeout: retrying...");
                         state = timeout_state;
                    }
                    break;
               case GET_ERROR:
                    /*
                     * This does not work correctly if load balancers are
                     * employed on one side of a multihomed host. ie, the
                     * tftp RRQ goes through the load balancer and has the
                     * source ports changed while the multicast traffic
                     * bypasses the load balancers.
                     *
                     * **** It is not compliant with RFC1350 to skip this
                     * **** test since the port number is the TID. Use this
                     * **** only if you know what you're doing.
                     */
                    if (sockaddr_get_port(sa) != sockaddr_get_port(&from))
                    {
                         if (data->checkport)
                         {
                              logger(LOG_WARNING, "packet discarded <%s>",
                                     sockaddr_print_addr(&from, addr_str,
                                                         sizeof(addr_str)));
                              break;
                         }
                         else
                              logger(LOG_WARNING, "source port mismatch, check bypassed");
                    }
                    Strncpy(string, tftphdr->th_msg,
                            (((data_size - 4) > MAXLEN) ? MAXLEN :
                             (data_size - 4)));
                    if (data->trace)
                         logger(LOG_DEBUG, "received ERROR <code: %d, msg: %s>",
                                ntohs(tftphdr->th_code), string);
                    state = S_ABORT;
                    break;
               case GET_DATA:
                    /* Check that source port match */
                    if (sockaddr_get_port(sa) != sockaddr_get_port(&from))
                    {
                         if (data->checkport)
                         {
                              logger(LOG_WARNING, "packet discarded <%s>",
                                     sockaddr_print_addr(&from, addr_str,
                                                         sizeof(addr_str)));
                              break;
                         }
                         else
                              logger(LOG_WARNING, "source port mismatch, check bypassed");
                    }
                    number_of_timeout = 0;
                    state = S_DATA_RECEIVED;
                    break;
               case GET_DISCARD:
                    /* FIXME: should we increment number_of_timeout */
                    logger(LOG_WARNING, "packet discarded <%s>",
                           sockaddr_print_addr(&from, addr_str,
                                               sizeof(addr_str)));
                    break;
               case ERR:
                    logger(LOG_ERR, "%s: %d: recvfrom: %s",
                           __FILE__, __LINE__, strerror(errno));
                    state = S_ABORT;
                    break;
               default:
                    logger(LOG_ERR, "%s: %d: abnormal return value %d",
                           __FILE__, __LINE__, result);
                    state = S_ABORT;
               }
               break;
          case S_DATA_RECEIVED:
               /* We need to seek to the right place in the file */
               block_number = ntohs(tftphdr->th_block);
               if (data->trace)
                    logger(LOG_DEBUG, "received DATA <block: %d, size: %d>",
                           block_number, data_size - 4);

               if (tftp_file_write(fp, tftphdr->th_data, data->data_buffer_size - 4, block_number,
                                   data_size - 4, convert, &prev_block_number, &temp)
                   != data_size - 4)
               {
                    logger(LOG_ERR, "%s: %d: error writing to file %s",
                           __FILE__, __LINE__, filename);
                    tftp_send_error(sockfd, sa, ENOSPACE, data->data_buffer,
                                    data->data_buffer_size);
                    if (data->trace)
                         logger(LOG_DEBUG, "sent ERROR <code: %d, msg: %s>",
                                ENOSPACE, tftp_errmsg[ENOSPACE]);
                    state = S_ABORT;
                    break;
               }
               if (data_size < data->data_buffer_size)
                    all_blocks_received = 1;
               else
                    all_blocks_received = 0;
               state = S_SEND_ACK;
               break;
          case S_END:
               fclose(fp);
               return OK;
          case S_ABORT:
               fclose(fp);
               return ERR;
          default:
               fclose(fp);
               logger(LOG_ERR, "%s: %d: tftpd_file.c: huh?",
                      __FILE__, __LINE__);
               return ERR;
          }
     }
}
Esempio n. 5
0
uint16_t web_server_connection_get_port(struct web_server_connection_t* wc) {
    
    return sockaddr_get_port(socket_get_remote_end_point(wc->socket));
    
}
Esempio n. 6
0
void web_server_connection_take_off(struct web_server_connection_t* wc) {
    
    mutex_lock(wc->mutex);
    
    wc->has_taken_off = wc->is_connected = true;
    
    socket_set_receive_callback(wc->socket, _web_server_connection_socket_recieve_callback, wc);
    
    mutex_unlock(wc->mutex);
    
    const char *ip = sockaddr_get_host(socket_get_remote_end_point(wc->socket));
    
    log_message(LOG_INFO, "RAOPConnection (%p) took over connection from %s:%d", wc, ip, sockaddr_get_port(socket_get_remote_end_point(wc->socket)));
    
}
Esempio n. 7
0
struct tcptableent *addentry(struct tcptable *table,
			     struct sockaddr_storage *saddr,
			     struct sockaddr_storage *daddr,
			     int protocol, char *ifname,
			     int *rev_lookup, int rvnfd)
{
	struct tcptableent *new_entry;
	struct closedlist *ctemp;

	/*
	 * Allocate and attach a new node if no closed entries found
	 */

	if (table->closedentries == NULL) {
		new_entry = xmalloc(sizeof(struct tcptableent));
		new_entry->oth_connection = xmalloc(sizeof(struct tcptableent));

		new_entry->oth_connection->oth_connection = new_entry;

		if (table->head == NULL) {
			new_entry->prev_entry = NULL;
			table->head = new_entry;

			table->firstvisible = new_entry;
		}
		if (table->tail != NULL) {
			table->tail->next_entry = new_entry;
			new_entry->prev_entry = table->tail;
		}
		table->lastpos++;
		new_entry->index = table->lastpos;
		table->lastpos++;
		new_entry->oth_connection->index = table->lastpos;

		table->tail = new_entry->oth_connection;
		new_entry->next_entry = new_entry->oth_connection;
		new_entry->next_entry->prev_entry = new_entry;
		new_entry->next_entry->next_entry = NULL;


		if (new_entry->oth_connection->index <=
		    table->firstvisible->index + (table->imaxy - 1))
			table->lastvisible = new_entry->oth_connection;
		else if (new_entry->index <=
			 table->firstvisible->index + (table->imaxy - 1))
			table->lastvisible = new_entry;

		new_entry->reused = new_entry->oth_connection->reused = 0;
		table->count++;

		rate_alloc(&new_entry->rate, 5);
		rate_alloc(&new_entry->oth_connection->rate, 5);

		print_tcp_num_entries(table);
	} else {
		/*
		 * If we reach this point, we're allocating off the list of closed
		 * entries.  In this case, we take the top entry, let the new_entry
		 * variable point to whatever the top is pointing to.  The new_entry's
		 * oth_connection also points to the reused entry's oth_connection
		 */

		new_entry = table->closedentries->closedentry;
		new_entry->oth_connection = table->closedentries->pair;

		ctemp = table->closedentries;
		table->closedentries = table->closedentries->next_entry;
		free(ctemp);

		/*
		 * Mark the closed list's tail as NULL if we use the last entry
		 * in the list to prevent a dangling reference.
		 */

		if (table->closedentries == NULL)
			table->closedtail = NULL;

		new_entry->reused = new_entry->oth_connection->reused = 1;

		/*
		 * Delete the old hash entries for this reallocated node;
		 */

		del_tcp_hash_node(table, new_entry);
		del_tcp_hash_node(table, new_entry->oth_connection);
	}

	/*
	 * Fill in address fields with raw IP addresses
	 */

	sockaddr_copy(&new_entry->saddr, saddr);
	sockaddr_copy(&new_entry->oth_connection->daddr, saddr);
	sockaddr_copy(&new_entry->daddr, daddr);
	sockaddr_copy(&new_entry->oth_connection->saddr, daddr);
	new_entry->protocol = protocol;

	/*
	 * Initialize count fields
	 */

	new_entry->pcount = new_entry->bcount = 0;
	new_entry->win = new_entry->psize = 0;
	new_entry->timedout = new_entry->oth_connection->timedout = 0;
	new_entry->oth_connection->pcount = new_entry->oth_connection->bcount =
	    0;
	new_entry->oth_connection->win = new_entry->oth_connection->psize = 0;

	/*
	 * Store interface name
	 */

	strcpy(new_entry->ifname, ifname);
	strcpy(new_entry->oth_connection->ifname, ifname);

	/*
	 * Zero out MAC address fields
	 */

	memset(new_entry->smacaddr, 0, sizeof(new_entry->smacaddr));
	memset(new_entry->oth_connection->smacaddr, 0, sizeof(new_entry->oth_connection->smacaddr));

	new_entry->stat = new_entry->oth_connection->stat = 0;

	new_entry->s_fstat =
	    revname(rev_lookup, &new_entry->saddr,
		    new_entry->s_fqdn, sizeof(new_entry->s_fqdn), rvnfd);

	new_entry->d_fstat =
	    revname(rev_lookup, &new_entry->daddr,
		    new_entry->d_fqdn, sizeof(new_entry->d_fqdn), rvnfd);

	/* set port service names (where applicable) */
	servlook(sockaddr_get_port(saddr), IPPROTO_TCP, new_entry->s_sname, 10);
	servlook(sockaddr_get_port(daddr), IPPROTO_TCP, new_entry->d_sname, 10);

	strcpy(new_entry->oth_connection->s_sname, new_entry->d_sname);
	strcpy(new_entry->oth_connection->d_sname, new_entry->s_sname);

	strcpy(new_entry->oth_connection->d_fqdn, new_entry->s_fqdn);
	strcpy(new_entry->oth_connection->s_fqdn, new_entry->d_fqdn);
	new_entry->oth_connection->s_fstat = new_entry->d_fstat;
	new_entry->oth_connection->d_fstat = new_entry->s_fstat;

	if (new_entry->index < new_entry->oth_connection->index) {
		new_entry->half_bracket = ACS_ULCORNER;
		new_entry->oth_connection->half_bracket = ACS_LLCORNER;
	} else {
		new_entry->half_bracket = ACS_LLCORNER;
		new_entry->oth_connection->half_bracket = ACS_ULCORNER;
	}

	new_entry->inclosed = new_entry->oth_connection->inclosed = 0;
	new_entry->finack = new_entry->oth_connection->finack = 0;
	new_entry->finsent = new_entry->oth_connection->finsent = 0;
	new_entry->partial = new_entry->oth_connection->partial = 0;
	new_entry->spanbr = new_entry->oth_connection->spanbr = 0;
	new_entry->conn_starttime = new_entry->oth_connection->conn_starttime =
	    time(NULL);

	rate_init(&new_entry->rate);
	rate_init(&new_entry->oth_connection->rate);

	/*
	 * Mark flow rate start time and byte counter for flow computation
	 * if the highlight bar is on either flow of the new connection.
	 */
	if (table->barptr == new_entry) {
		new_entry->starttime = time(NULL);
		new_entry->spanbr = 0;
	} else if (table->barptr == new_entry->oth_connection) {
		new_entry->oth_connection->starttime = time(NULL);
		new_entry->oth_connection->spanbr = 0;
	}

	/*
	 * Add entries to hash table
	 */

	add_tcp_hash_entry(table, new_entry);
	add_tcp_hash_entry(table, new_entry->oth_connection);

	return new_entry;
}