Statistics
| Branch: | Revision:

peerstreamer-src / src / pschannel.c @ cea8d274

History | View | Annotate | Download (6.27 KB)

1
/*******************************************************************
2
* PeerStreamer-ng is a P2P video streaming application exposing a ReST
3
* interface.
4
* Copyright (C) 2017 Luca Baldesi <luca.baldesi@unitn.it>
5
*
6
* This program is free software: you can redistribute it and/or modify
7
* it under the terms of the GNU Affero General Public License as published by
8
* the Free Software Foundation, either version 3 of the License, or
9
* (at your option) any later version.
10
*
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
* GNU Affero General Public License for more details.
15
*
16
* You should have received a copy of the GNU Affero General Public License
17
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
*******************************************************************/
19

    
20
#include<pschannel.h>
21
#include<ord_set.h>
22
#include<stdint.h>
23
#include<string.h>
24
#include<stdlib.h>
25
#include<stdio.h>
26
#include<tokens.h>
27
#include<debug.h>
28

    
29
int8_t pschannel_cmp(const void *ch1,const  void *ch2)
30
{
31
        const struct pschannel *psc1, *psc2;
32
        int res;
33

    
34
        psc1 = (const struct pschannel *) ch1;
35
        psc2 = (const struct pschannel *) ch2;
36
        res = strcmp(psc1->ipaddr, psc2->ipaddr);
37
        if (res == 0)
38
                res = strcmp(psc1->port, psc2->port);
39
        return res;
40
}
41

    
42
struct pschannel_bucket {
43
        struct ord_set * channels;
44
        char * csvfile;
45
        const struct pstreamer_manager * psm;
46
};
47

    
48
struct pschannel_bucket * pschannel_bucket_new(const char * csvfilename, const struct pstreamer_manager * psm)
49
{
50
        struct pschannel_bucket * pb;
51
        pb = (struct pschannel_bucket*) malloc(sizeof(struct pschannel_bucket));
52
        pb->channels = ord_set_new(10, pschannel_cmp);
53
        pb->psm = psm;
54
        if (csvfilename)
55
                pb->csvfile = strdup(csvfilename);
56
        else
57
                pb->csvfile = NULL;
58
        return pb;
59
}
60

    
61
uint8_t pschannel_bucket_insert(struct pschannel_bucket * pb, const char * name, const char * ip, const char * port, const char * quality, const char * sdpfile)
62
{
63
        struct pschannel * ch;
64
        void * res;
65

    
66
        if (pb && name && ip && port && quality && sdpfile)
67
        {
68
                ch = (struct pschannel *) malloc(sizeof(struct pschannel));
69
                memset(ch, 0, sizeof(struct pschannel));
70
                strncpy(ch->name, name, MAX_NAME_LENGTH-1);
71
                strncpy(ch->ipaddr, ip, MAX_IPADDR_LENGTH-1);
72
                strncpy(ch->port, port, MAX_PORT_LENGTH-1);
73
                strncpy(ch->quality, quality, MAX_QUALITY_LENGTH-1);
74
                strncpy(ch->sdpfile, sdpfile, MAX_SDPFILENAME_LENGTH-1);
75

    
76
                res = ord_set_insert(pb->channels, ch, 0);
77
                if (res != ch)  // there is a conflict
78
                        ord_set_insert(pb->channels, ch, 1);  // we just override the current value
79
                return 0;
80
        }
81
        else
82
                return 1;
83
}
84

    
85
const struct pschannel * pschannel_bucket_iter(const struct pschannel_bucket * pb, const struct pschannel * iter)
86
{
87
        const struct pschannel * res = NULL;
88

    
89
        if (pb)
90
                res = (const struct pschannel *) ord_set_iter(pb->channels, (const void *) iter);
91
        return res;
92
}
93

    
94
void pschannel_bucket_destroy(struct pschannel_bucket ** pb)
95
{
96
        if(pb && *pb)
97
        {
98
                ord_set_destroy(&((*pb)->channels), 1);
99
                if ((*pb)->csvfile)
100
                        free((*pb)->csvfile);
101
                free(*pb);
102
                *pb = NULL;
103
        }
104
}
105

    
106
char * pschannel_bucket_to_json(const struct pschannel_bucket * pb)
107
{
108
        char objstr[] = "{\"name\":\"\",\"ipaddr\":\"\",\"port\":\"\",\"quality\":\"\"},";
109
        size_t reslength, i;
110
        char * res = NULL;
111
        const struct pschannel * iter;
112

    
113
        if (pb)
114
        {
115
                reslength = strlen("[]") + (strlen(objstr) + MAX_NAME_LENGTH + 
116
                        MAX_IPADDR_LENGTH + MAX_PORT_LENGTH + MAX_QUALITY_LENGTH) * 
117
                           ord_set_length(pb->channels) + 1;
118

    
119
                res = (char *) malloc (sizeof(char) * reslength);
120

    
121
                res[0] = '[';
122
                i = 1;
123
                for(iter = NULL; (iter = pschannel_bucket_iter(pb, iter));)
124
                {
125
                        if (i > 1)
126
                                res[i++] = ',';
127
                        i += sprintf(res+i, "{\"name\":\"%s\",\"ipaddr\":\"%s\",\"port\":\"%s\",\"quality\":\"%s\"}", 
128
                                        iter->name, iter->ipaddr, iter->port, iter->quality);
129
                }
130
                res[i] = ']'; i++;
131
                res[i] = '\0'; i++;
132
        }
133

    
134
        return res;
135
}
136

    
137
const struct pschannel * pschannel_bucket_find(const struct pschannel_bucket * psb, const char * ipaddr, const char * port)
138
{
139
        struct pschannel ch;
140
        
141
        if (ipaddr && port)
142
        {
143
                strncpy(ch.ipaddr, ipaddr, MAX_IPADDR_LENGTH);
144
                strncpy(ch.port, port, MAX_PORT_LENGTH);
145
                return (const struct pschannel *) ord_set_find(psb->channels, &ch);
146

    
147
        } else
148
                return NULL;
149
}
150

    
151
int8_t pschannel_bucket_reset(struct pschannel_bucket * psb)
152
{
153
        if (psb)
154
        {
155
                ord_set_destroy(&(psb->channels), 1);
156
                psb->channels = ord_set_new(10, pschannel_cmp);
157
                return 0;
158
        }
159
        return 1;
160
}
161

    
162
int8_t pschannel_bucket_loadfile(struct pschannel_bucket * psb)
163
{
164
        int8_t res = -1;
165
        int ans;
166
        FILE *fp;
167
        char line[255];
168
        char ** tokens;
169
        uint32_t ntoks;
170
        
171
        if (psb && psb->csvfile && (fp = fopen(psb->csvfile, "r")))
172
        {
173
                ans = ftrylockfile(fp);
174
                if (ans == 0)
175
                {
176
                        debug("Refresing channel list from file\n");
177
                        while (fgets(line, 255, fp) != NULL)
178
                        {
179
                                tokens = tokens_create(line, ',', &ntoks);
180
                                if (tokens[0][0] != '#' && ntoks == 5)
181
                                        pschannel_bucket_insert(psb, tokens[0], tokens[1], tokens[2], tokens[3], tokens[4]);
182
                                tokens_destroy(&tokens, ntoks);
183
                        }
184
                        res = 0;
185
                        funlockfile(fp);
186
                } else
187
                        res = -2;
188
                fclose(fp);
189
        }
190
        return res;
191
}
192

    
193
int8_t pschannel_bucket_save2file(struct pschannel_bucket * psb)
194
{
195
        int8_t res = -1;
196
        FILE *fp;
197
        char sdpfile_out[MAX_SDPFILENAME_LENGTH+4];
198
        char ** tokens;
199
        uint32_t ntoks;
200
        const struct pschannel * iter = NULL;
201
        
202
        if (psb && psb->csvfile)
203
        {
204
                tokens = tokens_create(psb->csvfile, '.', &ntoks);
205
                snprintf(sdpfile_out, MAX_SDPFILENAME_LENGTH, "%s_out.csv", tokens[0]);
206
                tokens_destroy(&tokens, ntoks);
207

    
208
                if ((fp = fopen(sdpfile_out, "w")))
209
                {
210
                        if (ftrylockfile(fp) == 0)
211
                        {
212
                                debug("Dumping channel list to file\n");
213
                                for(iter = NULL; (iter = pschannel_bucket_iter(psb, iter));)
214
                                        fprintf(fp, "%s,%s,%s,%s,%s\n", iter->name, iter->ipaddr, iter->port,
215
                                                        iter->quality, iter->sdpfile);
216
                                funlockfile(fp);
217
                                res = 0;
218
                        }
219
                        fclose(fp);
220
                }
221
        }
222
        return res;
223
}
224

    
225
int8_t pschannel_bucket_load_local_streams(struct pschannel_bucket * pb)
226
{
227
        int8_t res = -1;
228
        const struct pstreamer * ps = NULL;
229

    
230
        if (pb && pb->psm)
231
        {
232
                while ((ps = pstreamer_manager_source_iter(pb->psm, ps)))
233
                        if (pstreamer_get_display_name(ps))
234
                                pschannel_bucket_insert(pb, pstreamer_get_display_name(ps), pstreamer_source_ipaddr(ps), pstreamer_source_port(ps), "good", "nosdpfile");
235
                res = 0;
236
        }
237
        return res;
238
}