tools: added unistd.h to brawchannel_unix.cc for gcc 4.7+
[barry.git] / tools / brawchannel_unix.cc
blob8f972b660cf62d0b457fa7f7391f456676dc7a7d
1 ///
2 /// \file brawchannel_unix.cc
3 /// Implements OS support for STDIN/STDOUT and TCP
4 ///
6 /*
7 Copyright (C) 2010-2012, RealVNC Ltd.
9 Some parts are inspired from bjavaloader.cc
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
20 See the GNU General Public License in the COPYING file at the
21 root directory of this project for more details.
24 #include "brawchannel.h"
25 #include "i18n.h"
26 #include <barry/barry.h>
28 #include <stdio.h>
29 #include <errno.h>
30 #include <iostream>
31 #include <netdb.h>
32 #include <sys/types.h>
33 #include <sys/socket.h>
34 #include <sys/select.h>
35 #include <netinet/in.h>
36 #include <netinet/tcp.h>
37 #include <arpa/inet.h>
38 #include <fcntl.h>
39 #include <string>
40 #include <unistd.h>
42 #define SD_SEND SHUT_WR
43 #define INVALID_SOCKET -1
44 #define INVALID_HANDLE -1
46 using namespace std;
47 using namespace Barry;
49 struct TcpStreamImpl
51 in_addr mHostAddress;
52 std::string mListenAddress;
53 long mPort;
54 int mListenSocket;
55 int mSocket;
59 ssize_t StdOutStream::write(const unsigned char* ptr, size_t size)
61 size_t written = ::write(STDOUT_FILENO, ptr, size);
62 if( written == 0 &&
63 ( ferror(stdout) != 0 || feof(stdout) != 0 ) ) {
64 return -1;
66 return static_cast<ssize_t>(written);
69 ssize_t StdInStream::read(unsigned char* ptr, size_t size, int timeout)
71 fd_set rfds;
72 struct timeval tv;
73 FD_ZERO(&rfds);
74 FD_SET(STDIN_FILENO, &rfds);
75 tv.tv_sec = READ_TIMEOUT_SECONDS;
76 tv.tv_usec = 0;
77 int ret = select(STDIN_FILENO + 1, &rfds, NULL, NULL, &tv);
78 if( ret < 0 ) {
79 cerr << _("Select failed with errno: ") << errno << endl;
80 return -1;
81 } else if ( ret && FD_ISSET(STDIN_FILENO, &rfds) ) {
82 return ::read(STDIN_FILENO, ptr, size);
83 } else {
84 return 0;
88 TcpStream::TcpStream(const std::string& addr, long port)
90 mImpl.reset(new TcpStreamImpl);
91 mImpl->mListenAddress = addr;
92 mImpl->mPort = port;
93 mImpl->mSocket = INVALID_SOCKET;
94 mImpl->mListenSocket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
95 if( mImpl->mListenSocket == INVALID_SOCKET ) {
96 cerr << _("Failed to create listening socket: ") <<
97 errno << endl;
99 if( mImpl->mListenAddress.length() == 0 ) {
100 mImpl->mHostAddress.s_addr = INADDR_ANY;
101 mImpl->mListenAddress = "*";
102 } else {
103 mImpl->mHostAddress.s_addr = inet_addr(mImpl->mListenAddress.c_str());
107 TcpStream::~TcpStream()
109 if( mImpl->mSocket != INVALID_SOCKET ) {
110 shutdown(mImpl->mSocket, SD_SEND);
111 close(mImpl->mSocket);
112 mImpl->mSocket = INVALID_SOCKET;
114 if( mImpl->mListenSocket != INVALID_SOCKET ) {
115 shutdown(mImpl->mListenSocket, SD_SEND);
116 close(mImpl->mListenSocket);
117 mImpl->mListenSocket = INVALID_SOCKET;
121 bool TcpStream::accept()
123 if( mImpl->mListenSocket == INVALID_SOCKET ||
124 mImpl->mHostAddress.s_addr == INADDR_NONE ) {
125 return false;
127 struct sockaddr_in serverAddr;
128 memset(&serverAddr, 0, sizeof(serverAddr));
129 serverAddr.sin_family = AF_INET;
130 serverAddr.sin_addr = mImpl->mHostAddress;
131 serverAddr.sin_port = htons(static_cast<u_short>(mImpl->mPort));
132 if( ::bind(mImpl->mListenSocket, (sockaddr*) & serverAddr, sizeof(serverAddr)) < 0 ) {
133 cerr << _("Failed to bind to listening address") << endl;
134 return false;
137 // Set the socket options
138 int one = 1;
139 if( setsockopt(mImpl->mListenSocket, SOL_SOCKET, SO_REUSEADDR,
140 reinterpret_cast<const char *> (&one), sizeof(one)) < 0 ) {
141 cerr << _("Failed to enable reuse of address") << endl;
142 return false;
145 if( ::listen(mImpl->mListenSocket, 5) == INVALID_SOCKET ) {
146 cerr << _("Failed to listen to listening address") << endl;
147 return false;
150 struct sockaddr_in clientAddr;
151 socklen_t len = sizeof(clientAddr);
152 cout << string_vprintf(_("Listening for connection on %s:%ld"),
153 mImpl->mListenAddress.c_str(),
154 mImpl->mPort) << endl;
156 mImpl->mSocket = ::accept(mImpl->mListenSocket, (struct sockaddr*) &clientAddr, &len);
157 shutdown(mImpl->mListenSocket, SD_SEND);
158 close(mImpl->mListenSocket);
159 mImpl->mListenSocket = INVALID_SOCKET;
160 if( mImpl->mSocket == INVALID_SOCKET ) {
161 cerr << _("Failed to accept on listening socket") << endl;
162 return false;
165 if( setsockopt(mImpl->mSocket, IPPROTO_TCP, TCP_NODELAY,
166 reinterpret_cast<const char *> (&one), sizeof(one)) < 0 ) {
167 cerr << _("Failed to set no delay") << endl;
168 return false;
171 if( fcntl(mImpl->mSocket, F_SETFL,
172 fcntl(mImpl->mSocket, F_GETFL, 0) | O_NONBLOCK) < 0 ) {
173 cerr << _("Failed to set non-blocking on socket") << endl;
174 return false;
177 return true;
180 ssize_t TcpInStream::read(unsigned char* ptr, size_t size, int timeout)
182 fd_set rfds;
183 struct timeval tv;
184 FD_ZERO(&rfds);
185 FD_SET(mStream.mImpl->mSocket, &rfds);
186 tv.tv_sec = READ_TIMEOUT_SECONDS;
187 tv.tv_usec = 0;
188 int ret = select(mStream.mImpl->mSocket + 1, &rfds, NULL, NULL, &tv);
189 if( ret < 0 ) {
190 cerr << _("Select failed with errno: ") << errno << endl;
191 return -1;
192 } else if ( ret && FD_ISSET(mStream.mImpl->mSocket, &rfds) ) {
193 return ::recv(mStream.mImpl->mSocket, reinterpret_cast<char *>(ptr), size, 0);
194 } else {
195 return 0;
199 ssize_t TcpOutStream::write(const unsigned char* ptr, size_t size)
201 return ::send(mStream.mImpl->mSocket, reinterpret_cast<const char*>(ptr), size, 0);