EIF_INTEGER en_socket_datagram_rcv_from (EIF_INTEGER fd, EIF_INTEGER fd1, EIF_INTEGER *a_last_fd, EIF_POINTER buf, EIF_INTEGER len, EIF_INTEGER flags, EIF_INTEGER timeout, SOCKETADDRESS *him) { int nsockets = 0; int fduse = 0; int result; int lenn = sizeof(SOCKETADDRESS); int ipv6_supported = en_ipv6_available(); if (fd > 0) { nsockets++; } if (fd1 > 0) { nsockets++; } if (nsockets == 2) { /* need to choose one of them */ int ret, t = (timeout == 0) ? -1: timeout; ret = net_timeout2 (fd, fd1, t, &fduse); if (ret == 2) { fduse = check_last_fd (a_last_fd, fd, fd1); } else if (ret == 0) { if (ret == 0) { eraise("Receive timed out", EN_PROG); } else { eraise("Receive error", EN_PROG); } return -1; } } else if (!ipv6_supported) { fduse = fd; } else if (fd >= 0) { /* ipv6 supported: and this socket bound to an IPV6 only address */ fduse = fd1; } else { /* ipv6 supported: and this socket bound to an IPV4 only address */ fduse = fd; } if (timeout && nsockets == 1) { int ret; ret = net_timeout(fduse, timeout); if (ret <= 0) { if (ret == 0) { eraise("Receive timed out", EN_PROG); } else { eraise("Receive error", EN_PROG); } return -1; } } result = recvfrom ((SOCKET) fduse, (char *) buf, (int) len, (int) flags, (struct sockaddr *) him, &lenn); eif_net_check (result); return (EIF_INTEGER) result; }
/* * send a message * return non-zero if message not sent successful with completed * queue info for status and transport */ int ebxml_send (XML*xml, QUEUEROW *r, MIME *msg) { DBUF *b; NETCON *conn; char host[MAX_PATH]; /* need buffers for redirect */ char path[MAX_PATH]; int port, route, timeout, delay, retry; SSL_CTX *ctx; char *rname, /* route name */ *content, /* message content */ buf[MAX_PATH]; /* format up the message */ if ((content = mime_format (msg)) == NULL) { queue_field_set (r, "PROCESSINGSTATUS", "done"); queue_field_set (r, "TRANSPORTSTATUS", "failed"); queue_field_set (r, "TRANSPORTERRORCODE", "failed formatting message"); return (-1); } debug ("Send content:\n%s\n", content); /* * get connection info from the record route */ if ((route = cfg_route_index (xml, queue_field_get (r, "ROUTEINFO"))) < 0) { queue_field_set (r, "PROCESSINGSTATUS", "done"); queue_field_set (r, "TRANSPORTSTATUS", "failed"); queue_field_set (r, "TRANSPORTERRORCODE", "bad route"); return (-1); } rname = cfg_route (xml, route, "Name"); ctx = ebxml_route_ctx (xml, route); strcpy (host, cfg_route (xml, route, "Host")); port = atoi (cfg_route (xml, route, "Port")); if ((retry = atoi (cfg_route (xml, route, "Retry"))) == 0) retry = cfg_retries (xml); timeout = atoi (cfg_route (xml, route, "Timeout")); delay = cfg_delay (xml); strcpy (path, cfg_route (xml, route, "Path")); sendmsg: info ("Sending ebXML %s:%d to %s\n", r->queue->name, r->rowid, rname); debug ("opening connection socket on port=%d retrys=%d timeout=%d\n", port, retry, timeout); if ((conn = net_open (host, port, 0, ctx)) == NULL) { error ("failed opening connection to %s:%d\n", host, port); goto retrysend; } /* set read timeout if given */ if (timeout) { net_timeout (conn, timeout * 1000); timeout <<= 1; /* bump each try */ } delay = 0; /* connection OK, don't delay */ queue_field_set (r, "MESSAGESENTTIME", ptime (NULL, buf)); sprintf (buf, "POST %s HTTP/1.1\r\n", path); // ch = ebxml_beautify (ch); /* all set... send the message */ debug ("sending message...\n"); net_write (conn, buf, strlen (buf)); net_write (conn, content, strlen (content)); debug ("reading response...\n"); b = ebxml_receive (conn); debug ("closing socket...\n"); net_close (conn); /* no reply? */ if (b == NULL) { warn ("Send response timed out or closed for %s\n", rname); retrysend: /* retry with a wait, or.. */ if (retry-- && phineas_running ()) { if (delay) { info ("Retrying send to %s in %d seconds\n", rname, delay); sleep (delay * 1000); delay <<= 1; } else /* reset connection delay */ delay = cfg_delay (xml); goto sendmsg; } if (ctx != NULL) /* give up! */ SSL_CTX_free (ctx); free (content); queue_field_set (r, "PROCESSINGSTATUS", "done"); queue_field_set (r, "TRANSPORTSTATUS", "failed"); queue_field_set (r, "TRANSPORTERRORCODE", "retries exhausted"); return (-1); } debug ("reply was %d bytes\n%.*s\n", dbuf_size (b), dbuf_size (b), dbuf_getbuf (b)); /* * handle redirects... * note this assumes the same SSL context should be used */ if (ebxml_redirect (dbuf_getbuf (b), host, &port, path)) { dbuf_free (b); goto sendmsg; } if (ctx != NULL) SSL_CTX_free (ctx); if (ebxml_parse_reply (dbuf_getbuf (b), r)) { queue_field_set (r, "PROCESSINGSTATUS", "done"); queue_field_set (r, "TRANSPORTSTATUS", "failed"); queue_field_set (r, "TRANSPORTERRORCODE", "garbled reply"); } debug ("send completed\n"); dbuf_free (b); free (content); return (0); }
EIF_INTEGER en_socket_stream_accept (EIF_INTEGER fd, EIF_INTEGER fd1, EIF_INTEGER *a_last_fd, SOCKETADDRESS *him, EIF_INTEGER timeout) { int len; SOCKET accepted; EIF_NET_INITIALIZE; if (fd != -1 && fd1 != -1) { fd_set rfds; struct timeval t, *tP=&t; int res, fd2; FD_ZERO(&rfds); FD_SET((SOCKET) fd,&rfds); FD_SET((SOCKET) fd1,&rfds); if (timeout) { t.tv_sec = timeout/1000; t.tv_usec = (timeout%1000)*1000; } else { tP = NULL; } res = select (fd, &rfds, NULL, NULL, tP); if (res == 0) { eraise("Accept timed out", EN_PROG); return -1; } else if (res == 1) { fd2 = FD_ISSET(fd, &rfds)? fd: fd1; } else if (res == 2) { /* avoid starvation */ if (*a_last_fd != -1) { fd2 = *a_last_fd==fd? fd1: fd; } else { fd2 = fd; } *a_last_fd = fd2; } else { eraise("select failed", EN_PROG); return -1; } if (fd2 == fd) { /* v4 */ len = sizeof (struct sockaddr_in); } else { len = sizeof (struct sockaddr_in6); } fd = fd2; } else { int ret; if (fd1 != -1) { fd = fd1; len = sizeof (struct sockaddr_in6); } else { len = sizeof (struct sockaddr_in); } if (timeout) { ret = net_timeout(fd, timeout); if (ret == 0) { eraise("Accept timed out", EN_PROG); return -1; } else if (ret == -1) { eraise("Socket closed", EN_PROG); return -1; } else if (ret == -2) { eraise("operation interrupted", EN_PROG); return -1; } } } accepted = check_socket_bounds(accept(fd, (struct sockaddr *)him, &len)); if (accepted == INVALID_SOCKET) { eif_net_check ((int)accepted); return -1; } else { return (int)accepted; } }