2013-03-17 07:45:21 +08:00
|
|
|
//
|
|
|
|
// ZoneMinder Stream Class Implementation, $Date$, $Revision$
|
|
|
|
// Copyright (C) 2001-2008 Philip Coombes
|
|
|
|
//
|
|
|
|
// This program is free software; you can redistribute it and/or
|
|
|
|
// modify it under the terms of the GNU General Public License
|
|
|
|
// as published by the Free Software Foundation; either version 2
|
|
|
|
// of the License, or (at your option) any later version.
|
|
|
|
//
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
|
|
// along with this program; if not, write to the Free Software
|
2016-12-26 23:23:16 +08:00
|
|
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
2013-03-17 07:45:21 +08:00
|
|
|
//
|
|
|
|
|
2021-02-04 11:47:28 +08:00
|
|
|
#include "zm_stream.h"
|
2013-03-17 07:45:21 +08:00
|
|
|
|
2021-02-04 11:47:28 +08:00
|
|
|
#include "zm_box.h"
|
2013-03-17 07:45:21 +08:00
|
|
|
#include "zm_monitor.h"
|
2021-03-04 06:48:02 +08:00
|
|
|
#include <cmath>
|
2021-02-04 11:47:28 +08:00
|
|
|
#include <sys/file.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <sys/stat.h>
|
2021-03-04 06:48:02 +08:00
|
|
|
#include <unistd.h>
|
2013-03-17 07:45:21 +08:00
|
|
|
|
2017-06-26 21:46:07 +08:00
|
|
|
StreamBase::~StreamBase() {
|
2013-09-27 19:08:11 +08:00
|
|
|
#if HAVE_LIBAVCODEC
|
2017-06-26 21:46:07 +08:00
|
|
|
if ( vid_stream ) {
|
2018-08-06 22:34:08 +08:00
|
|
|
delete vid_stream;
|
2020-08-26 07:45:48 +08:00
|
|
|
vid_stream = nullptr;
|
2016-04-04 22:11:48 +08:00
|
|
|
}
|
2013-09-27 19:08:11 +08:00
|
|
|
#endif
|
2016-04-04 22:11:48 +08:00
|
|
|
closeComms();
|
2013-03-17 07:45:21 +08:00
|
|
|
}
|
|
|
|
|
2020-09-03 04:36:05 +08:00
|
|
|
bool StreamBase::loadMonitor(int p_monitor_id) {
|
|
|
|
monitor_id = p_monitor_id;
|
|
|
|
|
2021-03-17 01:28:00 +08:00
|
|
|
if ( !(monitor or (monitor = Monitor::Load(monitor_id, false, Monitor::QUERY))) ) {
|
2018-04-13 01:14:00 +08:00
|
|
|
Error("Unable to load monitor id %d for streaming", monitor_id);
|
|
|
|
return false;
|
2016-04-04 22:11:48 +08:00
|
|
|
}
|
2020-11-25 22:53:06 +08:00
|
|
|
|
2020-03-10 01:14:09 +08:00
|
|
|
if ( monitor->GetFunction() == Monitor::NONE ) {
|
2020-11-25 22:53:06 +08:00
|
|
|
Info("Monitor %d has function NONE. Will not be able to connect to it.", monitor_id);
|
2020-03-10 01:14:09 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( !monitor->connect() ) {
|
2018-04-13 01:14:00 +08:00
|
|
|
Error("Unable to connect to monitor id %d for streaming", monitor_id);
|
2021-03-17 01:28:00 +08:00
|
|
|
monitor->disconnect();
|
2018-04-13 01:14:00 +08:00
|
|
|
return false;
|
2017-10-25 07:22:26 +08:00
|
|
|
}
|
2018-04-13 01:14:00 +08:00
|
|
|
|
|
|
|
return true;
|
2013-03-17 07:45:21 +08:00
|
|
|
}
|
|
|
|
|
2017-06-26 21:46:07 +08:00
|
|
|
bool StreamBase::checkInitialised() {
|
|
|
|
if ( !monitor ) {
|
2020-09-03 04:36:05 +08:00
|
|
|
Error("Cannot stream, not initialised");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if ( monitor->GetFunction() == Monitor::NONE ) {
|
2020-11-25 22:53:06 +08:00
|
|
|
Info("Monitor %d has function NONE. Will not be able to connect to it.", monitor_id);
|
2020-09-03 04:36:05 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if ( !monitor->ShmValid() ) {
|
|
|
|
Error("Monitor shm is not connected");
|
2018-04-13 01:14:00 +08:00
|
|
|
return false;
|
2016-04-04 22:11:48 +08:00
|
|
|
}
|
2018-04-13 01:14:00 +08:00
|
|
|
return true;
|
2013-03-17 07:45:21 +08:00
|
|
|
}
|
|
|
|
|
2018-04-13 01:14:00 +08:00
|
|
|
void StreamBase::updateFrameRate(double fps) {
|
2016-04-04 22:11:48 +08:00
|
|
|
frame_mod = 1;
|
2021-02-06 01:30:51 +08:00
|
|
|
if ( (fps < 0) || !fps || std::isinf(fps) ) {
|
2019-02-27 00:43:07 +08:00
|
|
|
Debug(1, "Zero or negative fps %f in updateFrameRate. Setting frame_mod=1 and effective_fps=0.0", fps);
|
2019-01-22 02:30:00 +08:00
|
|
|
effective_fps = 0.0;
|
2019-02-27 00:43:07 +08:00
|
|
|
base_fps = 0.0;
|
2019-01-22 02:30:00 +08:00
|
|
|
return;
|
|
|
|
}
|
2016-04-04 22:11:48 +08:00
|
|
|
base_fps = fps;
|
|
|
|
effective_fps = (base_fps*abs(replay_rate))/ZM_RATE_BASE;
|
|
|
|
frame_mod = 1;
|
2018-12-05 07:23:08 +08:00
|
|
|
Debug(3, "FPS:%.2f, MaxFPS:%.2f, BaseFPS:%.2f, EffectiveFPS:%.2f, FrameMod:%d, replay_rate(%d)",
|
|
|
|
fps, maxfps, base_fps, effective_fps, frame_mod, replay_rate);
|
2016-04-04 22:11:48 +08:00
|
|
|
// Min frame repeat?
|
2019-03-06 22:46:28 +08:00
|
|
|
// We want to keep the frame skip easy... problem is ... if effective = 31 and max = 30 then we end up with 15.5 fps.
|
2019-01-15 03:00:45 +08:00
|
|
|
while ( effective_fps > maxfps ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
effective_fps /= 2.0;
|
|
|
|
frame_mod *= 2;
|
2019-03-07 00:10:01 +08:00
|
|
|
Debug(3, "Changing fps to be < max %.2f EffectiveFPS:%.2f, FrameMod:%d",
|
|
|
|
maxfps, effective_fps, frame_mod);
|
2017-11-28 22:50:09 +08:00
|
|
|
}
|
2019-03-06 22:46:28 +08:00
|
|
|
} // void StreamBase::updateFrameRate(double fps)
|
2013-03-17 07:45:21 +08:00
|
|
|
|
2017-06-26 21:46:07 +08:00
|
|
|
bool StreamBase::checkCommandQueue() {
|
|
|
|
if ( sd >= 0 ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
CmdMsg msg;
|
2018-04-13 01:14:00 +08:00
|
|
|
memset(&msg, 0, sizeof(msg));
|
|
|
|
int nbytes = recvfrom(sd, &msg, sizeof(msg), MSG_DONTWAIT, 0, 0);
|
2017-06-26 21:46:07 +08:00
|
|
|
if ( nbytes < 0 ) {
|
|
|
|
if ( errno != EAGAIN ) {
|
2018-04-13 01:14:00 +08:00
|
|
|
Error("recvfrom(), errno = %d, error = %s", errno, strerror(errno));
|
|
|
|
return false;
|
2016-04-04 22:11:48 +08:00
|
|
|
}
|
2013-03-17 07:45:21 +08:00
|
|
|
}
|
2016-04-04 22:11:48 +08:00
|
|
|
//else if ( (nbytes != sizeof(msg)) )
|
|
|
|
//{
|
|
|
|
//Error( "Partial message received, expected %d bytes, got %d", sizeof(msg), nbytes );
|
|
|
|
//}
|
2017-06-26 21:46:07 +08:00
|
|
|
else {
|
2018-04-13 01:14:00 +08:00
|
|
|
Debug(2, "Message length is (%d)", nbytes);
|
|
|
|
processCommand(&msg);
|
|
|
|
return true;
|
2016-04-04 22:11:48 +08:00
|
|
|
}
|
2020-11-21 05:31:12 +08:00
|
|
|
} else if ( connkey ) {
|
2017-10-20 04:08:20 +08:00
|
|
|
Warning("No sd in checkCommandQueue, comms not open?");
|
2020-11-21 05:31:12 +08:00
|
|
|
} else {
|
|
|
|
// Perfectly valid if only getting a snapshot
|
|
|
|
Debug(1, "No sd in checkCommandQueue, comms not open?");
|
2016-04-04 22:11:48 +08:00
|
|
|
}
|
2018-04-13 01:14:00 +08:00
|
|
|
return false;
|
2020-11-21 05:31:12 +08:00
|
|
|
} // end bool StreamBase::checkCommandQueue()
|
2013-03-17 07:45:21 +08:00
|
|
|
|
2020-04-27 06:19:30 +08:00
|
|
|
Image *StreamBase::prepareImage(Image *image) {
|
2013-03-17 07:45:21 +08:00
|
|
|
|
2016-04-04 22:11:48 +08:00
|
|
|
// Do not bother to scale zoomed in images, just crop them and let the browser scale
|
|
|
|
// Works in FF2 but breaks FF3 which doesn't like image sizes changing in mid stream.
|
|
|
|
bool optimisedScaling = false;
|
2013-03-17 07:45:21 +08:00
|
|
|
|
2016-04-04 22:11:48 +08:00
|
|
|
bool image_copied = false;
|
2013-03-17 07:45:21 +08:00
|
|
|
|
2016-04-04 22:11:48 +08:00
|
|
|
int mag = (scale * zoom) / ZM_SCALE_BASE;
|
|
|
|
int act_mag = optimisedScaling?(mag > ZM_SCALE_BASE?ZM_SCALE_BASE:mag):mag;
|
2013-03-17 07:45:21 +08:00
|
|
|
|
2016-04-04 22:11:48 +08:00
|
|
|
int last_mag = (last_scale * last_zoom) / ZM_SCALE_BASE;
|
|
|
|
int last_act_mag = last_mag > ZM_SCALE_BASE?ZM_SCALE_BASE:last_mag;
|
|
|
|
int base_image_width = image->Width(), base_image_height = image->Height();
|
|
|
|
int virt_image_width = (base_image_width * mag) / ZM_SCALE_BASE, virt_image_height = (base_image_height * mag) / ZM_SCALE_BASE;
|
|
|
|
int last_virt_image_width = (base_image_width * last_mag) / ZM_SCALE_BASE, last_virt_image_height = (base_image_height * last_mag) / ZM_SCALE_BASE;
|
|
|
|
int act_image_width = (base_image_width * act_mag ) / ZM_SCALE_BASE, act_image_height = (base_image_height * act_mag ) / ZM_SCALE_BASE;
|
|
|
|
int last_act_image_width = (base_image_width * last_act_mag ) / ZM_SCALE_BASE, last_act_image_height = (base_image_height * last_act_mag ) / ZM_SCALE_BASE;
|
|
|
|
int disp_image_width = (image->Width() * scale) / ZM_SCALE_BASE, disp_image_height = (image->Height() * scale) / ZM_SCALE_BASE;
|
|
|
|
int last_disp_image_width = (image->Width() * last_scale) / ZM_SCALE_BASE, last_disp_image_height = (image->Height() * last_scale) / ZM_SCALE_BASE;
|
|
|
|
int send_image_width = (disp_image_width * act_mag ) / mag, send_image_height = (disp_image_height * act_mag ) / mag;
|
|
|
|
int last_send_image_width = (last_disp_image_width * last_act_mag ) / last_mag, last_send_image_height = (last_disp_image_height * last_act_mag ) / last_mag;
|
2020-04-27 06:19:30 +08:00
|
|
|
|
|
|
|
Debug(3,
|
|
|
|
"Scaling by %d, zooming by %d = magnifying by %d(%d)\n"
|
|
|
|
"Last scaling by %d, zooming by %d = magnifying by %d(%d)\n"
|
|
|
|
"Base image width = %d, height = %d\n"
|
|
|
|
"Virtual image width = %d, height = %d\n"
|
|
|
|
"Last virtual image width = %d, height = %d\n"
|
|
|
|
"Actual image width = %d, height = %d\n"
|
|
|
|
"Last actual image width = %d, height = %d\n"
|
|
|
|
"Display image width = %d, height = %d\n"
|
|
|
|
"Last display image width = %d, height = %d\n"
|
|
|
|
"Send image width = %d, height = %d\n"
|
|
|
|
"Last send image width = %d, height = %d\n",
|
|
|
|
scale, zoom, mag, act_mag,
|
|
|
|
last_scale, last_zoom, last_mag, last_act_mag,
|
|
|
|
base_image_width, base_image_height,
|
|
|
|
virt_image_width, virt_image_height,
|
|
|
|
last_virt_image_width, last_virt_image_height,
|
|
|
|
act_image_width, act_image_height,
|
|
|
|
last_act_image_width, last_act_image_height,
|
|
|
|
disp_image_width, disp_image_height,
|
|
|
|
last_disp_image_width, last_disp_image_height,
|
|
|
|
send_image_width, send_image_height,
|
|
|
|
last_send_image_width, last_send_image_height
|
|
|
|
);
|
|
|
|
|
|
|
|
if ( ( mag != ZM_SCALE_BASE ) && (act_mag != ZM_SCALE_BASE) ) {
|
|
|
|
Debug(3, "Magnifying by %d", mag);
|
|
|
|
static Image copy_image;
|
|
|
|
copy_image.Assign(*image);
|
|
|
|
image = ©_image;
|
|
|
|
image_copied = true;
|
|
|
|
image->Scale(mag);
|
2016-04-04 22:11:48 +08:00
|
|
|
}
|
|
|
|
|
2018-04-13 01:14:00 +08:00
|
|
|
Debug(3, "Real image width = %d, height = %d", image->Width(), image->Height());
|
2013-03-17 07:45:21 +08:00
|
|
|
|
2017-06-26 21:46:07 +08:00
|
|
|
if ( disp_image_width < virt_image_width || disp_image_height < virt_image_height ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
static Box last_crop;
|
2013-03-17 07:45:21 +08:00
|
|
|
|
2017-06-26 21:46:07 +08:00
|
|
|
if ( mag != last_mag || x != last_x || y != last_y ) {
|
2020-04-27 06:19:30 +08:00
|
|
|
Debug(3, "Got click at %d,%d x %d", x, y, mag);
|
2016-04-04 22:11:48 +08:00
|
|
|
|
|
|
|
if ( !(last_disp_image_width < last_virt_image_width || last_disp_image_height < last_virt_image_height) )
|
|
|
|
last_crop = Box();
|
|
|
|
|
|
|
|
// Recalculate crop parameters, as %ges
|
|
|
|
int click_x = (last_crop.LoX() * 100 ) / last_act_image_width; // Initial crop offset from last image
|
|
|
|
click_x += ( x * 100 ) / last_virt_image_width;
|
|
|
|
int click_y = (last_crop.LoY() * 100 ) / last_act_image_height; // Initial crop offset from last image
|
|
|
|
click_y += ( y * 100 ) / last_virt_image_height;
|
2020-04-27 06:19:30 +08:00
|
|
|
Debug(3, "Got adjusted click at %d%%,%d%%", click_x, click_y);
|
2016-04-04 22:11:48 +08:00
|
|
|
|
|
|
|
// Convert the click locations to the current image pixels
|
|
|
|
click_x = ( click_x * act_image_width ) / 100;
|
|
|
|
click_y = ( click_y * act_image_height ) / 100;
|
2020-04-27 06:19:30 +08:00
|
|
|
Debug(3, "Got readjusted click at %d,%d", click_x, click_y);
|
2016-04-04 22:11:48 +08:00
|
|
|
|
|
|
|
int lo_x = click_x - (send_image_width/2);
|
|
|
|
if ( lo_x < 0 )
|
|
|
|
lo_x = 0;
|
|
|
|
int hi_x = lo_x + (send_image_width-1);
|
2017-06-26 21:46:07 +08:00
|
|
|
if ( hi_x >= act_image_width ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
hi_x = act_image_width - 1;
|
|
|
|
lo_x = hi_x - (send_image_width - 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
int lo_y = click_y - (send_image_height/2);
|
2017-06-26 21:46:07 +08:00
|
|
|
if ( lo_y < 0 ) lo_y = 0;
|
2016-04-04 22:11:48 +08:00
|
|
|
int hi_y = lo_y + (send_image_height-1);
|
2017-06-26 21:46:07 +08:00
|
|
|
if ( hi_y >= act_image_height ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
hi_y = act_image_height - 1;
|
|
|
|
lo_y = hi_y - (send_image_height - 1);
|
|
|
|
}
|
|
|
|
last_crop = Box( lo_x, lo_y, hi_x, hi_y );
|
2020-04-27 06:19:30 +08:00
|
|
|
} // end if ( mag != last_mag || x != last_x || y != last_y )
|
|
|
|
|
|
|
|
Debug(3, "Cropping to %d,%d -> %d,%d", last_crop.LoX(), last_crop.LoY(), last_crop.HiX(), last_crop.HiY());
|
2017-06-26 21:46:07 +08:00
|
|
|
if ( !image_copied ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
static Image copy_image;
|
2020-04-27 06:19:30 +08:00
|
|
|
copy_image.Assign(*image);
|
2016-04-04 22:11:48 +08:00
|
|
|
image = ©_image;
|
|
|
|
image_copied = true;
|
|
|
|
}
|
2020-04-27 06:19:30 +08:00
|
|
|
image->Crop(last_crop);
|
|
|
|
} // end if difference in image vs displayed dimensions
|
|
|
|
|
2016-04-04 22:11:48 +08:00
|
|
|
last_scale = scale;
|
|
|
|
last_zoom = zoom;
|
|
|
|
last_x = x;
|
|
|
|
last_y = y;
|
|
|
|
|
2018-04-13 01:14:00 +08:00
|
|
|
return image;
|
2020-04-27 06:19:30 +08:00
|
|
|
} // end Image *StreamBase::prepareImage(Image *image)
|
2013-03-17 07:45:21 +08:00
|
|
|
|
2019-07-27 00:21:25 +08:00
|
|
|
bool StreamBase::sendTextFrame(const char *frame_text) {
|
|
|
|
Debug(2, "Sending %dx%d * %d text frame '%s'",
|
|
|
|
monitor->Width(), monitor->Height(), scale, frame_text);
|
2013-03-17 07:45:21 +08:00
|
|
|
|
2018-04-13 01:14:00 +08:00
|
|
|
Image image(monitor->Width(), monitor->Height(), monitor->Colours(), monitor->SubpixelOrder());
|
2020-10-06 01:16:22 +08:00
|
|
|
image.Clear();
|
|
|
|
image.Annotate(frame_text, image.centreCoord(frame_text, monitor->LabelSize()), monitor->LabelSize());
|
2013-03-17 07:45:21 +08:00
|
|
|
|
2017-06-26 21:46:07 +08:00
|
|
|
if ( scale != 100 ) {
|
2018-04-13 01:14:00 +08:00
|
|
|
image.Scale(scale);
|
2016-04-04 22:11:48 +08:00
|
|
|
}
|
2013-03-17 07:45:21 +08:00
|
|
|
#if HAVE_LIBAVCODEC
|
2017-06-26 21:46:07 +08:00
|
|
|
if ( type == STREAM_MPEG ) {
|
|
|
|
if ( !vid_stream ) {
|
2018-04-13 01:14:00 +08:00
|
|
|
vid_stream = new VideoStream("pipe:", format, bitrate, effective_fps, image.Colours(), image.SubpixelOrder(), image.Width(), image.Height());
|
|
|
|
fprintf(stdout, "Content-type: %s\r\n\r\n", vid_stream->MimeType());
|
2016-04-04 22:11:48 +08:00
|
|
|
vid_stream->OpenStream();
|
2013-03-17 07:45:21 +08:00
|
|
|
}
|
2020-09-03 04:36:05 +08:00
|
|
|
/* double pts = */ vid_stream->EncodeFrame(image.Buffer(), image.Size());
|
2017-06-26 21:46:07 +08:00
|
|
|
} else
|
2013-03-17 07:45:21 +08:00
|
|
|
#endif // HAVE_LIBAVCODEC
|
2016-04-04 22:11:48 +08:00
|
|
|
{
|
|
|
|
static unsigned char buffer[ZM_MAX_IMAGE_SIZE];
|
|
|
|
int n_bytes = 0;
|
|
|
|
|
2018-04-13 01:14:00 +08:00
|
|
|
image.EncodeJpeg(buffer, &n_bytes);
|
2016-04-04 22:11:48 +08:00
|
|
|
|
2020-09-03 04:36:05 +08:00
|
|
|
fputs("--" BOUNDARY "\r\nContent-Type: image/jpeg\r\n", stdout);
|
2019-07-27 00:21:25 +08:00
|
|
|
fprintf(stdout, "Content-Length: %d\r\n\r\n", n_bytes);
|
2018-04-13 01:14:00 +08:00
|
|
|
if ( fwrite(buffer, n_bytes, 1, stdout) != 1 ) {
|
|
|
|
Error("Unable to send stream text frame: %s", strerror(errno));
|
|
|
|
return false;
|
2013-03-17 07:45:21 +08:00
|
|
|
}
|
2020-09-03 04:36:05 +08:00
|
|
|
fputs("\r\n\r\n", stdout);
|
2018-04-13 01:14:00 +08:00
|
|
|
fflush(stdout);
|
2016-04-04 22:11:48 +08:00
|
|
|
}
|
2018-04-13 01:14:00 +08:00
|
|
|
last_frame_sent = TV_2_FLOAT(now);
|
|
|
|
return true;
|
2013-03-17 07:45:21 +08:00
|
|
|
}
|
|
|
|
|
2017-06-26 21:46:07 +08:00
|
|
|
void StreamBase::openComms() {
|
|
|
|
if ( connkey > 0 ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
|
2018-08-10 23:15:15 +08:00
|
|
|
// Have to mkdir because systemd is now chrooting and the dir may not exist
|
|
|
|
if ( mkdir(staticConfig.PATH_SOCKS.c_str(), 0755) ) {
|
|
|
|
if ( errno != EEXIST ) {
|
|
|
|
Error("Can't mkdir ZM_PATH_SOCKS %s: %s.", staticConfig.PATH_SOCKS.c_str(), strerror(errno));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-14 03:22:00 +08:00
|
|
|
unsigned int length = snprintf(
|
2018-08-10 23:15:15 +08:00
|
|
|
sock_path_lock,
|
|
|
|
sizeof(sock_path_lock),
|
|
|
|
"%s/zms-%06d.lock",
|
|
|
|
staticConfig.PATH_SOCKS.c_str(),
|
|
|
|
connkey
|
|
|
|
);
|
2016-05-03 00:39:55 +08:00
|
|
|
if ( length >= sizeof(sock_path_lock) ) {
|
|
|
|
Warning("Socket lock path was truncated.");
|
|
|
|
}
|
2018-04-13 01:14:00 +08:00
|
|
|
Debug(1, "Trying to open the lock on %s", sock_path_lock);
|
2015-12-05 04:39:37 +08:00
|
|
|
|
2018-10-29 03:09:32 +08:00
|
|
|
// Under systemd, we get chrooted to something like /tmp/systemd-apache-blh/ so the dir may not exist.
|
|
|
|
if ( mkdir(staticConfig.PATH_SOCKS.c_str(), 0755) ) {
|
2018-08-06 22:34:08 +08:00
|
|
|
if ( errno != EEXIST ) {
|
2018-10-29 03:09:32 +08:00
|
|
|
Error("Can't mkdir %s: %s", staticConfig.PATH_SOCKS.c_str(), strerror(errno));
|
2018-08-06 22:34:08 +08:00
|
|
|
return;
|
2018-11-02 22:57:47 +08:00
|
|
|
} else {
|
|
|
|
Debug(3, "SOCKS dir %s already exists", staticConfig.PATH_SOCKS.c_str() );
|
2018-08-06 22:34:08 +08:00
|
|
|
}
|
2018-10-29 03:09:32 +08:00
|
|
|
} else {
|
2018-11-02 22:57:47 +08:00
|
|
|
Debug(3, "Success making SOCKS dir %s", staticConfig.PATH_SOCKS.c_str() );
|
2018-08-06 22:34:08 +08:00
|
|
|
}
|
|
|
|
|
2016-05-03 00:39:55 +08:00
|
|
|
lock_fd = open(sock_path_lock, O_CREAT|O_WRONLY, S_IRUSR | S_IWUSR);
|
2017-06-26 21:46:07 +08:00
|
|
|
if ( lock_fd <= 0 ) {
|
2018-08-10 23:15:15 +08:00
|
|
|
Error("Unable to open sock lock file %s: %s", sock_path_lock, strerror(errno));
|
2016-05-03 00:39:55 +08:00
|
|
|
lock_fd = 0;
|
2018-11-14 03:22:00 +08:00
|
|
|
} else if ( flock(lock_fd, LOCK_EX) != 0 ) {
|
2018-08-10 23:15:15 +08:00
|
|
|
Error("Unable to lock sock lock file %s: %s", sock_path_lock, strerror(errno));
|
2016-05-03 00:39:55 +08:00
|
|
|
close(lock_fd);
|
|
|
|
lock_fd = 0;
|
2017-06-26 21:46:07 +08:00
|
|
|
} else {
|
2018-08-10 23:15:15 +08:00
|
|
|
Debug(1, "We have obtained a lock on %s fd: %d", sock_path_lock, lock_fd);
|
2016-05-03 00:39:55 +08:00
|
|
|
}
|
|
|
|
|
2018-04-13 01:14:00 +08:00
|
|
|
sd = socket(AF_UNIX, SOCK_DGRAM, 0);
|
2017-06-26 21:46:07 +08:00
|
|
|
if ( sd < 0 ) {
|
2018-04-13 01:14:00 +08:00
|
|
|
Fatal("Can't create socket: %s", strerror(errno));
|
2018-08-06 22:34:08 +08:00
|
|
|
} else {
|
2018-10-29 03:09:32 +08:00
|
|
|
Debug(3, "Have socket %d", sd);
|
2016-05-03 00:39:55 +08:00
|
|
|
}
|
|
|
|
|
2018-08-10 23:15:15 +08:00
|
|
|
length = snprintf(
|
|
|
|
loc_sock_path,
|
|
|
|
sizeof(loc_sock_path),
|
|
|
|
"%s/zms-%06ds.sock",
|
|
|
|
staticConfig.PATH_SOCKS.c_str(),
|
|
|
|
connkey
|
|
|
|
);
|
2016-05-03 00:39:55 +08:00
|
|
|
if ( length >= sizeof(loc_sock_path) ) {
|
|
|
|
Warning("Socket path was truncated.");
|
|
|
|
length = sizeof(loc_sock_path)-1;
|
|
|
|
}
|
2017-11-23 00:43:13 +08:00
|
|
|
// Unlink before bind, in case it already exists
|
2018-04-13 01:14:00 +08:00
|
|
|
unlink(loc_sock_path);
|
2016-05-03 00:39:55 +08:00
|
|
|
if ( sizeof(loc_addr.sun_path) < length ) {
|
2018-04-13 01:14:00 +08:00
|
|
|
Error("Not enough space %d in loc_addr.sun_path for socket file %s", sizeof(loc_addr.sun_path), loc_sock_path);
|
2016-05-03 00:39:55 +08:00
|
|
|
}
|
|
|
|
|
2018-04-13 01:14:00 +08:00
|
|
|
strncpy(loc_addr.sun_path, loc_sock_path, sizeof(loc_addr.sun_path));
|
2016-04-04 22:11:48 +08:00
|
|
|
loc_addr.sun_family = AF_UNIX;
|
2018-10-29 03:09:32 +08:00
|
|
|
Debug(3, "Binding to %s", loc_sock_path);
|
2018-11-08 00:54:18 +08:00
|
|
|
if ( ::bind(sd, (struct sockaddr *)&loc_addr, strlen(loc_addr.sun_path)+sizeof(loc_addr.sun_family)+1) < 0 ) {
|
2018-04-13 01:14:00 +08:00
|
|
|
Fatal("Can't bind: %s", strerror(errno));
|
2013-03-17 07:45:21 +08:00
|
|
|
}
|
2016-04-04 22:11:48 +08:00
|
|
|
|
2018-04-13 01:14:00 +08:00
|
|
|
snprintf(rem_sock_path, sizeof(rem_sock_path), "%s/zms-%06dw.sock", staticConfig.PATH_SOCKS.c_str(), connkey);
|
2020-04-25 06:03:00 +08:00
|
|
|
strncpy(rem_addr.sun_path, rem_sock_path, sizeof(rem_addr.sun_path));
|
2016-04-04 22:11:48 +08:00
|
|
|
rem_addr.sun_family = AF_UNIX;
|
2018-09-22 03:58:14 +08:00
|
|
|
|
2020-08-26 07:45:48 +08:00
|
|
|
gettimeofday(&last_comm_update, nullptr);
|
2016-05-03 00:39:55 +08:00
|
|
|
} // end if connKey > 0
|
2019-03-18 22:55:08 +08:00
|
|
|
Debug(3, "comms open at %s", loc_sock_path);
|
2017-11-22 12:57:34 +08:00
|
|
|
} // end void StreamBase::openComms()
|
2013-03-17 07:45:21 +08:00
|
|
|
|
2017-06-26 21:46:07 +08:00
|
|
|
void StreamBase::closeComms() {
|
|
|
|
if ( connkey > 0 ) {
|
|
|
|
if ( sd >= 0 ) {
|
2018-04-13 01:14:00 +08:00
|
|
|
close(sd);
|
2016-04-04 22:11:48 +08:00
|
|
|
sd = -1;
|
|
|
|
}
|
2017-06-26 21:46:07 +08:00
|
|
|
if ( loc_sock_path[0] ) {
|
2018-04-13 01:14:00 +08:00
|
|
|
unlink(loc_sock_path);
|
2016-04-04 22:11:48 +08:00
|
|
|
}
|
2017-11-23 00:43:13 +08:00
|
|
|
if ( lock_fd > 0 ) {
|
2016-04-04 22:11:48 +08:00
|
|
|
close(lock_fd); //close it rather than unlock it incase it got deleted.
|
2017-11-23 00:43:13 +08:00
|
|
|
// You cannot unlink the lockfile. You have to leave a mess around. SUCKS
|
|
|
|
//unlink(sock_path_lock);
|
2013-03-17 07:45:21 +08:00
|
|
|
}
|
2016-04-04 22:11:48 +08:00
|
|
|
}
|
2018-04-13 01:14:00 +08:00
|
|
|
} // end void StreamBase::closeComms
|