EXTERN void neko_thread_blocking( thread_main_func f, void *p ) { # if !defined(NEKO_THREADS) f(p); // nothing # elif defined(NEKO_WINDOWS) f(p); // we don't have pthreads issues # else // we have different APIs depending on the GC version, make sure we load // the good one at runtime static callb_func do_blocking = NULL; static std_func start = NULL, end = NULL; if( do_blocking ) do_blocking(f,p); else if( start ) { start(); f(p); end(); } else { void *self = dlopen(NULL,0); do_blocking = (callb_func)dlsym(self,"GC_do_blocking"); if( !do_blocking ) { start = (std_func)dlsym(self,"GC_start_blocking"); end = (std_func)dlsym(self,"GC_end_blocking"); if( !start || !end ) val_throw(alloc_string("Could not init GC blocking API")); } neko_thread_blocking(f,p); } # endif }
/** socket_recv : 'socket -> buf:string -> pos:int -> len:int -> int <doc>Read up to [len] bytes from [buf] starting at [pos] from a connected socket. Return the number of bytes readed.</doc> **/ static value socket_recv( value o, value data, value pos, value len ) { int p,l,dlen,ret; int retry = 0; val_check_kind(o,k_socket); val_check(data,string); val_check(pos,int); val_check(len,int); p = val_int(pos); l = val_int(len); dlen = val_strlen(data); if( p < 0 || l < 0 || p > dlen || p + l > dlen ) neko_error(); POSIX_LABEL(recv_again); if( retry++ > NRETRYS ) { sock_tmp t; t.sock = val_sock(o); t.buf = val_string(data) + p; t.size = l; neko_thread_blocking(tmp_recv,&t); ret = t.ret; } else ret = recv(val_sock(o), val_string(data) + p , l, MSG_NOSIGNAL); if( ret == SOCKET_ERROR ) { HANDLE_EINTR(recv_again); return block_error(); } return alloc_int(ret); }
/** socket_recv_from : 'socket -> buf:string -> pos:int -> length:int -> addr:{host:'int32,port:int} -> int <doc> Read data from an unconnected UDP socket, store the address from which we received data in addr. </doc> **/ static value socket_recv_from( value o, value data, value pos, value len, value addr ) { int p,l,dlen,ret; int retry = 0; struct sockaddr_in saddr; int slen = sizeof(saddr); val_check_kind(o,k_socket); val_check(data,string); val_check(pos,int); val_check(len,int); val_check(addr,object); p = val_int(pos); l = val_int(len); dlen = val_strlen(data); if( p < 0 || l < 0 || p > dlen || p + l > dlen ) neko_error(); POSIX_LABEL(recv_from_again); if( retry++ > NRETRYS ) { sock_tmp t; t.sock = val_sock(o); t.buf = val_string(data) + p; t.size = l; neko_thread_blocking(tmp_recv,&t); ret = t.ret; } else ret = recvfrom(val_sock(o), val_string(data) + p , l, MSG_NOSIGNAL, (struct sockaddr*)&saddr, &slen); if( ret == SOCKET_ERROR ) { HANDLE_EINTR(recv_from_again); #ifdef NEKO_WINDOWS if( WSAGetLastError() == WSAECONNRESET ) ret = 0; else #endif return block_error(); } alloc_field(addr,f_host,alloc_int32(*(int*)&saddr.sin_addr)); alloc_field(addr,f_port,alloc_int(ntohs(saddr.sin_port))); return alloc_int(ret); }
/** socket_recv_char : 'socket -> int <doc>Read a single char from a connected socket.</doc> **/ static value socket_recv_char( value o ) { int ret; int retry = 0; unsigned char cc; val_check_kind(o,k_socket); POSIX_LABEL(recv_char_again); if( retry++ > NRETRYS ) { sock_tmp t; t.sock = val_sock(o); t.buf = (char*)&cc; t.size = 1; neko_thread_blocking(tmp_recv,&t); ret = t.ret; } else ret = recv(val_sock(o),&cc,1,MSG_NOSIGNAL); if( ret == SOCKET_ERROR ) { HANDLE_EINTR(recv_char_again); return block_error(); } if( ret == 0 ) neko_error(); return alloc_int(cc); }