socket.cpp 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477
  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 *pres=0;
  69. if( getaddrinfo( hostname,service,&hints,&pres ) ) return -1;
  70. int sock=-1;
  71. for( addrinfo *res=pres;res;res=res->ai_next ){
  72. sock=socket( res->ai_family,res->ai_socktype,res->ai_protocol );
  73. if( sock==-1 ) continue;
  74. if( !connect( sock,res->ai_addr,res->ai_addrlen ) ) break;
  75. ::closesocket( sock );
  76. sock=-1;
  77. }
  78. freeaddrinfo( pres );
  79. return sock;
  80. }
  81. int _bind( const char *hostname,const char *service,int type ){
  82. init();
  83. addrinfo hints;
  84. memset( &hints,0,sizeof( hints ) );
  85. hints.ai_family=AF_UNSPEC;
  86. hints.ai_socktype=(type==1) ? SOCK_DGRAM : SOCK_STREAM;
  87. hints.ai_flags=AI_PASSIVE;
  88. addrinfo *pres=0;
  89. if( getaddrinfo( hostname,service,&hints,&pres ) ) return -1;
  90. int sock=-1;
  91. for( addrinfo *res=pres;res;res=res->ai_next ){
  92. sock=socket( res->ai_family,res->ai_socktype,res->ai_protocol );
  93. if( sock==-1 ) continue;
  94. if( !::bind( sock,res->ai_addr,res->ai_addrlen ) ) break;
  95. ::closesocket( sock );
  96. sock=-1;
  97. }
  98. freeaddrinfo( pres );
  99. return sock;
  100. }
  101. int _listen( const char *hostname,const char *service,int queue,int type ){
  102. int sock=_bind( hostname,service,type );
  103. if( sock!=-1 ) ::listen( sock,queue );
  104. return sock;
  105. }
  106. int connect( const char *hostname,const char *service,int type ){
  107. int sock=-1;
  108. if( bbFiber::getCurrentFiber() ){
  109. Future future;
  110. std::thread thread( [=,&future](){
  111. future.set( _connect( hostname,service,type ) );
  112. } );
  113. sock=future.get();
  114. thread.join();
  115. }else{
  116. sock=_connect( hostname,service,type );
  117. }
  118. return sock;
  119. }
  120. int bind( const char *hostname,const char *service ){
  121. int sock=-1;
  122. if( bbFiber::getCurrentFiber() ){
  123. Future future;
  124. std::thread thread( [=,&future](){
  125. future.set( _bind( hostname,service,1 ) );
  126. } );
  127. sock=future.get();
  128. thread.join();
  129. }else{
  130. sock=_bind( hostname,service,1 );
  131. }
  132. return sock;
  133. }
  134. int listen( const char *hostname,const char *service,int queue ){
  135. int sock=-1;
  136. if( bbFiber::getCurrentFiber() ){
  137. Future future;
  138. std::thread thread( [=,&future](){
  139. future.set( _listen( hostname,service,queue,0 ) );
  140. } );
  141. sock=future.get();
  142. thread.join();
  143. }else{
  144. sock=_listen( hostname,service,queue,0 );
  145. }
  146. return sock;
  147. }
  148. int accept( int socket ){
  149. sockaddr_storage clientaddr;
  150. socklen_t addrlen=sizeof( clientaddr );
  151. int newsock=-1;
  152. if( bbFiber::getCurrentFiber() ){
  153. Future future;
  154. std::thread thread( [&,socket](){
  155. future.set( ::accept( socket,(sockaddr*)&clientaddr,&addrlen ) );
  156. } );
  157. newsock=future.get();
  158. thread.join();
  159. }else{
  160. newsock=::accept( socket,(struct sockaddr*)&clientaddr,&addrlen );
  161. }
  162. return newsock;
  163. }
  164. void close( int socket ){
  165. if( bbFiber::getCurrentFiber() ){
  166. Future future;
  167. std::thread thread( [=,&future](){
  168. future.set( ::closesocket( socket ) );
  169. } );
  170. future.get();
  171. thread.join();
  172. }else{
  173. ::closesocket( socket );
  174. }
  175. }
  176. int cansend( int socket ){
  177. return 0;
  178. }
  179. int canrecv( int socket ){
  180. #if _WIN32
  181. u_long count=0;
  182. if( ioctlsocket( socket,FIONREAD,&count )==-1 ) count=0;
  183. #else
  184. int count=0;
  185. if( ioctl( socket,FIONREAD,&count )==-1 ) count=0;
  186. #endif
  187. return count;
  188. }
  189. int send( int socket,void *data,int size ){
  190. int n=-1;
  191. if( bbFiber::getCurrentFiber() && cansend( socket )<size ){
  192. Future future;
  193. std::thread thread( [=,&future](){
  194. future.set( ::send( socket,(const char*)data,size,0 ) );
  195. } );
  196. n=future.get();
  197. thread.join();
  198. }else{
  199. n=::send( socket,(const char*)data,size,0 );
  200. }
  201. if( n==-1 ){
  202. printf( "socket_send error! err=%i, socket=%i, data=%p, size=%i\n",err(),socket,data,size );fflush( stdout );
  203. }
  204. return n;
  205. }
  206. int sendto( int socket,void *data,int size,const void *addr,int addrlen ){
  207. int n=-1;
  208. if( bbFiber::getCurrentFiber() && cansend( socket )<size ){
  209. Future future;
  210. std::thread thread( [=,&future](){
  211. future.set( ::sendto( socket,(const char*)data,size,0,(const sockaddr*)addr,addrlen ) );
  212. } );
  213. n=future.get();
  214. thread.join();
  215. }else{
  216. n=::sendto( socket,(const char*)data,size,0,(const sockaddr*)addr,addrlen );
  217. }
  218. if( n==-1 ){
  219. printf( "socket_sendto error! err=%i, socket=%i, data=%p, size=%i\n",err(),socket,data,size );fflush( stdout );
  220. }
  221. return n;
  222. }
  223. int recv( int socket,void *data,int size ){
  224. int n=-1;
  225. if( bbFiber::getCurrentFiber() && canrecv( socket )<size ){
  226. Future future;
  227. std::thread thread( [=,&future](){
  228. future.set( ::recv( socket,(char*)data,size,0 ) );
  229. } );
  230. n=future.get();
  231. thread.join();
  232. }else{
  233. n=::recv( socket,(char*)data,size,0 );
  234. }
  235. if( n==-1 ){
  236. printf( "socket_recv error! err=%i, msg=%s, socket=%i, data=%p, size=%i\n",err(),strerror( err() ),socket,data,size );fflush( stdout );
  237. }
  238. return n;
  239. }
  240. int recvfrom( int socket,void *data,int size,void *addr,int *addrlen ){
  241. int n=-1;
  242. if( bbFiber::getCurrentFiber() && canrecv( socket )<size ){
  243. Future future;
  244. std::thread thread( [=,&future](){
  245. future.set( recvfrom( socket,(char*)data,size,0,(sockaddr*)addr,(socklen_t*)addrlen ) );
  246. } );
  247. n=future.get();
  248. thread.join();
  249. }else{
  250. n=::recvfrom( socket,(char*)data,size,0,(sockaddr*)addr,(socklen_t*)addrlen );
  251. }
  252. if( n==-1 ){
  253. printf( "socket_recvfrom error! err=%i, socket=%i, data=%p, size=%i\n",err(),socket,data,size );fflush( stdout );
  254. }
  255. return n;
  256. }
  257. void setopt( int socket,bbString name,int value ){
  258. const char *ip=(const char*)&value;
  259. int sz=sizeof( value );
  260. if( name=="TCP_NODELAY" ){
  261. setsockopt( socket,IPPROTO_TCP,TCP_NODELAY,ip,sz );
  262. }else if( name="SO_REUSEADDR" ){
  263. setsockopt( socket,SOL_SOCKET,SO_REUSEADDR,ip,sz );
  264. }else if( name=="SO_SNDTIMEO" ){
  265. setsockopt( socket,SOL_SOCKET,SO_SNDTIMEO,ip,sz );
  266. }else if( name=="SO_RCVTIMEO" ){
  267. setsockopt( socket,SOL_SOCKET,SO_RCVTIMEO,ip,sz );
  268. }
  269. }
  270. int getopt( int socket,bbString name ){
  271. int value=-1;
  272. char *ip=(char*)&value;
  273. int sz=sizeof( value );
  274. if( name=="TCP_NODELAY" ){
  275. getsockopt( socket,IPPROTO_TCP,TCP_NODELAY,ip,(socklen_t*)&sz );
  276. }else if( name="SO_REUSEADDR" ){
  277. getsockopt( socket,SOL_SOCKET,SO_REUSEADDR,ip,(socklen_t*)&sz );
  278. }else if( name=="SO_SNDTIMEO" ){
  279. getsockopt( socket,SOL_SOCKET,SO_SNDTIMEO,ip,(socklen_t*)&sz );
  280. }else if( name=="SO_RCVTIMEO" ){
  281. getsockopt( socket,SOL_SOCKET,SO_RCVTIMEO,ip,(socklen_t*)&sz );
  282. }
  283. return value;
  284. }
  285. int getsockaddr( int socket,void *addr,int *addrlen ){
  286. return getsockname( socket,(sockaddr*)addr,(socklen_t*)addrlen );
  287. }
  288. int getpeeraddr( int socket,void *addr,int *addrlen ){
  289. return getpeername( socket,(sockaddr*)addr,(socklen_t*)addrlen );
  290. }
  291. int sockaddrname( const void *addr,int addrlen,char *host,char *service ){
  292. return getnameinfo( (const sockaddr*)addr,addrlen,host,1023,service,79,0 );
  293. }
  294. }