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); }
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; }
/* * 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; } } }
/* * 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; } } }
uint16_t web_server_connection_get_port(struct web_server_connection_t* wc) { return sockaddr_get_port(socket_get_remote_end_point(wc->socket)); }
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))); }
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; }