1 /*
2 Copyright (C) 2004-2008 Grame
3 
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as published by
6 the Free Software Foundation; either version 2.1 of the License, or
7 (at your option) any later version.
8 
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 GNU Lesser General Public License for more details.
13 
14 You should have received a copy of the GNU Lesser General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 
18 */
19 
20 #include "JackFifo.h"
21 #include "JackTools.h"
22 #include "JackError.h"
23 #include "JackPlatformPlug.h"
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <unistd.h>
27 #include <fcntl.h>
28 #include <stdio.h>
29 
30 namespace Jack
31 {
32 
BuildName(const char * client_name,const char * server_name,char * res,int size)33 void JackFifo::BuildName(const char* client_name, const char* server_name, char* res, int size)
34 {
35     char ext_client_name[SYNC_MAX_NAME_SIZE + 1];
36     JackTools::RewriteName(client_name, ext_client_name);
37     sprintf(res, "%s/jack_fifo.%d_%s_%s", jack_client_dir, JackTools::GetUID(), server_name, ext_client_name);
38 }
39 
Signal()40 bool JackFifo::Signal()
41 {
42     bool res;
43     char c = 0;
44 
45     if (fFifo < 0) {
46         jack_error("JackFifo::Signal name = %s already deallocated!!", fName);
47         return false;
48     }
49 
50     if (fFlush)
51         return true;
52 
53     if ((res = (write(fFifo, &c, sizeof(c)) != sizeof(c)))) {
54         jack_error("JackFifo::Signal name = %s err = %s", fName, strerror(errno));
55     }
56     return !res;
57 }
58 
SignalAll()59 bool JackFifo::SignalAll()
60 {
61     bool res;
62     char c = 0;
63 
64     if (fFifo < 0) {
65         jack_error("JackFifo::SignalAll name = %s already deallocated!!", fName);
66         return false;
67     }
68 
69     if (fFlush)
70         return true;
71 
72     if ((res = (write(fFifo, &c, sizeof(c)) != sizeof(c)))) {
73         jack_error("JackFifo::SignalAll name = %s err = %s", fName, strerror(errno));
74     }
75     return !res;
76 }
77 
Wait()78 bool JackFifo::Wait()
79 {
80     bool res;
81     char c;
82 
83     if (fFifo < 0) {
84         jack_error("JackFifo::Wait name = %s already deallocated!!", fName);
85         return false;
86     }
87 
88     if ((res = (read(fFifo, &c, sizeof(c)) != sizeof(c)))) {
89         jack_error("JackFifo::Wait name = %s err = %s", fName, strerror(errno));
90     }
91     return !res;
92 }
93 
94 #ifdef __APPLE__
95 #warning JackFifo::TimedWait not available : synchronous mode may not work correctly if FIFO are used
TimedWait(long usec)96 bool JackFifo::TimedWait(long usec)
97 {
98     return Wait();
99 }
100 #else
101 // Does not work on OSX ??
TimedWait(long usec)102 bool JackFifo::TimedWait(long usec)
103 {
104     int res;
105 
106     if (fFifo < 0) {
107         jack_error("JackFifo::TimedWait name = %s already deallocated!!", fName);
108         return false;
109     }
110 
111     do {
112         res = poll(&fPoll, 1, usec / 1000);
113     } while (res < 0 && errno == EINTR);
114 
115     if (fPoll.revents & POLLIN) {
116         return Wait();
117     } else {
118         // Wait failure but we still continue...
119         jack_log("JackFifo::TimedWait name = %s usec = %ld err = %s", fName, usec, strerror(errno));
120         return true;
121     }
122 }
123 #endif
124 
125 // Server side
Allocate(const char * name,const char * server_name,int value)126 bool JackFifo::Allocate(const char* name, const char* server_name, int value)
127 {
128     struct stat statbuf;
129     BuildName(name, server_name, fName, sizeof(fName));
130     jack_log("JackFifo::Allocate name = %s", fName);
131 
132     if (stat(fName, &statbuf) < 0) {
133         if (errno == ENOENT || errno == EPERM) {
134             if (mkfifo(fName, 0666) < 0) {
135                 jack_error("Cannot create inter-client FIFO name = %s err = %s", fName, strerror(errno));
136                 return false;
137             }
138         } else {
139             jack_error("Cannot check on FIFO %s", name);
140             return false;
141         }
142     } else {
143         if (!S_ISFIFO(statbuf.st_mode)) {
144             jack_error("FIFO name = %s already exists, but is not a FIFO", name);
145             return false;
146         }
147     }
148 
149     if ((fFifo = open(fName, O_RDWR | O_CREAT, 0666)) < 0) {
150         jack_error("Cannot open FIFO name = %s err = %s", name, strerror(errno));
151         return false;
152     } else {
153         fPoll.fd = fFifo;
154         fPoll.events = POLLERR | POLLIN | POLLHUP | POLLNVAL;
155         return true;
156     }
157 }
158 
159 // Client side
ConnectAux(const char * name,const char * server_name,int access)160 bool JackFifo::ConnectAux(const char* name, const char* server_name, int access)
161 {
162     BuildName(name, server_name, fName, sizeof(fName));
163     jack_log("JackFifo::ConnectAux name = %s", fName);
164 
165     // Temporary...
166     if (fFifo >= 0) {
167         jack_log("Already connected name = %s", name);
168         return true;
169     }
170 
171     if ((fFifo = open(fName, access)) < 0) {
172         jack_error("Connect: can't connect named fifo name = %s err = %s", fName, strerror(errno));
173         return false;
174     } else {
175         fPoll.fd = fFifo;
176         fPoll.events = POLLERR | POLLIN | POLLHUP | POLLNVAL;
177         return true;
178     }
179 }
180 
Connect(const char * name,const char * server_name)181 bool JackFifo::Connect(const char* name, const char* server_name)
182 {
183     return ConnectAux(name, server_name, O_RDWR);
184 }
185 
ConnectOutput(const char * name,const char * server_name)186 bool JackFifo::ConnectOutput(const char* name, const char* server_name)
187 {
188     return ConnectAux(name, server_name, O_WRONLY | O_NONBLOCK);
189 }
190 
ConnectInput(const char * name,const char * server_name)191 bool JackFifo::ConnectInput(const char* name, const char* server_name)
192 {
193     return ConnectAux(name, server_name, O_RDONLY);
194 }
195 
Disconnect()196 bool JackFifo::Disconnect()
197 {
198     if (fFifo >= 0) {
199         jack_log("JackFifo::Disconnect %s", fName);
200         if (close(fFifo) != 0) {
201             jack_error("Disconnect: can't disconnect named fifo name = %s err = %s", fName, strerror(errno));
202             return false;
203         } else {
204             fFifo = -1;
205             return true;
206         }
207     } else {
208         return true;
209     }
210 }
211 
212 // Server side : destroy the fifo
Destroy()213 void JackFifo::Destroy()
214 {
215     if (fFifo > 0) {
216         jack_log("JackFifo::Destroy name = %s", fName);
217         unlink(fName);
218         if (close(fFifo) != 0) {
219             jack_error("Destroy: can't destroy fifo name = %s err = %s", fName, strerror(errno));
220         }
221         fFifo = -1;
222     } else {
223         jack_error("JackFifo::Destroy fifo < 0");
224     }
225 }
226 
227 } // end of namespace
228 
229