1 /* 2 This file is part of libmicrospdy 3 Copyright Copyright (C) 2013 Andrey Uzunov 4 5 This program is free software: you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation, either version 3 of the License, or 8 (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program. If not, see <http://www.gnu.org/licenses/>. 17 */ 18 19 /** 20 * @file request_response_with_callback.c 21 * @brief tests responses with callbacks 22 * @author Andrey Uzunov 23 */ 24 25 #include "platform.h" 26 #include "microspdy.h" 27 #include "stdio.h" 28 #include <sys/wait.h> 29 #include <ctype.h> 30 #include "common.h" 31 #include <sys/time.h> 32 #include <sys/stat.h> 33 34 int port; 35 36 pid_t parent; 37 pid_t child; 38 39 int run = 1; 40 int chunk_size=1; 41 42 void 43 killchild() 44 { 45 kill(child, SIGKILL); 46 exit(1); 47 } 48 49 void 50 killparent() 51 { 52 kill(parent, SIGKILL); 53 _exit(1); 54 } 55 56 ssize_t 57 response_callback (void *cls, 58 void *buffer, 59 size_t max, 60 bool *more) 61 { 62 FILE *fd =(FILE*)cls; 63 64 size_t n; 65 if(chunk_size % 2) 66 n = chunk_size; 67 else 68 n = max - chunk_size; 69 70 if(n < 1) n = 1; 71 else if (n > max) n=max; 72 chunk_size++; 73 74 int ret = fread(buffer,1,n,fd); 75 *more = feof(fd) == 0; 76 77 //printf("more is %i\n",*more); 78 79 if(!(*more)) 80 fclose(fd); 81 82 return ret; 83 } 84 85 86 void 87 response_done_callback(void *cls, 88 struct SPDY_Response * response, 89 struct SPDY_Request * request, 90 enum SPDY_RESPONSE_RESULT status, 91 bool streamopened) 92 { 93 (void)status; 94 (void)streamopened; 95 96 printf("answer for %s was sent\n", (char*)cls); 97 98 SPDY_destroy_request(request); 99 SPDY_destroy_response(response); 100 free(cls); 101 102 run = 0; 103 } 104 105 void 106 standard_request_handler(void *cls, 107 struct SPDY_Request * request, 108 uint8_t priority, 109 const char *method, 110 const char *path, 111 const char *version, 112 const char *host, 113 const char *scheme, 114 struct SPDY_NameValue * headers, 115 bool more) 116 { 117 (void)cls; 118 (void)request; 119 (void)priority; 120 (void)host; 121 (void)scheme; 122 (void)headers; 123 (void)method; 124 (void)version; 125 (void)more; 126 127 struct SPDY_Response *response=NULL; 128 struct SPDY_NameValue *resp_headers; 129 130 printf("received request for '%s %s %s'\n", method, path, version); 131 132 FILE *fd = fopen(DATA_DIR "spdy-draft.txt","r"); 133 134 if(NULL == (resp_headers = SPDY_name_value_create())) 135 { 136 fprintf(stdout,"SPDY_name_value_create failed\n"); 137 killchild(); 138 } 139 if(SPDY_YES != SPDY_name_value_add(resp_headers,SPDY_HTTP_HEADER_CONTENT_TYPE,"text/plain")) 140 { 141 fprintf(stdout,"SPDY_name_value_add failed\n"); 142 killchild(); 143 } 144 145 response = SPDY_build_response_with_callback(200,NULL, 146 SPDY_HTTP_VERSION_1_1,resp_headers,&response_callback,fd,SPDY_MAX_SUPPORTED_FRAME_SIZE); 147 SPDY_name_value_destroy(resp_headers); 148 149 if(NULL==response){ 150 fprintf(stdout,"no response obj\n"); 151 killchild(); 152 } 153 154 void *clspath = strdup(path); 155 156 if(SPDY_queue_response(request,response,true,false,&response_done_callback,clspath)!=SPDY_YES) 157 { 158 fprintf(stdout,"queue\n"); 159 killchild(); 160 } 161 } 162 163 int 164 parentproc() 165 { 166 int childstatus; 167 unsigned long long timeoutlong=0; 168 struct timeval timeout; 169 int ret; 170 fd_set read_fd_set; 171 fd_set write_fd_set; 172 fd_set except_fd_set; 173 int maxfd = -1; 174 struct SPDY_Daemon *daemon; 175 176 SPDY_init(); 177 178 daemon = SPDY_start_daemon(port, 179 DATA_DIR "cert-and-key.pem", 180 DATA_DIR "cert-and-key.pem", 181 NULL, 182 NULL, 183 &standard_request_handler, 184 NULL, 185 NULL, 186 SPDY_DAEMON_OPTION_SESSION_TIMEOUT, 187 1800, 188 SPDY_DAEMON_OPTION_END); 189 190 if(NULL==daemon){ 191 printf("no daemon\n"); 192 return 1; 193 } 194 195 do 196 { 197 FD_ZERO(&read_fd_set); 198 FD_ZERO(&write_fd_set); 199 FD_ZERO(&except_fd_set); 200 201 ret = SPDY_get_timeout(daemon, &timeoutlong); 202 if(SPDY_NO == ret || timeoutlong > 1000) 203 { 204 timeout.tv_sec = 1; 205 timeout.tv_usec = 0; 206 } 207 else 208 { 209 timeout.tv_sec = timeoutlong / 1000; 210 timeout.tv_usec = (timeoutlong % 1000) * 1000; 211 } 212 213 maxfd = SPDY_get_fdset (daemon, 214 &read_fd_set, 215 &write_fd_set, 216 &except_fd_set); 217 218 ret = select(maxfd+1, &read_fd_set, &write_fd_set, &except_fd_set, &timeout); 219 220 switch(ret) { 221 case -1: 222 printf("select error: %i\n", errno); 223 break; 224 case 0: 225 226 break; 227 default: 228 SPDY_run(daemon); 229 230 break; 231 } 232 } 233 while(waitpid(child,&childstatus,WNOHANG) != child); 234 235 SPDY_stop_daemon(daemon); 236 237 SPDY_deinit(); 238 239 return WEXITSTATUS(childstatus); 240 } 241 242 #define MD5_LEN 32 243 244 int 245 md5(char *cmd, char *md5_sum) 246 { 247 FILE *p = popen(cmd, "r"); 248 if (p == NULL) return 0; 249 250 int i, ch; 251 for (i = 0; i < MD5_LEN && isxdigit(ch = fgetc(p)); i++) { 252 *md5_sum++ = ch; 253 } 254 255 *md5_sum = '\0'; 256 pclose(p); 257 return i == MD5_LEN; 258 } 259 260 int 261 childproc() 262 { 263 char *cmd1; 264 char *cmd2; 265 char md5_sum1[33]; 266 char md5_sum2[33]; 267 int ret; 268 struct timeval tv1; 269 struct timeval tv2; 270 struct stat st; 271 //int secs; 272 uint64_t usecs; 273 274 asprintf(&cmd1, "spdycat https://127.0.0.1:%i/ | md5sum",port); 275 asprintf(&cmd2, "md5sum " DATA_DIR "spdy-draft.txt"); 276 277 gettimeofday(&tv1, NULL); 278 md5(cmd1,md5_sum1); 279 gettimeofday(&tv2, NULL); 280 md5(cmd2,md5_sum2); 281 282 printf("downloaded file md5: %s\n", md5_sum1); 283 printf("original file md5: %s\n", md5_sum2); 284 ret = strcmp(md5_sum1, md5_sum2); 285 286 if(0 == ret && 0 == stat(DATA_DIR "spdy-draft.txt", &st)) 287 { 288 usecs = (uint64_t)1000000 * (uint64_t)(tv2.tv_sec - tv1.tv_sec) + tv2.tv_usec - tv1.tv_usec; 289 printf("%lld bytes read in %llu usecs\n", (long long)st.st_size, (long long unsigned )usecs); 290 } 291 292 return ret; 293 } 294 295 296 int 297 main() 298 { 299 port = get_port(11123); 300 parent = getpid(); 301 302 child = fork(); 303 if (-1 == child) 304 { 305 fprintf(stderr, "can't fork, error %d\n", errno); 306 exit(EXIT_FAILURE); 307 } 308 309 if (child == 0) 310 { 311 int ret = childproc(); 312 _exit(ret); 313 } 314 else 315 { 316 int ret = parentproc(); 317 exit(ret); 318 } 319 return 1; 320 } 321