Add remaining files
[juce-lv2.git] / juce / source / src / native / linux / juce_linux_Network.cpp
blobe7358912670bcccf021e68d3a0b2814145090780
1 /*
2 ==============================================================================
4 This file is part of the JUCE library - "Jules' Utility Class Extensions"
5 Copyright 2004-11 by Raw Material Software Ltd.
7 ------------------------------------------------------------------------------
9 JUCE can be redistributed and/or modified under the terms of the GNU General
10 Public License (Version 2), as published by the Free Software Foundation.
11 A copy of the license is included in the JUCE distribution, or can be found
12 online at www.gnu.org/licenses.
14 JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
18 ------------------------------------------------------------------------------
20 To release a closed-source product which uses JUCE, commercial licenses are
21 available: visit www.rawmaterialsoftware.com/juce for more information.
23 ==============================================================================
26 // (This file gets included by juce_linux_NativeCode.cpp, rather than being
27 // compiled on its own).
28 #if JUCE_INCLUDED_FILE
31 //==============================================================================
32 void MACAddress::findAllAddresses (Array<MACAddress>& result)
34 const int s = socket (AF_INET, SOCK_DGRAM, 0);
35 if (s != -1)
37 char buf [1024];
38 struct ifconf ifc;
39 ifc.ifc_len = sizeof (buf);
40 ifc.ifc_buf = buf;
41 ioctl (s, SIOCGIFCONF, &ifc);
43 for (unsigned int i = 0; i < ifc.ifc_len / sizeof (struct ifreq); ++i)
45 struct ifreq ifr;
46 strcpy (ifr.ifr_name, ifc.ifc_req[i].ifr_name);
48 if (ioctl (s, SIOCGIFFLAGS, &ifr) == 0
49 && (ifr.ifr_flags & IFF_LOOPBACK) == 0
50 && ioctl (s, SIOCGIFHWADDR, &ifr) == 0)
52 result.addIfNotAlreadyThere (MACAddress ((const uint8*) ifr.ifr_hwaddr.sa_data));
56 close (s);
61 bool PlatformUtilities::launchEmailWithAttachments (const String& targetEmailAddress,
62 const String& emailSubject,
63 const String& bodyText,
64 const StringArray& filesToAttach)
66 jassertfalse; // xxx todo
68 return false;
72 //==============================================================================
73 class WebInputStream : public InputStream
75 public:
76 //==============================================================================
77 WebInputStream (const String& address_, bool isPost_, const MemoryBlock& postData_,
78 URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext,
79 const String& headers_, int timeOutMs_, StringPairArray* responseHeaders)
80 : socketHandle (-1), levelsOfRedirection (0),
81 address (address_), headers (headers_), postData (postData_), position (0),
82 finished (false), isPost (isPost_), timeOutMs (timeOutMs_)
84 createConnection (progressCallback, progressCallbackContext);
86 if (responseHeaders != nullptr && ! isError())
88 for (int i = 0; i < headerLines.size(); ++i)
90 const String& headersEntry = headerLines[i];
91 const String key (headersEntry.upToFirstOccurrenceOf (": ", false, false));
92 const String value (headersEntry.fromFirstOccurrenceOf (": ", false, false));
93 const String previousValue ((*responseHeaders) [key]);
94 responseHeaders->set (key, previousValue.isEmpty() ? value : (previousValue + "," + value));
99 ~WebInputStream()
101 closeSocket();
104 //==============================================================================
105 bool isError() const { return socketHandle < 0; }
106 bool isExhausted() { return finished; }
107 int64 getPosition() { return position; }
109 int64 getTotalLength()
111 jassertfalse; //xxx to do
112 return -1;
115 int read (void* buffer, int bytesToRead)
117 if (finished || isError())
118 return 0;
120 fd_set readbits;
121 FD_ZERO (&readbits);
122 FD_SET (socketHandle, &readbits);
124 struct timeval tv;
125 tv.tv_sec = jmax (1, timeOutMs / 1000);
126 tv.tv_usec = 0;
128 if (select (socketHandle + 1, &readbits, 0, 0, &tv) <= 0)
129 return 0; // (timeout)
131 const int bytesRead = jmax (0, (int) recv (socketHandle, buffer, bytesToRead, MSG_WAITALL));
132 if (bytesRead == 0)
133 finished = true;
134 position += bytesRead;
135 return bytesRead;
138 bool setPosition (int64 wantedPos)
140 if (isError())
141 return false;
143 if (wantedPos != position)
145 finished = false;
147 if (wantedPos < position)
149 closeSocket();
150 position = 0;
151 createConnection (0, 0);
154 skipNextBytes (wantedPos - position);
157 return true;
160 //==============================================================================
161 private:
162 int socketHandle, levelsOfRedirection;
163 StringArray headerLines;
164 String address, headers;
165 MemoryBlock postData;
166 int64 position;
167 bool finished;
168 const bool isPost;
169 const int timeOutMs;
171 void closeSocket()
173 if (socketHandle >= 0)
174 close (socketHandle);
176 socketHandle = -1;
177 levelsOfRedirection = 0;
180 void createConnection (URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext)
182 closeSocket();
184 uint32 timeOutTime = Time::getMillisecondCounter();
186 if (timeOutMs == 0)
187 timeOutTime += 60000;
188 else if (timeOutMs < 0)
189 timeOutTime = 0xffffffff;
190 else
191 timeOutTime += timeOutMs;
193 String hostName, hostPath;
194 int hostPort;
195 if (! decomposeURL (address, hostName, hostPath, hostPort))
196 return;
198 String serverName, proxyName, proxyPath;
199 int proxyPort = 0;
200 int port = 0;
202 const String proxyURL (getenv ("http_proxy"));
203 if (proxyURL.startsWithIgnoreCase ("http://"))
205 if (! decomposeURL (proxyURL, proxyName, proxyPath, proxyPort))
206 return;
208 serverName = proxyName;
209 port = proxyPort;
211 else
213 serverName = hostName;
214 port = hostPort;
217 struct addrinfo hints = { 0 };
218 hints.ai_family = AF_UNSPEC;
219 hints.ai_socktype = SOCK_STREAM;
220 hints.ai_flags = AI_NUMERICSERV;
222 struct addrinfo* result = nullptr;
223 if (getaddrinfo (serverName.toUTF8(), String (port).toUTF8(), &hints, &result) != 0 || result == 0)
224 return;
226 socketHandle = socket (result->ai_family, result->ai_socktype, 0);
228 if (socketHandle == -1)
230 freeaddrinfo (result);
231 return;
234 int receiveBufferSize = 16384;
235 setsockopt (socketHandle, SOL_SOCKET, SO_RCVBUF, (char*) &receiveBufferSize, sizeof (receiveBufferSize));
236 setsockopt (socketHandle, SOL_SOCKET, SO_KEEPALIVE, 0, 0);
238 #if JUCE_MAC
239 setsockopt (socketHandle, SOL_SOCKET, SO_NOSIGPIPE, 0, 0);
240 #endif
242 if (connect (socketHandle, result->ai_addr, result->ai_addrlen) == -1)
244 closeSocket();
245 freeaddrinfo (result);
246 return;
249 freeaddrinfo (result);
252 const MemoryBlock requestHeader (createRequestHeader (hostName, hostPort, proxyName, proxyPort,
253 hostPath, address, headers, postData, isPost));
255 if (! sendHeader (socketHandle, requestHeader, timeOutTime, progressCallback, progressCallbackContext))
257 closeSocket();
258 return;
262 String responseHeader (readResponse (socketHandle, timeOutTime));
264 if (responseHeader.isNotEmpty())
266 headerLines.clear();
267 headerLines.addLines (responseHeader);
269 const int statusCode = responseHeader.fromFirstOccurrenceOf (" ", false, false)
270 .substring (0, 3).getIntValue();
272 //int contentLength = findHeaderItem (lines, "Content-Length:").getIntValue();
273 //bool isChunked = findHeaderItem (lines, "Transfer-Encoding:").equalsIgnoreCase ("chunked");
275 String location (findHeaderItem (headerLines, "Location:"));
277 if (statusCode >= 300 && statusCode < 400 && location.isNotEmpty())
279 if (! location.startsWithIgnoreCase ("http://"))
280 location = "http://" + location;
282 if (++levelsOfRedirection <= 3)
284 address = location;
285 createConnection (progressCallback, progressCallbackContext);
286 return;
289 else
291 levelsOfRedirection = 0;
292 return;
296 closeSocket();
299 //==============================================================================
300 static String readResponse (const int socketHandle, const uint32 timeOutTime)
302 int bytesRead = 0, numConsecutiveLFs = 0;
303 MemoryBlock buffer (1024, true);
305 while (numConsecutiveLFs < 2 && bytesRead < 32768
306 && Time::getMillisecondCounter() <= timeOutTime)
308 fd_set readbits;
309 FD_ZERO (&readbits);
310 FD_SET (socketHandle, &readbits);
312 struct timeval tv;
313 tv.tv_sec = jmax (1, (int) (timeOutTime - Time::getMillisecondCounter()) / 1000);
314 tv.tv_usec = 0;
316 if (select (socketHandle + 1, &readbits, 0, 0, &tv) <= 0)
317 return String::empty; // (timeout)
319 buffer.ensureSize (bytesRead + 8, true);
320 char* const dest = (char*) buffer.getData() + bytesRead;
322 if (recv (socketHandle, dest, 1, 0) == -1)
323 return String::empty;
325 const char lastByte = *dest;
326 ++bytesRead;
328 if (lastByte == '\n')
329 ++numConsecutiveLFs;
330 else if (lastByte != '\r')
331 numConsecutiveLFs = 0;
334 const String header (CharPointer_UTF8 ((const char*) buffer.getData()));
336 if (header.startsWithIgnoreCase ("HTTP/"))
337 return header.trimEnd();
339 return String::empty;
342 static MemoryBlock createRequestHeader (const String& hostName, const int hostPort,
343 const String& proxyName, const int proxyPort,
344 const String& hostPath, const String& originalURL,
345 const String& headers, const MemoryBlock& postData,
346 const bool isPost)
348 String header (isPost ? "POST " : "GET ");
350 if (proxyName.isEmpty())
352 header << hostPath << " HTTP/1.0\r\nHost: "
353 << hostName << ':' << hostPort;
355 else
357 header << originalURL << " HTTP/1.0\r\nHost: "
358 << proxyName << ':' << proxyPort;
361 header << "\r\nUser-Agent: JUCE/" << JUCE_MAJOR_VERSION << '.' << JUCE_MINOR_VERSION
362 << "\r\nConnection: Close\r\nContent-Length: "
363 << (int) postData.getSize() << "\r\n"
364 << headers << "\r\n";
366 MemoryBlock mb;
367 mb.append (header.toUTF8(), (int) strlen (header.toUTF8()));
368 mb.append (postData.getData(), postData.getSize());
370 return mb;
373 static bool sendHeader (int socketHandle, const MemoryBlock& requestHeader, const uint32 timeOutTime,
374 URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext)
376 size_t totalHeaderSent = 0;
378 while (totalHeaderSent < requestHeader.getSize())
380 if (Time::getMillisecondCounter() > timeOutTime)
381 return false;
383 const int numToSend = jmin (1024, (int) (requestHeader.getSize() - totalHeaderSent));
385 if (send (socketHandle, static_cast <const char*> (requestHeader.getData()) + totalHeaderSent, numToSend, 0) != numToSend)
386 return false;
388 totalHeaderSent += numToSend;
390 if (progressCallback != nullptr && ! progressCallback (progressCallbackContext, totalHeaderSent, requestHeader.getSize()))
391 return false;
394 return true;
397 static bool decomposeURL (const String& url, String& host, String& path, int& port)
399 if (! url.startsWithIgnoreCase ("http://"))
400 return false;
402 const int nextSlash = url.indexOfChar (7, '/');
403 int nextColon = url.indexOfChar (7, ':');
404 if (nextColon > nextSlash && nextSlash > 0)
405 nextColon = -1;
407 if (nextColon >= 0)
409 host = url.substring (7, nextColon);
411 if (nextSlash >= 0)
412 port = url.substring (nextColon + 1, nextSlash).getIntValue();
413 else
414 port = url.substring (nextColon + 1).getIntValue();
416 else
418 port = 80;
420 if (nextSlash >= 0)
421 host = url.substring (7, nextSlash);
422 else
423 host = url.substring (7);
426 if (nextSlash >= 0)
427 path = url.substring (nextSlash);
428 else
429 path = "/";
431 return true;
434 static String findHeaderItem (const StringArray& lines, const String& itemName)
436 for (int i = 0; i < lines.size(); ++i)
437 if (lines[i].startsWithIgnoreCase (itemName))
438 return lines[i].substring (itemName.length()).trim();
440 return String::empty;
443 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WebInputStream);
446 InputStream* URL::createNativeStream (const String& address, bool isPost, const MemoryBlock& postData,
447 OpenStreamProgressCallback* progressCallback, void* progressCallbackContext,
448 const String& headers, const int timeOutMs, StringPairArray* responseHeaders)
450 ScopedPointer <WebInputStream> wi (new WebInputStream (address, isPost, postData,
451 progressCallback, progressCallbackContext,
452 headers, timeOutMs, responseHeaders));
454 return wi->isError() ? nullptr : wi.release();
458 #endif