socket.cpp 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487
  1. #include "socket.h"
  2. #include "../../async/native/async.h"
  3. #include "../../fiber/native/fiber.h"
  4. #if _WIN32
  5. #include <Ws2tcpip.h>
  6. typedef int socklen_t;
  7. #else
  8. #include <netdb.h>
  9. #include <unistd.h>
  10. #include <sys/socket.h>
  11. #include <sys/ioctl.h>
  12. #include <arpa/inet.h>
  13. #include <netinet/tcp.h>
  14. #define closesocket close
  15. #define ioctlsocket ioctl
  16. #endif
  17. namespace bbSocket{
  18. struct Future : public bbAsync::Event{
  19. int fiber;
  20. int result=-1;
  21. Future():fiber( bbFiber::getCurrentFiber() ){}
  22. void dispatch(){
  23. bbFiber::resumeFiber( fiber );
  24. }
  25. void set( int result ){
  26. this->result=result;
  27. post();
  28. }
  29. int get(){
  30. bbFiber::suspendCurrentFiber();
  31. return result;
  32. }
  33. };
  34. void init(){
  35. static bool done;
  36. if( done ) return;
  37. done=true;
  38. #if _WIN32
  39. WSADATA wsa;
  40. WSAStartup( MAKEWORD(2,2),&wsa );
  41. #endif
  42. }
  43. void dontBlock( int sock ){
  44. //make non-blocking
  45. u_long cmd=1;
  46. ioctlsocket( sock,FIONBIO,&cmd );
  47. }
  48. bool wouldBlock(){
  49. #if _WIN32
  50. return WSAGetLastError()==WSAEWOULDBLOCK;
  51. #else
  52. return errno==EAGAIN || errno==EWOULDBLOCK;
  53. #endif
  54. }
  55. int _connect( const char *hostname,const char *service ){
  56. init();
  57. addrinfo hints;
  58. memset( &hints,0,sizeof( hints ) );
  59. hints.ai_family=AF_UNSPEC;
  60. hints.ai_socktype=SOCK_STREAM;
  61. addrinfo *res=0;
  62. if( getaddrinfo( hostname,service,&hints,&res ) ) return -1;
  63. addrinfo *pres=res;
  64. int sock=-1;
  65. while( res ){
  66. sock=socket( res->ai_family,res->ai_socktype,res->ai_protocol );
  67. if( sock>=0 ){
  68. if( !connect( sock,res->ai_addr,res->ai_addrlen ) ) break;
  69. ::closesocket( sock );
  70. sock=-1;
  71. }
  72. res=res->ai_next;
  73. }
  74. freeaddrinfo( pres );
  75. if( sock<0 ) return -1;
  76. return sock;
  77. }
  78. int _listen( const char *service,int queue ){
  79. init();
  80. addrinfo hints;
  81. memset( &hints,0,sizeof( hints ) );
  82. hints.ai_family=AF_UNSPEC;
  83. hints.ai_socktype=SOCK_STREAM;
  84. hints.ai_flags=AI_PASSIVE;
  85. addrinfo *res=0;
  86. if( getaddrinfo( 0,service,&hints,&res ) ) return -1;
  87. addrinfo *pres=res;
  88. int sock=-1;
  89. while( res ){
  90. sock=socket( res->ai_family,res->ai_socktype,res->ai_protocol );
  91. if( sock>=0 ){
  92. if( !bind( sock,res->ai_addr,res->ai_addrlen ) ) break;
  93. ::closesocket( sock );
  94. sock=-1;
  95. }
  96. res=res->ai_next;
  97. }
  98. freeaddrinfo( pres );
  99. if( sock<0 ) return -1;
  100. // So server ports can be quickly reused...
  101. //
  102. #if __APPLE__ || __linux
  103. int flag=1;
  104. setsockopt( sock,SOL_SOCKET,SO_REUSEADDR,&flag,sizeof(flag) );
  105. #endif
  106. ::listen( sock,queue );
  107. return sock;
  108. }
  109. int connect( bbString hostname,bbString service ){
  110. if( hostname.length()>1023 || service.length()>79 ) return -1;
  111. char _hostname[1024];
  112. char _service[80];
  113. strcpy( _hostname,hostname.c_str() );
  114. strcpy( _service,service.c_str() );
  115. int result=-1;
  116. if( bbFiber::getCurrentFiber() ){
  117. Future future;
  118. std::thread thread( [=,&future](){
  119. future.set( _connect( _hostname,_service ) );
  120. } );
  121. result=future.get();
  122. thread.join();
  123. }else{
  124. result=_connect( _hostname,_service );
  125. }
  126. return result;
  127. }
  128. int listen( bbString service,int queue ){
  129. if( service.length()>79 ) return -1;
  130. char _service[80];
  131. strcpy( _service,service.c_str() );
  132. int result=-1;
  133. if( bbFiber::getCurrentFiber() ){
  134. Future future;
  135. std::thread thread( [=,&future](){
  136. future.set( _listen( _service,queue ) );
  137. } );
  138. result=future.get();
  139. thread.join();
  140. }else{
  141. result=_listen( _service,queue);
  142. }
  143. return result;
  144. }
  145. int accept( int socket ){
  146. sockaddr_storage clientaddr;
  147. socklen_t addrlen=sizeof( clientaddr );
  148. int newsock=-1;
  149. if( bbFiber::getCurrentFiber() ){
  150. Future future;
  151. std::thread thread( [&,socket](){
  152. future.set( ::accept( socket,(sockaddr*)&clientaddr,&addrlen ) );
  153. } );
  154. newsock=future.get();
  155. thread.join();
  156. }else{
  157. newsock=::accept( socket,(struct sockaddr*)&clientaddr,&addrlen );
  158. }
  159. return newsock;
  160. }
  161. void close( int socket ){
  162. if( bbFiber::getCurrentFiber() ){
  163. Future future;
  164. std::thread thread( [=,&future](){
  165. future.set( ::closesocket( socket ) );
  166. } );
  167. future.get();
  168. thread.join();
  169. }else{
  170. ::closesocket( socket );
  171. }
  172. }
  173. int send( int socket,void *data,int size ){
  174. int sent=0;
  175. while( size>0 ){
  176. int n=-1;
  177. if( bbFiber::getCurrentFiber() ){
  178. Future future;
  179. std::thread thread( [=,&future](){
  180. future.set( ::send( socket,(const char*)data,size,0 ) );
  181. } );
  182. n=future.get();
  183. thread.join();
  184. }else{
  185. n=::send( socket,(const char*)data,size,0 );
  186. }
  187. if( !n ) return sent;
  188. if( n<0 ){
  189. printf( "socket_send error!\n" );fflush( stdout );
  190. return sent;
  191. }
  192. data=(char*)data+n;
  193. size-=n;
  194. sent+=n;
  195. }
  196. return sent;
  197. }
  198. int recv( int socket,void *data,int size ){
  199. int n=-1;
  200. if( bbFiber::getCurrentFiber() ){
  201. Future future;
  202. std::thread thread( [=,&future](){
  203. future.set( ::recv( socket,(char*)data,size,0 ) );
  204. } );
  205. n=future.get();
  206. thread.join();
  207. }else{
  208. n=::recv( socket,(char*)data,size,0 );
  209. }
  210. if( !n ) return 0;
  211. if( n<0 ){
  212. printf( "socket_recv error!\n" );fflush( stdout );
  213. return 0;
  214. }
  215. return n;
  216. }
  217. void setopt( int socket,bbString name,int value ){
  218. if( name=="TCP_NODELAY" ){
  219. setsockopt( socket,IPPROTO_TCP,TCP_NODELAY,(const char*)&value,sizeof(value) );
  220. }
  221. }
  222. int getopt( int socket,bbString name ){
  223. int value=-1;
  224. socklen_t optlen=sizeof(value);
  225. if( name=="TCP_NODELAY" ){
  226. getsockopt( socket,IPPROTO_TCP,TCP_NODELAY,(char*)&value,&optlen );
  227. }
  228. return value;
  229. }
  230. /* ***** EXPERIMENTAL *****
  231. int send( int socket,void *data,int size ){
  232. if( !size ) return 0;
  233. int sent=0;
  234. while( size ){
  235. int n=::send( socket,(const char*)data,size,0 );
  236. if( !n ) return sent;
  237. if( n<0 ){
  238. if( !wouldBlock() ){
  239. printf( "socket_send error!\n",fflush( stdout ) );
  240. return sent;
  241. }
  242. Future future;
  243. std::thread thread( [=,&future](){
  244. fd_set writeset;
  245. FD_ZERO( &writeset );
  246. FD_SET( socket,&writeset );
  247. if( ::select( socket+1,0,&writeset,0,0 )==1 ){
  248. future.set( ::send( socket,(const char*)data,size,0 ) );
  249. }else{
  250. future.set( -1 );
  251. }
  252. } );
  253. n=future.get();
  254. thread.join();
  255. if( n<0 ){
  256. printf( "socket_send error!\n",fflush( stdout ) );
  257. return sent;
  258. }
  259. }
  260. data=(char*)data+n;
  261. size-=n;
  262. sent+=n;
  263. }
  264. return sent;
  265. }
  266. */
  267. /* ***** EXPERIMENTAL *****
  268. int recv( int socket,void *data,int size ){
  269. if( !size ) return 0;
  270. for( ;; ){
  271. int n=::recv( socket,(char*)data,size,0 );
  272. if( !n ) return 0;
  273. if( n<0 ){
  274. if( !wouldBlock() ){
  275. printf( "socket_recv error!\n" );fflush( stdout );
  276. return 0;
  277. }
  278. Future future;
  279. std::thread thread( [=,&future](){
  280. fd_set readset;
  281. FD_ZERO( &readset );
  282. FD_SET( socket,&readset );
  283. if( ::select( socket+1,&readset,0,0,0 )==1 ){
  284. future.set( ::recv( socket,(char*)data,size,0 ) );
  285. }else{
  286. future.set( -1 );
  287. }
  288. } );
  289. n=future.get();
  290. thread.join();
  291. if( n<0 ){
  292. printf( "socket_recv error!\n" );fflush( stdout );
  293. return 0;
  294. }
  295. }
  296. return n;
  297. }
  298. }
  299. */
  300. }