34102b533df9196a1aac799495a6ea38d2209251
[public/netxms.git] / src / libnetxms / nxproc_unix.cpp
1 /*
2 ** NetXMS - Network Management System
3 ** NetXMS Foundation Library
4 ** Copyright (C) 2003-2017 Victor Kirhenshtein
5 **
6 ** This program is free software; you can redistribute it and/or modify
7 ** it under the terms of the GNU Lesser General Public License as published
8 ** by the Free Software Foundation; either version 3 of the License, or
9 ** (at your option) any later version.
10 **
11 ** This program is distributed in the hope that it will be useful,
12 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 ** GNU General Public License for more details.
15 **
16 ** You should have received a copy of the GNU Lesser General Public License
17 ** along with this program; if not, write to the Free Software
18 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 **
20 ** File: nxproc_unix.cpp
21 **
22 **/
23
24 #include "libnetxms.h"
25 #include <nxproc.h>
26
27 /**
28 * Create listener end for named pipe
29 */
30 NamedPipeListener *NamedPipeListener::create(const TCHAR *name, NamedPipeRequestHandler reqHandler, void *userArg)
31 {
32 mode_t prevMask = 0;
33
34 int s = socket(AF_UNIX, SOCK_STREAM, 0);
35 if (s == INVALID_SOCKET)
36 {
37 nxlog_debug(2, _T("NamedPipeListener(%s): socket() call failed (%s)"), name, _tcserror(errno));
38 return NULL;
39 }
40
41 struct sockaddr_un addrLocal;
42 addrLocal.sun_family = AF_UNIX;
43 #ifdef UNICODE
44 sprintf(addrLocal.sun_path, "/tmp/.%S", name);
45 #else
46 sprintf(addrLocal.sun_path, "/tmp/.%s", name);
47 #endif
48 unlink(addrLocal.sun_path);
49 prevMask = umask(S_IWGRP | S_IWOTH);
50 if (bind(s, (struct sockaddr *)&addrLocal, SUN_LEN(&addrLocal)) == -1)
51 {
52 nxlog_debug(2, _T("NamedPipeListener(%s): bind failed (%s)"), name, _tcserror(errno));
53 umask(prevMask);
54 goto failure;
55 }
56 umask(prevMask);
57
58 if (listen(s, 5) == -1)
59 {
60 nxlog_debug(2, _T("NamedPipeListener(%s): listen() call failed (%s)"), name, _tcserror(errno));
61 goto failure;
62 }
63
64 return new NamedPipeListener(name, s, reqHandler, userArg);
65
66 failure:
67 close(s);
68 unlink(addrLocal.sun_path);
69 return NULL;
70 }
71
72 /**
73 * Pipe destructor
74 */
75 NamedPipeListener::~NamedPipeListener()
76 {
77 close(m_handle);
78 stop();
79 char path[MAX_PATH];
80 #ifdef UNICODE
81 sprintf(path, "/tmp/.%S", m_name);
82 #else
83 sprintf(path, "/tmp/.%s", m_name);
84 #endif
85 unlink(path);
86 }
87
88 /**
89 * Named pipe server thread
90 */
91 void NamedPipeListener::serverThread()
92 {
93 nxlog_debug(2, _T("NamedPipeListener(%s): waiting for connection"), m_name);
94 while(!m_stop)
95 {
96 struct sockaddr_un addrRemote;
97 socklen_t size = sizeof(struct sockaddr_un);
98 SOCKET cs = accept(m_handle, (struct sockaddr *)&addrRemote, &size);
99 if (cs > 0)
100 {
101 NamedPipe *cp = new NamedPipe(m_name, cs);
102 m_reqHandler(cp, m_userArg);
103 delete cp;
104 }
105 else
106 {
107 nxlog_debug(2, _T("NamedPipeListener(%s): accept failed (%s)"), m_name, _tcserror(errno));
108 }
109 }
110 }
111
112 /**
113 * Pipe destructor
114 */
115 NamedPipe::~NamedPipe()
116 {
117 close(m_handle);
118 MutexDestroy(m_writeLock);
119 }
120
121 /**
122 * Create client end for named pipe
123 */
124 NamedPipe *NamedPipe::connect(const TCHAR *name, UINT32 timeout)
125 {
126 int s = socket(AF_UNIX, SOCK_STREAM, 0);
127 if (s == INVALID_SOCKET)
128 {
129 nxlog_debug(2, _T("NamedPipe(%s): socket() call failed (%s)"), name, _tcserror(errno));
130 return NULL;
131 }
132
133 struct sockaddr_un remote;
134 remote.sun_family = AF_UNIX;
135 #ifdef UNICODE
136 sprintf(remote.sun_path, "/tmp/.%S", name);
137 #else
138 sprintf(remote.sun_path, "/tmp/.%s", name);
139 #endif
140 if (::connect(s, (struct sockaddr *)&remote, SUN_LEN(&remote)) == -1)
141 {
142 close(s);
143 return NULL;
144 }
145
146 return new NamedPipe(name, s);
147 }
148
149 /**
150 * Write to pipe
151 */
152 bool NamedPipe::write(const void *data, size_t size)
153 {
154 return SendEx(m_handle, data, size, 0, m_writeLock) == (int)size;
155 }