1 /*
2 * $Id$
3 *
4 * Copyright (c) 2002-2014, Universite catholique de Louvain (UCL), Belgium
5 * Copyright (c) 2002-2014, Professor Benoit Macq
6 * Copyright (c) 2010-2011, Kaori Hagihara
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS'
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include <stdio.h>
32 #include <string.h>
33 #include <stdlib.h>
34 #include "auxtrans_manager.h"
35
36 #ifdef _WIN32
37 #include <process.h>
38 #else
39 #include <pthread.h>
40 #endif
41
42 #ifdef SERVER
43 #include "fcgi_stdio.h"
44 #define logstream FCGI_stdout
45 #else
46 #define FCGI_stdout stdout
47 #define FCGI_stderr stderr
48 #define logstream stderr
49 #endif /*SERVER */
50
init_aux_transport(int tcp_auxport,int udp_auxport)51 auxtrans_param_t init_aux_transport(int tcp_auxport, int udp_auxport)
52 {
53 auxtrans_param_t auxtrans;
54
55 auxtrans.tcpauxport = tcp_auxport;
56 auxtrans.udpauxport = udp_auxport;
57
58 if (49152 <= tcp_auxport && tcp_auxport <= 65535) {
59 auxtrans.tcplistensock = open_listeningsocket((uint16_t)tcp_auxport);
60 } else {
61 auxtrans.tcplistensock = -1;
62 }
63
64 auxtrans.udplistensock = -1;
65 /* open listening socket for udp later */
66
67 return auxtrans;
68 }
69
close_aux_transport(auxtrans_param_t auxtrans)70 void close_aux_transport(auxtrans_param_t auxtrans)
71 {
72 if (auxtrans.tcplistensock != -1)
73 if (close_socket(auxtrans.tcplistensock) != 0) {
74 perror("close");
75 }
76
77 if (auxtrans.udplistensock != -1)
78 if (close_socket(auxtrans.udplistensock) != 0) {
79 perror("close");
80 }
81 }
82
83
84 /*!< auxiliary response parameters */
85 typedef struct aux_response_param {
86 char *cid; /*!< channel ID */
87 unsigned char *data; /*!< sending data */
88 OPJ_SIZE_T datalen; /*!< length of data */
89 OPJ_SIZE_T maxlenPerFrame; /*!< maximum data length to send per frame */
90 SOCKET listensock; /*!< listeing socket */
91 #ifdef _WIN32
92 HANDLE hTh; /*!< thread handle */
93 #endif
94 } aux_response_param_t;
95
96 aux_response_param_t * gene_auxresponse(OPJ_BOOL istcp,
97 auxtrans_param_t auxtrans, const char cid[], void *data, OPJ_SIZE_T datalen,
98 OPJ_SIZE_T maxlenPerFrame);
99
100 void delete_auxresponse(aux_response_param_t **auxresponse);
101
102
103 #ifdef _WIN32
104 unsigned __stdcall aux_streaming(void *arg);
105 #else
106 void * aux_streaming(void *arg);
107 #endif
108
send_responsedata_on_aux(OPJ_BOOL istcp,auxtrans_param_t auxtrans,const char cid[],void * data,OPJ_SIZE_T datalen,OPJ_SIZE_T maxlenPerFrame)109 void send_responsedata_on_aux(OPJ_BOOL istcp, auxtrans_param_t auxtrans,
110 const char cid[], void *data, OPJ_SIZE_T datalen, OPJ_SIZE_T maxlenPerFrame)
111 {
112 aux_response_param_t *auxresponse;
113 #ifdef _WIN32
114 unsigned int threadId;
115 #else
116 pthread_t thread;
117 int status;
118 #endif
119
120 if (istcp) {
121 if (auxtrans.tcplistensock == -1) {
122 fprintf(FCGI_stderr,
123 "Error: error in send_responsedata_on_aux(), tcp listening socket no open\n");
124 return;
125 }
126
127 auxresponse = gene_auxresponse(istcp, auxtrans, cid, data, datalen,
128 maxlenPerFrame);
129
130 #ifdef _WIN32
131 auxresponse->hTh = (HANDLE)_beginthreadex(NULL, 0, &aux_streaming, auxresponse,
132 0, &threadId);
133 if (auxresponse->hTh == 0) {
134 fprintf(FCGI_stderr, "ERRO: pthread_create() %s",
135 strerror((int)auxresponse->hTh));
136 }
137 #else
138 status = pthread_create(&thread, NULL, &aux_streaming, auxresponse);
139 if (status != 0) {
140 fprintf(FCGI_stderr, "ERROR: pthread_create() %s", strerror(status));
141 }
142 #endif
143 } else {
144 fprintf(FCGI_stderr,
145 "Error: error in send_responsedata_on_aux(), udp not implemented\n");
146 }
147 }
148
gene_auxresponse(OPJ_BOOL istcp,auxtrans_param_t auxtrans,const char cid[],void * data,OPJ_SIZE_T datalen,OPJ_SIZE_T maxlenPerFrame)149 aux_response_param_t * gene_auxresponse(OPJ_BOOL istcp,
150 auxtrans_param_t auxtrans, const char cid[], void *data, OPJ_SIZE_T datalen,
151 OPJ_SIZE_T maxlenPerFrame)
152 {
153 aux_response_param_t *auxresponse;
154
155 auxresponse = (aux_response_param_t *)opj_malloc(sizeof(aux_response_param_t));
156
157 auxresponse->cid = strdup(cid);
158 auxresponse->data = data;
159 auxresponse->datalen = datalen;
160 auxresponse->maxlenPerFrame = maxlenPerFrame;
161 auxresponse->listensock = istcp ? auxtrans.tcplistensock :
162 auxtrans.udplistensock;
163
164 return auxresponse;
165 }
166
delete_auxresponse(aux_response_param_t ** auxresponse)167 void delete_auxresponse(aux_response_param_t **auxresponse)
168 {
169 opj_free((*auxresponse)->cid);
170 opj_free((*auxresponse)->data);
171 opj_free(*auxresponse);
172 }
173
174 /**
175 * Identify cid sent from client
176 *
177 * @param [in] connected_socket file descriptor of the connected socket
178 * @param [in] refcid refenrece channel ID
179 * @param [in] fp file pointer for log of aux stream
180 * @return true if identified, false otherwise
181 */
182 OPJ_BOOL identify_cid(SOCKET connected_socket, char refcid[], FILE *fp);
183
184 OPJ_BOOL recv_ack(SOCKET connected_socket, void *data);
185
186 #ifdef _WIN32
aux_streaming(void * arg)187 unsigned __stdcall aux_streaming(void *arg)
188 #else
189 void * aux_streaming(void *arg)
190 #endif
191 {
192 SOCKET connected_socket;
193 unsigned char *chunk, *ptr;
194 OPJ_SIZE_T maxLenOfBody, remlen, chunklen;
195 const OPJ_SIZE_T headlen = 8;
196
197 aux_response_param_t *auxresponse = (aux_response_param_t *)arg;
198
199 #ifdef _WIN32
200 CloseHandle(auxresponse->hTh);
201 #else
202 pthread_detach(pthread_self());
203 #endif
204
205 chunk = (unsigned char *)opj_malloc(auxresponse->maxlenPerFrame);
206 maxLenOfBody = auxresponse->maxlenPerFrame - headlen;
207 remlen = auxresponse->datalen;
208
209 while ((connected_socket = accept_socket(auxresponse->listensock)) != -1) {
210 if (identify_cid(connected_socket, auxresponse->cid, FCGI_stderr)) {
211 ptr = auxresponse->data;
212 while (0 < remlen) {
213 memset(chunk, 0, auxresponse->maxlenPerFrame);
214
215 chunklen = remlen < maxLenOfBody ? remlen : maxLenOfBody;
216 chunklen += headlen;
217
218 chunk[0] = (chunklen >> 8) & 0xff;
219 chunk[1] = chunklen & 0xff;
220
221 memcpy(chunk + headlen, ptr, chunklen - headlen);
222
223 do {
224 send_stream(connected_socket, chunk, chunklen);
225 } while (!recv_ack(connected_socket, chunk));
226
227 remlen -= maxLenOfBody;
228 ptr += maxLenOfBody;
229 }
230 if (close_socket(connected_socket) != 0) {
231 perror("close");
232 }
233 break;
234 }
235 if (close_socket(connected_socket) != 0) {
236 perror("close");
237 }
238 }
239 opj_free(chunk);
240
241 delete_auxresponse(&auxresponse);
242
243 #ifdef _WIN32
244 _endthreadex(0);
245 #else
246 pthread_exit(0);
247 #endif
248
249 return 0;
250 }
251
252
identify_cid(SOCKET connected_socket,char refcid[],FILE * fp)253 OPJ_BOOL identify_cid(SOCKET connected_socket, char refcid[], FILE *fp)
254 {
255 char *cid;
256 OPJ_BOOL succeed;
257
258 if (!(cid = receive_string(connected_socket))) {
259 fprintf(fp,
260 "Error: error in identify_cid(), while receiving cid from client\n");
261 return OPJ_FALSE;
262 }
263
264 succeed = OPJ_FALSE;
265 if (strncmp(refcid, cid, strlen(refcid)) == 0) {
266 succeed = OPJ_TRUE;
267 }
268
269 opj_free(cid);
270
271 return succeed;
272 }
273
recv_ack(SOCKET connected_socket,void * data)274 OPJ_BOOL recv_ack(SOCKET connected_socket, void *data)
275 {
276 char *header;
277 OPJ_BOOL succeed;
278
279 header = receive_stream(connected_socket, 8);
280
281 if (memcmp(header, data, 8) != 0) {
282 succeed = OPJ_FALSE;
283 } else {
284 succeed = OPJ_TRUE;
285 }
286
287 opj_free(header);
288
289 return succeed;
290 }
291