socket.cpp 11 KB

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