Merge pull request #1244 from rouault/fix_pi_warnings
[openjpeg.git] / src / lib / openjpip / auxtrans_manager.c
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
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
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
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
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
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
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
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
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 }