/* * * Dispatcher for all incoming file change events * * */ static int register_fce(const char *u_name, int is_dir, int mode) { if (udp_sockets == 0) /* No listeners configured */ return AFP_OK; if (u_name == NULL) return AFPERR_PARAM; static int first_event = FCE_TRUE; /* do some initialization on the fly the first time */ if (first_event) { fce_initialize_history(); } /* handle files which should not cause events (.DS_Store atc. ) */ for (int i = 0; skip_files[i] != NULL; i++) { if (!strcmp( u_name, skip_files[i])) return AFP_OK; } char full_path_buffer[MAXPATHLEN + 1] = {""}; const char *cwd = getcwdpath(); if (mode == FCE_TM_SIZE) { strlcpy(full_path_buffer, u_name, MAXPATHLEN); } else if (!is_dir || mode == FCE_DIR_DELETE) { if (strlen( cwd ) + strlen( u_name) + 1 >= MAXPATHLEN) { LOG(log_error, logtype_afpd, "FCE file name too long: %s/%s", cwd, u_name ); return AFPERR_PARAM; } sprintf( full_path_buffer, "%s/%s", cwd, u_name ); } else { if (strlen( cwd ) >= MAXPATHLEN) { LOG(log_error, logtype_afpd, "FCE directory name too long: %s", cwd); return AFPERR_PARAM; } strcpy( full_path_buffer, cwd); } /* Can we ignore this event based on type or history? */ if (!(mode & FCE_TM_SIZE) && fce_handle_coalescation( full_path_buffer, is_dir, mode )) { LOG(log_debug9, logtype_afpd, "Coalesced fc event <%d> for <%s>", mode, full_path_buffer ); return AFP_OK; } LOG(log_debug9, logtype_afpd, "Detected fc event <%d> for <%s>", mode, full_path_buffer ); /* we do initilization on the fly, no blocking calls in here * (except when using FQDN in broken DNS environment) */ if (first_event == FCE_TRUE) { fce_init_udp(); /* Notify listeners the we start from the beginning */ send_fce_event( "", FCE_CONN_START ); first_event = FCE_FALSE; } /* Handle UDP transport */ send_fce_event( full_path_buffer, mode ); return AFP_OK; }
/* * Send the fce information to all (connected) listeners * We dont give return code because all errors are handled internally (I hope..) * */ static void send_fce_event( char *path, int mode ) { static int first_event = FCE_TRUE; struct fce_packet packet; void *data = &packet; static uint32_t event_id = 0; /* the unique packet couter to detect packet/data loss. Going from 0xFFFFFFFF to 0x0 is a valid increment */ time_t now = time(NULL); LOG(log_debug, logtype_afpd, "send_fce_event: start"); /* initialized ? */ if (first_event == FCE_TRUE) { first_event = FCE_FALSE; fce_init_udp(); /* Notify listeners the we start from the beginning */ send_fce_event( "", FCE_CONN_START ); } /* build our data packet */ ssize_t data_len = build_fce_packet( &packet, path, mode, ++event_id ); pack_fce_packet(&packet, iobuf, MAXIOBUF); for (int i = 0; i < udp_sockets; i++) { int sent_data = 0; struct udp_entry *udp_entry = udp_socket_list + i; /* we had a problem earlier ? */ if (udp_entry->sock == -1) { /* We still have to wait ?*/ if (now < udp_entry->next_try_on_error) continue; /* Reopen socket */ udp_entry->sock = socket(udp_entry->addrinfo.ai_family, udp_entry->addrinfo.ai_socktype, udp_entry->addrinfo.ai_protocol); if (udp_entry->sock == -1) { /* failed again, so go to rest again */ LOG(log_error, logtype_afpd, "Cannot recreate socket for fce UDP connection: errno %d", errno ); udp_entry->next_try_on_error = now + FCE_SOCKET_RETRY_DELAY_S; continue; } udp_entry->next_try_on_error = 0; /* Okay, we have a running socket again, send server that we had a problem on our side*/ data_len = build_fce_packet( &packet, "", FCE_CONN_BROKEN, 0 ); pack_fce_packet(&packet, iobuf, MAXIOBUF); sendto(udp_entry->sock, iobuf, data_len, 0, (struct sockaddr *)&udp_entry->sockaddr, udp_entry->addrinfo.ai_addrlen); /* Rebuild our original data packet */ data_len = build_fce_packet( &packet, path, mode, event_id ); pack_fce_packet(&packet, iobuf, MAXIOBUF); } sent_data = sendto(udp_entry->sock, iobuf, data_len, 0, (struct sockaddr *)&udp_entry->sockaddr, udp_entry->addrinfo.ai_addrlen); /* Problems ? */ if (sent_data != data_len) { /* Argh, socket broke, we close and retry later */ LOG(log_error, logtype_afpd, "send_fce_event: error sending packet to %s:%s, transfered %d of %d: %s", udp_entry->addr, udp_entry->port, sent_data, data_len, strerror(errno)); close( udp_entry->sock ); udp_entry->sock = -1; udp_entry->next_try_on_error = now + FCE_SOCKET_RETRY_DELAY_S; } } }