/* * This is the new connection handler. This function is called by the * event handler when data is pending on the listening socket (conn_fd). * If space is available, an interactive data structure is initialized and * the connected is established. */ void new_conn_handler() { #ifdef IPV6 struct sockaddr_in6 client; #else struct sockaddr_in client; #endif socklen_t client_len; struct hostent *c_hostent; int new_fd; int conn_index; client_len = sizeof(client); new_fd = accept(conn_fd, (struct sockaddr *) & client, &client_len); if (new_fd == -1) { socket_perror("new_conn_handler: accept", 0); return; } if (set_socket_nonblocking(new_fd, 1) == -1) { socket_perror("new_conn_handler: set_socket_nonblocking 1", 0); OS_socket_close(new_fd); return; } if (total_conns >= MAX_CONNS) { char *message = "no available slots -- closing connection.\n"; fprintf(stderr, "new_conn_handler: no available connection slots.\n"); OS_socket_write(new_fd, message, strlen(message)); if (OS_socket_close(new_fd) == -1) socket_perror("new_conn_handler: close", 0); return; } /* get some information about new connection */ for (conn_index = 0; conn_index < MAX_CONNS; conn_index++) { if (all_conns[conn_index].state == CONN_CLOSED) { DBG(("new_conn_handler: opening conn index %d", conn_index)); /* update global data for new fd */ all_conns[conn_index].fd = new_fd; all_conns[conn_index].state = CONN_OPEN; all_conns[conn_index].addr = client; char portname[256]; if(getnameinfo(&client, sizeof(client), all_conns[conn_index].sname, SNAME_LEN, portname, 255, NI_NAMEREQD|NI_NUMERICHOST)) strcpy(all_conns[conn_index].sname, "<unknown>"); total_conns++; return; } } fprintf(stderr, "new_conn_handler: sanity check failed!\n"); }
/* * This is the new connection handler. This function is called by the * event handler when data is pending on the listening socket (conn_fd). * If space is available, an interactive data structure is initialized and * the connected is established. */ void new_conn_handler() { struct sockaddr_in client; int client_len; struct hostent *c_hostent; int new_fd; int conn_index; client_len = sizeof(client); new_fd = accept(conn_fd, (struct sockaddr *) & client, (int *) &client_len); if (new_fd == -1) { socket_perror("new_conn_handler: accept", 0); return; } if (set_socket_nonblocking(new_fd, 1) == -1) { socket_perror("new_conn_handler: set_socket_nonblocking 1", 0); OS_socket_close(new_fd); return; } if (total_conns >= MAX_CONNS) { char *message = "no available slots -- closing connection.\n"; fprintf(stderr, "new_conn_handler: no available connection slots.\n"); OS_socket_write(new_fd, message, strlen(message)); if (OS_socket_close(new_fd) == -1) socket_perror("new_conn_handler: close", 0); return; } /* get some information about new connection */ c_hostent = gethostbyaddr((char *) &client.sin_addr.s_addr, sizeof(client.sin_addr.s_addr), AF_INET); for (conn_index = 0; conn_index < MAX_CONNS; conn_index++) { if (all_conns[conn_index].state == CONN_CLOSED) { DBG(("new_conn_handler: opening conn index %d", conn_index)); /* update global data for new fd */ all_conns[conn_index].fd = new_fd; all_conns[conn_index].state = CONN_OPEN; all_conns[conn_index].addr = client; if (c_hostent) strcpy(all_conns[conn_index].sname, c_hostent->h_name); else strcpy(all_conns[conn_index].sname, "<unknown>"); total_conns++; return; } } fprintf(stderr, "new_conn_handler: sanity check failed!\n"); }
int main (void) { socket_t *sock; ssize_t bytes; struct sockaddr_in address; if(NULL == (sock = socket_new(AF_INET, SOCK_STREAM, IPPROTO_IP)) ) { socket_perror(); exit(1); } address.sin_family = AF_INET; address.sin_port = htons(8585); inet_aton("127.0.0.1", &address.sin_addr); if(!socket_connect(sock, (struct sockaddr*)&address, (socklen_t)sizeof(address)) ) { socket_perror(); exit(1); } if(!socket_isconnected(sock)) { socket_perror(); puts("not connected!"); } if(!socket_send(sock,"this is a test 1", 17, MSG_NOFLAGS, &bytes) ) { socket_perror(); exit(1); } if(!socket_close(sock) ) { socket_perror(); exit(1); } return 0; }
static int socket_write(struct imap_socket *sock, const char *buf, int len) { int n; #ifndef NO_OPENSSL if (sock->ssl) n = SSL_write(sock->ssl, buf, len); else #endif n = write_in_full(sock->fd[1], buf, len); if (n != len) { socket_perror("write", sock, n); close(sock->fd[0]); close(sock->fd[1]); sock->fd[0] = sock->fd[1] = -1; } return n; }
static int socket_read(struct imap_socket *sock, char *buf, int len) { ssize_t n; #ifndef NO_OPENSSL if (sock->ssl) n = SSL_read(sock->ssl, buf, len); else #endif n = xread(sock->fd[0], buf, len); if (n <= 0) { socket_perror("read", sock, n); close(sock->fd[0]); close(sock->fd[1]); sock->fd[0] = sock->fd[1] = -1; } return n; }
void terminate (int conn_index) { if (conn_index < 0 || conn_index >= MAX_CONNS) { fprintf(stderr, "terminate: conn_index %d out of range.\n", conn_index); return; } if (all_conns[conn_index].state == CONN_CLOSED) { fprintf(stderr, "terminate: connection %d already closed.\n", conn_index); return; } DBG(("terminating connection %d", conn_index)); if (OS_socket_close(all_conns[conn_index].fd) == -1) { socket_perror("terminate: close", 0); return; } all_conns[conn_index].state = CONN_CLOSED; total_conns--; }
/* * Initialize connection socket. */ void init_conn_sock (int port_num, char * ipaddress) { #ifdef IPV6 struct sockaddr_in6 sin; #else struct sockaddr_in sin; #endif socklen_t sin_len; int optval; #ifdef WINSOCK WSADATA WSAData; WSAStartup(MAKEWORD(1,1), &WSAData); atexit(cleanup_sockets); #endif /* * create socket of proper type. */ #ifdef IPV6 if ((conn_fd = socket(AF_INET6, SOCK_STREAM, 0)) == INVALID_SOCKET) { #else if ((conn_fd = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) { #endif socket_perror("init_conn_sock: socket", 0); exit(1); } /* * enable local address reuse. */ optval = 1; if (setsockopt(conn_fd, SOL_SOCKET, SO_REUSEADDR, (char *) &optval, sizeof(optval)) == -1) { socket_perror("init_conn_sock: setsockopt", 0); exit(2); } /* * fill in socket address information. */ #ifdef IPV6 sin.sin6_family = AF_INET6; if(ipaddress) inet_pton(AF_INET6, ipaddress, &(sin.sin6_addr)); else sin.sin6_addr = in6addr_any; sin.sin6_port = htons((u_short) port_num); #else sin.sin_family = AF_INET; sin.sin_addr.s_addr = (ipaddress ? inet_addr(ipaddress) : INADDR_ANY); sin.sin_port = htons((u_short) port_num); #endif /* * bind name to socket. */ if (bind(conn_fd, (struct sockaddr *) & sin, sizeof(sin)) == -1) { socket_perror("init_conn_sock: bind", 0); exit(3); } /* * get socket name. */ sin_len = sizeof(sin); if (getsockname(conn_fd, (struct sockaddr *) & sin, &sin_len) == -1) { socket_perror("init_conn_sock: getsockname", 0); exit(4); } /* * register signal handler for SIGPIPE. */ #if defined(SIGPIPE) && defined(SIGNAL_ERROR)/* windows has no SIGPIPE */ if (signal(SIGPIPE, sigpipe_handler) == SIGNAL_ERROR) { socket_perror("init_conn_sock: signal SIGPIPE", 0); exit(5); } #endif /* * set socket non-blocking */ if (set_socket_nonblocking(conn_fd, 1) == -1) { socket_perror("init_conn_sock: set_socket_nonblocking 1", 0); exit(8); } /* * listen on socket for connections. */ if (listen(conn_fd, 128) == -1) { socket_perror("init_conn_sock: listen", 0); exit(10); } DBG(("listening for connections on port %d", port_num)); } /* * SIGPIPE handler -- does very little for now. */ #ifdef SIGNAL_FUNC_TAKES_INT void sigpipe_handler (int sig) { #else void sigpipe_handler() { #endif fprintf(stderr, "SIGPIPE received.\n"); }
void conn_data_handler (int fd) { int conn_index; int buf_index; int num_bytes; int msgtype; int leftover; char *buf; int res, msglen, expecting; long unread_bytes; if ((conn_index = index_by_fd(fd)) == -1) { fprintf(stderr, "conn_data_handler: invalid fd.\n"); return; } DBG(("conn_data_handler: read on fd %d", fd)); /* append new data to end of leftover data (if any) */ leftover = all_conns[conn_index].leftover; buf = (char *) &all_conns[conn_index].buf[0]; num_bytes = OS_socket_read(fd, buf + leftover, (IN_BUF_SIZE - 1) - leftover); switch (num_bytes) { case -1: switch (socket_errno) { case EWOULDBLOCK: DBG(("conn_data_handler: read on fd %d: Operation would block.", fd)); break; default: socket_perror("conn_data_handler: read", 0); terminate(conn_index); break; } break; case 0: if (all_conns[conn_index].state == CONN_CLOSED) fprintf(stderr, "get_user_data: tried to read from closed fd.\n"); terminate(conn_index); break; default: DBG(("conn_data_handler: read %d bytes on fd %d", num_bytes, fd)); num_bytes += leftover; buf_index = 0; expecting = 0; while (num_bytes > sizeof(int) && buf_index < (IN_BUF_SIZE - 1)) { /* get message type */ memcpy((char *) &msgtype, (char *) &buf[buf_index], sizeof(int)); DBG(("conn_data_handler: message type: %d", msgtype)); if (msgtype == NAMEBYIP) { if (buf[buf_index + sizeof(int)] == '\0') { /* no data here...resync */ buf_index++; num_bytes--; continue; } if (expecting && num_bytes < expecting) { /* * message truncated...back up to DATALEN message; exit * loop...and try again later */ buf_index -= (sizeof(int) + sizeof(int)); num_bytes += (sizeof(int) + sizeof(int)); break; } res = name_by_ip(conn_index, &buf[buf_index]); } else if (msgtype == IPBYNAME) { if (buf[buf_index + sizeof(int)] == '\0') { /* no data here...resync */ buf_index++; num_bytes--; continue; } if (expecting && num_bytes < expecting) { /* * message truncated...back up to DATALEN message; exit * loop...and try again later */ buf_index -= (sizeof(int) + sizeof(int)); num_bytes += (sizeof(int) + sizeof(int)); break; } res = ip_by_name(conn_index, &buf[buf_index]); } else if (msgtype == DATALEN) { if (num_bytes > (sizeof(int) + sizeof(int))) { memcpy((char *) &expecting, (char *) &buf[buf_index + sizeof(int)], sizeof(int)); /* * advance to next message */ buf_index += (sizeof(int) + sizeof(int)); num_bytes -= (sizeof(int) + sizeof(int)); if (expecting > IN_BUF_SIZE || expecting <= 0) { fprintf(stderr, "conn_data_handler: bad data length %d\n", expecting); expecting = 0; } continue; } else { /* * not enough bytes...assume truncated; exit loop...we'll * handle this message later */ break; } } else { fprintf(stderr, "conn_data_handler: unknown message type %08x\n", msgtype); /* advance through buffer */ buf_index++; num_bytes--; continue; } msglen = (int) (sizeof(int) + strlen(&buf[buf_index + sizeof(int)]) +1); if (res) { /* * ok...advance to next message */ buf_index += msglen; num_bytes -= msglen; } else if (msglen < num_bytes || (expecting && expecting == msglen)) { /* * failed... */ /* * this was a complete message...advance to the next one */ msglen = (int) (sizeof(int) + strlen(&buf[buf_index + sizeof(int)]) +1); buf_index += msglen; num_bytes -= msglen; expecting = 0; } else if (!OS_socket_ioctl(fd, FIONREAD, &unread_bytes) && unread_bytes > 0) { /* * msglen == num_bytes could be a complete message... if * there's unread data we'll assume it was truncated */ break; } else { /* * nothing more? then discard message (it was the last one) */ buf_index = 0; num_bytes = 0; break; } } /* keep track of leftover buffer contents */ if (num_bytes && buf_index) memmove(buf, &buf[buf_index], num_bytes); buf[num_bytes] = '\0'; all_conns[conn_index].leftover = num_bytes; break; } }
/* * Create an LPC efun socket */ int socket_create (enum socket_mode mode, svalue_t * read_callback, svalue_t * close_callback) { int type, i, fd, optval; #ifndef NO_BUFFER_TYPE int binary = 0; if (mode == STREAM_BINARY) { binary = 1; mode = STREAM; } else if (mode == DATAGRAM_BINARY) { binary = 1; mode = DATAGRAM; } #endif switch (mode) { case MUD: case STREAM: type = SOCK_STREAM; break; case DATAGRAM: type = SOCK_DGRAM; break; default: return EEMODENOTSUPP; } i = find_new_socket(); if (i >= 0) { #ifdef IPV6 fd = socket(PF_INET6, type, 0); #else fd = socket(PF_INET, type, 0); #endif if (fd == INVALID_SOCKET) { socket_perror("socket_create: socket", 0); return EESOCKET; } optval = 1; if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &optval, sizeof(optval)) == -1) { socket_perror("socket_create: setsockopt", 0); OS_socket_close(fd); return EESETSOCKOPT; } if (set_socket_nonblocking(fd, 1) == -1) { socket_perror("socket_create: set_socket_nonblocking", 0); OS_socket_close(fd); return EENONBLOCK; } lpc_socks[i].fd = fd; lpc_socks[i].flags = S_HEADER; if (type == SOCK_DGRAM) close_callback = 0; set_read_callback(i, read_callback); set_write_callback(i, 0); set_close_callback(i, close_callback); #ifndef NO_BUFFER_TYPE if (binary) { lpc_socks[i].flags |= S_BINARY; } #endif lpc_socks[i].mode = mode; lpc_socks[i].state = STATE_UNBOUND; memset((char *) &lpc_socks[i].l_addr, 0, sizeof(lpc_socks[i].l_addr)); memset((char *) &lpc_socks[i].r_addr, 0, sizeof(lpc_socks[i].r_addr)); lpc_socks[i].owner_ob = current_object; lpc_socks[i].release_ob = NULL; lpc_socks[i].r_buf = NULL; lpc_socks[i].r_off = 0; lpc_socks[i].r_len = 0; lpc_socks[i].w_buf = NULL; lpc_socks[i].w_off = 0; lpc_socks[i].w_len = 0; current_object->flags |= O_EFUN_SOCKET; debug(sockets, ("socket_create: created socket %d mode %d fd %d\n", i, mode, fd)); } return i; }
static int ssl_socket_connect(struct imap_socket *sock, int use_tls_only, int verify) { #if (OPENSSL_VERSION_NUMBER >= 0x10000000L) const SSL_METHOD *meth; #else SSL_METHOD *meth; #endif SSL_CTX *ctx; int ret; X509 *cert; SSL_library_init(); SSL_load_error_strings(); meth = SSLv23_method(); if (!meth) { ssl_socket_perror("SSLv23_method"); return -1; } ctx = SSL_CTX_new(meth); if (!ctx) { ssl_socket_perror("SSL_CTX_new"); return -1; } if (use_tls_only) SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); if (verify) SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); if (!SSL_CTX_set_default_verify_paths(ctx)) { ssl_socket_perror("SSL_CTX_set_default_verify_paths"); return -1; } sock->ssl = SSL_new(ctx); if (!sock->ssl) { ssl_socket_perror("SSL_new"); return -1; } if (!SSL_set_rfd(sock->ssl, sock->fd[0])) { ssl_socket_perror("SSL_set_rfd"); return -1; } if (!SSL_set_wfd(sock->ssl, sock->fd[1])) { ssl_socket_perror("SSL_set_wfd"); return -1; } #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME /* * SNI (RFC4366) * OpenSSL does not document this function, but the implementation * returns 1 on success, 0 on failure after calling SSLerr(). */ ret = SSL_set_tlsext_host_name(sock->ssl, server.host); if (ret != 1) warning("SSL_set_tlsext_host_name(%s) failed.", server.host); #endif ret = SSL_connect(sock->ssl); if (ret <= 0) { socket_perror("SSL_connect", sock, ret); return -1; } if (verify) { /* make sure the hostname matches that of the certificate */ cert = SSL_get_peer_certificate(sock->ssl); if (!cert) return error("unable to get peer certificate."); if (verify_hostname(cert, server.host) < 0) return -1; } return 0; }