"Fossies" - the Fresh Open Source Software Archive

Member "motion-Release-4.3.0/src/stream.c" (14 Jan 2020, 41788 Bytes) of package /linux/misc/motion-Release-4.3.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "stream.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2  *                 NOTICE
    3  *   This entire module (stream.c) is dead code and will be removed in its entirety very shortly
    4  *
    5  *   The only reason that it has not been removed yet is to allow for an emergency option to use
    6  *   the old stream method if for some reason the webu MHD option does not work on a particular
    7  *   platform.  It is only avaialable for activation using the undocumented option of
    8  *   cnt->conf.stream_preview_method == 99
    9  *
   10  *   NO REVISIONS SHOULD BE MADE TO THIS MODULE.  IT IS DEAD
   11  */
   12 
   13 
   14 /*
   15  *    stream.c (based in webcam.c)
   16  *    Streaming using jpeg images over a multipart/x-mixed-replace stream
   17  *    Copyright (C) 2002 Jeroen Vreeken (pe1rxq@amsat.org)
   18  *
   19  *    This program is free software; you can redistribute it and/or modify
   20  *    it under the terms of the GNU General Public License as published by
   21  *    the Free Software Foundation; either version 2 of the License, or
   22  *    (at your option) any later version.
   23  *
   24  *    This program is distributed in the hope that it will be useful,
   25  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
   26  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   27  *    GNU General Public License for more details.
   28  *
   29  *    You should have received a copy of the GNU General Public License
   30  *    along with this program; if not, write to the Free Software
   31  *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   32  */
   33 
   34 #include "translate.h"
   35 #include "md5.h"
   36 #include "picture.h"
   37 #include <sys/socket.h>
   38 #include <netinet/in.h>
   39 #include <arpa/inet.h>
   40 #include <netdb.h>
   41 #include <ctype.h>
   42 #include <fcntl.h>
   43 
   44 #define STREAM_REALM       "Motion Stream Security Access"
   45 #define KEEP_ALIVE_TIMEOUT 100
   46 
   47 typedef void* (*auth_handler)(void*);
   48 struct auth_param {
   49     struct context *cnt;
   50     struct stream *stm;
   51     int *stream_count;
   52     int sock;
   53     int sock_flags;
   54     int* thread_count;
   55     struct config *conf;
   56 };
   57 
   58 /**
   59  * get_host
   60  *      Gets the host (IP) of a client from the socket file descriptor
   61  * Returns nothing
   62  */
   63 static void get_host(char *buf, int fd)
   64 {
   65     struct sockaddr_storage client;
   66     int retcd;
   67 
   68     socklen_t client_len = sizeof(client);
   69     int res = getpeername(fd, (struct sockaddr *)&client, &client_len);
   70     if (res != 0)
   71         return;
   72 
   73     char host[NI_MAXHOST];
   74     res = getnameinfo((struct sockaddr *)&client, client_len, host, sizeof(host), NULL, 0, NI_NUMERICHOST);
   75     if (res != 0)
   76         return;
   77 
   78     retcd = snprintf(buf,NI_MAXHOST - 1,"%s",host);
   79     if ((retcd < 0) || (retcd >= (int)NI_MAXHOST-1)){
   80         MOTION_LOG(ERR, TYPE_STREAM, SHOW_ERRNO
   81             ,_("Error specifying host"));
   82     }
   83 
   84 }
   85 
   86 pthread_mutex_t stream_auth_mutex;
   87 
   88 /**
   89  * set_sock_timeout
   90  *
   91  * Returns : 0 or 1 on timeout
   92  */
   93 static int set_sock_timeout(int sock, int sec)
   94 {
   95     struct timeval tv;
   96 
   97     tv.tv_sec = sec;
   98     tv.tv_usec = 0;
   99 
  100     if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char*) &tv, sizeof(tv))) {
  101         MOTION_LOG(ERR, TYPE_STREAM, SHOW_ERRNO
  102             ,_("set socket timeout failed"));
  103         return 1;
  104     }
  105     return 0;
  106 }
  107 
  108 /**
  109  * read_http_request
  110  *
  111  *
  112  * Returns : 1 on success or 0 if any error happens
  113  */
  114 static int read_http_request(int sock, char* buffer, int buflen, char* uri, int uri_len)
  115 {
  116     int nread = 0;
  117     int ret,readb = 1;
  118     char method[10] = {'\0'};
  119     char url[512] = {'\0'};
  120     char protocol[10] = {'\0'};
  121 
  122 #define bad_request_response_raw \
  123         "HTTP/1.0 400 Bad Request\r\n" \
  124         "Content-type: text/plain\r\n\r\n" \
  125         "Bad Request\n"
  126 
  127 #define bad_method_response_template_raw \
  128         "HTTP/1.0 501 Method Not Implemented\r\n" \
  129         "Content-type: text/plain\r\n\r\n" \
  130         "Method Not Implemented\n"
  131 
  132 #define timeout_response_template_raw \
  133         "HTTP/1.0 408 Request Timeout\r\n" \
  134         "Content-type: text/plain\r\n\r\n" \
  135         "Request Timeout\n"
  136 
  137     buffer[0] = '\0';
  138 
  139     while ((strstr(buffer, "\r\n\r\n") == NULL) && (readb != 0) && (nread < buflen)) {
  140 
  141         readb = read(sock, buffer+nread, buflen - nread);
  142 
  143         if (readb == -1) {
  144             nread = -1;
  145             break;
  146         }
  147 
  148         nread += readb;
  149 
  150         if (nread > buflen) {
  151             MOTION_LOG(ERR, TYPE_STREAM, SHOW_ERRNO
  152                 ,_("motion-stream End buffer reached waiting for buffer ending"));
  153             break;
  154         }
  155 
  156         buffer[nread] = '\0';
  157     }
  158 
  159     /*
  160      * Make sure the last read didn't fail. If it did, there's a
  161      * problem with the connection, so give up.
  162      */
  163     if (nread == -1) {
  164         if(errno == EAGAIN) { // Timeout
  165             ret = write(sock, timeout_response_template_raw, strlen(timeout_response_template_raw));
  166             return 0;
  167         }
  168 
  169         MOTION_LOG(ERR, TYPE_STREAM, SHOW_ERRNO
  170             ,_("motion-stream READ give up!"));
  171         return 0;
  172     }
  173 
  174     ret = sscanf(buffer, "%9s %511s %9s", method, url, protocol);
  175 
  176     if (ret != 3) {
  177         ret = write(sock, bad_request_response_raw, sizeof(bad_request_response_raw));
  178         return 0;
  179     }
  180 
  181     /* Check Protocol */
  182     if (strcmp(protocol, "HTTP/1.0") && strcmp (protocol, "HTTP/1.1")) {
  183         /* We don't understand this protocol. Report a bad response. */
  184         ret = write(sock, bad_request_response_raw, sizeof(bad_request_response_raw));
  185         return 0;
  186     }
  187 
  188     if (strcmp(method, "GET")) {
  189         /*
  190          * This server only implements the GET method. If client
  191          * uses other method, report the failure.
  192          */
  193         char response[1024];
  194         snprintf(response, sizeof(response), bad_method_response_template_raw);
  195         ret = write(sock, response, strlen (response));
  196 
  197         return 0;
  198     }
  199 
  200     if(uri){
  201         ret = snprintf(uri, uri_len,"%s",url);
  202         if ((ret < 0) || (ret >= uri_len)){
  203             MOTION_LOG(ERR, TYPE_STREAM, SHOW_ERRNO
  204                 ,_("Unable to set uri"));
  205         }
  206     }
  207 
  208     return 1;
  209 }
  210 
  211 static void stream_add_client(struct stream *list, int sc);
  212 
  213 /**
  214  * handle_basic_auth
  215  *
  216  *
  217  */
  218 static void* handle_basic_auth(void* param)
  219 {
  220     struct auth_param *p = (struct auth_param*)param;
  221     char buffer[1024] = {'\0'};
  222     ssize_t length = 1023;
  223     char *auth, *h, *authentication;
  224     static const char *request_auth_response_template=
  225         "HTTP/1.0 401 Authorization Required\r\n"
  226         "Server: Motion/"VERSION"\r\n"
  227         "Max-Age: 0\r\n"
  228         "Expires: 0\r\n"
  229         "Cache-Control: no-cache, private\r\n"
  230         "Pragma: no-cache\r\n"
  231         "WWW-Authenticate: Basic realm=\""STREAM_REALM"\"\r\n\r\n";
  232 
  233     pthread_mutex_lock(&stream_auth_mutex);
  234     p->thread_count++;
  235     pthread_mutex_unlock(&stream_auth_mutex);
  236 
  237     if (!read_http_request(p->sock,buffer, length, NULL, 0))
  238         goto Invalid_Request;
  239 
  240 
  241     auth = strstr(buffer, "Authorization: Basic");
  242 
  243     if (!auth)
  244         goto Error;
  245 
  246     auth += sizeof("Authorization: Basic");
  247     h = strstr(auth, "\r\n");
  248 
  249     if(!h)
  250         goto Error;
  251 
  252     *h='\0';
  253 
  254     if (p->conf->stream_authentication != NULL) {
  255 
  256         char *userpass = NULL;
  257         size_t auth_size = strlen(p->conf->stream_authentication);
  258 
  259         authentication = mymalloc(BASE64_LENGTH(auth_size) + 1);
  260         userpass = mymalloc(auth_size + 4);
  261         /* motion_base64_encode can read 3 bytes after the end of the string, initialize it. */
  262         memset(userpass, 0, auth_size + 4);
  263         strcpy(userpass, p->conf->stream_authentication);
  264         motion_base64_encode(userpass, authentication, auth_size);
  265         free(userpass);
  266 
  267         if (strcmp(auth, authentication)) {
  268             free(authentication);
  269             char host[NI_MAXHOST] = "unknown";
  270             get_host(host, p->sock);
  271             MOTION_LOG(ALR, TYPE_STREAM, NO_ERRNO
  272                 ,_("motion-stream - failed auth attempt from %s"), host);
  273             goto Error;
  274         }
  275         free(authentication);
  276     }
  277 
  278     // OK - Access
  279 
  280     /* Set socket to non blocking */
  281     if (fcntl(p->sock, F_SETFL, p->sock_flags) < 0) {
  282         MOTION_LOG(ERR, TYPE_STREAM, SHOW_ERRNO,_("fcntl"));
  283         goto Error;
  284     }
  285 
  286     /* Lock the mutex */
  287     pthread_mutex_lock(&stream_auth_mutex);
  288 
  289     stream_add_client(p->stm, p->sock);
  290     (*p->stream_count)++;
  291     p->thread_count--;
  292 
  293     /* Unlock the mutex */
  294     pthread_mutex_unlock(&stream_auth_mutex);
  295 
  296     free(p);
  297     pthread_exit(NULL);
  298 
  299 Error:
  300     if (write(p->sock, request_auth_response_template, strlen (request_auth_response_template)) < 0)
  301         MOTION_LOG(DBG, TYPE_STREAM, SHOW_ERRNO
  302             ,_("write failure 1:handle_basic_auth"));
  303 
  304 Invalid_Request:
  305     close(p->sock);
  306 
  307     pthread_mutex_lock(&stream_auth_mutex);
  308     p->thread_count--;
  309     pthread_mutex_unlock(&stream_auth_mutex);
  310 
  311     free(p);
  312     pthread_exit(NULL);
  313 }
  314 
  315 
  316 #define HASHLEN 16
  317 typedef char HASH[HASHLEN];
  318 #define HASHHEXLEN 32
  319 typedef char HASHHEX[HASHHEXLEN+1];
  320 #define IN
  321 #define OUT
  322 /**
  323  * CvtHex
  324  *      Calculates H(A1) as per HTTP Digest spec -- taken from RFC 2617.
  325  */
  326 static void CvtHex(IN HASH Bin, OUT HASHHEX Hex)
  327 {
  328     unsigned short i;
  329     unsigned char j;
  330 
  331     for (i = 0; i < HASHLEN; i++) {
  332         j = (Bin[i] >> 4) & 0xf;
  333         if (j <= 9)
  334             Hex[i*2] = (j + '0');
  335          else
  336             Hex[i*2] = (j + 'a' - 10);
  337         j = Bin[i] & 0xf;
  338         if (j <= 9)
  339             Hex[i*2+1] = (j + '0');
  340          else
  341             Hex[i*2+1] = (j + 'a' - 10);
  342     };
  343     Hex[HASHHEXLEN] = '\0';
  344 };
  345 
  346 /**
  347  * DigestCalcHA1
  348  *      Calculates H(A1) as per spec.
  349  */
  350 static void DigestCalcHA1(
  351     IN char * pszAlg,
  352     IN char * pszUserName,
  353     IN char * pszRealm,
  354     IN char * pszPassword,
  355     IN char * pszNonce,
  356     IN char * pszCNonce,
  357     OUT HASHHEX SessionKey
  358     )
  359 {
  360     MD5_CTX Md5Ctx;
  361     HASH HA1;
  362 
  363     MD5Init(&Md5Ctx);
  364     MD5Update(&Md5Ctx, (unsigned char *)pszUserName, strlen(pszUserName));
  365     MD5Update(&Md5Ctx, (unsigned char *)":", 1);
  366     MD5Update(&Md5Ctx, (unsigned char *)pszRealm, strlen(pszRealm));
  367     MD5Update(&Md5Ctx, (unsigned char *)":", 1);
  368     MD5Update(&Md5Ctx, (unsigned char *)pszPassword, strlen(pszPassword));
  369     MD5Final((unsigned char *)HA1, &Md5Ctx);
  370 
  371     if (strcmp(pszAlg, "md5-sess") == 0) {
  372         MD5Init(&Md5Ctx);
  373         MD5Update(&Md5Ctx, (unsigned char *)HA1, HASHLEN);
  374         MD5Update(&Md5Ctx, (unsigned char *)":", 1);
  375         MD5Update(&Md5Ctx, (unsigned char *)pszNonce, strlen(pszNonce));
  376         MD5Update(&Md5Ctx, (unsigned char *)":", 1);
  377         MD5Update(&Md5Ctx, (unsigned char *)pszCNonce, strlen(pszCNonce));
  378         MD5Final((unsigned char *)HA1, &Md5Ctx);
  379     };
  380     CvtHex(HA1, SessionKey);
  381 };
  382 
  383 /**
  384  * DigestCalcResponse
  385  *      Calculates request-digest/response-digest as per HTTP Digest spec.
  386  */
  387 static void DigestCalcResponse(
  388     IN HASHHEX HA1,           /* H(A1) */
  389     IN char * pszNonce,       /* nonce from server */
  390     IN char * pszNonceCount,  /* 8 hex digits */
  391     IN char * pszCNonce,      /* client nonce */
  392     IN char * pszQop,         /* qop-value: "", "auth", "auth-int" */
  393     IN char * pszMethod,      /* method from the request */
  394     IN char * pszDigestUri,   /* requested URL */
  395     IN HASHHEX HEntity,       /* H(entity body) if qop="auth-int" */
  396     OUT HASHHEX Response      /* request-digest or response-digest */
  397     )
  398 {
  399     MD5_CTX Md5Ctx;
  400     HASH HA2;
  401     HASH RespHash;
  402     HASHHEX HA2Hex;
  403 
  404     // Calculate H(A2)
  405     MD5Init(&Md5Ctx);
  406     MD5Update(&Md5Ctx, (unsigned char *)pszMethod, strlen(pszMethod));
  407     MD5Update(&Md5Ctx, (unsigned char *)":", 1);
  408     MD5Update(&Md5Ctx, (unsigned char *)pszDigestUri, strlen(pszDigestUri));
  409 
  410     if (strcmp(pszQop, "auth-int") == 0) {
  411         MD5Update(&Md5Ctx, (unsigned char *)":", 1);
  412         MD5Update(&Md5Ctx, (unsigned char *)HEntity, HASHHEXLEN);
  413     }
  414     MD5Final((unsigned char *)HA2, &Md5Ctx);
  415     CvtHex(HA2, HA2Hex);
  416 
  417     // Calculate response
  418     MD5Init(&Md5Ctx);
  419     MD5Update(&Md5Ctx, (unsigned char *)HA1, HASHHEXLEN);
  420     MD5Update(&Md5Ctx, (unsigned char *)":", 1);
  421     MD5Update(&Md5Ctx, (unsigned char *)pszNonce, strlen(pszNonce));
  422     MD5Update(&Md5Ctx, (unsigned char *)":", 1);
  423 
  424     if (*pszQop) {
  425         MD5Update(&Md5Ctx, (unsigned char *)pszNonceCount, strlen(pszNonceCount));
  426         MD5Update(&Md5Ctx, (unsigned char *)":", 1);
  427         MD5Update(&Md5Ctx, (unsigned char *)pszCNonce, strlen(pszCNonce));
  428         MD5Update(&Md5Ctx, (unsigned char *)":", 1);
  429         MD5Update(&Md5Ctx, (unsigned char *)pszQop, strlen(pszQop));
  430         MD5Update(&Md5Ctx, (unsigned char *)":", 1);
  431     }
  432     MD5Update(&Md5Ctx, (unsigned char *)HA2Hex, HASHHEXLEN);
  433     MD5Final((unsigned char *)RespHash, &Md5Ctx);
  434     CvtHex(RespHash, Response);
  435 };
  436 
  437 
  438 /**
  439  * handle_md5_digest
  440  *
  441  *
  442  */
  443 static void* handle_md5_digest(void* param)
  444 {
  445     struct auth_param *p = (struct auth_param*)param;
  446     char buffer[1024] = {'\0'};
  447     ssize_t length = 1023;
  448     char *auth, *h, *username, *realm, *uri, *nonce, *response;
  449     int username_len, realm_len, uri_len, nonce_len, response_len;
  450 #define SERVER_NONCE_LEN 17
  451     char server_nonce[SERVER_NONCE_LEN];
  452 #define SERVER_URI_LEN 512
  453     char server_uri[SERVER_URI_LEN];
  454     char* server_user = NULL, *server_pass = NULL;
  455     unsigned int rand1,rand2;
  456     int retcd, len_user,len_pass;
  457 
  458     HASHHEX HA1;
  459     HASHHEX HA2 = "";
  460     HASHHEX server_response;
  461     static const char *request_auth_response_template=
  462         "HTTP/1.0 401 Authorization Required\r\n"
  463         "Server: Motion/"VERSION"\r\n"
  464         "Max-Age: 0\r\n"
  465         "Expires: 0\r\n"
  466         "Cache-Control: no-cache, private\r\n"
  467         "Pragma: no-cache\r\n"
  468         "WWW-Authenticate: Digest";
  469     static const char *auth_failed_html_template=
  470         "<!DOCTYPE html>\n"
  471         "<html>\n"
  472         "<head><title>401 Authorization Required</title></head>\n"
  473         "<body>\n"
  474         "<h1>Authorization Required</h1>\n"
  475         "<p>This server could not verify that you are authorized to access the document "
  476         "requested.  Either you supplied the wrong credentials (e.g., bad password), "
  477         "or your browser doesn't understand how to supply the credentials required.</p>\n"
  478         "</body>\n"
  479         "</html>\n";
  480     static const char *internal_error_template=
  481         "HTTP/1.0 500 Internal Server Error\r\n"
  482         "Server: Motion/"VERSION"\r\n"
  483         "Content-Type: text/html\r\n"
  484         "Connection: Close\r\n\r\n"
  485         "<!DOCTYPE html>\n"
  486         "<html>\n"
  487         "<head><title>500 Internal Server Error</title></head>\n"
  488         "<body>\n"
  489         "<h1>500 Internal Server Error</h1>\n"
  490         "</body>\n"
  491         "</html>\n";
  492 
  493     pthread_mutex_lock(&stream_auth_mutex);
  494     p->thread_count++;
  495     pthread_mutex_unlock(&stream_auth_mutex);
  496 
  497     set_sock_timeout(p->sock, KEEP_ALIVE_TIMEOUT);
  498     srand(time(NULL));
  499     rand1 = (unsigned int)(42000000.0 * rand() / (RAND_MAX + 1.0));
  500     rand2 = (unsigned int)(42000000.0 * rand() / (RAND_MAX + 1.0));
  501     snprintf(server_nonce, SERVER_NONCE_LEN, "%08x%08x", rand1, rand2);
  502 
  503     if (!p->conf->stream_authentication) {
  504         MOTION_LOG(ERR, TYPE_STREAM, SHOW_ERRNO
  505             ,_("Error no authentication data"));
  506         goto InternalError;
  507     }
  508     h = strstr(p->conf->stream_authentication, ":");
  509 
  510     if (!h) {
  511         MOTION_LOG(ERR, TYPE_STREAM, SHOW_ERRNO
  512             ,_("Error no authentication data (no ':' found)"));
  513         goto InternalError;
  514     }
  515 
  516     len_user = (h - p->conf->stream_authentication);
  517     len_pass = strlen(h);
  518     server_user = (char*)malloc(len_user + 1);
  519     server_pass = (char*)malloc(len_pass + 1);
  520 
  521     if (!server_user || !server_pass) {
  522         MOTION_LOG(ERR, TYPE_STREAM, SHOW_ERRNO
  523             ,_("Error malloc failed"));
  524         goto InternalError;
  525     }
  526 
  527     retcd = snprintf(server_user, len_user+1, "%s", p->conf->stream_authentication);
  528     if ((retcd < 0) || (retcd >= len_user)) {
  529         MOTION_LOG(ERR, TYPE_STREAM, SHOW_ERRNO
  530             ,_("Error server user"));
  531         goto InternalError;
  532     }
  533 
  534     retcd = snprintf(server_pass, len_pass+1, "%s", h);
  535     if ((retcd < 0) || (retcd >= len_user)) {
  536         MOTION_LOG(ERR, TYPE_STREAM, SHOW_ERRNO
  537             ,_("Error server pass"));
  538         goto InternalError;
  539     }
  540 
  541 
  542     while(1) {
  543         if(!read_http_request(p->sock, buffer, length, server_uri, SERVER_URI_LEN - 1))
  544             goto Invalid_Request;
  545 
  546         auth = strstr(buffer, "Authorization: Digest");
  547         if(!auth)
  548             goto Error;
  549 
  550         auth += sizeof("Authorization: Digest");
  551         h = strstr(auth, "\r\n");
  552 
  553         if (!h)
  554             goto Error;
  555         *h = '\0';
  556 
  557         // Username
  558         h=strstr(auth, "username=\"");
  559 
  560         if (!h)
  561             goto Error;
  562 
  563         username = h + 10;
  564         h = strstr(username + 1, "\"");
  565 
  566         if (!h)
  567             goto Error;
  568 
  569         username_len = h - username;
  570 
  571         // Realm
  572         h = strstr(auth, "realm=\"");
  573         if (!h)
  574             goto Error;
  575 
  576         realm = h + 7;
  577         h = strstr(realm + 1, "\"");
  578 
  579         if (!h)
  580             goto Error;
  581 
  582         realm_len = h - realm;
  583 
  584         // URI
  585         h = strstr(auth, "uri=\"");
  586 
  587         if (!h)
  588             goto Error;
  589 
  590         uri = h + 5;
  591         h = strstr(uri + 1, "\"");
  592 
  593         if (!h)
  594             goto Error;
  595 
  596         uri_len = h - uri;
  597 
  598         // Nonce
  599         h = strstr(auth, "nonce=\"");
  600 
  601         if (!h)
  602             goto Error;
  603 
  604         nonce = h + 7;
  605         h = strstr(nonce + 1, "\"");
  606 
  607         if (!h)
  608             goto Error;
  609 
  610         nonce_len = h - nonce;
  611 
  612         // Response
  613         h = strstr(auth, "response=\"");
  614 
  615         if (!h)
  616             goto Error;
  617 
  618         response = h + 10;
  619         h = strstr(response + 1, "\"");
  620 
  621         if (!h)
  622             goto Error;
  623 
  624         response_len = h - response;
  625 
  626         username[username_len] = '\0';
  627         realm[realm_len] = '\0';
  628         uri[uri_len] = '\0';
  629         nonce[nonce_len] = '\0';
  630         response[response_len] = '\0';
  631 
  632         DigestCalcHA1((char*)"md5", server_user, (char*)STREAM_REALM, server_pass, (char*)server_nonce, (char*)NULL, HA1);
  633         DigestCalcResponse(HA1, server_nonce, NULL, NULL, (char*)"", (char*)"GET", server_uri, HA2, server_response);
  634 
  635         if (strcmp(server_response, response) == 0){
  636             break;
  637         } else {
  638             char host[NI_MAXHOST] = "unknown";
  639             get_host(host, p->sock);
  640             MOTION_LOG(ALR, TYPE_STREAM, NO_ERRNO
  641                 ,_("motion-stream - failed auth attempt from %s"), host);
  642         }
  643 
  644 Error:
  645         rand1 = (unsigned int)(42000000.0 * rand() / (RAND_MAX + 1.0));
  646         rand2 = (unsigned int)(42000000.0 * rand() / (RAND_MAX + 1.0));
  647         snprintf(server_nonce, SERVER_NONCE_LEN, "%08x%08x", rand1, rand2);
  648         snprintf(buffer, length, "%s realm=\""STREAM_REALM"\", nonce=\"%s\"\r\n"
  649                 "Content-Type: text/html\r\n"
  650                 "Keep-Alive: timeout=%i\r\n"
  651                 "Connection: keep-alive\r\n"
  652                 "Content-Length: %zu\r\n\r\n",
  653                 request_auth_response_template, server_nonce,
  654                 KEEP_ALIVE_TIMEOUT, strlen(auth_failed_html_template));
  655         if (write(p->sock, buffer, strlen(buffer)) < 0)
  656             MOTION_LOG(DBG, TYPE_STREAM, SHOW_ERRNO
  657                 ,_("write failure 1:handle_md5_digest"));
  658         if (write(p->sock, auth_failed_html_template, strlen(auth_failed_html_template)) < 0)
  659             MOTION_LOG(DBG, TYPE_STREAM, SHOW_ERRNO
  660                 ,_("write failure 2:handle_md5_digest"));
  661     }
  662 
  663     // OK - Access
  664 
  665     /* Set socket to non blocking */
  666     if (fcntl(p->sock, F_SETFL, p->sock_flags) < 0) {
  667         MOTION_LOG(ERR, TYPE_STREAM, SHOW_ERRNO,_("fcntl"));
  668         goto Error;
  669     }
  670 
  671     free(server_user);
  672     free(server_pass);
  673 
  674     /* Lock the mutex */
  675     pthread_mutex_lock(&stream_auth_mutex);
  676 
  677     stream_add_client(p->stm, p->sock);
  678     (*p->stream_count)++;
  679 
  680     p->thread_count--;
  681     /* Unlock the mutex */
  682     pthread_mutex_unlock(&stream_auth_mutex);
  683 
  684     free(p);
  685     pthread_exit(NULL);
  686 
  687 InternalError:
  688     free(server_user);
  689     free(server_pass);
  690 
  691     if (write(p->sock, internal_error_template, strlen(internal_error_template)) < 0)
  692       MOTION_LOG(DBG, TYPE_STREAM, SHOW_ERRNO
  693         ,_("write failure 3:handle_md5_digest"));
  694 
  695 Invalid_Request:
  696     close(p->sock);
  697 
  698     pthread_mutex_lock(&stream_auth_mutex);
  699     p->thread_count--;
  700     pthread_mutex_unlock(&stream_auth_mutex);
  701 
  702     free(p);
  703     pthread_exit(NULL);
  704 }
  705 
  706 /**
  707  * do_client_auth
  708  *
  709  *
  710  */
  711 static void do_client_auth(struct context *cnt, struct stream *stm, int *stream_count, int sc)
  712 {
  713     pthread_t thread_id;
  714     pthread_attr_t attr;
  715     auth_handler handle_func;
  716     struct auth_param* handle_param = NULL;
  717     int flags;
  718     static int first_call = 0;
  719     static int thread_count = 0;
  720 
  721     if(first_call == 0) {
  722         first_call = 1;
  723         /* Initialize the mutex */
  724         pthread_mutex_init(&stream_auth_mutex, NULL);
  725     }
  726 
  727     switch(cnt->conf.stream_auth_method)
  728     {
  729     case 1: // Basic
  730       handle_func = handle_basic_auth;
  731       break;
  732     case 2: // MD5 Digest
  733       handle_func = handle_md5_digest;
  734       break;
  735     default:
  736         MOTION_LOG(ERR, TYPE_STREAM, SHOW_ERRNO
  737             ,_("Error unknown stream authentication method"));
  738       goto Error;
  739       break;
  740     }
  741 
  742     handle_param = mymalloc(sizeof(struct auth_param));
  743     handle_param->cnt = cnt;
  744     handle_param->stm = stm;
  745     handle_param->stream_count = stream_count;
  746     handle_param->sock = sc;
  747     handle_param->conf = &cnt->conf;
  748     handle_param->thread_count = &thread_count;
  749 
  750     /* Set socket to blocking */
  751     if ((flags = fcntl(sc, F_GETFL, 0)) < 0) {
  752         MOTION_LOG(ERR, TYPE_STREAM, SHOW_ERRNO, _("fcntl"));
  753         goto Error;
  754     }
  755     handle_param->sock_flags = flags;
  756 
  757     if (fcntl(sc, F_SETFL, flags & (~O_NONBLOCK)) < 0) {
  758         MOTION_LOG(ERR, TYPE_STREAM, SHOW_ERRNO, _("fcntl"));
  759         goto Error;
  760     }
  761 
  762     if (thread_count >= DEF_MAXSTREAMS)
  763         goto Error;
  764 
  765     if (pthread_attr_init(&attr)) {
  766         MOTION_LOG(ERR, TYPE_STREAM, SHOW_ERRNO,_("Error pthread_attr_init"));
  767         goto Error;
  768     }
  769 
  770     if (pthread_create(&thread_id, &attr, handle_func, handle_param)) {
  771         MOTION_LOG(ERR, TYPE_STREAM, SHOW_ERRNO,_("Error pthread_create"));
  772         goto Error;
  773     }
  774     pthread_detach(thread_id);
  775 
  776     if (pthread_attr_destroy(&attr))
  777         MOTION_LOG(ERR, TYPE_STREAM, SHOW_ERRNO,_("Error pthread_attr_destroy"));
  778 
  779     return;
  780 
  781 Error:
  782     close(sc);
  783     free(handle_param);
  784 }
  785 
  786 /**
  787  * http_bindsock
  788  *      Sets up a TCP/IP socket for incoming requests. It is called only during
  789  *      initialisation of Motion from the function stream_init
  790  *      The function sets up a a socket on the port number given by _port_.
  791  *      If the parameter _local_ is not zero the socket is setup to only accept connects from localhost.
  792  *      Otherwise any client IP address is accepted. The function returns an integer representing the socket.
  793  *
  794  * Returns: socket descriptor or -1 if any error happens
  795  */
  796 int http_bindsock(int port, int local, int ipv6_enabled)
  797 {
  798     int sd = socket(ipv6_enabled?AF_INET6:AF_INET, SOCK_STREAM, IPPROTO_TCP);
  799 
  800     if (sd == -1){
  801         MOTION_LOG(CRT, TYPE_STREAM, SHOW_ERRNO,_("error creating socket"));
  802         return -1;
  803     }
  804     /* We can not do a SOCK_CLOEXEC on open since it is not supported on all platforms*/
  805     if (fcntl(sd, F_SETFD, FD_CLOEXEC) == -1){
  806         MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO,_("Unable to set FD_CLOEXEC"));
  807     };
  808 
  809     int yes = 1, no = 0;
  810     if (setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) != 0)
  811     {
  812         MOTION_LOG(CRT, TYPE_STREAM, SHOW_ERRNO
  813             ,_("setting SO_REUSEADDR to yes failed"));
  814         /* we can carry on even if this failed */
  815     }
  816 
  817     if (ipv6_enabled)
  818     {
  819         if (setsockopt(sd, IPPROTO_IPV6, IPV6_V6ONLY, &no, sizeof(no)) != 0)
  820         {
  821             MOTION_LOG(CRT, TYPE_STREAM, SHOW_ERRNO
  822                 ,_("setting IPV6_V6ONLY to no failed"));
  823             /* we can carry on even if this failed */
  824         }
  825     }
  826 
  827     const char *addr_str;
  828     struct sockaddr_storage sin;
  829     socklen_t sinsize;
  830     bzero(&sin, sizeof(struct sockaddr_storage));
  831     sin.ss_family = ipv6_enabled?AF_INET6:AF_INET;
  832     if (ipv6_enabled) {
  833         struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&sin;
  834         sin6->sin6_family = AF_INET6;
  835         sin6->sin6_port = htons(port);
  836         if(local) {
  837             addr_str = "::1";
  838             sin6->sin6_addr = in6addr_loopback;
  839         } else {
  840             addr_str = "any IPv4/IPv6 address";
  841             sin6->sin6_addr = in6addr_any;
  842         }
  843         sinsize = sizeof(*sin6);
  844     } else {
  845         struct sockaddr_in *sin4 = (struct sockaddr_in*)&sin;
  846         sin4->sin_family = AF_INET;
  847         sin4->sin_port = htons(port);
  848         if(local) {
  849             addr_str = "127.0.0.1";
  850             sin4->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
  851         } else {
  852             addr_str = "any IPv4 address";
  853             sin4->sin_addr.s_addr = htonl(INADDR_ANY);
  854         }
  855         sinsize = sizeof(*sin4);
  856     }
  857 
  858     if (bind(sd, (struct sockaddr*)&sin, sinsize) != 0) {
  859         MOTION_LOG(CRT, TYPE_STREAM, SHOW_ERRNO
  860             ,_("error binding on %s port %d"), addr_str, port);
  861         close(sd);
  862         return -1;
  863     }
  864 
  865     if (listen(sd, DEF_MAXWEBQUEUE) != 0) {
  866         MOTION_LOG(CRT, TYPE_STREAM, SHOW_ERRNO,_("error listening"));
  867         close(sd);
  868         return -1;
  869     }
  870 
  871     MOTION_LOG(NTC, TYPE_STREAM, NO_ERRNO
  872         ,_("listening on %s port %d"), addr_str, port);
  873 
  874     return sd;
  875 }
  876 
  877 /**
  878  * http_acceptsock
  879  *
  880  *
  881  * Returns: socket descriptor or -1 if any error happens.
  882  */
  883 static int http_acceptsock(int sl)
  884 {
  885     int sc;
  886     struct sockaddr_storage addr;
  887     socklen_t addr_len = sizeof(addr);
  888     sc = accept(sl, (struct sockaddr*)&addr, &addr_len);
  889 
  890     if (sc < 0) {
  891         MOTION_LOG(CRT, TYPE_STREAM, SHOW_ERRNO,_("motion-stream accept()"));
  892         return -1;
  893     }
  894 
  895     unsigned long i = 1;
  896     ioctl(sc, FIONBIO, &i);
  897     return sc;
  898 }
  899 
  900 
  901 /**
  902  * stream_flush
  903  *      Sends any outstanding data to all connected clients.
  904  *      It continuously goes through the client list until no data is able
  905  *      to be sent (either because there isn't any, or because the clients
  906  *      are not able to accept it).
  907  */
  908 static void stream_flush(struct stream *list, int *stream_count, int lim)
  909 {
  910     int written;            /* The number of bytes actually written. */
  911     struct stream *client;  /* Pointer to the client being served. */
  912     int workdone = 0;       /* Flag set any time data is successfully
  913                                written. */
  914 
  915     client = list->next;
  916 
  917     while (client) {
  918 
  919         /* If data waiting for client, try to send it. */
  920         if (client->tmpbuffer) {
  921 
  922             /*
  923              * We expect that list->filepos < list->tmpbuffer->size
  924              * should always be true.  The check is more for safety,
  925              * in case of trouble is some other part of the code.
  926              * Note that if it is false, the following section will
  927              * clean up.
  928              */
  929             if (client->filepos < client->tmpbuffer->size) {
  930 
  931                 /*
  932                  * Here we are finally ready to write out the
  933                  * data.  Remember that (because the socket
  934                  * has been set non-blocking) we may only
  935                  * write out part of the buffer.  The var
  936                  * 'filepos' contains how much of the buffer
  937                  * has already been written.
  938                  */
  939                 written = write(client->socket,
  940                           client->tmpbuffer->ptr + client->filepos,
  941                           client->tmpbuffer->size - client->filepos);
  942 
  943                 /*
  944                  * If any data has been written, update the
  945                  * data pointer and set the workdone flag.
  946                  */
  947                 if (written > 0) {
  948                     client->filepos += written;
  949                     workdone = 1;
  950                 }
  951             } else
  952                 written = 0;
  953 
  954             /*
  955              * If we have written the entire buffer to the socket,
  956              * or if there was some error (other than EAGAIN, which
  957              * means the system couldn't take it), this request is
  958              * finished.
  959              */
  960             if ((client->filepos >= client->tmpbuffer->size) ||
  961                 (written < 0 && errno != EAGAIN)) {
  962                 /* If no other clients need this buffer, free it. */
  963                 if (--client->tmpbuffer->ref <= 0) {
  964                     free(client->tmpbuffer->ptr);
  965                     free(client->tmpbuffer);
  966                     if (client->cors_header != NULL) free(client->cors_header);
  967                 }
  968 
  969                 /* Mark this client's buffer as empty. */
  970                 client->tmpbuffer = NULL;
  971                 client->nr++;
  972             }
  973 
  974             /*
  975              * If the client is no longer connected, or the total
  976              * number of frames already sent to this client is
  977              * greater than our configuration limit, disconnect
  978              * the client and free the stream struct.
  979              */
  980             if ((written < 0 && errno != EAGAIN) ||
  981                 (lim && !client->tmpbuffer && client->nr > lim)) {
  982                 void *tmp;
  983 
  984                 close(client->socket);
  985 
  986                 if (client->next)
  987                     client->next->prev = client->prev;
  988 
  989                 client->prev->next = client->next;
  990                 tmp = client;
  991                 client = client->prev;
  992                 free(tmp);
  993                 (*stream_count)--;
  994             }
  995         }   /* End if (client->tmpbuffer) */
  996 
  997         /*
  998          * Step the the next client in the list.  If we get to the
  999          * end of the list, check if anything was written during
 1000          * that loop; (if so) reset the 'workdone' flag and go back
 1001          * to the beginning.
 1002          */
 1003         client = client->next;
 1004 
 1005         if (!client && workdone) {
 1006             client = list->next;
 1007             workdone = 0;
 1008         }
 1009     }   /* End while (client) */
 1010 }
 1011 
 1012 /**
 1013  * stream_tmpbuffer
 1014  *      Routine to create a new "tmpbuffer", which is a common
 1015  *      object used by all clients connected to a single camera.
 1016  *
 1017  * Returns: new allocated stream_buffer.
 1018  */
 1019 static struct stream_buffer *stream_tmpbuffer(int size)
 1020 {
 1021     struct stream_buffer *tmpbuffer = mymalloc(sizeof(struct stream_buffer));
 1022     tmpbuffer->ref = 0;
 1023     tmpbuffer->ptr = mymalloc(size);
 1024 
 1025     return tmpbuffer;
 1026 }
 1027 
 1028 const char *base_header = "HTTP/1.0 200 OK\r\n"
 1029                           "Server: Motion/"VERSION"\r\n"
 1030                           "Connection: close\r\n"
 1031                           "Max-Age: 0\r\n"
 1032                           "Expires: 0\r\n"
 1033                           "Cache-Control: no-cache, private\r\n"
 1034                           "Pragma: no-cache\r\n"
 1035                           "Content-Type: multipart/x-mixed-replace; "
 1036                           "boundary=BoundaryString\r\n\r\n";
 1037 #define BASE_HEADER_LEN strlen(base_header)
 1038 /**
 1039  * stream_add_client
 1040  *
 1041  *
 1042  */
 1043 static void stream_add_client(struct stream *list, int sc)
 1044 {
 1045     struct stream *new = mymalloc(sizeof(struct stream));
 1046     memset(new, 0, sizeof(struct stream));
 1047     new->socket = sc;
 1048 
 1049     // Copy the HTTP headers into tmpbuffer.
 1050 
 1051     if (list->cors_header == NULL) {
 1052 
 1053         new->tmpbuffer = stream_tmpbuffer(BASE_HEADER_LEN);
 1054         if (new->tmpbuffer == NULL) {
 1055             MOTION_LOG(ERR, TYPE_STREAM, SHOW_ERRNO
 1056                 ,_("Error creating tmpbuffer in stream_add_client"));
 1057         } else {
 1058             memcpy(new->tmpbuffer->ptr, base_header, BASE_HEADER_LEN);
 1059             new->tmpbuffer->size = BASE_HEADER_LEN;
 1060         }
 1061 
 1062     } else {
 1063 
 1064         const char *cors_header_key = "Access-Control-Allow-Origin: ";
 1065         size_t cors_header_key_len = strlen(cors_header_key);
 1066         size_t cors_header_len = strlen(list->cors_header);
 1067         size_t size = BASE_HEADER_LEN-2 + cors_header_key_len + cors_header_len + 4;
 1068 
 1069         new->tmpbuffer = stream_tmpbuffer(size);
 1070         if (new->tmpbuffer == NULL) {
 1071             MOTION_LOG(ERR, TYPE_STREAM, SHOW_ERRNO
 1072                 ,_("Error creating tmpbuffer in stream_add_client"));
 1073         } else {
 1074             // Basically copy over the base headers (without the second \r\n),
 1075             // and then the CORS header key, value, and \r\n\r\n.
 1076             memcpy(new->tmpbuffer->ptr, base_header, BASE_HEADER_LEN-2);
 1077             memcpy(&new->tmpbuffer->ptr[BASE_HEADER_LEN-2], cors_header_key, cors_header_key_len);
 1078             memcpy(&new->tmpbuffer->ptr[BASE_HEADER_LEN-2 + cors_header_key_len], list->cors_header, cors_header_len);
 1079             memcpy(&new->tmpbuffer->ptr[BASE_HEADER_LEN-2 + cors_header_key_len + cors_header_len], "\r\n\r\n", 4);
 1080             new->tmpbuffer->size = size;
 1081         }
 1082 
 1083     }
 1084 
 1085     new->prev = list;
 1086     new->next = list->next;
 1087 
 1088     if (new->next)
 1089         new->next->prev = new;
 1090 
 1091     list->next = new;
 1092 }
 1093 
 1094 /**
 1095  * stream_add_write
 1096  *
 1097  *
 1098  */
 1099 static void stream_add_write(struct stream *list, struct stream_buffer *tmpbuffer, unsigned int fps)
 1100 {
 1101     struct timeval curtimeval;
 1102     unsigned long int curtime;
 1103 
 1104     gettimeofday(&curtimeval, NULL);
 1105     curtime = curtimeval.tv_usec + 1000000L * curtimeval.tv_sec;
 1106 
 1107     while (list->next) {
 1108         list = list->next;
 1109 
 1110         if (list->tmpbuffer == NULL && ((curtime - list->last) >= 1000000L / fps)) {
 1111             list->last = curtime;
 1112             list->tmpbuffer = tmpbuffer;
 1113             tmpbuffer->ref++;
 1114             list->filepos = 0;
 1115         }
 1116     }
 1117 
 1118     if (tmpbuffer->ref <= 0) {
 1119         free(tmpbuffer->ptr);
 1120         free(tmpbuffer);
 1121     }
 1122 }
 1123 
 1124 
 1125 /**
 1126  * stream_check_write
 1127  *      We walk through the chain of stream structs until we reach the end.
 1128  *      Here we check if the tmpbuffer points to NULL.
 1129  *      We return 1 if it finds a list->tmpbuffer which is a NULL pointer which would
 1130  *      be the next client ready to be sent a new image. If not a 0 is returned.
 1131  *
 1132  * Returns:
 1133  */
 1134 static int stream_check_write(struct stream *list)
 1135 {
 1136     while (list->next) {
 1137         list = list->next;
 1138 
 1139         if (list->tmpbuffer == NULL)
 1140             return 1;
 1141     }
 1142     return 0;
 1143 }
 1144 
 1145 
 1146 /**
 1147  * stream_init
 1148  *      This function is called from motion.c for each motion thread starting up.
 1149  *      The function setup the incoming tcp socket that the clients connect to.
 1150  *      The function returns an integer representing the socket.
 1151  *
 1152  * Returns: stream socket descriptor.
 1153  */
 1154 int stream_init(struct stream *stm,
 1155                 int port,
 1156                 int localhost,
 1157                 int ipv6_enabled,
 1158                 const char *cors_header)
 1159 {
 1160     stm->socket = http_bindsock(port, localhost, ipv6_enabled);
 1161     stm->next = NULL;
 1162     stm->prev = NULL;
 1163     stm->cors_header = NULL;
 1164 
 1165     if (cors_header != NULL) {
 1166 
 1167         size_t size = strlen(cors_header) + 1;
 1168         stm->cors_header = mymalloc(size);
 1169         if (stm->cors_header == NULL) {
 1170             MOTION_LOG(ERR, TYPE_STREAM, SHOW_ERRNO
 1171                 ,_("Error allocated cors_header in stream_init"));
 1172             return stm->socket;
 1173         }
 1174         memcpy(stm->cors_header, cors_header, size);
 1175 
 1176     }
 1177 
 1178     return stm->socket;
 1179 }
 1180 
 1181 /**
 1182  * stream_stop
 1183  *      This function is called from the motion_loop when it ends
 1184  *      and motion is terminated or restarted.
 1185  */
 1186 void stream_stop(struct stream *stm)
 1187 {
 1188     struct stream *list;
 1189     struct stream *next = stm->next;
 1190 
 1191     /* TODO friendly info which socket is closing */
 1192     MOTION_LOG(NTC, TYPE_STREAM, NO_ERRNO
 1193         ,_("Closing motion-stream listen socket & active motion-stream sockets"));
 1194 
 1195     close(stm->socket);
 1196     stm->socket = -1;
 1197     free(stm->cors_header);
 1198 
 1199     while (next) {
 1200         list = next;
 1201         next = list->next;
 1202 
 1203         if (list->tmpbuffer) {
 1204             free(list->tmpbuffer->ptr);
 1205             free(list->tmpbuffer);
 1206             if (list->cors_header != NULL) free(list->cors_header);
 1207         }
 1208 
 1209         close(list->socket);
 1210         free(list);
 1211     }
 1212 
 1213     MOTION_LOG(NTC, TYPE_STREAM, NO_ERRNO
 1214         ,_("Closed motion-stream listen socket & active motion-stream sockets"));
 1215 }
 1216 
 1217 /*
 1218  * stream_put
 1219  *      Is the starting point of the stream loop. It is called from
 1220  *      the motion_loop with the argument 'image' pointing to the latest frame.
 1221  *      If config option 'stream_motion' is 'on' this function is called once
 1222  *      per second (frame 0) and when Motion is detected excl pre_capture.
 1223  *      If config option 'stream_motion' is 'off' this function is called once
 1224  *      per captured picture frame.
 1225  *      It is always run in setup mode for each picture frame captured and with
 1226  *      the special setup image.
 1227  *      The function does two things:
 1228  *          It looks for possible waiting new clients and adds them.
 1229  *          It sends latest picture frame to all connected clients.
 1230  *      Note: Clients that have disconnected are handled in the stream_flush()
 1231  *          function.
 1232  */
 1233 void stream_put(struct context *cnt, struct stream *stm, int *stream_count, unsigned char *image,
 1234             int do_scale_down)
 1235 {
 1236     struct timeval timeout;
 1237     struct stream_buffer *tmpbuffer;
 1238     fd_set fdread;
 1239     int sl = stm->socket;
 1240     int sc;
 1241     /* Tthe following string has an extra 16 chars at end for length. */
 1242     const char jpeghead[] = "--BoundaryString\r\n"
 1243                             "Content-type: image/jpeg\r\n"
 1244                             "Content-Length:                ";
 1245     int headlength = sizeof(jpeghead) - 1;    /* Don't include terminator. */
 1246     char len[20];    /* Will be used for sprintf, must be >= 16 */
 1247 
 1248     /* will point either to the original image or a scaled down */
 1249     unsigned char *img = image;
 1250     int image_width = cnt->imgs.width;
 1251     int image_height = cnt->imgs.height;
 1252     int image_size = cnt->imgs.size_norm;
 1253     /*
 1254      * Timeout struct used to timeout the time we wait for a client
 1255      * and we do not wait at all.
 1256      */
 1257     timeout.tv_sec = 0;
 1258     timeout.tv_usec = 0;
 1259     FD_ZERO(&fdread);
 1260     FD_SET(stm->socket, &fdread);
 1261 
 1262     /*
 1263      * If we have not reached the max number of allowed clients per
 1264      * thread we will check to see if new clients are waiting to connect.
 1265      * If this is the case we add the client as a new stream struct and
 1266      * add this to the end of the chain of stream structs that are linked
 1267      * to each other.
 1268      */
 1269     if ((*stream_count < DEF_MAXSTREAMS) &&
 1270         (select(sl + 1, &fdread, NULL, NULL, &timeout) > 0)) {
 1271         sc = http_acceptsock(sl);
 1272         if (cnt->conf.stream_auth_method == 0) {
 1273             stream_add_client(stm, sc);
 1274             (*stream_count)++;
 1275         } else  {
 1276             do_client_auth(cnt, stm, stream_count, sc);
 1277         }
 1278     }
 1279 
 1280     /* if there is no connected clients - nothing to do, return */
 1281     if (*stream_count <= 0)
 1282         return;
 1283 
 1284     /* Lock the mutex */
 1285     if (cnt->conf.stream_auth_method != 0)
 1286         pthread_mutex_lock(&stream_auth_mutex);
 1287 
 1288 
 1289     /* Call flush to send any previous partial-sends which are waiting. */
 1290     stream_flush(stm, stream_count, cnt->conf.stream_limit);
 1291 
 1292     /* Check if any clients have available buffers. */
 1293     if (stream_check_write(stm)) {
 1294         /*
 1295          * Yes - create a new tmpbuffer for current image.
 1296          * Note that this should create a buffer which is *much* larger
 1297          * than necessary, but it is difficult to estimate the
 1298          * minimum size actually required.
 1299          */
 1300         tmpbuffer = stream_tmpbuffer(cnt->imgs.size_norm);
 1301 
 1302         /* Check if allocation was ok. */
 1303         if (tmpbuffer) {
 1304             int imgsize;
 1305 
 1306             /*
 1307              * We need a pointer that points to the picture buffer
 1308              * just after the mjpeg header. We create a working pointer wptr
 1309              * to be used in the call to put_picture_memory which we can change
 1310              * and leave tmpbuffer->ptr intact.
 1311              */
 1312             unsigned char *wptr = tmpbuffer->ptr;
 1313 
 1314             /*
 1315              * For web protocol, our image needs to be preceded
 1316              * with a little HTTP, so we put that into the buffer
 1317              * first.
 1318              */
 1319             memcpy(wptr, jpeghead, headlength);
 1320 
 1321             /* Update our working pointer to point past header. */
 1322             wptr += headlength;
 1323 
 1324             /* Create a jpeg image and place into tmpbuffer. */
 1325             tmpbuffer->size = put_picture_memory(cnt, wptr, image_size, img,
 1326                                        cnt->conf.stream_quality, image_width, image_height);
 1327 
 1328             /* Fill in the image length into the header. */
 1329             imgsize = sprintf(len, "%9ld\r\n\r\n", tmpbuffer->size);
 1330             memcpy(wptr - imgsize, len, imgsize);
 1331 
 1332             /* Append a CRLF for good measure. */
 1333             memcpy(wptr + tmpbuffer->size, "\r\n", 2);
 1334 
 1335             /*
 1336              * Now adjust tmpbuffer->size to reflect the
 1337              * header at the beginning and the extra CRLF
 1338              * at the end.
 1339              */
 1340             tmpbuffer->size += headlength + 2;
 1341 
 1342             /*
 1343              * And finally put this buffer to all clients with
 1344              * no outstanding data from previous frames.
 1345              */
 1346             stream_add_write(stm, tmpbuffer, cnt->conf.stream_maxrate);
 1347         } else {
 1348             MOTION_LOG(ERR, TYPE_STREAM, SHOW_ERRNO,_("Error creating tmpbuffer"));
 1349         }
 1350     }
 1351 
 1352     /*
 1353      * Now we call flush again.  This time (assuming some clients were
 1354      * ready for the new frame) the new data will be written out.
 1355      */
 1356     stream_flush(stm, stream_count, cnt->conf.stream_limit);
 1357 
 1358     /* Unlock the mutex */
 1359     if (cnt->conf.stream_auth_method != 0)
 1360         pthread_mutex_unlock(&stream_auth_mutex);
 1361 
 1362     /* free resized image buffer */
 1363     if (do_scale_down)
 1364     {
 1365         free (img);
 1366     }
 1367 
 1368     return;
 1369 }