void Server::handleBtnHRequest(SOCKET connection, Request & request) { // The button request must have a get variable name 'key'. If not, send a 400 error and return if (request.get.find("key") == request.get.end()) { ssend(connection, "HTTP/1.0 400 BAD REQUEST\r\n\r\n<h1>Need a key</h1>"); return ; } // Open the MFD (with no image format) ServerMFD *mfd = openMFD(request.get["key"], "", false); // If the open of the MFD failed, send a 500 error and return if (!mfd) { ssend(connection, "HTTP/1.0 412 Precondition Failed\r\n\r\n<h1>Could not find the MFD</h1>"); return ; } // Send a 200 HTTP error code ssend(connection, "HTTP/1.0 200 OK\r\n\r\n"); // Get the button id from the resource int btnId = atoi(request.resource.c_str()); // If the button Id is a correct number // It may very well be -1, which means that this is just an enquiry and not a button press if (btnId >= 0) { // Inform that we want to start a button press mfd->startBtnProcess(); // Register the button press into the corresponding event queue // We are probably not in the main (Orbiter) thread // Therefore, we cannot use directly the Orbiter API as Orbiter is not thread-safe (Martin Schweiger if you read this...) WaitForSingleObject(_mfdsMutex, INFINITE); _btnPress.push(std::pair<ServerMFD*, int>(mfd, btnId)); ReleaseMutex(_mfdsMutex); // Wait for the end of the button process mfd->waitForBtnProcess(); // Force the refresh of the MFD as the button press has probably a consequence on the display WaitForSingleObject(_mfdsMutex, INFINITE); _forceRefresh.push(mfd); ReleaseMutex(_mfdsMutex); } // send the buttons status in JSON unsigned int btnPrevId = 0; ssend(connection, mfd->getJSON().c_str()); // Close the MFD closeMFD(request.get["key"]); }
void Server::handleRequest(SOCKET connection, Request & request) { // If the request is for a MFD if (request.resource.substr(0, 5) == "/mfd/") { // Remove the "/mfd/" from the resource string request.resource = request.resource.substr(5); // Handle the request handleMFDRequest(connection, request); } // If the request is for a file else if (request.resource.substr(0, 5) == "/web/") { // Remove the "/web/" from the resource string request.resource = request.resource.substr(5); // Handle the request handleWebRequest(connection, request); } // If the request is for a button WebSocket else if (request.resource.substr(0, 5) == "/btn/") { // Remove the "/btn/" from the resource string request.resource = request.resource.substr(5); // Handle the request handleBtnRequest(connection, request); } // If the request is for a button classic HTTP enquiry else if (request.resource.substr(0, 7) == "/btn_h/") { // Remove the "/btn_h/" from the resource string request.resource = request.resource.substr(7); // Handle the request handleBtnHRequest(connection, request); } // If the request is for root, redirect to /web/ else if (request.resource == "/") ssend(connection, "HTTP/1.0 301 Moved Permanently\r\nLocation: /web/\r\n\r\n"); // The request is unknown: send a 404 error else ssend(connection, "HTTP/1.0 404 Not Found\r\n\r\n"); }
void ia(t_client *it) { int random; usleep(rand() % 1000 + 400000); if (it->size > 0) { random = rand() % it->size; ssend(it->client->fd, it->ia[random]); } }
int tcp_srv_send(struct nmdb_srv *srv, unsigned char *buf, size_t bsize) { ssize_t rv; uint32_t len; len = htonl(bsize); memcpy(buf, (const void *) &len, 4); rv = ssend(srv->fd, buf, bsize, 0); if (rv != bsize) return 0; return 1; }
void parse(char *line) { int i = 0; char *cmd = NULL, *who = NULL, *rest = NULL, parc = 0; char *parv[100]; char ltmp[strlen(line)]; strip_newline(line); strcpy(ltmp, line); ssend(":%s PRIVMSG %s :%s\n", bot.nick, bot.protoChan, line); parc = parse_line(line, parv); if(!parv[1]) return; if(!strcmp(parv[0], "SERVER")) { add_server(parv[1], parv[6][0], bot.server->numeric); bot.uplink = get_serv(parv[6][0]); add_server(bot.server->name, bot.scnum, bot.uplink->numeric); add_nick(bot.nick, bot.ident, bot.host, bot.modes, bot.fullnum); bot.uplink->uplink = bot.server; bot.server->uplink = bot.uplink; notify("SRV (*) %s\n", parv[1]); return; } cmd = parv[1]; if(parv[0][0] == ':') *parv[0]++; if(parc >= 4 && parv[3][0] == ':') *parv[3]++; if(!strcmp(parv[0], "PASS")) cmd = parv[0]; for(i = 0; parsetable[i].cmd; i++) { if(!strcmp(parsetable[i].cmd, cmd)) { parsetable[i].run(parv, parc); return; } } }
int make_coffe(t_client *it) { int ret; char tmp[BUFF_SIZE] = {0}; static int flag = 0; ret = 1; memset(tmp, 0, BUFF_SIZE); if (!flag) { ret = recv(it->client->fd, tmp, BUFF_SIZE, 0); ssend(it->client->fd, "%s\n", it->team); !ret ? printf("00PS: connection closed by server.\n") : ret > 0 ? printf("%s\n", tmp) : 0; flag = 1; } else { ret = recv(it->client->fd, tmp, BUFF_SIZE, 0); if (ret >= 0) printf("%s\n", tmp); } return (!ret ? 0 : ret > 0 ? 1 : -1); }
int tcp_srv_send(moc_srv *srv, unsigned char *buf, size_t bsize, moc_arg *arg) { ssize_t rv; uint32_t len; len = htonl(bsize); memcpy(buf, (const void *) &len, 4); if (srv->fd <= 0) { bool reconnectok = true; /* * connect closed by server, catched by: * 1. el_routine() on #ifdef EVENTLOOP or * 2. moc_trigger() on #ifndef EVENTLOP */ mtc_dbg("connection closed, reconnect"); /* * although we reconnect to the server agin, * but we haven't do application's JOIN command to do further communicate * so, application need do JOIN on reconnect * fireup an _reconnect callback here */ if (!tcp_server_reconnect(srv)) { mtc_dbg("reconnect failure"); reconnectok = false; #ifndef EVENTLOOP return 0; #endif } #ifdef EVENTLOOP unsigned char lbuf[SBSIZE]; memcpy(lbuf, buf, bsize); struct msqueue_entry *e = msqueue_entry_create(); if (!e) { mtc_err("no mem"); return 0; } e->ename = strdup(srv->evt->ename); e->cmd = strdup("_reconnect"); if (reconnectok) hdf_set_value(e->hdfrcv, "success", "1"); else hdf_set_value(e->hdfrcv, "success", "0"); mssync_lock(&arg->callbacksync); msqueue_put(arg->callbackqueue, e); mssync_unlock(&arg->callbacksync); mssync_signal(&arg->callbacksync); if (reconnectok) { /* * suspend trigger thread, wait for application JOIN */ sleep(1); rv = ssend(srv->fd, lbuf, bsize, MSG_NOSIGNAL); if (rv != bsize) return 0; return 1; } else return 0; #endif } rv = ssend(srv->fd, buf, bsize, MSG_NOSIGNAL); if (rv != bsize) { if (rv < 0 && errno == EPIPE) { mtc_dbg("%s %d closed", srv->evt->ename, srv->fd); close(srv->fd); srv->fd = -1; /* if (!tcp_server_reconnect(srv)) return 0; rv = ssend(srv->fd, buf, bsize, MSG_NOSIGNAL); if (rv == bsize) return 1; */ } return 0; } return 1; }
void send_response(int socket, http_response *resp) { char str[STR_SIZE], cookie_str[STR_SIZE]; time_t now, day_from_now, epoch; node *cookie; // Get time time(&now); day_from_now = now + (24*60*60); epoch = 0; /* Start of header */ // Write HTTP version and status ssend(socket, HTTP_VERSION); ssend(socket, status_str[resp->status]); ssend(socket, "\n"); // Write allowed methods if (resp->status == METHOD_NOT_ALLOWED) { ssend(socket, HDR_ALLOW); ssend(socket, http_method_str[resp->allow]); ssend(socket, "\n"); } // Write connection ssend(socket, HDR_CONNECTION); ssend(socket, connection_str[resp->connection]); ssend(socket, "\n"); // Write new cookies if (resp->cookie && resp->opt_flags & OPT_COOKIE_EXPIRE) { strftime(str, 0x100, RFC_822_FMT, gmtime(&day_from_now)); cookie = resp->cookie; while (cookie) { ssend(socket, HDR_SET_COOKIE); sprintf(cookie_str, "%s=%s;path=/;expires=%s;\n", cookie->name, cookie->value, str); ssend(socket, cookie_str); cookie = cookie->next; } } else if (resp->cookie) { cookie = resp->cookie; while (cookie) { ssend(socket, HDR_SET_COOKIE); sprintf(cookie_str, "%s=%s;path=/;\n", cookie->name, cookie->value); ssend(socket, cookie_str); cookie = cookie->next; } } // Write cookies to be deleted if (resp->expire) { strftime(str, 0x100, RFC_822_FMT, gmtime(&epoch)); cookie = resp->expire; while (cookie) { ssend(socket, HDR_SET_COOKIE); sprintf(cookie_str, "%s=%s;path=/;expires=%s;\n", cookie->name, cookie->value, str); ssend(socket, cookie_str); cookie = cookie->next; } } // Write cache control ssend(socket, HDR_CACHE_CTRL); ssend(socket, cache_control_str[resp->cache_control]); ssend(socket, "\n"); // Write content type ssend(socket, HDR_CONTENT_TYPE); ssend(socket, content_type_str[resp->content_type]); ssend(socket, "\n"); // Write content length if (resp->opt_flags & OPT_CONTENT_LENGTH) { ssend(socket, HDR_CONTENT_LEN); sprintf(str, "%u", (unsigned int) strlen(resp->body)); ssend(socket, str); ssend(socket, "\n"); } // Write last modified time if (resp->opt_flags & OPT_LAST_MODIFIED) { ssend(socket, HDR_LAST_MOD); strftime(str, 0x100, RFC_822_FMT, gmtime(&resp->last_modified)); ssend(socket, str); ssend(socket, "\n"); } // Timestamp ssend(socket, HDR_DATE); strftime(str, 0x100, RFC_822_FMT, gmtime(&now)); ssend(socket, str); ssend(socket, "\n"); ssend(socket, "\n"); /* End of header */ if (strlen(resp->body)) { ssend(socket, resp->body); } }
void parse_ping(char **parv, int parc) { ssend(":%s PONG %s %s\n", bot.server->name, bot.server->name, parv[1]); }
void parse_eob(char **parv, int parc) { if(get_serv(parv[0][0]) == bot.uplink) { ssend("%c EA\n", bot.scnum); notify("EOB (%c) from uplink", parv[0][0]); } }
void parse_version(char **parv, int parc) { ssend(":%s 351 %s %s %s :http://mercury.darktech.org/cs/\n", bot.server->name, parv[0], bot.version, bot.server->name); }
void parse_admin(char **parv, int parc) { ssend(":%s 256 %s :Administrative info about %s\n", bot.server->name, parv[0]); }
void Server::handleBtnRequest(SOCKET connection, Request & request) { // The button request must have a get variable name 'key'. If not, send a 400 error and return if (request.get.find("key") == request.get.end()) { ssend(connection, "HTTP/1.0 400 BAD REQUEST\r\n\r\n<h1>Need a key</h1>"); return ; } // The request must be a web-socket request, check that the request provided the needed WebSocket information headers // If not, send a 412 error and return if ( request.headers.find("connection") == request.headers.end() || _stricmp(request.headers["connection"].c_str(), "upgrade") != 0 || request.headers.find("upgrade") == request.headers.end() || _stricmp(request.headers["upgrade"].c_str(), "WebSocket") != 0) { ssend(connection, "HTTP/1.0 412 Precondition Failed\r\n\r\n<h1>Connection to this URL must use WebSockets</h1>"); return ; } // The request must have a host and a origin headers. If not, send a 400 error and return if (request.headers.find("host") == request.headers.end() || request.headers.find("origin") == request.headers.end()) { ssend(connection, "HTTP/1.0 400 BAD REQUEST\r\n\r\n<h1>Missing host or origin header</h1>"); return ; } // The request must have a sec-websocket-key 1 and 2 headers. If not, send a 400 error and return if (request.headers.find("sec-websocket-key1") == request.headers.end() || request.headers.find("sec-websocket-key2") == request.headers.end()) { ssend(connection, "HTTP/1.0 400 BAD REQUEST\r\n\r\n<h1>Missing sec-websocket-key1 or sec-websocket-key2 header</h1>"); return ; } // The MFD to use the buttons on ServerMFD *mfd = 0; // Open the MFD (with no image format) mfd = openMFD(request.get["key"]); // If the open of the MFD failed, send a 500 error and return if (!mfd) { ssend(connection, "HTTP/1.0 500 Internal Server Error\r\n\r\n<h1>Could not open the MFD</h1>"); return ; } // Used to calculate the response security string of the WebSocket protocol // C.f. decodeSecWebsocket note... union { struct { INT32 sec1; INT32 sec2; char key[8]; } head; BYTE ascii[16]; } handshake; // Getting the sec-websocket-key2 calculation results handshake.head.sec1 = getBigEndian(decodeSecWebsocket(request.headers["sec-websocket-key1"])); handshake.head.sec2 = getBigEndian(decodeSecWebsocket(request.headers["sec-websocket-key2"])); // Getting the 8 bytes of the body // As soHTTP does not ensure that all the body is read, // read from the socket and add the result to the body // while the body does not contains the 8 needed bytes while (request.body.length() < 8) { char tmp[8]; int r = recv(connection, tmp, 8, 0); request.body += std::string(tmp, r); } // Copying the body 8 bytes into the WebSocket security structure strncpy(handshake.head.key, request.body.substr(0, 8).c_str(), 8); // Getting a windows cryptography context HCRYPTPROV hProv = 0; CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT); // Getting a windows MD5 Hash object from the cryptography context HCRYPTHASH hHash = 0; CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash); // Hashing the security handshake using the MD5 Hash object CryptHashData(hHash, handshake.ascii, 16, 0); // Getting the resultof the MD5 Hash into rgbHash DWORD cbHash = 16; // = MD5 Len BYTE rgbHash[16]; CryptGetHashParam(hHash, HP_HASHVAL, rgbHash, &cbHash, 0); // Destroying the Hash object and cryptographic context CryptDestroyHash(hHash); CryptReleaseContext(hProv, 0); // Sending the WebSocket headers ssend(connection, "HTTP/1.1 101 WebSocket Protocol Handshake\r\n"); ssend(connection, "Connection: Upgrade\r\n"); ssend(connection, "Upgrade: WebSocket\r\n"); ssend(connection, "Sec-WebSocket-Origin: "); ssend(connection, request.headers["origin"].c_str()); ssend(connection, "\r\n"); ssend(connection, "Sec-WebSocket-Location: ws://"); ssend(connection, request.headers["host"].c_str()); ssend(connection, "/btn/?"); ssend(connection, request.getString.c_str()); ssend(connection, "\r\n"); ssend(connection, "Sec-WebSocket-Protocol: Orbiter-WebMFD-Buttons\r\n"); ssend(connection, "\r\n"); // Sending the WebSocket hashed handshake send(connection, (char*)rgbHash, 16, 0); // Set the connection socket to timeout. // This is necessary for regular button check int toVal = (int)WEBMFD_REFRESH_ASK_MS; setsockopt(connection, SOL_SOCKET, SO_RCVTIMEO, (char*)&toVal, sizeof(int)); // Id of the button labels, used to check if the button labels have changed unsigned int BtnPrevId = 0; // Infinite loop that will run until the connection stops for (;;) { // Get the JSON string if the button labels have changed std::string JSON = mfd->getJSONIf(BtnPrevId); // If the JSON string has evolved, it is returned if (!JSON.empty()) { // send the buttons status in JSON inside a WebMFD message send(connection, "\0", 1, 0); ssend(connection, JSON.c_str()); int sent = send(connection, "\xFF", 1, 0); // If the sending of the response has failed, break the connection if (sent == SOCKET_ERROR) break ; } // The buffer to read the buttons pressed unsigned char buf[5] = {0,}; // Read 4 bytes from the sockets which should be: // 255 <btnId-ascii-digit-tenth> <btnId-ascii-digit-unit> 0 int ret = recv(connection, (char*)buf, 4, 0); // If the read has failed if (ret <= 0) { // If the read has failed because of a timeout, continue the loop if (WSAGetLastError() == WSAETIMEDOUT) continue ; // If the read has failed for any other reason, break the connection break; } // If the packet is not a 4 bytes websocket message, ignores it if (ret != 4 || buf[0] != 0 || buf[3] != 255) continue ; // Reading the btnId (ignoring the first byte, which is 255) int btnId = atoi((const char *)buf + 1); // If the given button Id is a correct number if (btnId >= 0) { // Inform that we want to start a button press mfd->startBtnProcess(); // Register the button press into the corresponding event queue // We are probably not in the main (Orbiter) thread // Therefore, we cannot use directly the Orbiter API as Orbiter is not thread-safe (Martin Schweiger if you read this...) WaitForSingleObject(_mfdsMutex, INFINITE); _btnPress.push(std::pair<ServerMFD*, int>(mfd, btnId)); ReleaseMutex(_mfdsMutex); // Wait for the end of the button process mfd->waitForBtnProcess(); // If the button pressed was the close one, break the connection if (btnId == 99) break ; // Force the refresh of the MFD as the button press has probably a consequence on the display WaitForSingleObject(_mfdsMutex, INFINITE); _forceRefresh.push(mfd); ReleaseMutex(_mfdsMutex); } // If the given button id is -1, it means that this is just an enquiry and not a button press // Therefore, BtnPrevId is set to 0, which will force, in the begining of the next loop, the button JSON send else if (btnId == -1) BtnPrevId = 0; } // Close the MFD closeMFD(request.get["key"]); }
void Server::handleWebRequest(SOCKET connection, Request & request) { // If the file request does not specify a resource if (request.resource == "") { // Open an item list of the WebMFD directory WIN32_FIND_DATA FindFileData; HANDLE hFind; hFind = FindFirstFile("WebMFD\\*", &FindFileData); // If the WebMFD directory cannot be listed, send a 500 error and return if (hFind == INVALID_HANDLE_VALUE) { printf ("HTTP/1.0 500 Internal Error\r\n\r\n<h1>Could not browse WebMFD directory</h1>", GetLastError()); return ; } // The list in which all the WebMFD sub-directories names will be stored stringList dirs; // Browse the WebMFD directory... do // If the item is a directory and is not the current directory if ((FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY && FindFileData.cFileName[0] != '.' && FindFileData.cFileName[0] != '_') // Add it's name to the list dirs.push_back(FindFileData.cFileName); // ...While there are item to be found while (FindNextFile(hFind, &FindFileData) != 0); // close the item list FindClose(hFind); // If only one subdirectoy has been found, redirect to this subdirectory if (dirs.size() == 1) { ssend(connection, "HTTP/1.0 307 Temporary Redirect\r\nLocation: "); ssend(connection, dirs.front().c_str()); ssend(connection, "/\r\n\r\n"); } // There are more than one sub-directory else { // Send a 200 HTTP code along with the HTML header of the list ssend(connection, "HTTP/1.0 200 OK\r\n" "\r\n" "<html>" "<head>" "<title>Interface list</title>" "<link rel='Stylesheet' type='text/css' href='_InterfaceChoice.css' />" "</head>" "<body>" "<h1>Choose an Interface</h1>" ); // For each sub-directory name in the list for (stringList::iterator i = dirs.begin(); i != dirs.end(); ++i) { // Send a HTML hyperlink for it ssend(connection, "<div class='interface'><h3><a href='"); ssend(connection, i->c_str()); ssend(connection, "/'>"); ssend(connection, i->c_str()); ssend(connection, "</a></h3>"); // If there is a description HANDLE descFile = CreateFile((std::string("WebMFD\\") + *i + "\\description.txt").c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (descFile != INVALID_HANDLE_VALUE) { // Send the description (using a 256 bytes buffer) ssend(connection, " <p class='desc'>"); char buffer[256]; DWORD read; for (;;) { if (!ReadFile(descFile, buffer, 256, &read, NULL)) break ; if (!read) break ; send(connection, buffer, read, 0); } ssend(connection, "</p>"); } ssend(connection, "</div>"); } // Send the HTML footer of the list ssend(connection, "<p class='footer'>Tip: if you are always using the same interface, delete all the others in the WebMFD directory to automatically use the remain one</p>" "</body>" "</html>" ); } } // The request does specifies a resource: the resource is a file else // Use the SoHTTP utility function to send the requested file sendFromDir(connection, "WebMFD", request.resource.c_str()); }
void Server::handleMFDRequest(SOCKET connection, Request & request) { // If a MFD request has to be /mfd/mfd.[format] // If the resource asked starts with "mfd." // Which means that it is probably a correct request. if (request.resource.substr(0, 4) == "mfd.") { // Remove the "mfd." from the resource string std::string format = request.resource.substr(4); // If the format of the resource (the remaining string) is not "mpng" or "mjpeg", send a 400 error if (format != "mjpeg" && format != "mpng") ssend(connection, "HTTP/1.0 400 BAD REQUEST\r\n\r\n<h1>Unkonwn format (only mjpeg and mpng are allowed)</h1>"); // If the key is not given in the request in get variable, send a 400 error else if (request.get.find("key") == request.get.end()) ssend(connection, "HTTP/1.0 400 BAD REQUEST\r\n\r\n<h1>Need a key</h1>"); // The request is correct else { // The number of time we have waited for a tenth of the refreshing time. int nbWaits = 0; // Remove the 'm' of "mjpeg" or "mpng" format = format.substr(1); // Get the MFD for the corresponding key ServerMFD *mfd = openMFD(request.get["key"], format); // Check that the MFD has correctly been opened if (!mfd) return ; // Send a 200 HTTP code followed by the Content-Type header needed for the motion image stream ssend(connection, "HTTP/1.0 200 OK\r\nContent-Type: multipart/x-mixed-replace; boundary=--MFDNextImage--\r\n"); // Id of the image, used to check if the image has changed unsigned int id = 0; // Infinite loop that will run until the connection stops for (;;) { // Get a stream containing the image if, and only if, the id of the image has changed // Will also update the id to the id of the new image imageStream * stream = mfd->getStreamIf(format, id); // If there is a new image if (stream) { // If the close button has been pressed, break the stream if (mfd->getClose()) break ; // Send the next image boundary in the motion image stream ssend(connection, "\r\n--MFDNextImage--\r\nContent-Type: image/"); ssend(connection, format.c_str()); ssend(connection, "\r\n"); // Send the content-length header and the empty line indicating the end of the headers in the motion image stream char length[15]; _itoa_s(stream->size, length, 15, 10); ssend(connection, "Content-Length: "); ssend(connection, length); ssend(connection, "\r\n\r\n"); // The buffer used to read the image char buffer[256]; // The number of bytes read at each iteration of the read loop // Set to one to enable to start the loop ULONG read; // The Read call return status // Wether Read succeeds HRESULT readHr; // Number of byte read at each iteration of the read loop int sent; // The total number of bytes sent int totalSent = 0; // Transfer from stream to socket... do { // The number of bytes to read left in the image int bytesToRead = stream->size - totalSent; // Read by range of maximum 256 bytes if (bytesToRead > 256) bytesToRead = 256; // Read the bytes of the stream readHr = stream->stream->Read(buffer, bytesToRead, &read); // If the read has succeeded if (readHr == S_OK && read) { // Write on the socket what has been read from the stream sent = send(connection, buffer, read, 0); totalSent += sent; } } // ...While the read has succeded and more bytes are to be read while (readHr == S_OK && totalSent < stream->size && read && sent != SOCKET_ERROR); // If the last socket send has failed, then it means that the socket has been close, break the stream if (sent == SOCKET_ERROR) break ; // Release the image stream mfd->closeStream(); // reset the number of waits nbWaits = 0; } else { // Increment the number of times we have waited since the last image ++nbWaits; // If we have waited more then a refreshing time if (nbWaits > 10) { // Force the MFD refresh WaitForSingleObject(_mfdsMutex, INFINITE); _forceRefresh.push(mfd); ReleaseMutex(_mfdsMutex); // reset the number of waits nbWaits = 0; } } // Wait for a tenth of the refreshing interval before asking if there is a new image Sleep((DWORD)(WEBMFD_REFRESH_ASK_MS)); } // Close the MFD closeMFD(request.get["key"], format); } } // The resource does not starts with "mfd." and is threfore an incorect request: send a 404 error else ssend(connection, "HTTP/1.0 404 Not Found\r\n\r\n"); }