00001
00011 #define _GNU_SOURCE
00012 #include <stdio.h>
00013 #include <stdlib.h>
00014 #include <string.h>
00015 #include <errno.h>
00016 #include <time.h>
00017 #include <assert.h>
00018 #include <string.h>
00019 #include <stdarg.h>
00020 #include <fcntl.h>
00021
00022 #include <unistd.h>
00023 #include <sys/select.h>
00024 #include <sys/types.h>
00025 #include <sys/socket.h>
00026 #include <netinet/in.h>
00027 #include <arpa/inet.h>
00028 #include <netdb.h>
00029
00030 #include "mihl.h"
00031
00032 #include "glovars.h"
00033
00034 #include "tcp_utils.h"
00035 #include "b64.h"
00036
00047 int tcp_read( SOCKET sockfd, char *buffer, int maxlen ) {
00048 maxlen--;
00049 int dcount;
00050 int index = 0;
00051 int errcnt = 0;
00052 for ( ;; ) {
00053 errno = 0;
00054 dcount = recv( sockfd, &buffer[index], maxlen-index, 0 );
00055 if ( (dcount == -1) && (errno == EINTR) ) {
00056 printf( "%s %d : >>> %d <<<<\n", __FILE__, __LINE__, ERRNO );
00057 Sleep( 1000 );
00058 continue;
00059 }
00060 if ( (dcount == -1) && (errno == ECONNRESET) ) {
00061 dcount = 0;
00062 break;
00063 }
00064 if ( dcount == 0 ) {
00065
00066
00067 buffer[dcount+index] = 0;
00068 return dcount+index;
00069 }
00070 if ( dcount == -1 ) {
00071 printf( "\n%d\n", ERRNO );
00072 fflush( stdout );
00073 assert( 0 );
00074 }
00075 if ( dcount+index == maxlen )
00076 break;
00077 errcnt = 0;
00078 fd_set ready;
00079 struct timeval tv;
00080 FD_ZERO( &ready );
00081 FD_SET( sockfd, &ready );
00082 tv.tv_sec = 0;
00083 tv.tv_usec = 1;
00084 int status = select( (int)sockfd+1, &ready, NULL, NULL, &tv );
00085 if ( (status <= 0) || !FD_ISSET( sockfd, &ready ) )
00086 break;
00087 index += dcount;
00088 }
00089
00090 buffer[dcount+index] = 0;
00091 return dcount+index;
00092 }
00093
00104 int tcp_write( SOCKET sockfd, const char *buff, int buff_len ) {
00105
00106 int cnt = 0;
00107 errno = 0;
00108 char const *pbuff = buff;
00109 int len = buff_len;
00110 for (;;) {
00111
00112 int dcount = send( sockfd, (const char *)pbuff, len, MSG_NOSIGNAL );
00113
00114 if ( (dcount == -1) && (errno == EPIPE) ) {
00115 printf( "%s %d : >>> %d <<<<\015\012", __FILE__, __LINE__, ERRNO );
00116 fflush( stdout );
00117 return -1;
00118 }
00119
00120 if ( (dcount == -1) && (ERRNO == ECONNRESET) ) {
00121 printf( "%s %d : >>> %d <<<<\n", __FILE__, __LINE__, ERRNO );
00122 fflush( stdout );
00123 return -1;
00124 }
00125 if ( (dcount == -1) && (errno == EINTR) ) {
00126 printf( "%s %d : >>> %d <<<<\n", __FILE__, __LINE__, ERRNO );
00127 fflush( stdout );
00128 Sleep( 50 );
00129 continue;
00130 }
00131 cnt += dcount;
00132 if ( dcount == len )
00133 break;
00134 pbuff += dcount;
00135 len -= dcount;
00136 }
00137 return cnt;
00138 }
00139
00156 void decode_keys_values( mihl_cnx_t *cnx, char *_request,
00157 int *nb_options, char *options_names[], char *options_values[], int maxnb_options,
00158 int *nb_variables, char *vars_names[], char *vars_values[], int maxnb_values ) {
00159
00160 *nb_options = 0;
00161 *nb_variables = 0;
00162 int l = (int)strlen(_request);
00163 if ( l == 0 )
00164 return;
00165 char *request = (char *)malloc(l*2);
00166 strcpy( request, _request );
00167 char *eol = strstr( request, "\r\n" );
00168 char *line = request;
00169 while ( eol && (*nb_options < maxnb_options) ) {
00170 *eol = 0;
00171 eol += 2;
00172 char *colon = strchr( line, ':' );
00173 if ( colon ) {
00174 *colon = 0;
00175 char *p = line;
00176 char *q = &colon[2];
00177 if ( q ) {
00178 options_names[*nb_options] = strdup(p);
00179 if ( *q == ' ' )
00180 q++;
00181 options_values[*nb_options] = strdup(q);
00182 (*nb_options)++;
00183 }
00184 }
00185 line = eol;
00186 eol = strstr( eol, "\r\n" );
00187 }
00188
00189
00190 strcpy( request, _request );
00191 eol = strstr( request, "\r\n\r\n" );
00192 if ( eol ) {
00193 eol += 4;
00194 if ( strchr( eol, '=' ) != NULL ) {
00195 strcat( eol, "&" );
00196 for (;;) {
00197 char *item = strchr( eol, '&' );
00198 if ( item == NULL )
00199 break;
00200 *item = 0;
00201 char *equ = strchr( eol, '=' );
00202 if ( equ == NULL )
00203 break;
00204 *equ++ = 0;
00205 vars_names[*nb_variables] = strdup(eol);
00206 vars_values[*nb_variables] = strdup(equ);
00207 (*nb_variables)++;
00208 eol = &item[1];
00209 }
00210 }
00211 }
00212
00213 free(request);
00214 request = NULL;
00215
00216 for ( int n = 0; n < *nb_options; n++ ) {
00217 char *key = options_names[n];
00218 char *value = options_values[n];
00219
00220 if ( !strcmp( key, "Host" ) )
00221 cnx->info.host = strdup( value );
00222 else if ( !strcmp( key, "User-Agent" ) )
00223 cnx->info.user_agent = strdup( value );
00224 else if ( !strcmp( key, "Keep-Alive" ) )
00225 cnx->keep_alive = atoi( value );
00226 else if ( !strcmp( key, "Authorization" ) )
00227 cnx->authorization = strdup( value );
00228 else if ( !strcmp( key, "Connection" ) ) {
00229 if ( !strcmp( value, "keep-alive" ) )
00230 cnx->is_keep_alive = 1;
00231 }
00232 }
00233
00234 #if 0
00235 for ( int n = 0; n < *nb_variables; n++ ) {
00236 char *key = vars_names[n];
00237 char *value = vars_values[n];
00238 printf( " %d: '%s' = '%s'\n", n, key, value );
00239 }
00240 #endif
00241
00242 }
00243
00261 int mihl_add( mihl_cnx_t *cnx, char const *fmt, ... ) {
00262 if ( cnx->html_buffer_len + 1024 >= cnx->html_buffer_sz ) {
00263 cnx->html_buffer_sz += 8192;
00264 cnx->html_buffer = (char *)realloc( cnx->html_buffer, cnx->html_buffer_sz );
00265 }
00266
00267 va_list ap;
00268 va_start( ap, fmt );
00269 int len = vsnprintf( &cnx->html_buffer[cnx->html_buffer_len], 1024-3, fmt, ap );
00270 va_end( ap );
00271 strcat( cnx->html_buffer, "\r\n" );
00272
00273 len += 2;
00274 cnx->html_buffer_len += len;
00275 return len;
00276 }
00277
00289 int mihl_send( mihl_cnx_t *cnx, char const *answer, char const *fmt_header, ... ) {
00290 char header[2048];
00291 if ( !answer ) {
00292 static char const ok200[] = "HTTP/1.1 200 OK\r\n";
00293 strncpy( header, ok200, sizeof(header)-1 );
00294 }
00295 else {
00296 strncpy( header, answer, sizeof(header)-1 );
00297 }
00298 int l = strlen( header );
00299 va_list ap;
00300 va_start( ap, fmt_header );
00301 int len1 = vsnprintf( &header[l], sizeof(header)-l-1, fmt_header, ap );
00302 va_end( ap );
00303 int len2 = sprintf( &header[l+len1], "Content-Length: %d\r\n\r\n",
00304 cnx->html_buffer_len );
00305 int count = tcp_write( cnx->sockfd, header, l+len1+len2 );
00306 if ( count == -1 ) {
00307 printf( "\n>>> %s %d: OOPS %d!!!!!\015\012", __FILE__, __LINE__, ERRNO );
00308 fflush( stdout );
00309 return -1;
00310 }
00311
00312 if ( count != -1 ) {
00313 count = tcp_write( cnx->sockfd, cnx->html_buffer, cnx->html_buffer_len );
00314 if ( count == -1 ) {
00315 printf( "\n>>> %s %d: OOPS %d!!!!!\n", __FILE__, __LINE__, ERRNO );
00316 fflush( stdout );
00317 return -1;
00318 }
00319 }
00320
00321 cnx->html_buffer_len = 0;
00322 return count;
00323 }
00324
00333 static int filelength( int fd ) {
00334 off_t len = lseek( fd, 0, SEEK_END );
00335 lseek( fd, 0, SEEK_SET );
00336 return (int)len;
00337 }
00338
00350 int read_file( char const *fname, char **file, int *length ) {
00351 int fd = open( fname, O_RDONLY | O_BINARY );
00352 if ( fd == -1 )
00353 return -1;
00354
00355 int len = filelength( fd );
00356 *file = (char *)malloc( len+1 );
00357 if ( *file == NULL )
00358 return -1;
00359
00360 int count = read( fd, *file, len );
00361 if ( count != len )
00362 return -1;
00363
00364 close( fd );
00365 *length = len;
00366 (*file)[len] = 0;
00367 return len;
00368 }