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#include <sys/param.h>
18
19#include <atalk/fce_api.h>
20#include <atalk/util.h>
21
22#define MAXBUFLEN 1024
23
24static char *fce_ev_names[] = {
25    "",
26    "FCE_FILE_MODIFY",
27    "FCE_FILE_DELETE",
28    "FCE_DIR_DELETE",
29    "FCE_FILE_CREATE",
30    "FCE_DIR_CREATE"
31};
32
33static int unpack_fce_packet(unsigned char *buf, struct fce_packet *packet)
34{
35    unsigned char *p = buf;
36
37    memcpy(&packet->magic[0], p, sizeof(packet->magic));
38    p += sizeof(packet->magic);
39
40    packet->version = *p;
41    p++;
42
43    packet->mode = *p;
44    p++;
45
46    memcpy(&packet->event_id, p, sizeof(packet->event_id));
47    p += sizeof(packet->event_id);
48    packet->event_id = ntohl(packet->event_id);
49
50    memcpy(&packet->datalen, p, sizeof(packet->datalen));
51    p += sizeof(packet->datalen);
52    packet->datalen = ntohs(packet->datalen);
53
54    memcpy(&packet->data[0], p, packet->datalen);
55    packet->data[packet->datalen] = 0; /* 0 terminate strings */
56    p += packet->datalen;
57
58    return 0;
59}
60
61int main(void)
62{
63    int sockfd;
64    struct addrinfo hints, *servinfo, *p;
65    int rv;
66    int numbytes;
67    struct sockaddr_storage their_addr;
68    char buf[MAXBUFLEN];
69    socklen_t addr_len;
70
71    memset(&hints, 0, sizeof hints);
72    hints.ai_family = AF_UNSPEC; // set to AF_INET to force IPv4
73    hints.ai_socktype = SOCK_DGRAM;
74
75    if ((rv = getaddrinfo(NULL, FCE_DEFAULT_PORT_STRING, &hints, &servinfo)) != 0) {
76        fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
77        return 1;
78    }
79
80    // loop through all the results and bind to the first we can
81    for(p = servinfo; p != NULL; p = p->ai_next) {
82        if ((sockfd = socket(p->ai_family, p->ai_socktype,
83                             p->ai_protocol)) == -1) {
84            perror("listener: socket");
85            continue;
86        }
87
88        if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
89            close(sockfd);
90            perror("listener: bind");
91            continue;
92        }
93
94        break;
95    }
96
97    if (p == NULL) {
98        fprintf(stderr, "listener: failed to bind socket\n");
99        return 2;
100    }
101
102    freeaddrinfo(servinfo);
103
104    printf("listener: waiting to recvfrom...\n");
105
106    addr_len = sizeof their_addr;
107
108    struct fce_packet packet;
109    while (1) {
110        if ((numbytes = recvfrom(sockfd,
111                                 buf,
112                                 MAXBUFLEN - 1,
113                                 0,
114                                 (struct sockaddr *)&their_addr,
115                                 &addr_len)) == -1) {
116            perror("recvfrom");
117            exit(1);
118        }
119
120        unpack_fce_packet((unsigned char *)buf, &packet);
121
122        if (memcmp(packet.magic, FCE_PACKET_MAGIC, sizeof(packet.magic)) == 0) {
123
124            switch (packet.mode) {
125            case FCE_CONN_START:
126                printf("FCE Start\n");
127                break;
128
129            case FCE_CONN_BROKEN:
130                printf("Broken FCE connection\n");
131                break;
132
133            default:
134                printf("ID: %" PRIu32 ", Event: %s, Path: %s\n",
135                       packet.event_id, fce_ev_names[packet.mode], packet.data);
136                break;
137            }
138        }
139    }
140
141    close(sockfd);
142    return 0;
143}
144