1#ifdef HAVE_CONFIG_H
2#include "config.h"
3#endif /* HAVE_CONFIG_H */
4
5#include <stdio.h>
6#include <stdlib.h>
7#include <unistd.h>
8#include <errno.h>
9#include <string.h>
10#include <sys/types.h>
11#include <sys/socket.h>
12#include <netinet/in.h>
13#include <arpa/inet.h>
14#include <netdb.h>
15#include <inttypes.h>
16#include <sys/types.h>
17
18#include <sys/param.h>
19#include <sys/cdefs.h>
20
21#include <atalk/fce_api.h>
22#include <atalk/util.h>
23
24#define MAXBUFLEN 1024
25
26static char *fce_ev_names[] = {
27    "",
28    "FCE_FILE_MODIFY",
29    "FCE_FILE_DELETE",
30    "FCE_DIR_DELETE",
31    "FCE_FILE_CREATE",
32    "FCE_DIR_CREATE",
33    "FCE_TM_SIZE"
34};
35
36// get sockaddr, IPv4 or IPv6:
37static void *get_in_addr(struct sockaddr *sa)
38{
39    if (sa->sa_family == AF_INET) {
40        return &(((struct sockaddr_in*)sa)->sin_addr);
41    }
42
43    return &(((struct sockaddr_in6*)sa)->sin6_addr);
44}
45
46static int unpack_fce_packet(unsigned char *buf, struct fce_packet *packet)
47{
48    unsigned char *p = buf;
49
50    memcpy(&packet->magic[0], p, sizeof(packet->magic));
51    p += sizeof(packet->magic);
52
53    packet->version = *p;
54    p++;
55
56    packet->mode = *p;
57    p++;
58
59    memcpy(&packet->event_id, p, sizeof(packet->event_id));
60    p += sizeof(packet->event_id);
61    packet->event_id = ntohl(packet->event_id);
62
63    memcpy(&packet->datalen, p, sizeof(packet->datalen));
64    p += sizeof(packet->datalen);
65    packet->datalen = ntohs(packet->datalen);
66
67    memcpy(&packet->data[0], p, packet->datalen);
68    p += packet->datalen;
69
70    return 0;
71}
72
73int main(void)
74{
75    int sockfd;
76    struct addrinfo hints, *servinfo, *p;
77    int rv;
78    int numbytes;
79    struct sockaddr_storage their_addr;
80    char buf[MAXBUFLEN];
81    socklen_t addr_len;
82    char s[INET6_ADDRSTRLEN];
83    uint64_t tmsize;
84
85    memset(&hints, 0, sizeof hints);
86    hints.ai_family = AF_UNSPEC; // set to AF_INET to force IPv4
87    hints.ai_socktype = SOCK_DGRAM;
88
89    if ((rv = getaddrinfo(NULL, FCE_DEFAULT_PORT_STRING, &hints, &servinfo)) != 0) {
90        fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
91        return 1;
92    }
93
94    // loop through all the results and bind to the first we can
95    for(p = servinfo; p != NULL; p = p->ai_next) {
96        if ((sockfd = socket(p->ai_family, p->ai_socktype,
97                             p->ai_protocol)) == -1) {
98            perror("listener: socket");
99            continue;
100        }
101
102        if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
103            close(sockfd);
104            perror("listener: bind");
105            continue;
106        }
107
108        break;
109    }
110
111    if (p == NULL) {
112        fprintf(stderr, "listener: failed to bind socket\n");
113        return 2;
114    }
115
116    freeaddrinfo(servinfo);
117
118    printf("listener: waiting to recvfrom...\n");
119
120    addr_len = sizeof their_addr;
121
122    struct fce_packet packet;
123    while (1) {
124        if ((numbytes = recvfrom(sockfd,
125                                 buf,
126                                 MAXBUFLEN - 1,
127                                 0,
128                                 (struct sockaddr *)&their_addr,
129                                 &addr_len)) == -1) {
130            perror("recvfrom");
131            exit(1);
132        }
133
134        unpack_fce_packet(buf, &packet);
135
136        if (memcmp(packet.magic, FCE_PACKET_MAGIC, sizeof(packet.magic)) == 0) {
137
138            switch (packet.mode) {
139            case FCE_TM_SIZE:
140                memcpy(&tmsize, packet.data, sizeof(uint64_t));
141                tmsize = ntoh64(tmsize);
142                printf("ID: %" PRIu32 ", Event: %s, Volume: %s, TM used size: %" PRIu64 " \n",
143                       packet.event_id, fce_ev_names[packet.mode], packet.data + sizeof(uint64_t), tmsize);
144                break;
145
146            case FCE_CONN_START:
147                printf("FCE Start\n");
148                break;
149
150            case FCE_CONN_BROKEN:
151                printf("Broken FCE connection\n");
152                break;
153
154            default:
155                printf("ID: %" PRIu32 ", Event: %s, Path: %s\n",
156                       packet.event_id, fce_ev_names[packet.mode], packet.data);
157                break;
158            }
159        }
160    }
161
162    close(sockfd);
163    return 0;
164}
165