Line data Source code
1 : /*
2 : test_web_api.c
3 : Created by Danny Goossen, Gioxa Ltd on 26/3/17.
4 :
5 : MIT License
6 :
7 : Copyright (c) 2017 deployctl, Gioxa Ltd.
8 :
9 : Permission is hereby granted, free of charge, to any person obtaining a copy
10 : of this software and associated documentation files (the "Software"), to deal
11 : in the Software without restriction, including without limitation the rights
12 : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 : copies of the Software, and to permit persons to whom the Software is
14 : furnished to do so, subject to the following conditions:
15 :
16 : The above copyright notice and this permission notice shall be included in all
17 : copies or substantial portions of the Software.
18 :
19 : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 : SOFTWARE.
26 :
27 : */
28 : #include "../src/deployd.h"
29 : #include "test_web_api.h"
30 :
31 :
32 : /*------------------------------------------------------------------------
33 : *
34 : * Signal handler
35 : *
36 : *------------------------------------------------------------------------*/
37 :
38 6 : static void signal_handler(sig)
39 : int sig;
40 : {
41 : int i;
42 : switch(sig) {
43 :
44 : case SIGSTOP:
45 : case SIGQUIT:
46 : case SIGINT:
47 : case SIGTERM:
48 : case SIGSEGV:
49 6 : debug ("\nsighandler: Signal %d : %s !!!\n",sig,strsignal(sig));
50 6291468 : for (i=getdtablesize();i>=0;--i)
51 : {
52 6291462 : close(i); /* close all descriptors */
53 : }
54 6 : exit(0);
55 : break;
56 : }
57 : // LCOV_EXCL_START
58 : // should never come here, and if, makes nod difference
59 : }
60 : // LCOV_EXCL_STOP
61 : /**********************************************************************************
62 : * Test web server, returns 0 on success.
63 : * forks and keeps running in background with pid: child_pid
64 : * Listens on localhost:<port>
65 : *
66 : * Stop with : stop_test_web(child_pid);
67 : *
68 : * webserver contains 4 buffers
69 : *
70 : * char request[1024] => format with %d for port in Host header:
71 : * e.g: "GET /test "HTTP/1.1\r\nHost: localhost:%d\r\n .... "
72 : *
73 : * char reply_header[1024]: format as printf=> first %d for port, %d for content length, %s for content
74 : * e.g : "HTTP/1.1 200 OK\r\nServer: testweb/0.0.1\r\nContent-Length:%d\r\n\r\n%s"
75 : * char reply_content[1024]; content as per above
76 : *
77 : * char reply_fail[1024] :=> response on failure
78 : *
79 : * if request == request=> response is reply... else reply_fail
80 : *
81 : **********************************************************************************/
82 :
83 :
84 6 : int webserver( pid_t * child_pid, u_int16_t * port, webserver_t * webserver, int id)
85 : {
86 : // first bind!
87 6 : int bind_result=0;
88 6 : int fd = socket(AF_INET, SOCK_STREAM, 0);
89 :
90 : struct sockaddr_in serv_addr;
91 6 : bzero((char *) &serv_addr, sizeof(serv_addr));
92 :
93 : // configure server information
94 6 : serv_addr.sin_family = AF_INET;
95 6 : serv_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
96 6 : serv_addr.sin_port = ntohs(0);
97 6 : bind_result=bind(fd,(struct sockaddr *) &serv_addr, sizeof(serv_addr));
98 6 : if (bind_result!=SOCKET_ERROR )
99 : {
100 6 : socklen_t size = sizeof(serv_addr);
101 6 : getsockname(fd, (struct sockaddr *) &serv_addr, &size);
102 6 : *port = ntohs(serv_addr.sin_port);
103 : // then fork
104 6 : *child_pid = fork();
105 :
106 12 : if(*child_pid == 0)
107 : {
108 : //the child
109 6 : int fds=INVALID_SOCKET;
110 6 : signal(SIGKILL,&signal_handler); /* catch kill signal */
111 6 : signal(SIGTERM,&signal_handler); /* catch kill signal */
112 6 : signal(SIGSTOP,&signal_handler); /* catch kill signal */
113 6 : signal(SIGQUIT,&signal_handler); /* catch kill signal */
114 6 : signal(SIGSEGV,&signal_handler); /* catch kill signal */
115 : // socket and bind
116 6 : listen(fd, 1);
117 6 : int accept_error=0;
118 : while (1) {
119 13 : fds=accept(fd, NULL,NULL);
120 7 : if (fds==INVALID_SOCKET ) accept_error=errno;
121 7 : if (fds==INVALID_SOCKET && accept_error==EINTR) continue;
122 7 : if (fds==INVALID_SOCKET && accept_error!=EINTR) break;
123 7 : debug("child: got a connection\n");
124 7 : size_t read_size=0;
125 7 : size_t write_size=0;
126 : char * buff[0x10000];
127 :
128 7 : usleep(1000); // make sure client has sent it!! so only one read for the whole buff.
129 : do{
130 7 : read_size=recv(fds, buff, 0x10000, 0);
131 : }
132 : // LCOV_EXCL_START
133 : // never get to it
134 : while (read_size==0 && (read_size!=SOCKET_ERROR || (read_size==SOCKET_ERROR && errno==EINTR) ));
135 : // LCOV_EXCL_STOP
136 :
137 7 : buff[read_size]=0;
138 7 : debug("Child : received \n>>>%s<<<\n",buff);
139 : // get the port correct in request
140 : char temp[1024];
141 7 : sprintf(temp, webserver->request,*port);
142 7 : debug("Child : >>>cmp2\n>>>%s<<<\n==\n>>>%s<<<\n",temp,buff);
143 7 : if (strcmp((const char* )buff, temp)==0){
144 6 : sprintf((char *)buff, webserver->reply_header,strlen(webserver->reply_content),webserver->reply_content);
145 : }
146 : else {
147 1 : sprintf((char *)buff, "%s",webserver->reply_fail);
148 : }
149 7 : write_size=write(fds,(char *)buff,strlen((char*)buff));
150 7 : read_size=0;
151 : }
152 : // LCOV_EXCL_START
153 : // should never come here
154 : exit(0);
155 : // LCOV_EXCL_STOP
156 : }
157 6 : else if (*child_pid>0)
158 : {
159 : // the parent
160 : //close the accept filehandle and return return
161 6 : close(fd);
162 6 : return 0;
163 : }
164 : }
165 : // LCOV_EXCL_START
166 : // should never come here
167 : return -1;
168 : // LCOV_EXCL_STOP
169 : }
170 :
171 6 : int stop_test_web(pid_t child_pid)
172 : {
173 : //kill
174 6 : kill(child_pid,SIGQUIT); // TODO need to check with WHOANG
175 6 : usleep(100000);
176 6 : int status=0;
177 6 : pid_t w = waitpid(child_pid,&status, 0);
178 6 : if (w==-1) { sock_error("waitpid"); return 1; }
179 6 : else if (WIFEXITED(status))
180 : {
181 6 : error("exit webserver w error: %d\n",WEXITSTATUS(status));
182 : }
183 : // LCOV_EXCL_START
184 : // we never get here
185 : else { return 1; }
186 : // LCOV_EXCL_STOP
187 6 : return 0;
188 : }
|