636e55fd814fc1fb20bf0e47a0a819332eb17db5
[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   auxtrans.udplistensock = -1;
64   /* open listening socket for udp later */
65
66   return auxtrans;
67 }
68
69 void close_aux_transport( auxtrans_param_t auxtrans)
70 {
71   if( auxtrans.tcplistensock != -1)
72     if( close_socket( auxtrans.tcplistensock) != 0)
73       perror("close");
74
75   if( auxtrans.udplistensock != -1)
76     if( close_socket( auxtrans.udplistensock) != 0)
77       perror("close");
78 }
79
80
81 /*!< auxiliary response parameters */
82 typedef struct aux_response_param{
83   char *cid;            /*!< channel ID */
84   unsigned char *data;  /*!< sending data */
85   OPJ_SIZE_T datalen;          /*!< length of data */
86   OPJ_SIZE_T maxlenPerFrame;   /*!< maximum data length to send per frame */
87   SOCKET listensock;    /*!< listeing socket */
88 #ifdef _WIN32
89   HANDLE hTh;           /*!< thread handle */
90 #endif
91 } aux_response_param_t;
92
93 aux_response_param_t * gene_auxresponse( OPJ_BOOL istcp, auxtrans_param_t auxtrans, const char cid[], void *data, OPJ_SIZE_T datalen, OPJ_SIZE_T maxlenPerFrame);
94
95 void delete_auxresponse( aux_response_param_t **auxresponse);
96
97
98 #ifdef _WIN32
99 unsigned __stdcall aux_streaming( void *arg);
100 #else
101 void * aux_streaming( void *arg);
102 #endif
103
104 void send_responsedata_on_aux( OPJ_BOOL istcp, auxtrans_param_t auxtrans, const char cid[], void *data, OPJ_SIZE_T datalen, OPJ_SIZE_T maxlenPerFrame)
105 {
106   aux_response_param_t *auxresponse;
107 #ifdef _WIN32
108   unsigned int threadId;
109 #else
110   pthread_t thread;
111   int status;
112 #endif
113   
114   if( istcp){
115     if( auxtrans.tcplistensock == -1){
116       fprintf( FCGI_stderr, "Error: error in send_responsedata_on_aux(), tcp listening socket no open\n");
117       return;
118     }
119
120     auxresponse = gene_auxresponse( istcp, auxtrans, cid, data, datalen, maxlenPerFrame);
121
122 #ifdef _WIN32
123     auxresponse->hTh = (HANDLE)_beginthreadex( NULL, 0, &aux_streaming, auxresponse, 0, &threadId);
124     if( auxresponse->hTh == 0)
125       fprintf( FCGI_stderr,"ERRO: pthread_create() %s", strerror( (int)auxresponse->hTh));
126 #else
127     status = pthread_create( &thread, NULL, &aux_streaming, auxresponse);
128     if( status != 0)
129       fprintf( FCGI_stderr,"ERROR: pthread_create() %s",strerror(status));
130 #endif   
131   }
132   else
133     fprintf( FCGI_stderr, "Error: error in send_responsedata_on_aux(), udp not implemented\n");
134 }
135
136 aux_response_param_t * gene_auxresponse( OPJ_BOOL istcp, auxtrans_param_t auxtrans, const char cid[], void *data, OPJ_SIZE_T datalen, OPJ_SIZE_T maxlenPerFrame)
137 {
138   aux_response_param_t *auxresponse;
139
140   auxresponse = (aux_response_param_t *)opj_malloc( sizeof(aux_response_param_t));
141
142   auxresponse->cid = strdup( cid);
143   auxresponse->data = data;
144   auxresponse->datalen = datalen;
145   auxresponse->maxlenPerFrame = maxlenPerFrame;
146   auxresponse->listensock = istcp ? auxtrans.tcplistensock : auxtrans.udplistensock;
147
148   return auxresponse;
149 }
150
151 void delete_auxresponse( aux_response_param_t **auxresponse)
152 {
153   opj_free( (*auxresponse)->cid);
154   opj_free( (*auxresponse)->data);
155   opj_free( *auxresponse);
156 }
157
158 /**
159  * Identify cid sent from client
160  *
161  * @param [in] connected_socket file descriptor of the connected socket
162  * @param [in] refcid           refenrece channel ID
163  * @param [in] fp               file pointer for log of aux stream
164  * @return                      true if identified, false otherwise
165  */
166 OPJ_BOOL identify_cid( SOCKET connected_socket, char refcid[], FILE *fp);
167
168 OPJ_BOOL recv_ack( SOCKET connected_socket, void *data);
169
170 #ifdef _WIN32
171 unsigned __stdcall aux_streaming( void *arg)
172 #else
173 void * aux_streaming( void *arg)
174 #endif
175 {
176   SOCKET connected_socket;
177   unsigned char *chunk, *ptr;
178   OPJ_SIZE_T maxLenOfBody, remlen, chunklen;
179   const OPJ_SIZE_T headlen = 8;
180   
181   aux_response_param_t *auxresponse = (aux_response_param_t *)arg;
182
183 #ifdef _WIN32
184   CloseHandle( auxresponse->hTh);
185 #else
186   pthread_detach( pthread_self());
187 #endif
188
189   chunk = (unsigned char *)opj_malloc( auxresponse->maxlenPerFrame);
190   maxLenOfBody = auxresponse->maxlenPerFrame - headlen;
191   remlen = auxresponse->datalen;
192
193   while((connected_socket = accept_socket( auxresponse->listensock)) != -1){
194     if( identify_cid( connected_socket, auxresponse->cid, FCGI_stderr)){
195       ptr = auxresponse->data;
196       while( 0 < remlen){
197         memset( chunk, 0, auxresponse->maxlenPerFrame);
198
199         chunklen = remlen<maxLenOfBody?remlen:maxLenOfBody;
200         chunklen += headlen;
201
202         chunk[0] = (chunklen >> 8) & 0xff;
203         chunk[1] = chunklen & 0xff;
204
205         memcpy( chunk+headlen, ptr, chunklen-headlen);
206
207         do{
208           send_stream( connected_socket, chunk, chunklen);
209         }while( !recv_ack( connected_socket, chunk));
210
211         remlen -= maxLenOfBody;
212         ptr += maxLenOfBody;
213       }
214       if( close_socket( connected_socket) != 0)
215         perror("close");
216       break;
217     }
218   }
219   opj_free( chunk);
220
221   delete_auxresponse( &auxresponse);
222   
223 #ifdef _WIN32
224   _endthreadex(0);
225 #else
226   pthread_exit(0);
227 #endif
228
229   return 0;
230 }
231
232
233 OPJ_BOOL identify_cid( SOCKET connected_socket, char refcid[], FILE *fp)
234 {
235   char *cid;
236   OPJ_BOOL succeed;
237
238   if(!(cid = receive_string( connected_socket))){
239     fprintf( fp, "Error: error in identify_cid(), while receiving cid from client\n");
240     return OPJ_FALSE;
241   }
242   
243   succeed = OPJ_FALSE;
244   if( strncmp( refcid, cid, strlen( refcid)) == 0)
245     succeed = OPJ_TRUE;
246   
247   opj_free( cid);
248
249   return succeed;
250 }
251
252 OPJ_BOOL recv_ack( SOCKET connected_socket, void *data)
253 {
254   char *header;
255   OPJ_BOOL succeed;
256   
257   header = receive_stream( connected_socket, 8);
258   
259   if( memcmp( header, data, 8) != 0)
260     succeed = OPJ_FALSE;
261   else
262     succeed = OPJ_TRUE;
263   
264   opj_free( header);
265
266   return succeed;
267 }