PageRenderTime 49ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/addons/ofxNetwork/src/ofxTCPClient.cpp

http://github.com/openframeworks/openFrameworks
C++ | 370 lines | 269 code | 44 blank | 57 comment | 66 complexity | b42b091e413a963142312720646bb974 MD5 | raw file
Possible License(s): LGPL-3.0, LGPL-2.1, MPL-2.0-no-copyleft-exception, GPL-2.0, GPL-3.0, BSD-3-Clause
  1. #include "ofxTCPClient.h"
  2. #include "ofAppRunner.h"
  3. #include "ofxNetworkUtils.h"
  4. //--------------------------
  5. ofxTCPClient::ofxTCPClient(){
  6. connected = false;
  7. messageSize = 0;
  8. port = 0;
  9. index = -1;
  10. str = "";
  11. tmpStr = "";
  12. ipAddr ="000.000.000.000";
  13. partialPrevMsg = "";
  14. messageDelimiter = "[/TCP]";
  15. memset(tmpBuff, 0, TCP_MAX_MSG_SIZE+1);
  16. }
  17. //--------------------------
  18. ofxTCPClient::~ofxTCPClient(){
  19. close();
  20. }
  21. //--------------------------
  22. void ofxTCPClient::setVerbose(bool _verbose){
  23. ofLogWarning("ofxTCPClient") << "setVerbose(): is deprecated, replaced by ofLogWarning and ofLogError";
  24. }
  25. //--------------------------
  26. bool ofxTCPClient::setup(string ip, int _port, bool blocking){
  27. ofxTCPSettings settings(ip, _port);
  28. settings.blocking = blocking;
  29. return setup(settings);
  30. }
  31. //--------------------------
  32. bool ofxTCPClient::setup(const ofxTCPSettings & settings){
  33. if( !TCPClient.Create() ){
  34. ofLogError("ofxTCPClient") << "setup(): couldn't create client";
  35. return false;
  36. }else if( !TCPClient.Connect((char *)settings.address.c_str(), settings.port) ){
  37. ofLogError("ofxTCPClient") << "setup(): couldn't connect to " << settings.address << " " << settings.port;
  38. TCPClient.Close(); //we free the connection
  39. return false;
  40. }
  41. TCPClient.SetNonBlocking(!settings.blocking);
  42. setMessageDelimiter(settings.messageDelimiter);
  43. port = settings.port;
  44. ipAddr = settings.address;
  45. connected = true;
  46. return true;
  47. }
  48. //don't use this one
  49. //for server to use internally only!
  50. //--------------------------
  51. bool ofxTCPClient::setupConnectionIdx(int _index, bool blocking){
  52. index = _index;
  53. //this fetches the port that the server
  54. //sets up the connection on
  55. //different to the server's listening port
  56. InetAddr addr;
  57. if( TCPClient.GetRemoteAddr(&addr) ){
  58. port = addr.GetPort();
  59. ipAddr = addr.DottedDecimal();
  60. }
  61. TCPClient.SetNonBlocking(!blocking);
  62. connected = true;
  63. return true;
  64. }
  65. //--------------------------
  66. bool ofxTCPClient::close(){
  67. if( connected ){
  68. if( !TCPClient.Close() ){
  69. ofLogError("ofxTCPClient") << "close(): couldn't close client";
  70. return false;
  71. }else{
  72. ofLogVerbose("ofxTCPClient") << "closing client";
  73. connected = false;
  74. return true;
  75. }
  76. }else{
  77. return true;
  78. }
  79. }
  80. //--------------------------
  81. void ofxTCPClient::setMessageDelimiter(string delim){
  82. if(delim != ""){
  83. messageDelimiter = delim;
  84. }
  85. }
  86. //--------------------------
  87. bool ofxTCPClient::send(string message){
  88. // tcp is a stream oriented protocol
  89. // so there's no way to be sure were
  90. // a message ends without using a terminator
  91. // note that you will receive a trailing [/TCP]\0
  92. // if sending from here and receiving from receiveRaw or
  93. // other applications
  94. if(!connected){
  95. ofLogWarning("ofxTCPClient") << "send(): not connected, call setup() first";
  96. return false;
  97. }
  98. message = partialPrevMsg + message + messageDelimiter;
  99. message += (char)0; //for flash
  100. int ret = TCPClient.SendAll( message.c_str(), message.length() );
  101. int errorCode = 0;
  102. if(ret<0) errorCode = ofxNetworkCheckError();
  103. if( isClosingCondition(ret, errorCode) ){
  104. ofLogWarning("ofxTCPClient") << "send(): client disconnected";
  105. close();
  106. return false;
  107. }else if(ret<0){
  108. ofLogError("ofxTCPClient") << "send(): sending failed";
  109. return false;
  110. }else if(ret<(int)message.length()){
  111. // in case of partial send, store the
  112. // part that hasn't been sent and send
  113. // with the next message to not corrupt
  114. // next messages
  115. partialPrevMsg=message.substr(ret);
  116. return true;
  117. }else{
  118. partialPrevMsg = "";
  119. return true;
  120. }
  121. }
  122. //--------------------------
  123. bool ofxTCPClient::sendRawMsg(const char * msg, int size){
  124. // tcp is a stream oriented protocol
  125. // so there's no way to be sure were
  126. // a message ends without using a terminator
  127. // note that you will receive a trailing [/TCP]\0
  128. // if sending from here and receiving from receiveRaw or
  129. // other applications
  130. if(!connected){
  131. ofLogWarning("ofxTCPClient") << "sendRawMsg(): not connected, call setup() first";
  132. return false;
  133. }
  134. tmpBuffSend.append(msg,size);
  135. tmpBuffSend.append(messageDelimiter.c_str(),messageDelimiter.size());
  136. int ret = TCPClient.SendAll( tmpBuffSend.getData(), tmpBuffSend.size() );
  137. int errorCode = 0;
  138. if(ret<0) errorCode = ofxNetworkCheckError();
  139. if( isClosingCondition(ret, errorCode) ){
  140. ofLogWarning("ofxTCPClient") << "sendRawMsg(): client disconnected";
  141. close();
  142. return false;
  143. }else if(ret<0){
  144. ofLogError("ofxTCPClient") << "sendRawMsg(): sending failed";
  145. return false;
  146. }else if(ret<size){
  147. // in case of partial send, store the
  148. // part that hasn't been sent and send
  149. // with the next message to not corrupt
  150. // next messages
  151. tmpBuffSend.set(&tmpBuffSend.getData()[ret],tmpBuffSend.size()-ret);
  152. return true;
  153. }else{
  154. tmpBuffSend.clear();
  155. return true;
  156. }
  157. }
  158. //--------------------------
  159. bool ofxTCPClient::sendRaw(string message){
  160. if( message.length() == 0) return false;
  161. int ret = TCPClient.SendAll(message.c_str(), message.length());
  162. int errorCode = 0;
  163. if(ret<0) errorCode = ofxNetworkCheckError();
  164. if( isClosingCondition(ret, errorCode) ){
  165. ofLogError("ofxTCPClient") << "sendRawBytes(): sending failed";
  166. close();
  167. return false;
  168. }else{
  169. return ret > 0;
  170. }
  171. }
  172. //--------------------------
  173. bool ofxTCPClient::sendRawBytes(const char* rawBytes, const int numBytes){
  174. if( numBytes <= 0) return false;
  175. int ret = TCPClient.SendAll(rawBytes, numBytes);
  176. int errorCode = 0;
  177. if(ret<0) errorCode = ofxNetworkCheckError();
  178. if( isClosingCondition(ret, errorCode) ){
  179. ofLogError("ofxTCPClient") << "sendRawBytes(): sending failed";
  180. close();
  181. return false;
  182. }else{
  183. return ret > 0;
  184. }
  185. }
  186. //this only works after you have called receive
  187. //--------------------------
  188. int ofxTCPClient::getNumReceivedBytes(){
  189. return messageSize;
  190. }
  191. //--------------------------
  192. static void removeZeros(char * buffer, int size){
  193. for(int i=0;i<size-1;i++){
  194. if(buffer[i]==(char)0){
  195. for(int j=i;j<size-1;j++){
  196. buffer[j]=buffer[j+1];
  197. }
  198. buffer[size-1]=(char)0;
  199. }
  200. }
  201. }
  202. //--------------------------
  203. bool ofxTCPClient::isClosingCondition(int messageSize, int errorCode){
  204. return (messageSize == SOCKET_ERROR && (errorCode == OFXNETWORK_ERROR(CONNRESET) || errorCode == OFXNETWORK_ERROR(CONNABORTED) || errorCode == OFXNETWORK_ERROR(CONNREFUSED) || errorCode == EPIPE || errorCode == OFXNETWORK_ERROR(NOTCONN)))
  205. || (messageSize == 0 && !TCPClient.IsNonBlocking() && TCPClient.GetTimeoutReceive()!=NO_TIMEOUT);
  206. }
  207. //--------------------------
  208. string ofxTCPClient::receive(){
  209. str = "";
  210. int length=0;
  211. //only get data from the buffer if we don't have already some complete message
  212. if(tmpStr.find(messageDelimiter)==string::npos){
  213. memset(tmpBuff, 0, TCP_MAX_MSG_SIZE+1); //one more so there's always a \0 at the end for string concat
  214. length = TCPClient.Receive(tmpBuff, TCP_MAX_MSG_SIZE);
  215. if(length>0){ // don't copy the data if there was an error or disconnection
  216. removeZeros(tmpBuff,length);
  217. tmpStr += tmpBuff;
  218. }
  219. }
  220. // check for connection reset or disconnection
  221. int errorCode = 0;
  222. if(length<0) errorCode = ofxNetworkCheckError();
  223. if(isClosingCondition(length,errorCode)){
  224. close();
  225. if(tmpStr.length()==0) // return if there's no more data left in the buffer
  226. return "";
  227. }
  228. // process any available data
  229. if(tmpStr.find(messageDelimiter)!=string::npos){
  230. str=tmpStr.substr(0,tmpStr.find(messageDelimiter));
  231. tmpStr=tmpStr.substr(tmpStr.find(messageDelimiter)+messageDelimiter.size());
  232. }
  233. return str;
  234. }
  235. //--------------------------
  236. static int findDelimiter(char * data, int size, string delimiter){
  237. unsigned int posInDelimiter=0;
  238. for(int i=0;i<size;i++){
  239. if(data[i]==delimiter[posInDelimiter]){
  240. posInDelimiter++;
  241. if(posInDelimiter==delimiter.size()) return i-delimiter.size()+1;
  242. }else{
  243. posInDelimiter=0;
  244. }
  245. }
  246. return -1;
  247. }
  248. //--------------------------
  249. int ofxTCPClient::receiveRawMsg(char * receiveBuffer, int numBytes){
  250. int length=-2;
  251. //only get data from the buffer if we don't have already some complete message
  252. if(findDelimiter(tmpBuffReceive.getData(),tmpBuffReceive.size(),messageDelimiter)==-1){
  253. memset(tmpBuff, 0, TCP_MAX_MSG_SIZE);
  254. length = receiveRawBytes(tmpBuff, TCP_MAX_MSG_SIZE);
  255. if(length>0){ // don't copy the data if there was an error or disconnection
  256. tmpBuffReceive.append(tmpBuff,length);
  257. }
  258. }
  259. // process any available data
  260. int posDelimiter = findDelimiter(tmpBuffReceive.getData(),tmpBuffReceive.size(),messageDelimiter);
  261. if(posDelimiter>0){
  262. memcpy(receiveBuffer,tmpBuffReceive.getData(),posDelimiter);
  263. if(tmpBuffReceive.size() > posDelimiter + (int)messageDelimiter.size()){
  264. memcpy(tmpBuff,tmpBuffReceive.getData()+posDelimiter+messageDelimiter.size(),tmpBuffReceive.size()-(posDelimiter+messageDelimiter.size()));
  265. tmpBuffReceive.set(tmpBuff,tmpBuffReceive.size()-(posDelimiter+messageDelimiter.size()));
  266. }else{
  267. tmpBuffReceive.clear();
  268. }
  269. }
  270. if(posDelimiter>0){
  271. return posDelimiter;
  272. }else{
  273. return 0;
  274. }
  275. }
  276. //--------------------------
  277. int ofxTCPClient::receiveRawBytes(char * receiveBuffer, int numBytes){
  278. messageSize = TCPClient.Receive(receiveBuffer, numBytes);
  279. int errorCode = 0;
  280. if(messageSize<0) errorCode = ofxNetworkCheckError();
  281. // 0 is not an error... -1 is
  282. if(isClosingCondition(messageSize, errorCode)){
  283. close();
  284. }
  285. return messageSize;
  286. }
  287. //--------------------------
  288. int ofxTCPClient::peekReceiveRawBytes(char * receiveBuffer, int numBytes){
  289. messageSize = TCPClient.PeekReceive(receiveBuffer, numBytes);
  290. int errorCode = 0;
  291. if(messageSize<0) errorCode = ofxNetworkCheckError();
  292. if(isClosingCondition(messageSize, errorCode)){
  293. close();
  294. }
  295. return messageSize;
  296. }
  297. //--------------------------
  298. string ofxTCPClient::receiveRaw(){
  299. messageSize = TCPClient.Receive(tmpBuff, TCP_MAX_MSG_SIZE);
  300. int errorCode = 0;
  301. if(messageSize<0) errorCode = ofxNetworkCheckError();
  302. if(isClosingCondition(messageSize, errorCode)){
  303. close();
  304. }else if(messageSize>=0 && messageSize<TCP_MAX_MSG_SIZE) {
  305. // null terminate!!
  306. tmpBuff[messageSize] = 0;
  307. }
  308. return tmpBuff;
  309. }
  310. //--------------------------
  311. bool ofxTCPClient::isConnected(){
  312. if (connected) {
  313. if (!TCPClient.CheckIsConnected()) {
  314. close();
  315. }
  316. }
  317. return connected;
  318. }
  319. //--------------------------
  320. int ofxTCPClient::getPort(){
  321. return port;
  322. }
  323. //--------------------------
  324. string ofxTCPClient::getIP(){
  325. return ipAddr;
  326. }