blob: f04da6b7eb0dd3d43f2a1d9621f8d5c165dec756 [file] [log] [blame]
Holger Hans Peter Freythereef86b52010-06-15 18:45:06 +08001/* Routines to talk to the MSC using the IPA Protocol */
2/*
3 * (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
Holger Hans Peter Freytherdf6143a2010-06-15 18:46:56 +08004 * (C) 2010 by On-Waves
Holger Hans Peter Freythereef86b52010-06-15 18:45:06 +08005 * All Rights Reserved
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 */
22
23#include <openbsc/bsc_msc.h>
Holger Hans Peter Freyther6c0a04e2010-03-26 10:41:20 +010024#include <openbsc/debug.h>
25
26#include <osmocore/write_queue.h>
Holger Hans Peter Freythereef86b52010-06-15 18:45:06 +080027
28#include <arpa/inet.h>
29#include <sys/socket.h>
Holger Hans Peter Freyther6c0a04e2010-03-26 10:41:20 +010030#include <errno.h>
31#include <fcntl.h>
Holger Hans Peter Freythereef86b52010-06-15 18:45:06 +080032#include <stdio.h>
33#include <string.h>
34#include <unistd.h>
35
Holger Hans Peter Freyther6c0a04e2010-03-26 10:41:20 +010036/* called in the case of a non blocking connect */
37static int msc_connection_connect(struct bsc_fd *fd, unsigned int what)
38{
39 int rc;
40 int val;
41 struct write_queue *queue;
42
43 socklen_t len = sizeof(val);
44
45 if ((what & BSC_FD_WRITE) == 0) {
46 LOGP(DMSC, LOGL_ERROR, "Callback but not readable.\n");
47 return -1;
48 }
49
50 /* check the socket state */
51 rc = getsockopt(fd->fd, SOL_SOCKET, SO_ERROR, &val, &len);
52 if (rc != 0) {
53 LOGP(DMSC, LOGL_ERROR, "getsockopt for the MSC socket failed.\n");
54 goto error;
55 }
56 if (val != 0) {
57 LOGP(DMSC, LOGL_ERROR, "Not connected to the MSC.\n");
58 goto error;
59 }
60
61
62 /* go to full operation */
63 queue = container_of(fd, struct write_queue, bfd);
64 fd->cb = write_queue_bfd_cb;
65 fd->when = BSC_FD_READ;
66 if (!llist_empty(&queue->msg_queue))
67 fd->when |= BSC_FD_WRITE;
68 return 0;
69
70error:
71 bsc_unregister_fd(fd);
72 close(fd->fd);
73 fd->fd = -1;
74 fd->cb = write_queue_bfd_cb;
75 fd->when = 0;
76 return -1;
77}
78static void setnonblocking(struct bsc_fd *fd)
79{
80 int flags;
81
82 flags = fcntl(fd->fd, F_GETFL);
83 if (flags < 0) {
84 perror("fcntl get failed");
85 close(fd->fd);
86 fd->fd = -1;
87 return;
88 }
89
90 flags |= O_NONBLOCK;
91 flags = fcntl(fd->fd, F_SETFL, flags);
92 if (flags < 0) {
93 perror("fcntl get failed");
94 close(fd->fd);
95 fd->fd = -1;
96 return;
97 }
98}
99
Holger Hans Peter Freythereef86b52010-06-15 18:45:06 +0800100int connect_to_msc(struct bsc_fd *fd, const char *ip, int port)
101{
102 struct sockaddr_in sin;
103 int on = 1, ret;
104
105 printf("Attempting to connect MSC at %s:%d\n", ip, port);
106
107 fd->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
Holger Hans Peter Freythereef86b52010-06-15 18:45:06 +0800108 fd->data = NULL;
109 fd->priv_nr = 1;
110
111 if (fd->fd < 0) {
112 perror("Creating TCP socket failed");
113 return fd->fd;
114 }
115
Holger Hans Peter Freyther6c0a04e2010-03-26 10:41:20 +0100116 /* make it non blocking */
117 setnonblocking(fd);
Holger Hans Peter Freythereef86b52010-06-15 18:45:06 +0800118
119 memset(&sin, 0, sizeof(sin));
120 sin.sin_family = AF_INET;
121 sin.sin_port = htons(port);
122 inet_aton(ip, &sin.sin_addr);
123
124 setsockopt(fd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
125 ret = connect(fd->fd, (struct sockaddr *) &sin, sizeof(sin));
126
Holger Hans Peter Freyther6c0a04e2010-03-26 10:41:20 +0100127 if (ret == -1 && errno == EINPROGRESS) {
128 LOGP(DMSC, LOGL_ERROR, "MSC Connection in progress\n");
129 fd->when = BSC_FD_WRITE;
130 fd->cb = msc_connection_connect;
131 } else if (ret < 0) {
Holger Hans Peter Freythereef86b52010-06-15 18:45:06 +0800132 perror("Connection failed");
Holger Hans Peter Freyther6c0a04e2010-03-26 10:41:20 +0100133 close(fd->fd);
134 fd->fd = -1;
Holger Hans Peter Freythereef86b52010-06-15 18:45:06 +0800135 return ret;
Holger Hans Peter Freyther6c0a04e2010-03-26 10:41:20 +0100136 } else {
137 fd->when = BSC_FD_READ;
138 fd->cb = write_queue_bfd_cb;
Holger Hans Peter Freythereef86b52010-06-15 18:45:06 +0800139 }
140
141 ret = bsc_register_fd(fd);
142 if (ret < 0) {
143 perror("Registering the fd failed");
144 close(fd->fd);
145 return ret;
146 }
147
148 return ret;
149}