5 #define HTTPGW_MAX_CLIENT 128
11 const char * HTTPGW_HEADERS[HTTPGW_MAX_HEADER] = {
22 char* headers[HTTPGW_MAX_HEADER];
23 } http_requests[HTTPGW_MAX_CLIENT];
26 int http_gw_reqs_open = 0;
27 int http_gw_reqs_count = 0;
29 void HttpGwNewRequestCallback (SOCKET http_conn);
30 void HttpGwNewRequestCallback (SOCKET http_conn);
32 http_gw_t* HttpGwFindRequest (SOCKET sock) {
33 for(int i=0; i<http_gw_reqs_open; i++)
34 if (http_requests[i].sink==sock)
35 return http_requests+i;
40 void HttpGwCloseConnection (SOCKET sock) {
41 http_gw_t* req = HttpGwFindRequest(sock);
43 dprintf("%s @%i closed http connection %i\n",tintstr(),req->id,sock);
44 for(int i=0; i<HTTPGW_MAX_HEADER; i++)
45 if (req->headers[i]) {
46 free(req->headers[i]);
47 req->headers[i] = NULL;
49 *req = http_requests[--http_gw_reqs_open];
51 swift::close_socket(sock);
52 swift::Datagram::Listen3rdPartySocket(sckrwecb_t(sock));
56 void HttpGwMayWriteCallback (SOCKET sink) {
57 http_gw_t* req = HttpGwFindRequest(sink);
58 uint64_t complete = swift::SeqComplete(req->transfer);
59 if (complete>req->offset) { // send data
61 uint64_t tosend = std::min((uint64_t)1<<12,complete-req->offset);
62 size_t rd = pread(req->transfer,buf,tosend,req->offset); // hope it is cached
64 HttpGwCloseConnection(sink);
67 int wn = send(sink, buf, rd, 0);
69 print_error("send fails");
70 HttpGwCloseConnection(sink);
73 dprintf("%s @%i sent %ib\n",tintstr(),req->id,(int)wn);
77 if (req->tosend==0) { // done; wait for new request
78 dprintf("%s @%i done\n",tintstr(),req->id);
79 sckrwecb_t wait_new_req
80 (req->sink,HttpGwNewRequestCallback,NULL,HttpGwCloseConnection);
81 swift::Datagram::Listen3rdPartySocket (wait_new_req);
82 } else { // wait for data
83 dprintf("%s @%i waiting for data\n",tintstr(),req->id);
84 sckrwecb_t wait_swift_data(req->sink,NULL,NULL,HttpGwCloseConnection);
85 swift::Datagram::Listen3rdPartySocket(wait_swift_data);
91 void HttpGwSwiftProgressCallback (int transfer, bin64_t bin) {
92 for (int httpc=0; httpc<http_gw_reqs_open; httpc++)
93 if (http_requests[httpc].transfer==transfer)
94 if ( (bin.base_offset()<<10) == http_requests[httpc].offset ) {
95 dprintf("%s @%i progress: %s\n",tintstr(),http_requests[httpc].id,bin.str());
96 sckrwecb_t maywrite_callbacks
97 (http_requests[httpc].sink,NULL,
98 HttpGwMayWriteCallback,HttpGwCloseConnection);
99 Datagram::Listen3rdPartySocket (maywrite_callbacks);
104 void HttpGwFirstProgressCallback (int transfer, bin64_t bin) {
105 if (bin!=bin64_t(0,0)) // need the first packet
107 swift::RemoveProgressCallback(transfer,&HttpGwFirstProgressCallback);
108 swift::AddProgressCallback(transfer,&HttpGwSwiftProgressCallback,0);
109 for (int httpc=0; httpc<http_gw_reqs_open; httpc++) {
110 http_gw_t * req = http_requests + httpc;
111 if (req->transfer==transfer && req->tosend==0) { // FIXME states
112 uint64_t file_size = swift::Size(transfer);
115 "HTTP/1.1 200 OK\r\n"\
116 "Connection: keep-alive\r\n"\
117 "Content-Type: video/ogg\r\n"\
118 /*"X-Content-Duration: 32\r\n"*/\
119 "Content-Length: %lli\r\n"\
120 "Accept-Ranges: bytes\r\n"\
123 send(req->sink,response,strlen(response),0);
124 req->tosend = file_size;
125 dprintf("%s @%i headers_sent size %lli\n",tintstr(),req->id,file_size);
128 HttpGwSwiftProgressCallback(transfer,bin);
132 void HttpGwNewRequestCallback (SOCKET http_conn){
133 http_gw_t* req = http_requests + http_gw_reqs_open++;
134 req->id = ++http_gw_reqs_count;
135 req->sink = http_conn;
138 dprintf("%s @%i new http request\n",tintstr(),req->id);
139 // read headers - the thrilling part
140 // we surely do not support pipelining => one request at a time
141 #define HTTPGW_MAX_REQ_SIZE 1024
142 char buf[HTTPGW_MAX_REQ_SIZE+1];
143 int rd = recv(http_conn,buf,HTTPGW_MAX_REQ_SIZE,0);
144 if (rd<=0) { // if conn is closed by the peer, rd==0
145 HttpGwCloseConnection(http_conn);
150 char* reqline = strtok(buf,"\r\n");
151 char method[16], url[512], version[16], crlf[5];
152 if (3!=sscanf(reqline,"%16s %512s %16s",method,url,version)) {
153 HttpGwCloseConnection(http_conn);
156 // HTTP header fields
158 while (headerline=strtok(NULL,"\n\r")) {
159 char header[128], value[256];
160 if (2!=sscanf(headerline,"%120[^: ]: %250[^\r\n]",header,value)) {
161 HttpGwCloseConnection(http_conn);
164 for(int i=0; i<HTTPGW_MAX_HEADER; i++)
165 if (0==strcasecmp(HTTPGW_HEADERS[i],header) && !req->headers[i])
166 req->headers[i] = strdup(value);
169 char * hashch=strtok(url,"/"), hash[41];
170 while (hashch && (1!=sscanf(hashch,"%40[0123456789abcdefABCDEF]",hash) || strlen(hash)!=40))
171 hashch = strtok(NULL,"/");
172 if (strlen(hash)!=40) {
173 HttpGwCloseConnection(http_conn);
176 dprintf("%s @%i demands %s\n",tintstr(),req->id,hash);
177 // initiate transmission
178 Sha1Hash root_hash = Sha1Hash(true,hash);
179 int file = swift::Find(root_hash);
181 file = swift::Open(hash,root_hash);
182 req->transfer = file;
183 if (swift::Size(file)) {
184 HttpGwFirstProgressCallback(file,bin64_t(0,0));
186 swift::AddProgressCallback(file,&HttpGwFirstProgressCallback,0);
187 sckrwecb_t install (http_conn,NULL,NULL,HttpGwCloseConnection);
188 swift::Datagram::Listen3rdPartySocket(install);
193 // be liberal in what you do, be conservative in what you accept
194 void HttpGwNewConnectionCallback (SOCKET serv) {
195 Address client_address;
197 SOCKET conn = accept (serv, (sockaddr*) & (client_address.addr), &len);
198 if (conn==INVALID_SOCKET) {
199 print_error("client conn fails");
202 make_socket_nonblocking(conn);
203 // submit 3rd party socket to the swift loop
205 (conn,HttpGwNewRequestCallback,NULL,HttpGwCloseConnection);
206 swift::Datagram::Listen3rdPartySocket(install);
210 void HttpGwError (SOCKET s) {
211 print_error("httpgw is dead");
212 dprintf("%s @0 closed http gateway\n",tintstr());
214 swift::Datagram::Listen3rdPartySocket(sckrwecb_t(s));
219 SOCKET InstallHTTPGateway (Address bind_to) {
221 #define gw_ensure(x) { if (!(x)) { \
222 print_error("http binding fails"); close_socket(fd); \
223 return INVALID_SOCKET; } }
224 gw_ensure ( (fd=socket(AF_INET, SOCK_STREAM, 0)) != INVALID_SOCKET );
226 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (setsockoptptr_t)&enable, sizeof(int));
227 //setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, (setsockoptptr_t)&enable, sizeof(int));
228 //struct sigaction act;
229 //memset(&act,0,sizeof(struct sigaction));
230 //act.sa_handler = SIG_IGN;
231 //sigaction (SIGPIPE, &act, NULL); // FIXME
232 signal( SIGPIPE, SIG_IGN );
233 gw_ensure ( 0==bind(fd, (sockaddr*)&(bind_to.addr), sizeof(struct sockaddr_in)) );
234 gw_ensure (make_socket_nonblocking(fd));
235 gw_ensure ( 0==listen(fd,8) );
236 sckrwecb_t install_http(fd,HttpGwNewConnectionCallback,NULL,HttpGwError);
237 gw_ensure (swift::Datagram::Listen3rdPartySocket(install_http));
238 dprintf("%s @0 installed http gateway on %s\n",tintstr(),bind_to.str());