📄 sock.c
字号:
/* * should be used by all gsms network code to support timeouts * and esy porting * * Authors: Michael Jochum <e9725005@stud3.tuwien.ac.at> * Gerhard Khueny <e9625442@student.tuwien.ac.at> * TODO: * * Fixes: * * For license terms, see the file COPYING in the project directory. */#include <stdio.h>#include <unistd.h>#include <fcntl.h>#include <string.h>#include <errno.h>#include <unistd.h>#include <sys/types.h>#include <sys/socket.h>#include <sys/time.h>#include <netinet/in.h>#include <netdb.h>#include <signal.h>#include <assert.h>/* #include <gnome-i18n.h> */#include <gnome.h>#include <glib.h>#include "sock.h"#ifndef SOCKET_LOG_DOMAIN#define SOCKET_LOG_DOMAIN "SOCKET" #endif/* calls select and waits for input on s */static gint wait_for_data(const GSmsSocket * s){ fd_set read_fd_set; struct timeval tv; gint res; tv.tv_sec = s->timeout; tv.tv_usec = 0; FD_ZERO(&read_fd_set); FD_SET(s->fd, &read_fd_set); /* Block until input arrives or time is up. */ res = select(s->fd + 1, &read_fd_set, NULL, NULL, &tv); if (res == 0) { g_log(SOCKET_LOG_DOMAIN, G_LOG_LEVEL_WARNING, _("Timeout while reading from socket")); return GSMS_SOCKET_ERR_TIMEOUT; } if (res < 0) { g_log(SOCKET_LOG_DOMAIN, G_LOG_LEVEL_WARNING, _("Error reading from socket (select): %s"), strerror(errno)); return GSMS_SOCKET_ERR_ERRNO; } return GSMS_SOCKET_SUCCESS;}/* allocate socket struct, set timout and create the socket */GSmsSocket *gsms_socket_create(gint timeout){ GSmsSocket *s; s = g_new(GSmsSocket, 1); s->timeout = timeout; g_log(SOCKET_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, _("Creating new socket with %ds timeout."), timeout); /* Create the socket. */ if ((s->fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) { g_free(s); g_log(SOCKET_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, _("Creating socket.")); return NULL; } return s;}/* open connection - connecto to a specified host *//* TODO: Timeout for gethostbyname (not easy) */gint gsms_socket_open_connection(const GSmsSocket * s, const gchar * host, const guint16 port){ struct sockaddr_in servername; struct hostent *hostinfo; gint flags; fd_set write_fd_set; struct timeval tv; gint res; g_return_val_if_fail(s != NULL, GSMS_SOCKET_ERR); g_return_val_if_fail(host != NULL, GSMS_SOCKET_ERR); /* resolv hostname --- TODO: add timeout */ g_log(SOCKET_LOG_DOMAIN, G_LOG_LEVEL_INFO, _("Resolving hostname for %s"), host); hostinfo = gethostbyname(host); if (hostinfo == NULL) return GSMS_SOCKET_ERR_UNKNOWN_HOST; /* connetct to host with timeout */ servername.sin_family = AF_INET; servername.sin_port = htons(port); servername.sin_addr = *(struct in_addr *) hostinfo->h_addr; g_log(SOCKET_LOG_DOMAIN, G_LOG_LEVEL_INFO, _("Connecting to host %s:%d"), host, port); /* Get the flags (should all be 0?) */ flags = fcntl(s->fd, F_GETFL, 0); if (flags == -1) { g_log(SOCKET_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, _("could not get flags for network socket")); return GSMS_SOCKET_ERR; } if (fcntl(s->fd, F_SETFL, flags | O_NONBLOCK) == -1) { g_log(SOCKET_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, _("could not set nonblocking mode for network socket")); return GSMS_SOCKET_ERR; } /* Connect (but non-blocking!) */ res = connect(s->fd, (struct sockaddr *) &servername, sizeof(servername)); if (res < 0) { if (errno != EINPROGRESS) { g_log(SOCKET_LOG_DOMAIN, G_LOG_LEVEL_WARNING, _("error connecting %s:%d : %s"), host, port, strerror(errno)); return GSMS_SOCKET_ERR_ERRNO; } } tv.tv_sec = s->timeout; tv.tv_usec = 0; FD_ZERO(&write_fd_set); FD_SET(s->fd, &write_fd_set); /* Block until input arrives or time is up. */ res = select(s->fd + 1, NULL, &write_fd_set, NULL, &tv); if (res == 0) { g_log(SOCKET_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, _("Timeout while trying to connect to %s:%d"), host, port); return GSMS_SOCKET_ERR_TIMEOUT; } if (res < 0) { g_log(SOCKET_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, _("select failed while connecting to host %s:%d : %s"), host, port, strerror(errno)); return GSMS_SOCKET_ERR_ERRNO; } if (FD_ISSET(s->fd, &write_fd_set)) { gint error, len; len = sizeof(error); /* Get the error option */ if (getsockopt (s->fd, SOL_SOCKET, SO_ERROR, (void *) &error, &len) >= 0) { /* Check if there is an error */ if (!error) { /* Reset the flags */ if (fcntl(s->fd, F_SETFL, flags) == 0) { return GSMS_SOCKET_SUCCESS; } } } } g_log(SOCKET_LOG_DOMAIN, G_LOG_LEVEL_WARNING, _("could not connect to %s:%d : %s"), host, port, strerror(errno)); return GSMS_SOCKET_ERR;}/* close socket and free struct */gint gsms_socket_close(GSmsSocket * s){ g_return_val_if_fail(s != NULL, GSMS_SOCKET_ERR); close(s->fd); g_free(s); return GSMS_SOCKET_SUCCESS;}/* set the socket timeout in seconds */void gsms_socket_set_timeout(GSmsSocket * s, guint timeout){ g_return_if_fail(s != NULL); s->timeout = timeout; return;}/* reads up to len bytes from s and saves them into buffer */gint gsms_socket_read(const GSmsSocket * s, gchar * buffer, gint len){ int res; g_return_val_if_fail(s != NULL, GSMS_SOCKET_ERR); g_return_val_if_fail(buffer != NULL, GSMS_SOCKET_ERR); g_return_val_if_fail(len > 0, GSMS_SOCKET_ERR); res = wait_for_data(s); if (res < 0) return res; res = read(s->fd, buffer, len); if (res < 0) { g_log(SOCKET_LOG_DOMAIN, G_LOG_LEVEL_WARNING, _("Error reading from socket: %s"), strerror(errno)); return GSMS_SOCKET_ERR_ERRNO; } return res;}/* writes up to len bytes to the socket *//* returnes bytes written */gint gsms_socket_write(const GSmsSocket * s, gchar * buffer, gint len){ int res; fd_set write_fd_set; struct timeval tv; g_return_val_if_fail(s != NULL, GSMS_SOCKET_ERR); g_return_val_if_fail(buffer != NULL, GSMS_SOCKET_ERR); g_return_val_if_fail(len > 0, GSMS_SOCKET_ERR); tv.tv_sec = s->timeout; tv.tv_usec = 0; FD_ZERO(&write_fd_set); FD_SET(s->fd, &write_fd_set); /* Block until input arrives or time is up. */ res = select(s->fd + 1, NULL, &write_fd_set, NULL, &tv); if (res == 0) { g_log(SOCKET_LOG_DOMAIN, G_LOG_LEVEL_WARNING, _("write timed out")); return GSMS_SOCKET_ERR_TIMEOUT; } if (res < 0) { g_log(SOCKET_LOG_DOMAIN, G_LOG_LEVEL_WARNING, _("Error writing to socket (select): %s"), strerror(errno)); return GSMS_SOCKET_ERR_ERRNO; } res = write(s->fd, buffer, len); if (res < 0) { g_log(SOCKET_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, _("Error writng to socket: %s"), strerror(errno)); return GSMS_SOCKET_ERR_ERRNO; } return res;}/* Reads data up to the next newline. If no newline is found within len bytes len bytes from s are returned. */gint gsms_socket_read_line(const GSmsSocket * s, gchar * buffer, gint len){ gint n; gchar *newline; g_return_val_if_fail(s != NULL, GSMS_SOCKET_ERR); g_return_val_if_fail(buffer != NULL, GSMS_SOCKET_ERR); g_return_val_if_fail(len > 0, GSMS_SOCKET_ERR); len--; n = wait_for_data(s); if (n < 0) return n; /* get next data but leave them in the network input buffer */ if ((n = recv(s->fd, buffer, len, MSG_PEEK)) <= 0) { g_log(SOCKET_LOG_DOMAIN, G_LOG_LEVEL_WARNING, _("Error reading line from socket (recv): %s"), strerror(errno)); return GSMS_SOCKET_ERR_ERRNO; } if ((newline = (char *) memchr(buffer, '\n', n)) != NULL) n = newline - buffer + 1; if ((n = read(s->fd, buffer, n)) == -1) { g_log(SOCKET_LOG_DOMAIN, G_LOG_LEVEL_WARNING, _("Error reading line from socket: %s"), strerror(errno)); return GSMS_SOCKET_ERR_ERRNO; } buffer += n; *buffer = '\0'; return n;}gint gsms_socket_write_str(const GSmsSocket * s, gchar * buffer){ g_return_val_if_fail(s != NULL, GSMS_SOCKET_ERR); g_return_val_if_fail(buffer != NULL, GSMS_SOCKET_ERR); return gsms_socket_write(s, buffer, strlen(buffer));}/* read exactly len bytes from input */gint gsms_socket_read_block(const GSmsSocket * s, gchar * buf, gint len){ gint res; gint bytes_read = 0; g_return_val_if_fail(s != NULL, GSMS_SOCKET_ERR); g_return_val_if_fail(buf != NULL, GSMS_SOCKET_ERR); g_return_val_if_fail(len > 0, GSMS_SOCKET_ERR); while ((res = gsms_socket_read(s, buf, len)) > 0) { buf += res; bytes_read += res; len -= res; if (len == 0) break; g_return_val_if_fail(len > 0, GSMS_SOCKET_ERR); } if (res < 0) return res; return bytes_read;}/* write eaxtly len bytes */gint gsms_socket_write_block(const GSmsSocket * s, gchar * buf, gint len){ gint res; g_return_val_if_fail(s != NULL, GSMS_SOCKET_ERR); g_return_val_if_fail(buf != NULL, GSMS_SOCKET_ERR); g_return_val_if_fail(len > 0, GSMS_SOCKET_ERR); while ((res = gsms_socket_write(s, buf, len)) < len) { buf += res; len -= res; if (len == 0) break; g_return_val_if_fail(len > 0, GSMS_SOCKET_ERR); } if (res < 0) return res; return GSMS_SOCKET_SUCCESS;}gint gsms_socket_printf(const GSmsSocket * s, gchar * format, ...){ va_list ap; gchar *buf; gint res; g_return_val_if_fail(s != NULL, GSMS_SOCKET_ERR); g_return_val_if_fail(format != NULL, GSMS_SOCKET_ERR); va_start(ap, format); buf = g_strdup_vprintf(format, ap); res = gsms_socket_write_str(s, buf); g_free(buf); return res;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -