00001 #include "slate.hpp"
00002
00003 void socket_module_init(struct object_heap* oh) {
00004 oh->socketTicketCount = SLATE_NETTICKET_MAXIMUM;
00005 oh->socketTickets = (struct slate_addrinfo_request*)calloc(oh->socketTicketCount * sizeof(struct slate_addrinfo_request), 1);
00006 #if 0
00007 oh->socketTicketMutex = PTHREAD_MUTEX_INITIALIZER;
00008 #endif
00009 }
00010
00011
00012 word_t socket_return(word_t ret) {
00013
00014 if (ret >= 0) return ret;
00015
00016 switch (-ret) {
00017 #ifdef WIN32
00018
00019 #else
00020 case EACCES: return -2;
00021 case EAFNOSUPPORT: return -3;
00022 case EINVAL: return -4;
00023 case EMFILE: return -5;
00024 case ENFILE: return -5;
00025 case ENOMEM: return -6;
00026 case EPROTONOSUPPORT: return -3;
00027 case EADDRINUSE: return -7;
00028 case EBADF: return -8;
00029 case ENOTSOCK: return -8;
00030 case EFAULT: return -4;
00031 case EOPNOTSUPP: return -3;
00032 case EAGAIN: return -9;
00033
00034 case ECONNABORTED: return -11;
00035 case EINTR: return -12;
00036 case EPERM: return -2;
00037 case EALREADY: return -13;
00038 case ECONNREFUSED: return -14;
00039 case EINPROGRESS: return -15;
00040 case EISCONN: return -16;
00041 case ENETUNREACH: return -17;
00042 case ETIMEDOUT: return -18;
00043 #endif
00044
00045 default: return -1;
00046 }
00047
00048 }
00049
00050 int socket_select_setup(struct OopArray* selectOn, fd_set* fdList, int* maxFD) {
00051 word_t fdCount, i;
00052
00053 FD_ZERO(fdList);
00054 fdCount = array_size(selectOn);
00055
00056 for (i = 0; i < fdCount; i++) {
00057 struct Object* fdo = object_array_get_element((struct Object*)selectOn, i);
00058 word_t fd = object_to_smallint(fdo);
00059 if (!object_is_smallint(fdo) || fd >= FD_SETSIZE) {
00060 return -1;
00061 }
00062 *maxFD = max(*maxFD, fd);
00063 FD_SET(fd, fdList);
00064 assert(FD_ISSET(fd, fdList));
00065 }
00066
00067 return fdCount;
00068 }
00069
00070 void socket_select_find_available(struct OopArray* selectOn, fd_set* fdList, struct OopArray* readyPipes, word_t readyCount) {
00071 word_t fdCount, i, readyIndex;
00072 fdCount = array_size(selectOn);
00073
00074 for (i = 0, readyIndex = 0; i < fdCount && readyIndex < readyCount; i++) {
00075 if (FD_ISSET(object_to_smallint(object_array_get_element((struct Object*)selectOn, i)), fdList)) {
00076 readyPipes->elements[readyIndex++] = object_array_get_element((struct Object*)selectOn, i);
00077 }
00078 }
00079 }
00080
00081 void prim_selectOnReadPipesFor(struct object_heap* oh, struct Object* args[], word_t arity, struct OopArray* opts, word_t resultStackPointer) {
00082 struct OopArray* selectOn = (struct OopArray*) args[0];
00083 struct OopArray* readyPipes;
00084 word_t waitTime = object_to_smallint(args[1]);
00085 int retval, fdCount, maxFD;
00086 struct timeval tv;
00087 fd_set fdList;
00088 maxFD = 0;
00089
00090 ASSURE_SMALLINT_ARG(1);
00091
00092 if ((fdCount = socket_select_setup(selectOn, &fdList, &maxFD)) < 0) {
00093 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
00094 return;
00095 }
00096
00097
00098 tv.tv_sec = waitTime / 1000000;
00099 tv.tv_usec = waitTime % 1000000;
00100 retval = select(maxFD+1, &fdList, NULL, NULL, &tv);
00101
00102 if (retval < 0) {
00103 oh->cached.interpreter->stack->elements[resultStackPointer] = oh->cached.nil;
00104 return;
00105 }
00106
00107
00108 readyPipes = heap_clone_oop_array_sized(oh, get_special(oh, SPECIAL_OOP_ARRAY_PROTO), retval);
00109 socket_select_find_available(selectOn, &fdList, readyPipes, retval);
00110
00111 oh->cached.interpreter->stack->elements[resultStackPointer] = (struct Object*)readyPipes;
00112
00113 }
00114
00115
00116 int socket_lookup_domain(word_t domain) {
00117 switch (domain) {
00118 case SLATE_DOMAIN_LOCAL: return AF_UNIX;
00119 case SLATE_DOMAIN_IPV4: return AF_INET;
00120 case SLATE_DOMAIN_IPV6: return AF_INET6;
00121 default: return AF_INET;
00122 }
00123 }
00124
00125 int socket_reverse_lookup_domain(word_t domain) {
00126 switch (domain) {
00127 case AF_UNIX: return SLATE_DOMAIN_LOCAL;
00128 case AF_INET: return SLATE_DOMAIN_IPV4;
00129 case AF_INET6: return SLATE_DOMAIN_IPV6;
00130 default: return SLATE_DOMAIN_IPV4;
00131 }
00132 }
00133
00134 int socket_lookup_type(word_t type) {
00135 switch (type) {
00136 case SLATE_TYPE_STREAM: return SOCK_STREAM;
00137 default: return SOCK_STREAM;
00138 }
00139 }
00140
00141 int socket_reverse_lookup_type(word_t type) {
00142 switch (type) {
00143 case SOCK_STREAM: return SLATE_TYPE_STREAM;
00144 default: return SLATE_TYPE_STREAM;
00145 }
00146 }
00147
00148 int socket_lookup_protocol(word_t protocol) {
00149 switch (protocol) {
00150 default: return 0;
00151 }
00152 }
00153
00154 int socket_reverse_lookup_protocol(word_t protocol) {
00155 switch (protocol) {
00156 default: return 0;
00157 }
00158 }
00159
00160 int socket_set_nonblocking(int fd) {
00161 int flags;
00162
00163 #ifdef WIN32
00164 #pragma message("TODO WIN32 port set-nonblocking on socket")
00165 return 0;
00166 #else
00167 if ((flags = fcntl(fd, F_GETFL, 0)) == -1)
00168 flags = 0;
00169 return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
00170 #endif
00171 }
00172
00173 #ifdef WIN32
00174 DWORD WINAPI socket_getaddrinfo_callback(LPVOID ptr) {
00175 #else
00176 void *socket_getaddrinfo_callback(void *ptr) {
00177 #endif
00178 struct slate_addrinfo_request* req = (struct slate_addrinfo_request*)ptr;
00179
00180 struct addrinfo ai;
00181 memset(&ai, 0, sizeof(ai));
00182 ai.ai_flags = req->flags;
00183 ai.ai_family = socket_lookup_domain(req->family);
00184 ai.ai_socktype = socket_lookup_type(req->type);
00185 ai.ai_protocol = socket_lookup_protocol(req->protocol);
00186
00187 req->result = getaddrinfo(req->hostname, req->service, &ai, &req->addrResult);
00188 req->finished = 1;
00189 #ifdef WIN32
00190 return 0;
00191 #else
00192 return NULL;
00193 #endif
00194 }
00195
00196 int socket_getaddrinfo(struct object_heap* oh, struct ByteArray* hostname, word_t hostnameSize, struct ByteArray* service, word_t serviceSize, word_t family, word_t type, word_t protocol, word_t flags) {
00197 int i;
00198 #ifdef WIN32
00199 HANDLE thread;
00200 DWORD pret;
00201 oh->socketThreadMutex = CreateMutex(NULL, FALSE, TEXT("SocketThreadMutex"));
00202 #else
00203 pthread_t thread;
00204 int pret;
00205 #if 0
00206 pthread_mutex_lock(&oh->socketTicketMutex);
00207 #endif
00208 #endif
00209 for (i = 0; i < oh->socketTicketCount; i++) {
00210 if (oh->socketTickets[i].inUse == 0) {
00211
00212 oh->socketTickets[i].inUse = 1;
00213 oh->socketTickets[i].result = 0;
00214 oh->socketTickets[i].finished = 0;
00215 oh->socketTickets[i].addrResult = 0;
00216 oh->socketTickets[i].family = family;
00217 oh->socketTickets[i].type = type;
00218 oh->socketTickets[i].protocol = protocol;
00219 oh->socketTickets[i].flags = flags;
00220 oh->socketTickets[i].oh = oh;
00221 oh->socketTickets[i].ticketNumber = i;
00222 if (hostnameSize == 0) {
00223 oh->socketTickets[i].hostname = NULL;
00224 } else {
00225 oh->socketTickets[i].hostname = (char*)calloc(hostnameSize, 1);
00226 extractCString(hostname, (byte_t*)oh->socketTickets[i].hostname, hostnameSize);
00227 }
00228 if (serviceSize == 0) {
00229 oh->socketTickets[i].service = NULL;
00230 } else {
00231 oh->socketTickets[i].service = (char*)calloc(hostnameSize, 1);
00232 extractCString(service, (byte_t*)oh->socketTickets[i].service, serviceSize);
00233 }
00234
00235 #ifdef WIN32
00236 ReleaseMutex(oh->socketThreadMutex);
00237 thread = CreateThread(NULL, 0, socket_getaddrinfo_callback, (void*) &oh->socketTickets[i], 0, &pret);
00238 #else
00239 #if 0
00240 pthread_mutex_unlock(&oh->socketTicketMutex);
00241 #endif
00242 pret = pthread_create(&thread, NULL, socket_getaddrinfo_callback, (void*) &oh->socketTickets[i]);
00243 #endif
00244 if (pret != 0) {
00245 free(oh->socketTickets[i].hostname);
00246 free(oh->socketTickets[i].service);
00247 oh->socketTickets[i].hostname = NULL;
00248 oh->socketTickets[i].service = NULL;
00249 return -1;
00250 }
00251 return i;
00252 }
00253 }
00254 #ifdef WIN32
00255 ReleaseMutex(oh->socketThreadMutex);
00256 #else
00257 #if 0
00258 pthread_mutex_unlock(&oh->socketTicketMutex);
00259 #endif
00260 #endif
00261
00262 return -1;
00263
00264 }