socket.cpp 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558
  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. int err(){
  35. #if _WIN32
  36. return WSAGetLastError();
  37. #else
  38. return errno;
  39. #endif
  40. }
  41. void init(){
  42. static bool done;
  43. if( done ) return;
  44. done=true;
  45. #if _WIN32
  46. WSADATA wsa;
  47. WSAStartup( MAKEWORD(2,2),&wsa );
  48. #endif
  49. }
  50. void dontBlock( int sock ){
  51. //make non-blocking
  52. u_long cmd=1;
  53. ioctlsocket( sock,FIONBIO,&cmd );
  54. }
  55. bool wouldBlock(){
  56. #if _WIN32
  57. return WSAGetLastError()==WSAEWOULDBLOCK;
  58. #else
  59. return errno==EAGAIN || errno==EWOULDBLOCK;
  60. #endif
  61. }
  62. int _connect( const char *hostname,const char *service,int type ){
  63. init();
  64. addrinfo hints;
  65. memset( &hints,0,sizeof( hints ) );
  66. hints.ai_family=AF_UNSPEC;
  67. hints.ai_socktype=(type==1) ? SOCK_DGRAM : SOCK_STREAM;
  68. addrinfo *res=0;
  69. if( getaddrinfo( hostname,service,&hints,&res ) ) return -1;
  70. addrinfo *pres=res;
  71. int sock=-1;
  72. while( res ){
  73. sock=socket( res->ai_family,res->ai_socktype,res->ai_protocol );
  74. if( sock>=0 ){
  75. if( !connect( sock,res->ai_addr,res->ai_addrlen ) ) break;
  76. ::closesocket( sock );
  77. sock=-1;
  78. }
  79. res=res->ai_next;
  80. }
  81. freeaddrinfo( pres );
  82. if( sock<0 ) return -1;
  83. return sock;
  84. }
  85. int _bind( const char *service,int type ){
  86. init();
  87. addrinfo hints;
  88. memset( &hints,0,sizeof( hints ) );
  89. hints.ai_family=AF_UNSPEC;
  90. hints.ai_socktype=(type==1) ? SOCK_DGRAM : SOCK_STREAM;
  91. hints.ai_flags=AI_PASSIVE;
  92. addrinfo *res=0;
  93. if( getaddrinfo( 0,service,&hints,&res ) ) return -1;
  94. addrinfo *pres=res;
  95. int sock=-1;
  96. while( res ){
  97. sock=socket( res->ai_family,res->ai_socktype,res->ai_protocol );
  98. if( sock>=0 ){
  99. if( !::bind( sock,res->ai_addr,res->ai_addrlen ) ) break;
  100. ::closesocket( sock );
  101. sock=-1;
  102. }
  103. res=res->ai_next;
  104. }
  105. freeaddrinfo( pres );
  106. if( sock<0 ) return -1;
  107. // So server ports can be quickly reused...
  108. //
  109. #if __APPLE__ || __linux
  110. int flag=1;
  111. setsockopt( sock,SOL_SOCKET,SO_REUSEADDR,&flag,sizeof(flag) );
  112. #endif
  113. return sock;
  114. }
  115. int _listen( const char *service,int queue,int type ){
  116. init();
  117. addrinfo hints;
  118. memset( &hints,0,sizeof( hints ) );
  119. hints.ai_family=AF_UNSPEC;
  120. hints.ai_socktype=(type==1) ? SOCK_DGRAM : SOCK_STREAM;
  121. hints.ai_flags=AI_PASSIVE;
  122. addrinfo *res=0;
  123. if( getaddrinfo( 0,service,&hints,&res ) ) return -1;
  124. addrinfo *pres=res;
  125. int sock=-1;
  126. while( res ){
  127. sock=socket( res->ai_family,res->ai_socktype,res->ai_protocol );
  128. if( sock>=0 ){
  129. if( !::bind( sock,res->ai_addr,res->ai_addrlen ) ) break;
  130. ::closesocket( sock );
  131. sock=-1;
  132. }
  133. res=res->ai_next;
  134. }
  135. freeaddrinfo( pres );
  136. if( sock<0 ) return -1;
  137. // So server ports can be quickly reused...
  138. //
  139. #if __APPLE__ || __linux
  140. int flag=1;
  141. setsockopt( sock,SOL_SOCKET,SO_REUSEADDR,&flag,sizeof(flag) );
  142. #endif
  143. ::listen( sock,queue );
  144. return sock;
  145. }
  146. int connect( bbString hostname,bbString service,int type ){
  147. if( hostname.length()>1023 || service.length()>79 ) return -1;
  148. char _hostname[1024];
  149. char _service[80];
  150. strcpy( _hostname,hostname.c_str() );
  151. strcpy( _service,service.c_str() );
  152. int result=-1;
  153. if( bbFiber::getCurrentFiber() ){
  154. Future future;
  155. std::thread thread( [=,&future](){
  156. future.set( _connect( _hostname,_service,type ) );
  157. } );
  158. result=future.get();
  159. thread.join();
  160. }else{
  161. result=_connect( _hostname,_service,type );
  162. }
  163. return result;
  164. }
  165. int bind( bbString service ){
  166. if( service.length()>79 ) return -1;
  167. char _service[80];
  168. strcpy( _service,service.c_str() );
  169. int result=-1;
  170. if( bbFiber::getCurrentFiber() ){
  171. Future future;
  172. std::thread thread( [=,&future](){
  173. future.set( _bind( _service,1 ) );
  174. } );
  175. result=future.get();
  176. thread.join();
  177. }else{
  178. result=_bind( _service,1 );
  179. }
  180. return result;
  181. }
  182. int listen( bbString service,int queue ){
  183. if( service.length()>79 ) return -1;
  184. char _service[80];
  185. strcpy( _service,service.c_str() );
  186. int result=-1;
  187. if( bbFiber::getCurrentFiber() ){
  188. Future future;
  189. std::thread thread( [=,&future](){
  190. future.set( _listen( _service,queue,0 ) );
  191. } );
  192. result=future.get();
  193. thread.join();
  194. }else{
  195. result=_listen( _service,queue,0 );
  196. }
  197. return result;
  198. }
  199. int accept( int socket ){
  200. sockaddr_storage clientaddr;
  201. socklen_t addrlen=sizeof( clientaddr );
  202. int newsock=-1;
  203. if( bbFiber::getCurrentFiber() ){
  204. Future future;
  205. std::thread thread( [&,socket](){
  206. future.set( ::accept( socket,(sockaddr*)&clientaddr,&addrlen ) );
  207. } );
  208. newsock=future.get();
  209. thread.join();
  210. }else{
  211. newsock=::accept( socket,(struct sockaddr*)&clientaddr,&addrlen );
  212. }
  213. return newsock;
  214. }
  215. void close( int socket ){
  216. if( bbFiber::getCurrentFiber() ){
  217. Future future;
  218. std::thread thread( [=,&future](){
  219. future.set( ::closesocket( socket ) );
  220. } );
  221. future.get();
  222. thread.join();
  223. }else{
  224. ::closesocket( socket );
  225. }
  226. }
  227. int cansend( int socket ){
  228. #if _WIN32
  229. u_long count=0;
  230. #else
  231. int count=0;
  232. if( ioctl( socket,FIONWRITE,&count )<0 ) count=0;
  233. #endif
  234. return count;
  235. }
  236. int canrecv( int socket ){
  237. #if _WIN32
  238. u_long count=0;
  239. if( ioctlsocket( socket,FIONREAD,&count )==SOCKET_ERROR ){
  240. puts( "ERROR!" );
  241. count=0;
  242. }
  243. #else
  244. int count=0;
  245. if( ioctl( socket,FIONREAD,&count )<0 ) count=0;
  246. #endif
  247. return count;
  248. }
  249. int send( int socket,void *data,int size ){
  250. int n=-1;
  251. if( bbFiber::getCurrentFiber() && cansend( socket )<size ){
  252. Future future;
  253. std::thread thread( [=,&future](){
  254. future.set( ::send( socket,(const char*)data,size,0 ) );
  255. } );
  256. n=future.get();
  257. thread.join();
  258. }else{
  259. n=::send( socket,(const char*)data,size,0 );
  260. }
  261. if( n<0 ){
  262. printf( "socket_send error! err=%i, socket=%i, data=%p, size=%i\n",err(),socket,data,size );fflush( stdout );
  263. }
  264. return n;
  265. }
  266. int sendto( int socket,void *data,int size,const void *addr,int addrlen ){
  267. int n=-1;
  268. if( bbFiber::getCurrentFiber() && cansend( socket )<size ){
  269. Future future;
  270. std::thread thread( [=,&future](){
  271. future.set( ::sendto( socket,(const char*)data,size,0,(const sockaddr*)addr,addrlen ) );
  272. } );
  273. n=future.get();
  274. thread.join();
  275. }else{
  276. n=::sendto( socket,(const char*)data,size,0,(const sockaddr*)addr,addrlen );
  277. }
  278. if( n<0 ){
  279. printf( "socket_sendto error! err=%i, socket=%i, data=%p, size=%i\n",err(),socket,data,size );fflush( stdout );
  280. }
  281. return n;
  282. }
  283. int recv( int socket,void *data,int size ){
  284. int n=-1;
  285. if( bbFiber::getCurrentFiber() && canrecv( socket )<size ){
  286. Future future;
  287. std::thread thread( [=,&future](){
  288. future.set( ::recv( socket,(char*)data,size,0 ) );
  289. } );
  290. n=future.get();
  291. thread.join();
  292. }else{
  293. n=::recv( socket,(char*)data,size,0 );
  294. }
  295. if( n<0 ){
  296. printf( "socket_recv error! err=%i, socket=%i, data=%p, size=%i\n",err(),socket,data,size );fflush( stdout );
  297. }
  298. return n;
  299. }
  300. int recvfrom( int socket,void *data,int size,void *addr,int *addrlen ){
  301. int n=-1;
  302. if( bbFiber::getCurrentFiber() && canrecv( socket )<size ){
  303. Future future;
  304. std::thread thread( [=,&future](){
  305. future.set( ::recvfrom( socket,(char*)data,size,0,(sockaddr*)addr,addrlen ) );
  306. } );
  307. n=future.get();
  308. thread.join();
  309. }else{
  310. n=::recvfrom( socket,(char*)data,size,0,(sockaddr*)addr,addrlen );
  311. }
  312. if( n<0 ){
  313. printf( "socket_recvfrom error! n=%i, err=%i, socket=%i, data=%p, size=%i\n",n,err(),socket,data,size );fflush( stdout );
  314. }
  315. return n;
  316. }
  317. void setopt( int socket,bbString name,int value ){
  318. const char *ip=(const char*)&value;
  319. int sz=sizeof(int);
  320. if( name=="TCP_NODELAY" ){
  321. setsockopt( socket,IPPROTO_TCP,TCP_NODELAY,ip,sz );
  322. }else if( name=="SO_SNDTIMEO" ){
  323. setsockopt( socket,SOL_SOCKET,SO_SNDTIMEO,ip,sz );
  324. }else if( name=="SO_RCVTIMEO" ){
  325. setsockopt( socket,SOL_SOCKET,SO_RCVTIMEO,ip,sz );
  326. }
  327. }
  328. int getopt( int socket,bbString name ){
  329. int value=-1;
  330. socklen_t optlen=sizeof(value);
  331. char *ip=(char*)&value;
  332. int sz=sizeof(int);
  333. int *szp=&sz;
  334. if( name=="TCP_NODELAY" ){
  335. getsockopt( socket,IPPROTO_TCP,TCP_NODELAY,ip,szp );
  336. }else if( name=="SO_SNDTIMEO" ){
  337. getsockopt( socket,SOL_SOCKET,SO_SNDTIMEO,ip,szp );
  338. }else if( name=="SO_RCVTIMEO" ){
  339. getsockopt( socket,SOL_SOCKET,SO_RCVTIMEO,ip,szp );
  340. }
  341. }
  342. int getsockaddr( int socket,void *addr,int *addrlen ){
  343. return getsockname( socket,(sockaddr*)addr,addrlen );
  344. }
  345. int getpeeraddr( int socket,void *addr,int *addrlen ){
  346. return getpeername( socket,(sockaddr*)addr,addrlen );
  347. }
  348. int sockaddrname( const void *addr,int addrlen,char *host,char *service ){
  349. getnameinfo( (const sockaddr*)addr,addrlen,host,1023,service,79,0 );
  350. }
  351. }